Skip to content

Commit

Permalink
Deprecate JIT runtime override methods that take void * (#6344)
Browse files Browse the repository at this point in the history
* Deprecate JIT runtime override methods that take void *

* Clean up comments
  • Loading branch information
abadams committed Oct 26, 2021
1 parent 6211da9 commit 86cb6c7
Show file tree
Hide file tree
Showing 52 changed files with 341 additions and 420 deletions.
21 changes: 15 additions & 6 deletions src/Func.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3275,29 +3275,38 @@ void Func::compile_to_assembly(const string &filename, const vector<Argument> &a

// JIT-related code

namespace {
template<typename A, typename B>
void set_handler(A &a, B b) {
a = (A)b;
}
} // namespace

// Deprecated setters for JIT handlers
void Func::set_error_handler(void (*handler)(void *, const char *)) {
pipeline().set_error_handler(handler);
set_handler(jit_handlers().custom_error, handler);
}

void Func::set_custom_allocator(void *(*cust_malloc)(void *, size_t),
void (*cust_free)(void *, void *)) {
pipeline().set_custom_allocator(cust_malloc, cust_free);
set_handler(jit_handlers().custom_malloc, cust_malloc);
set_handler(jit_handlers().custom_free, cust_free);
}

void Func::set_custom_do_par_for(int (*cust_do_par_for)(void *, int (*)(void *, int, uint8_t *), int, int, uint8_t *)) {
pipeline().set_custom_do_par_for(cust_do_par_for);
set_handler(jit_handlers().custom_do_par_for, cust_do_par_for);
}

void Func::set_custom_do_task(int (*cust_do_task)(void *, int (*)(void *, int, uint8_t *), int, uint8_t *)) {
pipeline().set_custom_do_task(cust_do_task);
set_handler(jit_handlers().custom_do_task, cust_do_task);
}

void Func::set_custom_trace(int (*trace_fn)(void *, const halide_trace_event_t *)) {
pipeline().set_custom_trace(trace_fn);
set_handler(jit_handlers().custom_trace, trace_fn);
}

void Func::set_custom_print(void (*cust_print)(void *, const char *)) {
pipeline().set_custom_print(cust_print);
set_handler(jit_handlers().custom_print, cust_print);
}

void Func::add_custom_lowering_pass(IRMutator *pass, std::function<void()> deleter) {
Expand Down
93 changes: 10 additions & 83 deletions src/Func.h
Original file line number Diff line number Diff line change
Expand Up @@ -1048,101 +1048,28 @@ class Func {
*/
void compile_jit(const Target &target = get_jit_target_from_environment());

/** Set the error handler function that be called in the case of
* runtime errors during halide pipelines. If you are compiling
* statically, you can also just define your own function with
* signature
\code
extern "C" void halide_error(void *user_context, const char *);
\endcode
* This will clobber Halide's version.
*/
/** Deprecated variants of the above that use a void pointer
* instead of a JITUserContext pointer. */
// @{
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_error_handler(void (*handler)(void *, const char *));

/** Set a custom malloc and free for halide to use. Malloc should
* return 32-byte aligned chunks of memory, and it should be safe
* for Halide to read slightly out of bounds (up to 8 bytes before
* the start or beyond the end). If compiling statically, routines
* with appropriate signatures can be provided directly
\code
extern "C" void *halide_malloc(void *, size_t)
extern "C" void halide_free(void *, void *)
\endcode
* These will clobber Halide's versions. See HalideRuntime.h
* for declarations.
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_allocator(void *(*malloc)(void *, size_t),
void (*free)(void *, void *));

/** Set a custom task handler to be called by the parallel for
* loop. It is useful to set this if you want to do some
* additional bookkeeping at the granularity of parallel
* tasks. The default implementation does this:
\code
extern "C" int halide_do_task(void *user_context,
int (*f)(void *, int, uint8_t *),
int idx, uint8_t *state) {
return f(user_context, idx, state);
}
\endcode
* If you are statically compiling, you can also just define your
* own version of the above function, and it will clobber Halide's
* version.
*
* If you're trying to use a custom parallel runtime, you probably
* don't want to call this. See instead \ref Func::set_custom_do_par_for .
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_do_task(
int (*custom_do_task)(void *, int (*)(void *, int, uint8_t *),
int, uint8_t *));

/** Set a custom parallel for loop launcher. Useful if your app
* already manages a thread pool. The default implementation is
* equivalent to this:
\code
extern "C" int halide_do_par_for(void *user_context,
int (*f)(void *, int, uint8_t *),
int min, int extent, uint8_t *state) {
int exit_status = 0;
parallel for (int idx = min; idx < min+extent; idx++) {
int job_status = halide_do_task(user_context, f, idx, state);
if (job_status) exit_status = job_status;
}
return exit_status;
}
\endcode
*
* However, notwithstanding the above example code, if one task
* fails, we may skip over other tasks, and if two tasks return
* different error codes, we may select one arbitrarily to return.
*
* If you are statically compiling, you can also just define your
* own version of the above function, and it will clobber Halide's
* version.
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_do_par_for(
int (*custom_do_par_for)(void *, int (*)(void *, int, uint8_t *), int,
int, uint8_t *));

/** Set custom routines to call when tracing is enabled. Call this
* on the output Func of your pipeline. This then sets custom
* routines for the entire pipeline, not just calls to this
* Func.
*
* If you are statically compiling, you can also just define your
* own versions of the tracing functions (see HalideRuntime.h),
* and they will clobber Halide's versions. */
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_trace(int (*trace_fn)(void *, const halide_trace_event_t *));

/** Set the function called to print messages from the runtime.
* If you are compiling statically, you can also just define your
* own function with signature
\code
extern "C" void halide_print(void *user_context, const char *);
\endcode
* This will clobber Halide's version.
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_print(void (*handler)(void *, const char *));
// @}

/** Get a struct containing the currently set custom functions
* used by JIT. This can be mutated. Changes will take effect the
Expand Down
4 changes: 2 additions & 2 deletions src/JITModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ void free_handler(JITUserContext *context, void *ptr) {
}
}

int do_task_handler(JITUserContext *context, halide_task_t f, int idx,
int do_task_handler(JITUserContext *context, int (*f)(JITUserContext *, int, uint8_t *), int idx,
uint8_t *closure) {
if (context) {
return (*context->handlers.custom_do_task)(context, f, idx, closure);
Expand All @@ -541,7 +541,7 @@ int do_task_handler(JITUserContext *context, halide_task_t f, int idx,
}
}

int do_par_for_handler(JITUserContext *context, halide_task_t f,
int do_par_for_handler(JITUserContext *context, int (*f)(JITUserContext *, int, uint8_t *),
int min, int size, uint8_t *closure) {
if (context) {
return (*context->handlers.custom_do_par_for)(context, f, min, size, closure);
Expand Down
74 changes: 71 additions & 3 deletions src/JITModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,85 @@ class Module;

struct JITUserContext;

/** A set of custom overrides of runtime functions */
/** A set of custom overrides of runtime functions. These only apply
* when JIT-compiling code. If you are doing AOT compilation, see
* HalideRuntime.h for instructions on how to replace runtime
* functions. */
struct JITHandlers {
/** Set the function called to print messages from the runtime. */
void (*custom_print)(JITUserContext *, const char *){nullptr};

/** A custom malloc and free for halide to use. Malloc should
* return 32-byte aligned chunks of memory, and it should be safe
* for Halide to read slightly out of bounds (up to 8 bytes before
* the start or beyond the end). */
// @{
void *(*custom_malloc)(JITUserContext *, size_t){nullptr};
void (*custom_free)(JITUserContext *, void *){nullptr};
int (*custom_do_task)(JITUserContext *, halide_task_t, int, uint8_t *){nullptr};
int (*custom_do_par_for)(JITUserContext *, halide_task_t, int, int, uint8_t *){nullptr};
// @}

/** A custom task handler to be called by the parallel for
* loop. It is useful to set this if you want to do some
* additional bookkeeping at the granularity of parallel
* tasks. The default implementation does this:
\code
extern "C" int halide_do_task(JITUserContext *user_context,
int (*f)(void *, int, uint8_t *),
int idx, uint8_t *state) {
return f(user_context, idx, state);
}
\endcode
*
* If you're trying to use a custom parallel runtime, you probably
* don't want to call this. See instead custom_do_par_for.
*/
int (*custom_do_task)(JITUserContext *, int (*)(JITUserContext *, int, uint8_t *), int, uint8_t *){nullptr};

/** A custom parallel for loop launcher. Useful if your app
* already manages a thread pool. The default implementation is
* equivalent to this:
\code
extern "C" int halide_do_par_for(JITUserContext *user_context,
int (*f)(void *, int, uint8_t *),
int min, int extent, uint8_t *state) {
int exit_status = 0;
parallel for (int idx = min; idx < min+extent; idx++) {
int job_status = halide_do_task(user_context, f, idx, state);
if (job_status) exit_status = job_status;
}
return exit_status;
}
\endcode
*
* However, notwithstanding the above example code, if one task
* fails, we may skip over other tasks, and if two tasks return
* different error codes, we may select one arbitrarily to return.
*/
int (*custom_do_par_for)(JITUserContext *, int (*)(JITUserContext *, int, uint8_t *), int, int, uint8_t *){nullptr};

/** The error handler function that be called in the case of
* runtime errors during halide pipelines. */
void (*custom_error)(JITUserContext *, const char *){nullptr};

/** A custom routine to call when tracing is enabled. Call this
* on the output Func of your pipeline. This then sets custom
* routines for the entire pipeline, not just calls to this
* Func. */
int32_t (*custom_trace)(JITUserContext *, const halide_trace_event_t *){nullptr};

/** A method to use for Halide to resolve symbol names dynamically
* in the calling process or library from within the Halide
* runtime. Equivalent to dlsym with a null first argument. */
void *(*custom_get_symbol)(const char *name){nullptr};

/** A method to use for Halide to dynamically load libraries from
* within the runtime. Equivalent to dlopen. Returns a handle to
* the opened library. */
void *(*custom_load_library)(const char *name){nullptr};

/** A method to use for Halide to dynamically find a symbol within
* an opened library. Equivalent to dlsym. Takes a handle
* returned by custom_load_library as the first argument. */
void *(*custom_get_library_symbol)(void *lib, const char *name){nullptr};
};

Expand Down
96 changes: 10 additions & 86 deletions src/Pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,103 +349,27 @@ class Pipeline {
*/
void compile_jit(const Target &target = get_jit_target_from_environment());

// TODO: deprecate all of these and replace with versions that take a JITUserContext

/** Set the error handler function that be called in the case of
* runtime errors during halide pipelines. If you are compiling
* statically, you can also just define your own function with
* signature
\code
extern "C" void halide_error(void *user_context, const char *);
\endcode
* This will clobber Halide's version.
*/
/** Deprecated variants of the above that use a void pointer
* instead of a JITUserContext pointer. */
// @{
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_error_handler(void (*handler)(void *, const char *));

/** Set a custom malloc and free for halide to use. Malloc should
* return 32-byte aligned chunks of memory, and it should be safe
* for Halide to read slightly out of bounds (up to 8 bytes before
* the start or beyond the end). If compiling statically, routines
* with appropriate signatures can be provided directly
\code
extern "C" void *halide_malloc(void *, size_t)
extern "C" void halide_free(void *, void *)
\endcode
* These will clobber Halide's versions. See HalideRuntime.h
* for declarations.
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_allocator(void *(*malloc)(void *, size_t),
void (*free)(void *, void *));

/** Set a custom task handler to be called by the parallel for
* loop. It is useful to set this if you want to do some
* additional bookkeeping at the granularity of parallel
* tasks. The default implementation does this:
\code
extern "C" int halide_do_task(void *user_context,
int (*f)(void *, int, uint8_t *),
int idx, uint8_t *state) {
return f(user_context, idx, state);
}
\endcode
* If you are statically compiling, you can also just define your
* own version of the above function, and it will clobber Halide's
* version.
*
* If you're trying to use a custom parallel runtime, you probably
* don't want to call this. See instead \ref Func::set_custom_do_par_for .
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_do_task(
int (*custom_do_task)(void *, int (*)(void *, int, uint8_t *),
int, uint8_t *));

/** Set a custom parallel for loop launcher. Useful if your app
* already manages a thread pool. The default implementation is
* equivalent to this:
\code
extern "C" int halide_do_par_for(void *user_context,
int (*f)(void *, int, uint8_t *),
int min, int extent, uint8_t *state) {
int exit_status = 0;
parallel for (int idx = min; idx < min+extent; idx++) {
int job_status = halide_do_task(user_context, f, idx, state);
if (job_status) exit_status = job_status;
}
return exit_status;
}
\endcode
*
* However, notwithstanding the above example code, if one task
* fails, we may skip over other tasks, and if two tasks return
* different error codes, we may select one arbitrarily to return.
*
* If you are statically compiling, you can also just define your
* own version of the above function, and it will clobber Halide's
* version.
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_do_par_for(
int (*custom_do_par_for)(void *, int (*)(void *, int, uint8_t *), int,
int, uint8_t *));

/** Set custom routines to call when tracing is enabled. Call this
* on the output Func of your pipeline. This then sets custom
* routines for the entire pipeline, not just calls to this
* Func.
*
* If you are statically compiling, you can also just define your
* own versions of the tracing functions (see HalideRuntime.h),
* and they will clobber Halide's versions. */
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_trace(int (*trace_fn)(void *, const halide_trace_event_t *));

/** Set the function called to print messages from the runtime.
* If you are compiling statically, you can also just define your
* own function with signature
\code
extern "C" void halide_print(void *user_context, const char *);
\endcode
* This will clobber Halide's version.
*/
HALIDE_ATTRIBUTE_DEPRECATED("Custom handlers should by set by modifying the struct returned by jit_handlers()")
void set_custom_print(void (*handler)(void *, const char *));
// @}

/** Install a set of external C functions or Funcs to satisfy
* dependencies introduced by HalideExtern and define_extern
Expand Down
6 changes: 3 additions & 3 deletions src/runtime/HalideRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ extern "C" {
* replaced with user-defined versions by defining an extern "C"
* function with the same name and signature.
*
* When doing Just In Time (JIT) compilation methods on the Func being
* compiled must be called instead. The corresponding methods are
* documented below.
* When doing Just In Time (JIT) compilation members of
* some_pipeline_or_func.jit_handlers() must be replaced instead. The
* corresponding methods are documented below.
*
* All of these functions take a "void *user_context" parameter as their
* first argument; if the Halide kernel that calls back to any of these
Expand Down
Loading

0 comments on commit 86cb6c7

Please sign in to comment.