def test_nobuildmethod(): x, y, c = hl.Var(), hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() b_in = hl.Buffer(hl.Float(32), [2, 2]) b_in.fill(123) b_out = hl.Buffer(hl.Int(32), [2, 2]) f = nobuildmethod.generate(target, b_in, 1.0) f.realize(b_out) assert b_out.all_equal(123)
def test_partialbuildmethod(): x, y, c = hl.Var(), hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() b_in = hl.Buffer(hl.Float(32), [2, 2]) b_in.fill(123) b_out = hl.Buffer(hl.Int(32), [2, 2]) try: f = partialbuildmethod.generate(target, b_in, 1) except RuntimeError as e: assert "Generators that use build() (instead of generate()+Output<>) are not supported in the Python bindings." in str(e) else: assert False, 'Did not see expected exception!'
def test_looplevel(): x, y = hl.Var('x'), hl.Var('y') target = hl.get_jit_target_from_environment() buffer_input = hl.Buffer(hl.UInt(8), [4, 4]) buffer_input.fill(123) func_input = hl.Func("func_input") func_input[x, y] = x + y simple_compute_at = hl.LoopLevel() simple = simplestub.generate(target, buffer_input, func_input, 3.5, compute_level=simple_compute_at) computed_output = hl.Func('computed_output') computed_output[x, y] = simple[x, y] + 3 simple_compute_at.set(hl.LoopLevel(computed_output, x)) _realize_and_check(computed_output, 3)
def get_bilateral_grid(input, r_sigma, s_sigma, aot=False): x = hl.Var('x') y = hl.Var('y') z = hl.Var('z') c = hl.Var('c') # Add a boundary condition clamped = hl.BoundaryConditions.repeat_edge(input) # Construct the bilateral grid r = hl.RDom([(0, s_sigma), (0, s_sigma)], 'r') val = clamped[x * s_sigma + r.x - s_sigma // 2, y * s_sigma + r.y - s_sigma // 2] val = hl.clamp(val, 0.0, 1.0) zi = hl.i32(val / r_sigma + 0.5) histogram = hl.Func('histogram') histogram[x, y, z, c] = 0.0 histogram[x, y, zi, c] += hl.select(c == 0, val, 1.0) # Blur the histogram using a five-tap filter blurx, blury, blurz = hl.Func('blurx'), hl.Func('blury'), hl.Func('blurz') blurz[x, y, z, c] = histogram[x, y, z - 2, c] + histogram[ x, y, z - 1, c] * 4 + histogram[x, y, z, c] * 6 + histogram[ x, y, z + 1, c] * 4 + histogram[x, y, z + 2, c] blurx[x, y, z, c] = blurz[x - 2, y, z, c] + blurz[x - 1, y, z, c] * 4 + blurz[ x, y, z, c] * 6 + blurz[x + 1, y, z, c] * 4 + blurz[x + 2, y, z, c] blury[x, y, z, c] = blurx[x, y - 2, z, c] + blurx[x, y - 1, z, c] * 4 + blurx[ x, y, z, c] * 6 + blurx[x, y + 1, z, c] * 4 + blurx[x, y + 2, z, c] # Take trilinear samples to compute the output val = hl.clamp(clamped[x, y], 0.0, 1.0) zv = val / r_sigma zi = hl.i32(zv) zf = zv - zi xf = hl.f32(x % s_sigma) / s_sigma yf = hl.f32(y % s_sigma) / s_sigma xi = x / s_sigma yi = y / s_sigma interpolated = hl.Func('interpolated') interpolated[x, y, c] = hl.lerp( hl.lerp( hl.lerp(blury[xi, yi, zi, c], blury[xi + 1, yi, zi, c], xf), hl.lerp(blury[xi, yi + 1, zi, c], blury[xi + 1, yi + 1, zi, c], xf), yf), hl.lerp( hl.lerp(blury[xi, yi, zi + 1, c], blury[xi + 1, yi, zi + 1, c], xf), hl.lerp(blury[xi, yi + 1, zi + 1, c], blury[xi + 1, yi + 1, zi + 1, c], xf), yf), zf) # Normalize bilateral_grid = hl.Func('bilateral_grid') bilateral_grid[x, y] = interpolated[x, y, 0] / interpolated[x, y, 1] if aot: target = hl.get_target_from_environment() else: target = hl.get_jit_target_from_environment() if target.has_gpu_feature(): # GPU schedule # Currently running this directly from the Python code is very slow. # Probably because of the dispatch time because generated code # is same speed as C++ generated code. print("Compiling for GPU.") xb = hl.Var('xb') yb = hl.Var('yb') zb = hl.Var('zb') histogram.compute_root().reorder(c, z, x, y).gpu_tile(x, y, xb, yb, 8, 8) histogram.update().reorder(c, r.x, r.y, x, y).gpu_tile(x, y, xb, yb, 8, 8).unroll(c) blurx.compute_root().gpu_tile(x, y, z, xb, yb, zb, 16, 16, 1) blury.compute_root().gpu_tile(x, y, z, xb, yb, zb, 16, 16, 1) blurz.compute_root().gpu_tile(x, y, z, xb, yb, zb, 8, 8, 4) bilateral_grid.compute_root().gpu_tile(x, y, xb, yb, s_sigma, s_sigma) else: # CPU schedule print("Compiling for CPU.") histogram.compute_root().parallel(z) histogram.update().reorder(c, r.x, r.y, x, y).unroll(c) blurz.compute_root().reorder(c, z, x, y).parallel(y).vectorize(x, 4).unroll(c) blurx.compute_root().reorder(c, x, y, z).parallel(z).vectorize(x, 4).unroll(c) blury.compute_root().reorder(c, x, y, z).parallel(z).vectorize(x, 4).unroll(c) bilateral_grid.compute_root().parallel(y).vectorize(x, 4) return bilateral_grid
def test_simplestub(): x, y = hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() b_in = hl.Buffer(hl.UInt(8), [2, 2]) b_in.fill(123) f_in = hl.Func("f") f_in[x, y] = x + y # ----------- Inputs by-position f = simplestub.generate(target, b_in, f_in, 3.5) _realize_and_check(f) # ----------- Inputs by-name f = simplestub.generate(target, buffer_input=b_in, func_input=f_in, float_arg=3.5) _realize_and_check(f) # ----------- Inputs w/ mixed by-position and by-name f = simplestub.generate(target, b_in, f_in, float_arg=3.5) _realize_and_check(f) f = simplestub.generate(target, b_in, float_arg=3.5, func_input=f_in) _realize_and_check(f) # ----------- Above set again, w/ GeneratorParam mixed in k = 42 f = simplestub.generate(target, b_in, f_in, 3.5, offset=k) _realize_and_check(f, k) f = simplestub.generate(target, offset=k, buffer_input=b_in, func_input=f_in, float_arg=3.5) _realize_and_check(f, k) f = simplestub.generate(target, b_in, f_in, offset=k, float_arg=3.5) _realize_and_check(f, k) f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, func_input=f_in) _realize_and_check(f, k) # ----------- Test various failure modes try: # too many positional args f = simplestub.generate(target, b_in, f_in, 3.5, 4) except RuntimeError as e: assert 'Expected at most 3 positional args, but saw 4.' in str(e) else: assert False, 'Did not see expected exception!' try: # Inputs that can't be converted to what the receiver needs (positional) f = simplestub.generate(target, 3.141592, "happy") except RuntimeError as e: assert 'Unable to cast Python instance' in str(e) else: assert False, 'Did not see expected exception!' try: # Inputs that can't be converted to what the receiver needs (named) f = simplestub.generate(target, b_in, f_in, float_arg="bogus") except RuntimeError as e: assert 'Unable to cast Python instance' in str(e) else: assert False, 'Did not see expected exception!' try: # Missing required inputs f = simplestub.generate(target, b_in, f_in) except RuntimeError as e: assert "Generator Input named 'float_arg' was not specified." in str(e) else: assert False, 'Did not see expected exception!' try: # Input specified by both pos and kwarg f = simplestub.generate(target, b_in, f_in, 3.5, float_arg=4.5) except RuntimeError as e: assert "Generator Input named 'float_arg' was specified by both position and keyword." in str( e) else: assert False, 'Did not see expected exception!' try: # Bad input name f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, funk_input=f_in) except RuntimeError as e: assert "Generator Input named 'func_input' was not specified." in str( e) else: assert False, 'Did not see expected exception!' try: # Bad gp name f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, func_input=f_in, nonexistent_generator_param="wat") except RuntimeError as e: assert "Generator simplestub has no GeneratorParam named: nonexistent_generator_param" in str( e) else: assert False, 'Did not see expected exception!'
def test_complexstub(): constant_image = _make_constant_image() input = hl.ImageParam(hl.UInt(8), 3, 'input') input.set(constant_image) x, y, c = hl.Var(), hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() float_arg = 1.25 int_arg = 33 r = complexstub(target, typed_buffer_input=constant_image, untyped_buffer_input=constant_image, simple_input=input, array_input=[input, input], float_arg=float_arg, int_arg=[int_arg, int_arg], untyped_buffer_output_type="uint8", vectorize=True) # return value is a tuple; unpack separately to avoid # making the callsite above unreadable (simple_output, tuple_output, array_output, typed_buffer_output, untyped_buffer_output, static_compiled_buffer_output) = r b = simple_output.realize(32, 32, 3, target) assert b.type() == hl.Float(32) for x in range(32): for y in range(32): for c in range(3): expected = constant_image[x, y, c] actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual) b = tuple_output.realize(32, 32, 3, target) assert b[0].type() == hl.Float(32) assert b[1].type() == hl.Float(32) assert len(b) == 2 for x in range(32): for y in range(32): for c in range(3): expected1 = constant_image[x, y, c] * float_arg expected2 = expected1 + int_arg actual1, actual2 = b[0][x, y, c], b[1][x, y, c] assert expected1 == actual1, "Expected1 %s Actual1 %s" % ( expected1, actual1) assert expected2 == actual2, "Expected2 %s Actual1 %s" % ( expected2, actual2) assert len(array_output) == 2 for a in array_output: b = a.realize(32, 32, target) assert b.type() == hl.Int(16) for x in range(32): for y in range(32): expected = constant_image[x, y, 0] + int_arg actual = b[x, y] assert expected == actual, "Expected %s Actual %s" % (expected, actual) # TODO: Output<Buffer<>> has additional behaviors useful when a Stub # is used within another Generator; this isn't yet implemented since there # isn't yet Python bindings for Generator authoring. This section # of the test may need revision at that point. b = typed_buffer_output.realize(32, 32, 3, target) assert b.type() == hl.Float(32) for x in range(32): for y in range(32): for c in range(3): expected = constant_image[x, y, c] actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual) b = untyped_buffer_output.realize(32, 32, 3, target) assert b.type() == hl.UInt(8) for x in range(32): for y in range(32): for c in range(3): expected = constant_image[x, y, c] actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual) b = static_compiled_buffer_output.realize(4, 4, 1, target) assert b.type() == hl.UInt(8) for x in range(4): for y in range(4): for c in range(1): expected = constant_image[x, y, c] + 42 actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual)
implicit_bounds_args['exterior'] = test_exterior realize_and_check( bc(**func_input_args), checker, input, test_min, test_extent, test_min, test_extent, vector_width, target) realize_and_check( bc(**image_input_args), checker, input, test_min, test_extent, test_min, test_extent, vector_width, target) realize_and_check( bc(**undef_min_args), checker, input, 0, W, test_min, test_extent, vector_width, target) realize_and_check( bc(**undef_max_args), checker, input, test_min, test_extent, 0, H, vector_width, target) realize_and_check( bc(**implicit_bounds_args), checker, input, test_min, test_extent, test_min, test_extent, vector_width, target) if __name__ == '__main__': target = hl.get_jit_target_from_environment() vector_width_power_max = 6 # https://github.com/halide/Halide/issues/2148 if target.has_feature(hl.TargetFeature.Metal): vector_width_power_max = 3; for i in range(0, vector_width_power_max): vector_width = 1 << i test_all(vector_width, target)
def test_simple(gen): x, y = hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() b_in = hl.Buffer(hl.UInt(8), [2, 2]) b_in.fill(123) f_in = hl.Func("f") f_in[x, y] = x + y # ----------- Inputs by-position f = gen(target, b_in, f_in, 3.5) _realize_and_check(f) # ----------- Inputs by-name f = gen(target, buffer_input=b_in, func_input=f_in, float_arg=3.5) _realize_and_check(f) f = gen(target, float_arg=3.5, buffer_input=b_in, func_input=f_in) _realize_and_check(f) # ----------- Above set again, w/ GeneratorParam mixed in k = 42 gp = {"offset": k} # (positional) f = gen(target, b_in, f_in, 3.5, generator_params=gp) _realize_and_check(f, k) # (keyword) f = gen(target, generator_params=gp, buffer_input=b_in, func_input=f_in, float_arg=3.5) _realize_and_check(f, k) f = gen(target, buffer_input=b_in, generator_params=gp, func_input=f_in, float_arg=3.5) _realize_and_check(f, k) f = gen(target, buffer_input=b_in, func_input=f_in, generator_params=gp, float_arg=3.5) _realize_and_check(f, k) f = gen(target, buffer_input=b_in, float_arg=3.5, func_input=f_in, generator_params=gp) _realize_and_check(f, k) # ----------- Test various failure modes try: # Inputs w/ mixed by-position and by-name f = gen(target, b_in, f_in, float_arg=3.5) except RuntimeError as e: assert 'Cannot use both positional and keyword arguments for inputs.' in str( e) else: assert False, 'Did not see expected exception!' try: # too many positional args f = gen(target, b_in, f_in, 3.5, 4) except RuntimeError as e: assert 'Expected exactly 3 positional args for inputs, but saw 4.' in str( e) else: assert False, 'Did not see expected exception!' try: # too few positional args f = gen(target, b_in, f_in) except RuntimeError as e: assert 'Expected exactly 3 positional args for inputs, but saw 2.' in str( e) else: assert False, 'Did not see expected exception!' try: # Inputs that can't be converted to what the receiver needs (positional) f = gen(target, hl.f32(3.141592), "happy", k) except RuntimeError as e: assert 'Unable to cast Python instance' in str(e) else: assert False, 'Did not see expected exception!' try: # Inputs that can't be converted to what the receiver needs (named) f = gen(target, b_in, f_in, float_arg="bogus") except RuntimeError as e: assert 'Unable to cast Python instance' in str(e) else: assert False, 'Did not see expected exception!' try: # Input specified by both pos and kwarg f = gen(target, b_in, f_in, 3.5, float_arg=4.5) except RuntimeError as e: assert "Cannot use both positional and keyword arguments for inputs." in str( e) else: assert False, 'Did not see expected exception!' try: # generator_params is not a dict f = gen(target, b_in, f_in, 3.5, generator_params=[1, 2, 3]) except TypeError as e: assert "cannot convert dictionary" in str(e) else: assert False, 'Did not see expected exception!' try: # Bad gp name f = gen(target, b_in, f_in, 3.5, generator_params={"foo": 0}) except RuntimeError as e: assert "has no GeneratorParam named: foo" in str(e) else: assert False, 'Did not see expected exception!' try: # Bad input name f = gen(target, buffer_input=b_in, float_arg=3.5, generator_params=gp, funk_input=f_in) except RuntimeError as e: assert "Unknown input 'funk_input' specified via keyword argument." in str( e) else: assert False, 'Did not see expected exception!' try: # Bad gp name f = gen(target, buffer_input=b_in, float_arg=3.5, generator_params=gp, func_input=f_in, nonexistent_generator_param="wat") except RuntimeError as e: assert "Unknown input 'nonexistent_generator_param' specified via keyword argument." in str( e) else: assert False, 'Did not see expected exception!'
def test_simplestub(): x, y = hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() b_in = hl.Buffer(hl.UInt(8), [2, 2]) b_in.fill(123) f_in = hl.Func("f") f_in[x, y] = x + y # ----------- Inputs by-position f = simplestub.generate(target, b_in, f_in, 3.5) _realize_and_check(f) # ----------- Inputs by-name f = simplestub.generate(target, buffer_input=b_in, func_input=f_in, float_arg=3.5) _realize_and_check(f) # ----------- Inputs w/ mixed by-position and by-name f = simplestub.generate(target, b_in, f_in, float_arg=3.5) _realize_and_check(f) f = simplestub.generate(target, b_in, float_arg=3.5, func_input=f_in) _realize_and_check(f) # ----------- Above set again, w/ GeneratorParam mixed in k = 42 f = simplestub.generate(target, b_in, f_in, 3.5, offset=k) _realize_and_check(f, k) f = simplestub.generate(target, offset=k, buffer_input=b_in, func_input=f_in, float_arg=3.5) _realize_and_check(f, k) f = simplestub.generate(target, b_in, f_in, offset=k, float_arg=3.5) _realize_and_check(f, k) f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, func_input=f_in) _realize_and_check(f, k) # ----------- Test various failure modes try: # too many positional args f = simplestub.generate(target, b_in, f_in, 3.5, 4) except RuntimeError as e: assert 'Expected at most 3 positional args, but saw 4.' in str(e) else: assert False, 'Did not see expected exception!' try: # Inputs that can't be converted to what the receiver needs (positional) f = simplestub.generate(target, 3.141592, "happy") except RuntimeError as e: assert 'Unable to cast Python instance' in str(e) else: assert False, 'Did not see expected exception!' try: # Inputs that can't be converted to what the receiver needs (named) f = simplestub.generate(target, b_in, f_in, float_arg="bogus") except RuntimeError as e: assert 'Unable to cast Python instance' in str(e) else: assert False, 'Did not see expected exception!' try: # Missing required inputs f = simplestub.generate(target, b_in, f_in) except RuntimeError as e: assert "Generator Input named 'float_arg' was not specified." in str(e) else: assert False, 'Did not see expected exception!' try: # Input specified by both pos and kwarg f = simplestub.generate(target, b_in, f_in, 3.5, float_arg=4.5) except RuntimeError as e: assert "Generator Input named 'float_arg' was specified by both position and keyword." in str(e) else: assert False, 'Did not see expected exception!' try: # Bad input name f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, funk_input=f_in) except RuntimeError as e: assert "Generator Input named 'func_input' was not specified." in str(e) else: assert False, 'Did not see expected exception!' try: # Bad gp name f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, func_input=f_in, nonexistent_generator_param="wat") except RuntimeError as e: assert "Generator has no GeneratorParam named: nonexistent_generator_param" in str(e) else: assert False, 'Did not see expected exception!'
def test_complexstub(): constant_image = _make_constant_image() input = hl.ImageParam(hl.UInt(8), 3, 'input') input.set(constant_image) x, y, c = hl.Var(), hl.Var(), hl.Var() target = hl.get_jit_target_from_environment() float_arg = 1.25 int_arg = 33 r = complexstub(target, typed_buffer_input=constant_image, untyped_buffer_input=constant_image, simple_input=input, array_input=[ input, input ], float_arg=float_arg, int_arg=[ int_arg, int_arg ], untyped_buffer_output_type="uint8", vectorize=True) # return value is a tuple; unpack separately to avoid # making the callsite above unreadable (simple_output, tuple_output, array_output, typed_buffer_output, untyped_buffer_output, static_compiled_buffer_output) = r b = simple_output.realize(32, 32, 3, target) assert b.type() == hl.Float(32) for x in range(32): for y in range(32): for c in range(3): expected = constant_image[x, y, c] actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual) b = tuple_output.realize(32, 32, 3, target) assert b[0].type() == hl.Float(32) assert b[1].type() == hl.Float(32) assert len(b) == 2 for x in range(32): for y in range(32): for c in range(3): expected1 = constant_image[x, y, c] * float_arg expected2 = expected1 + int_arg actual1, actual2 = b[0][x, y, c], b[1][x, y, c] assert expected1 == actual1, "Expected1 %s Actual1 %s" % (expected1, actual1) assert expected2 == actual2, "Expected2 %s Actual1 %s" % (expected2, actual2) assert len(array_output) == 2 for a in array_output: b = a.realize(32, 32, target) assert b.type() == hl.Int(16) for x in range(32): for y in range(32): expected = constant_image[x, y, 0] + int_arg actual = b[x, y] assert expected == actual, "Expected %s Actual %s" % (expected, actual) # TODO: Output<Buffer<>> has additional behaviors useful when a Stub # is used within another Generator; this isn't yet implemented since there # isn't yet Python bindings for Generator authoring. This section # of the test may need revision at that point. b = typed_buffer_output.realize(32, 32, 3, target) assert b.type() == hl.Float(32) for x in range(32): for y in range(32): for c in range(3): expected = constant_image[x, y, c] actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual) b = untyped_buffer_output.realize(32, 32, 3, target) assert b.type() == hl.UInt(8) for x in range(32): for y in range(32): for c in range(3): expected = constant_image[x, y, c] actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual) b = static_compiled_buffer_output.realize(4, 4, 1, target) assert b.type() == hl.UInt(8) for x in range(4): for y in range(4): for c in range(1): expected = constant_image[x, y, c] + 42 actual = b[x, y, c] assert expected == actual, "Expected %s Actual %s" % (expected, actual)