WEAK void sampling_profiler_thread(void *) { halide_profiler_state *s = halide_profiler_get_state(); // grab the lock halide_mutex_lock(&s->lock); while (s->current_func != halide_profiler_please_stop) { uint64_t t1 = halide_current_time_ns(NULL); uint64_t t = t1; while (1) { uint64_t t_now = halide_current_time_ns(NULL); int func = s->current_func; if (func == halide_profiler_please_stop) { break; } else if (func >= 0) { // Assume all time since I was last awake is due to // the currently running func. bill_func(s, func, t_now - t); } t = t_now; // Release the lock, sleep, reacquire. int sleep_ms = s->sleep_time; halide_mutex_unlock(&s->lock); halide_sleep_ms(NULL, sleep_ms); halide_mutex_lock(&s->lock); } } s->started = false; halide_mutex_unlock(&s->lock); }
WEAK void halide_profiler_reset() { halide_profiler_state *s = halide_profiler_get_state(); ScopedMutexLock lock(&s->lock); while (s->pipelines) { halide_profiler_pipeline_stats *p = s->pipelines; s->pipelines = (halide_profiler_pipeline_stats *)(p->next); free(p->funcs); free(p); } s->first_free_id = 0; }
WEAK halide_profiler_pipeline_stats *find_or_create_pipeline(const char *pipeline_name, int num_funcs, const uint64_t *func_names) { halide_profiler_state *s = halide_profiler_get_state(); for (halide_profiler_pipeline_stats *p = s->pipelines; p; p = (halide_profiler_pipeline_stats *)(p->next)) { // The same pipeline will deliver the same global constant // string, so they can be compared by pointer. if (p->name == pipeline_name && p->num_funcs == num_funcs) { return p; } } // Create a new pipeline stats entry. halide_profiler_pipeline_stats *p = (halide_profiler_pipeline_stats *)malloc(sizeof(halide_profiler_pipeline_stats)); if (!p) return NULL; p->next = s->pipelines; p->name = pipeline_name; p->first_func_id = s->first_free_id; p->num_funcs = num_funcs; p->runs = 0; p->time = 0; p->samples = 0; p->memory_current = 0; p->memory_peak = 0; p->memory_total = 0; p->num_allocs = 0; p->active_threads_numerator = 0; p->active_threads_denominator = 0; p->funcs = (halide_profiler_func_stats *)malloc(num_funcs * sizeof(halide_profiler_func_stats)); if (!p->funcs) { free(p); return NULL; } for (int i = 0; i < num_funcs; i++) { p->funcs[i].time = 0; p->funcs[i].name = (const char *)(func_names[i]); p->funcs[i].memory_current = 0; p->funcs[i].memory_peak = 0; p->funcs[i].memory_total = 0; p->funcs[i].num_allocs = 0; p->funcs[i].stack_peak = 0; p->funcs[i].active_threads_numerator = 0; p->funcs[i].active_threads_denominator = 0; } s->first_free_id += num_funcs; s->pipelines = p; return p; }
// Returns the address of the pipeline state associated with pipeline_name. WEAK halide_profiler_pipeline_stats *halide_profiler_get_pipeline_state(const char *pipeline_name) { halide_profiler_state *s = halide_profiler_get_state(); ScopedMutexLock lock(&s->lock); for (halide_profiler_pipeline_stats *p = s->pipelines; p; p = (halide_profiler_pipeline_stats *)(p->next)) { // The same pipeline will deliver the same global constant // string, so they can be compared by pointer. if (p->name == pipeline_name) { return p; } } return NULL; }
WEAK void halide_profiler_reset() { // WARNING: Do not call this method while any other halide // pipeline is running; halide_profiler_memory_allocate/free and // halide_profiler_stack_peak_update update the profiler pipeline's // state without grabbing the global profiler state's lock. halide_profiler_state *s = halide_profiler_get_state(); ScopedMutexLock lock(&s->lock); while (s->pipelines) { halide_profiler_pipeline_stats *p = s->pipelines; s->pipelines = (halide_profiler_pipeline_stats *)(p->next); free(p->funcs); free(p); } s->first_free_id = 0; }
WEAK void sampling_profiler_thread(void *) { halide_profiler_state *s = halide_profiler_get_state(); // grab the lock halide_mutex_lock(&s->lock); while (s->current_func != halide_profiler_please_stop) { uint64_t t1 = halide_current_time_ns(NULL); uint64_t t = t1; while (1) { int func, active_threads; if (s->get_remote_profiler_state) { // Execution has disappeared into remote code running // on an accelerator (e.g. Hexagon DSP) s->get_remote_profiler_state(&func, &active_threads); } else { func = s->current_func; active_threads = s->active_threads; } uint64_t t_now = halide_current_time_ns(NULL); if (func == halide_profiler_please_stop) { break; } else if (func >= 0) { // Assume all time since I was last awake is due to // the currently running func. bill_func(s, func, t_now - t, active_threads); } t = t_now; // Release the lock, sleep, reacquire. int sleep_ms = s->sleep_time; halide_mutex_unlock(&s->lock); halide_sleep_ms(NULL, sleep_ms); halide_mutex_lock(&s->lock); } } s->started = false; halide_mutex_unlock(&s->lock); }
// Returns a token identifying this pipeline instance. WEAK int halide_profiler_pipeline_start(void *user_context, const char *pipeline_name, int num_funcs, const uint64_t *func_names) { halide_profiler_state *s = halide_profiler_get_state(); ScopedMutexLock lock(&s->lock); if (!s->started) { halide_start_clock(user_context); halide_spawn_thread(sampling_profiler_thread, NULL); s->started = true; } halide_profiler_pipeline_stats *p = find_or_create_pipeline(pipeline_name, num_funcs, func_names); if (!p) { // Allocating space to track the statistics failed. return halide_error_out_of_memory(user_context); } p->runs++; return p->first_func_id; }
int halide_hexagon_remote_profiler_set_current_func(int current_func) { halide_profiler_get_state()->current_func = current_func; return 0; }
int halide_hexagon_remote_poll_profiler_state(int *func, int *threads) { *func = halide_profiler_get_state()->current_func; *threads = halide_profiler_get_state()->active_threads; return 0; }
WEAK void halide_profiler_report(void *user_context) { halide_profiler_state *s = halide_profiler_get_state(); ScopedMutexLock lock(&s->lock); halide_profiler_report_unlocked(user_context, s); }