Skip to content

Hex bench experiment #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 2 additions & 36 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,7 @@ if (Halide_TARGET MATCHES "wasm")
return()
endif()

# add_app(HelloAndroid) # TODO(#5374): missing CMake build
# add_app(HelloAndroidCamera2) # TODO(#5374): missing CMake build
# add_app(HelloPyTorch) # TODO(#5374): missing CMake build
# add_app(HelloiOS) # TODO(#5374): missing CMake build
# add_app(auto_viz) # TODO(#5374): missing CMake build
add_app(bgu)
add_app(bilateral_grid)
add_app(blur)
add_app(c_backend)
add_app(camera_pipe)
add_app(compositing)
add_app(conv_layer)
add_app(cuda_mat_mul)
add_app(depthwise_separable_conv)
add_app(fft)
add_app(hannk)
add_app(harris)
# add_app(hexagon_benchmarks) # TODO(#5374): missing CMake build
# add_app(hexagon_dma) # TODO(#5374): missing CMake build
add_app(hist)
add_app(iir_blur)
add_app(interpolate)
add_app(lens_blur)
add_app(linear_algebra)
# add_app(linear_blur) # TODO(#5374): missing CMake build
add_app(local_laplacian)
add_app(max_filter)
add_app(nl_means)
# add_app(nn_ops) # TODO(#5374): missing CMake build
# add_app(onnx) # TODO(#5374): missing CMake build
# add_app(openglcompute) # TODO(#5374): missing CMake build
add_app(resize)
# add_app(resnet_50) # TODO(#5374): missing CMake build
# add_app(simd_op_check) # TODO(#5374): missing CMake build
add_app(stencil_chain)
add_app(unsharp)
add_app(wavelet)
add_app(HelloBaremetal)
add_app(hexagon_benchmarks) # TODO(#5374): missing CMake build
# add_app(hexagon_dma) # TODO(#5374): missing CMake build
45 changes: 45 additions & 0 deletions apps/hexagon_benchmarks/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
cmake_minimum_required(VERSION 3.22)
project(hexagon_benchmarks)

enable_testing()

# Set up language settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
# Find Halide
find_package(Halide REQUIRED)

macro(add_generator_and_library FILTER_NAME)
set(GENERATOR_EXE ${FILTER_NAME}.generator)
set(GENERATOR_SRC ${FILTER_NAME}_generator.cpp)
add_halide_generator(${GENERATOR_EXE} SOURCES ${GENERATOR_SRC})
add_halide_library(${FILTER_NAME} FROM ${GENERATOR_EXE})
endmacro()

add_generator_and_library(dilate3x3)
add_generator_and_library(gaussian5x5)
add_generator_and_library(median3x3)
add_generator_and_library(sobel)

# Main executable
add_executable(process process.cpp)
target_compile_options(process PRIVATE $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-O2>)
if (Halide_TARGET MATCHES "hvx")
target_compile_definitions(process PRIVATE DILATE3X3 GAUSSIAN5X5 MEDIAN3X3 SOBEL TARGET_HAS_HVX)
else()
target_compile_definitions(process PRIVATE DILATE3X3 GAUSSIAN5X5 MEDIAN3X3 SOBEL)
endif()
target_link_libraries(process
PRIVATE
Halide::Tools
dilate3x3 gaussian5x5 median3x3 sobel)

# Test that the app actually works!
add_test(NAME hexagon_benchmarks COMMAND process -n 1)
set_tests_properties(hexagon_benchmarks PROPERTIES
LABELS hexagon_benchmarks
PASS_REGULAR_EXPRESSION "Success!"
SKIP_REGULAR_EXPRESSION "\\[SKIP\\]")
12 changes: 6 additions & 6 deletions apps/hexagon_benchmarks/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class Conv3x3a16Descriptor : public PipelineDescriptorBase {
sum = clamp<int16_t>(sum, 0, 255);
uint8_t out_xy = u8_out(x, y);
if (sum != out_xy) {
printf("Conv3x3a16: Mismatch at %d %d : %d != %d\n", x, y, out_xy, sum);
fprintf(stderr,"Conv3x3a16: Mismatch at %d %d : %d != %d\n", x, y, out_xy, sum);
abort();
}
});
Expand Down Expand Up @@ -187,7 +187,7 @@ class Dilate3x3Descriptor : public PipelineDescriptorBase {

uint8_t out_xy = u8_out(x, y);
if (max_val != out_xy) {
printf("Dilate3x3: Mismatch at %d %d : %d != %d\n", x, y, out_xy, max_val);
fprintf(stderr,"Dilate3x3: Mismatch at %d %d : %d != %d\n", x, y, out_xy, max_val);
abort();
}
});
Expand Down Expand Up @@ -256,7 +256,7 @@ class Median3x3Descriptor : public PipelineDescriptorBase {
uint8_t median_val = inp9[4];
uint8_t out_xy = u8_out(x, y);
if (median_val != out_xy) {
printf("Median3x3: Mismatch at %d %d : %d != %d\n", x, y, out_xy, median_val);
fprintf(stderr,"Median3x3: Mismatch at %d %d : %d != %d\n", x, y, out_xy, median_val);
abort();
}
});
Expand Down Expand Up @@ -327,7 +327,7 @@ class Gaussian5x5Descriptor : public PipelineDescriptorBase {
uint8_t blur_val = blur >> 8;
uint8_t out_xy = u8_out(x, y);
if (blur_val != out_xy) {
printf("Gaussian5x5: Mismatch at %d %d : %d != %d\n", x, y, out_xy, blur_val);
fprintf(stderr,"Gaussian5x5: Mismatch at %d %d : %d != %d\n", x, y, out_xy, blur_val);
abort();
}
});
Expand Down Expand Up @@ -403,7 +403,7 @@ class SobelDescriptor : public PipelineDescriptorBase {

uint8_t out_xy = u8_out(x, y);
if (sobel_val != out_xy) {
printf("Sobel: Mismatch at %d %d : %d != %d\n", x, y, out_xy, sobel_val);
fprintf(stderr,"Sobel: Mismatch at %d %d : %d != %d\n", x, y, out_xy, sobel_val);
abort();
}
});
Expand Down Expand Up @@ -487,7 +487,7 @@ class Conv3x3a32Descriptor : public PipelineDescriptorBase {
sum = clamp(sum, 0, 255);
uint8_t out_xy = u8_out(x, y);
if (sum != out_xy) {
printf("Conv3x3a32: Mismatch at %d %d : %d != %d\n", x, y, out_xy, sum);
fprintf(stderr,"Conv3x3a32: Mismatch at %d %d : %d != %d\n", x, y, out_xy, sum);
abort();
}
});
Expand Down
5 changes: 0 additions & 5 deletions python_bindings/src/halide/halide_/PyParameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ void define_parameter(py::module &m) {
.def(py::init<const Parameter &>(), py::arg("p"))
.def(py::init<const Type &, bool, int>())
.def(py::init<const Type &, bool, int, const std::string &>())
.def(py::init<const Type &, bool, int, const std::string &,
const Buffer<void> &, int, const std::vector<BufferConstraint> &,
MemoryType>())
.def(py::init<const Type &, bool, int, const std::string &,
uint64_t, const Expr &, const Expr &, const Expr &, const Expr &>())
.def("_to_argument", [](const Parameter &p) -> Argument {
return Argument(p.name(),
p.is_buffer() ? Argument::InputBuffer : Argument::InputScalar,
Expand Down
30 changes: 30 additions & 0 deletions src/AddImageChecks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,36 @@ Stmt add_image_checks(const Stmt &s,
class Injector : public IRMutator {
using IRMutator::visit;

Expr visit(const Variable *op) override {
// In the bounds inference lets we skip over, respect any buffer
// constraints.

// Note that in the case where the constraint doesn't hold, this
// changes the value of this Expr! This is safe because these lets
// are internal names, and no user-provided constraints can depend
// on them, so changing their value to use the constraint value
// instead of the actual buffer value can't possibly change whether
// or not the constraint check is going to pass.
const Parameter &p = op->param;
if (p.defined() && p.is_buffer()) {
for (int i = 0; i < p.dimensions(); i++) {
if (p.min_constraint(i).defined() &&
op->name == p.name() + ".min." + std::to_string(i)) {
return p.min_constraint(i);
}
if (p.extent_constraint(i).defined() &&
op->name == p.name() + ".extent." + std::to_string(i)) {
return p.extent_constraint(i);
}
if (p.stride_constraint(i).defined() &&
op->name == p.name() + ".stride." + std::to_string(i)) {
return p.stride_constraint(i);
}
}
}
return op;
}

Stmt visit(const Block *op) override {
const Evaluate *e = op->first.as<Evaluate>();
if (e && Call::as_intrinsic(e->value, {Call::add_image_checks_marker})) {
Expand Down
29 changes: 26 additions & 3 deletions src/Bounds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2190,7 +2190,7 @@ class BoxesTouched : public IRGraphVisitor {
// Map variable name to all other vars which values depend on that variable.
map<VarInstance, set<VarInstance>> children;

bool in_producer{false};
bool in_producer{false}, in_unreachable{false};
map<std::string, Expr> buffer_lets;

using IRGraphVisitor::visit;
Expand Down Expand Up @@ -2810,16 +2810,23 @@ class BoxesTouched : public IRGraphVisitor {

// Fork the boxes touched and go down each path
map<string, Box> then_boxes, else_boxes;
bool then_unreachable = false, else_unreachable = false;
then_boxes.swap(boxes);
std::swap(then_unreachable, in_unreachable);
op->then_case.accept(this);
then_boxes.swap(boxes);
std::swap(then_unreachable, in_unreachable);

if (op->else_case.defined()) {
else_boxes.swap(boxes);
std::swap(else_unreachable, in_unreachable);
op->else_case.accept(this);
else_boxes.swap(boxes);
std::swap(else_unreachable, in_unreachable);
}

in_unreachable = then_unreachable && else_unreachable;

// Make sure all the then boxes have an entry on the else
// side so that the merge doesn't skip them.
for (pair<const string, Box> &i : then_boxes) {
Expand All @@ -2832,13 +2839,22 @@ class BoxesTouched : public IRGraphVisitor {
Box &then_box = then_boxes[i.first];
Box &orig_box = boxes[i.first];

if (then_box.maybe_unused()) {
if (else_unreachable) {
// Don't incorporate the condition into
// then.used. boxes_touched assumes that asserts pass, so if
// the else case contains an assert(false), conservatively
// assume the then case will unconditionally run. This
// provides more useful bounds for bounds queries on
// pipelines that use specialize_fail.
} else if (then_box.maybe_unused()) {
then_box.used = then_box.used && op->condition;
} else {
then_box.used = op->condition;
}

if (else_box.maybe_unused()) {
if (then_unreachable) {
// Conservatively assume the else case will run.
} else if (else_box.maybe_unused()) {
else_box.used = else_box.used && !op->condition;
} else {
else_box.used = !op->condition;
Expand All @@ -2850,6 +2866,13 @@ class BoxesTouched : public IRGraphVisitor {
}
}

void visit(const AssertStmt *op) override {
if (is_const_zero(op->condition)) {
in_unreachable = true;
}
IRGraphVisitor::visit(op);
}

void visit(const For *op) override {
TRACK_BOXES_TOUCHED;
TRACK_BOXES_TOUCHED_INFO("var:", op->name);
Expand Down
22 changes: 12 additions & 10 deletions src/Bounds.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ Box box_intersection(const Box &a, const Box &b);
/** Test if box a provably contains box b */
bool box_contains(const Box &a, const Box &b);

/** Compute rectangular domains large enough to cover all the 'Call's
* to each function that occurs within a given statement or
* expression. This is useful for figuring out what regions of things
* to evaluate. */
/** Compute rectangular domains large enough to cover all the 'Call's to each
* function that occurs within a given statement or expression. This is useful
* for figuring out what regions of things to evaluate. Respects control flow
* (e.g. encodes if statement conditions), but assumes all encountered asserts
* pass. If it encounters an assert(false) in one if branch, assumes the
* opposite if branch runs unconditionally. */
// @{
std::map<std::string, Box> boxes_required(const Expr &e,
const Scope<Interval> &scope = Scope<Interval>::empty_scope(),
Expand All @@ -118,9 +120,9 @@ std::map<std::string, Box> boxes_required(Stmt s,
const FuncValueBounds &func_bounds = empty_func_value_bounds());
// @}

/** Compute rectangular domains large enough to cover all the
* 'Provides's to each function that occurs within a given statement
* or expression. */
/** Compute rectangular domains large enough to cover all the 'Provides's to
* each function that occurs within a given statement or expression. Handles
* asserts in the same way as boxes_required. */
// @{
std::map<std::string, Box> boxes_provided(const Expr &e,
const Scope<Interval> &scope = Scope<Interval>::empty_scope(),
Expand All @@ -130,9 +132,9 @@ std::map<std::string, Box> boxes_provided(Stmt s,
const FuncValueBounds &func_bounds = empty_func_value_bounds());
// @}

/** Compute rectangular domains large enough to cover all the 'Call's
* and 'Provides's to each function that occurs within a given
* statement or expression. */
/** Compute rectangular domains large enough to cover all the 'Call's and
* 'Provides's to each function that occurs within a given statement or
* expression. Handles asserts in the same way as boxes_required. */
// @{
std::map<std::string, Box> boxes_touched(const Expr &e,
const Scope<Interval> &scope = Scope<Interval>::empty_scope(),
Expand Down
Loading