7 template<
typename ContextT,
typename ModuleStateT>
9 struct CachedCompilation {
11 ModuleStateT module_state{};
15 CachedCompilation(ContextT context, ModuleStateT module_state,
17 : context(context), module_state(module_state),
18 kernel_id(kernel_id), use_count(use_count) {
24 static constexpr
float kLoadFactor{.5f};
25 static constexpr
int kInitialTableBits{7};
26 int log2_compilations_size{0};
27 CachedCompilation *compilations{
nullptr};
30 static constexpr
uint32_t kInvalidId{0};
31 static constexpr
uint32_t kDeletedId{1};
37 uintptr_t addr = (uintptr_t)context +
id;
40 if (
sizeof(uintptr_t) >= 8) {
41 return (addr * (uintptr_t)0x9E3779B97F4A7C15) >> (64 - bits);
43 return (addr * (uintptr_t)0x9E3779B9) >> (32 - bits);
48 if (log2_compilations_size == 0) {
53 if ((count + 1) > (1 << log2_compilations_size) * kLoadFactor) {
59 uintptr_t index =
kernel_hash(entry.context, entry.kernel_id, log2_compilations_size);
60 for (
int i = 0; i < (1 << log2_compilations_size); i++) {
61 uintptr_t effective_index = (index + i) & ((1 << log2_compilations_size) - 1);
62 if (compilations[effective_index].kernel_id <= kDeletedId) {
63 compilations[effective_index] = entry;
74 ModuleStateT *&module_state,
int increment) {
75 if (log2_compilations_size == 0) {
78 uintptr_t index =
kernel_hash(context,
id, log2_compilations_size);
79 for (
int i = 0; i < (1 << log2_compilations_size); i++) {
80 uintptr_t effective_index = (index + i) & ((1 << log2_compilations_size) - 1);
82 if (compilations[effective_index].kernel_id == kInvalidId) {
85 if (compilations[effective_index].context == context &&
86 compilations[effective_index].kernel_id ==
id) {
87 module_state = &compilations[effective_index].module_state;
89 compilations[effective_index].use_count += increment;
98 ScopedMutexLock lock_guard(&mutex);
100 ModuleStateT *mod_ptr;
102 module_state = *mod_ptr;
109 if (size_bits != log2_compilations_size) {
110 int new_size = (1 << size_bits);
111 int old_size = (1 << log2_compilations_size);
112 CachedCompilation *new_table = (CachedCompilation *)
malloc(new_size *
sizeof(CachedCompilation));
113 if (new_table ==
nullptr) {
117 memset(new_table, 0, new_size *
sizeof(CachedCompilation));
118 CachedCompilation *old_table = compilations;
119 compilations = new_table;
120 log2_compilations_size = size_bits;
123 for (
int32_t i = 0; i < old_size; i++) {
124 if (old_table[i].kernel_id != kInvalidId &&
125 old_table[i].kernel_id != kDeletedId) {
126 bool result =
insert(old_table[i]);
136 template<
typename FreeModuleT>
142 for (
int i = 0; i < (1 << log2_compilations_size); i++) {
143 if (compilations[i].kernel_id > kInvalidId &&
144 (all || (compilations[i].context == context)) &&
145 compilations[i].use_count == 0) {
146 debug(
user_context) <<
"Releasing cached compilation: " << compilations[i].module_state
147 <<
" id " << compilations[i].kernel_id
148 <<
" context " << compilations[i].context <<
"\n";
149 f(compilations[i].module_state);
150 compilations[i].module_state =
nullptr;
151 compilations[i].kernel_id = kDeletedId;
157 template<
typename FreeModuleT>
159 ScopedMutexLock lock_guard(&mutex);
164 template<
typename FreeModuleT>
166 ScopedMutexLock lock_guard(&mutex);
172 compilations =
nullptr;
173 log2_compilations_size = 0;
177 template<
typename CompileModuleT,
typename... Args>
179 ContextT context, ModuleStateT &result,
182 ScopedMutexLock lock_guard(&mutex);
186 *id_ptr = unique_id++;
196 ModuleStateT compiled_module = f(args...);
198 <<
" id " << *id_ptr <<
" context " << context <<
"\n";
199 if (compiled_module ==
nullptr) {
203 if (!
insert({context, compiled_module, *id_ptr, 1})) {
206 result = compiled_module;
#define HALIDE_MUST_USE_RESULT
HALIDE_MUST_USE_RESULT bool lookup(ContextT context, void *state_ptr, ModuleStateT &module_state)
static ALWAYS_INLINE uintptr_t kernel_hash(ContextT context, uint32_t id, uint32_t bits)
void release_hold(void *user_context, ContextT context, void *state_ptr)
HALIDE_MUST_USE_RESULT bool insert(const CachedCompilation &entry)
HALIDE_MUST_USE_RESULT bool kernel_state_setup(void *user_context, void **state_ptr, ContextT context, ModuleStateT &result, CompileModuleT f, Args... args)
void release_all(void *user_context, FreeModuleT &f)
void delete_context(void *user_context, ContextT context, FreeModuleT &f)
HALIDE_MUST_USE_RESULT bool resize_table(int size_bits)
void release_context(void *user_context, bool all, ContextT context, FreeModuleT &f)
HALIDE_MUST_USE_RESULT bool find_internal(ContextT context, uint32_t id, ModuleStateT *&module_state, int increment)
For optional debugging during codegen, use the debug class as follows:
HALIDE_ALWAYS_INLINE auto mod(A &&a, B &&b) -> decltype(IRMatcher::operator%(a, b))
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
signed __INT32_TYPE__ int32_t
void * memset(void *s, int val, size_t n)
unsigned __INT32_TYPE__ uint32_t
#define halide_assert(user_context, cond)