xref: /aosp_15_r20/external/executorch/runtime/platform/profiler.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1*523fa7a6SAndroid Build Coastguard Worker /*
2*523fa7a6SAndroid Build Coastguard Worker  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*523fa7a6SAndroid Build Coastguard Worker  * All rights reserved.
4*523fa7a6SAndroid Build Coastguard Worker  *
5*523fa7a6SAndroid Build Coastguard Worker  * This source code is licensed under the BSD-style license found in the
6*523fa7a6SAndroid Build Coastguard Worker  * LICENSE file in the root directory of this source tree.
7*523fa7a6SAndroid Build Coastguard Worker  */
8*523fa7a6SAndroid Build Coastguard Worker 
9*523fa7a6SAndroid Build Coastguard Worker #include <string.h>
10*523fa7a6SAndroid Build Coastguard Worker 
11*523fa7a6SAndroid Build Coastguard Worker #include <executorch/runtime/platform/assert.h>
12*523fa7a6SAndroid Build Coastguard Worker #include <executorch/runtime/platform/platform.h>
13*523fa7a6SAndroid Build Coastguard Worker #include <executorch/runtime/platform/profiler.h>
14*523fa7a6SAndroid Build Coastguard Worker #include <inttypes.h>
15*523fa7a6SAndroid Build Coastguard Worker 
16*523fa7a6SAndroid Build Coastguard Worker namespace executorch {
17*523fa7a6SAndroid Build Coastguard Worker namespace runtime {
18*523fa7a6SAndroid Build Coastguard Worker 
19*523fa7a6SAndroid Build Coastguard Worker namespace {
20*523fa7a6SAndroid Build Coastguard Worker static uint8_t prof_buf[prof_buf_size * MAX_PROFILE_BLOCKS];
21*523fa7a6SAndroid Build Coastguard Worker // Base pointer for header
22*523fa7a6SAndroid Build Coastguard Worker static prof_header_t* prof_header =
23*523fa7a6SAndroid Build Coastguard Worker     (prof_header_t*)((uintptr_t)prof_buf + prof_header_offset);
24*523fa7a6SAndroid Build Coastguard Worker // Base pointer for profiling entries
25*523fa7a6SAndroid Build Coastguard Worker static prof_event_t* prof_arr =
26*523fa7a6SAndroid Build Coastguard Worker     (prof_event_t*)((uintptr_t)prof_buf + prof_events_offset);
27*523fa7a6SAndroid Build Coastguard Worker // Base pointer for memory allocator info array
28*523fa7a6SAndroid Build Coastguard Worker static prof_allocator_t* mem_allocator_arr =
29*523fa7a6SAndroid Build Coastguard Worker     (prof_allocator_t*)((uintptr_t)prof_buf + prof_mem_alloc_info_offset);
30*523fa7a6SAndroid Build Coastguard Worker // Base pointer for memory profiling entries
31*523fa7a6SAndroid Build Coastguard Worker static mem_prof_event_t* mem_prof_arr =
32*523fa7a6SAndroid Build Coastguard Worker     (mem_prof_event_t*)((uintptr_t)prof_buf + prof_mem_alloc_events_offset);
33*523fa7a6SAndroid Build Coastguard Worker 
34*523fa7a6SAndroid Build Coastguard Worker static uint32_t num_blocks = 0;
35*523fa7a6SAndroid Build Coastguard Worker static bool prof_stats_dumped = false;
36*523fa7a6SAndroid Build Coastguard Worker prof_state_t profile_state_tls{-1, 0u};
37*523fa7a6SAndroid Build Coastguard Worker } // namespace
38*523fa7a6SAndroid Build Coastguard Worker 
get_profile_tls_state()39*523fa7a6SAndroid Build Coastguard Worker const prof_state_t& get_profile_tls_state() {
40*523fa7a6SAndroid Build Coastguard Worker   return profile_state_tls;
41*523fa7a6SAndroid Build Coastguard Worker }
42*523fa7a6SAndroid Build Coastguard Worker 
set_profile_tls_state(const prof_state_t & state)43*523fa7a6SAndroid Build Coastguard Worker void set_profile_tls_state(const prof_state_t& state) {
44*523fa7a6SAndroid Build Coastguard Worker   profile_state_tls = state;
45*523fa7a6SAndroid Build Coastguard Worker }
46*523fa7a6SAndroid Build Coastguard Worker 
ExecutorchProfilerInstructionScope(const prof_state_t & state)47*523fa7a6SAndroid Build Coastguard Worker ExecutorchProfilerInstructionScope::ExecutorchProfilerInstructionScope(
48*523fa7a6SAndroid Build Coastguard Worker     const prof_state_t& state)
49*523fa7a6SAndroid Build Coastguard Worker     : old_state_(get_profile_tls_state()) {
50*523fa7a6SAndroid Build Coastguard Worker   set_profile_tls_state(state);
51*523fa7a6SAndroid Build Coastguard Worker }
52*523fa7a6SAndroid Build Coastguard Worker 
~ExecutorchProfilerInstructionScope()53*523fa7a6SAndroid Build Coastguard Worker ExecutorchProfilerInstructionScope::~ExecutorchProfilerInstructionScope() {
54*523fa7a6SAndroid Build Coastguard Worker   set_profile_tls_state(old_state_);
55*523fa7a6SAndroid Build Coastguard Worker }
56*523fa7a6SAndroid Build Coastguard Worker 
begin_profiling(const char * name)57*523fa7a6SAndroid Build Coastguard Worker uint32_t begin_profiling(const char* name) {
58*523fa7a6SAndroid Build Coastguard Worker   ET_CHECK_MSG(
59*523fa7a6SAndroid Build Coastguard Worker       prof_header->prof_entries < MAX_PROFILE_EVENTS,
60*523fa7a6SAndroid Build Coastguard Worker       "Out of profiling buffer space. Increase MAX_PROFILE_EVENTS and re-compile.");
61*523fa7a6SAndroid Build Coastguard Worker   uint32_t curr_counter = prof_header->prof_entries;
62*523fa7a6SAndroid Build Coastguard Worker   prof_header->prof_entries++;
63*523fa7a6SAndroid Build Coastguard Worker   prof_arr[curr_counter].end_time = 0;
64*523fa7a6SAndroid Build Coastguard Worker   prof_arr[curr_counter].name_str = name;
65*523fa7a6SAndroid Build Coastguard Worker   prof_state_t state = get_profile_tls_state();
66*523fa7a6SAndroid Build Coastguard Worker   prof_arr[curr_counter].chain_idx = state.chain_idx;
67*523fa7a6SAndroid Build Coastguard Worker   prof_arr[curr_counter].instruction_idx = state.instruction_idx;
68*523fa7a6SAndroid Build Coastguard Worker   // Set start time at the last to ensure that we're not capturing
69*523fa7a6SAndroid Build Coastguard Worker   // any of the overhead in this function.
70*523fa7a6SAndroid Build Coastguard Worker   prof_arr[curr_counter].start_time = et_pal_current_ticks();
71*523fa7a6SAndroid Build Coastguard Worker   return curr_counter;
72*523fa7a6SAndroid Build Coastguard Worker }
73*523fa7a6SAndroid Build Coastguard Worker 
end_profiling(uint32_t token_id)74*523fa7a6SAndroid Build Coastguard Worker void end_profiling(uint32_t token_id) {
75*523fa7a6SAndroid Build Coastguard Worker   ET_CHECK_MSG(token_id < MAX_PROFILE_EVENTS, "Invalid token id.");
76*523fa7a6SAndroid Build Coastguard Worker   prof_arr[token_id].end_time = et_pal_current_ticks();
77*523fa7a6SAndroid Build Coastguard Worker }
78*523fa7a6SAndroid Build Coastguard Worker 
dump_profile_stats(prof_result_t * prof_result)79*523fa7a6SAndroid Build Coastguard Worker void dump_profile_stats(prof_result_t* prof_result) {
80*523fa7a6SAndroid Build Coastguard Worker   prof_result->prof_data = (uint8_t*)prof_buf;
81*523fa7a6SAndroid Build Coastguard Worker   prof_result->num_bytes = num_blocks * prof_buf_size;
82*523fa7a6SAndroid Build Coastguard Worker   prof_result->num_blocks = num_blocks;
83*523fa7a6SAndroid Build Coastguard Worker 
84*523fa7a6SAndroid Build Coastguard Worker   if (!prof_stats_dumped) {
85*523fa7a6SAndroid Build Coastguard Worker     for (size_t i = 0; i < num_blocks; i++) {
86*523fa7a6SAndroid Build Coastguard Worker       prof_header_t* prof_header_local =
87*523fa7a6SAndroid Build Coastguard Worker           (prof_header_t*)(prof_buf + prof_buf_size * i);
88*523fa7a6SAndroid Build Coastguard Worker       prof_event_t* prof_event_local =
89*523fa7a6SAndroid Build Coastguard Worker           (prof_event_t*)(prof_buf + prof_buf_size * i + prof_events_offset);
90*523fa7a6SAndroid Build Coastguard Worker       // Copy over the string names into the space allocated in prof_event_t. We
91*523fa7a6SAndroid Build Coastguard Worker       // avoided doing this earlier to keep the overhead in begin_profiling and
92*523fa7a6SAndroid Build Coastguard Worker       // end_profiling as low as possible.
93*523fa7a6SAndroid Build Coastguard Worker       for (size_t j = 0; j < prof_header_local->prof_entries; j++) {
94*523fa7a6SAndroid Build Coastguard Worker         size_t str_len = strlen(prof_event_local[j].name_str);
95*523fa7a6SAndroid Build Coastguard Worker         const char* str_ptr = prof_event_local[j].name_str;
96*523fa7a6SAndroid Build Coastguard Worker         memset(prof_event_local[j].name, 0, PROF_NAME_MAX_LEN);
97*523fa7a6SAndroid Build Coastguard Worker         if (str_len > PROF_NAME_MAX_LEN) {
98*523fa7a6SAndroid Build Coastguard Worker           memcpy(prof_event_local[j].name, str_ptr, PROF_NAME_MAX_LEN);
99*523fa7a6SAndroid Build Coastguard Worker         } else {
100*523fa7a6SAndroid Build Coastguard Worker           memcpy(prof_event_local[j].name, str_ptr, str_len);
101*523fa7a6SAndroid Build Coastguard Worker         }
102*523fa7a6SAndroid Build Coastguard Worker       }
103*523fa7a6SAndroid Build Coastguard Worker     }
104*523fa7a6SAndroid Build Coastguard Worker   }
105*523fa7a6SAndroid Build Coastguard Worker 
106*523fa7a6SAndroid Build Coastguard Worker   prof_stats_dumped = true;
107*523fa7a6SAndroid Build Coastguard Worker }
108*523fa7a6SAndroid Build Coastguard Worker 
reset_profile_stats()109*523fa7a6SAndroid Build Coastguard Worker void reset_profile_stats() {
110*523fa7a6SAndroid Build Coastguard Worker   prof_stats_dumped = false;
111*523fa7a6SAndroid Build Coastguard Worker   prof_header->prof_entries = 0;
112*523fa7a6SAndroid Build Coastguard Worker   prof_header->allocator_entries = 0;
113*523fa7a6SAndroid Build Coastguard Worker   prof_header->mem_prof_entries = 0;
114*523fa7a6SAndroid Build Coastguard Worker }
115*523fa7a6SAndroid Build Coastguard Worker 
track_allocation(int32_t id,uint32_t size)116*523fa7a6SAndroid Build Coastguard Worker void track_allocation(int32_t id, uint32_t size) {
117*523fa7a6SAndroid Build Coastguard Worker   if (id == -1)
118*523fa7a6SAndroid Build Coastguard Worker     return;
119*523fa7a6SAndroid Build Coastguard Worker   ET_CHECK_MSG(
120*523fa7a6SAndroid Build Coastguard Worker       prof_header->mem_prof_entries < MAX_MEM_PROFILE_EVENTS,
121*523fa7a6SAndroid Build Coastguard Worker       "Out of memory profiling buffer space. Increase MAX_MEM_PROFILE_EVENTS\
122*523fa7a6SAndroid Build Coastguard Worker        to %" PRIu32 " and re-compile.",
123*523fa7a6SAndroid Build Coastguard Worker       prof_header->mem_prof_entries);
124*523fa7a6SAndroid Build Coastguard Worker   mem_prof_arr[prof_header->mem_prof_entries].allocator_id = id;
125*523fa7a6SAndroid Build Coastguard Worker   mem_prof_arr[prof_header->mem_prof_entries].allocation_size = size;
126*523fa7a6SAndroid Build Coastguard Worker   prof_header->mem_prof_entries++;
127*523fa7a6SAndroid Build Coastguard Worker }
128*523fa7a6SAndroid Build Coastguard Worker 
track_allocator(const char * name)129*523fa7a6SAndroid Build Coastguard Worker uint32_t track_allocator(const char* name) {
130*523fa7a6SAndroid Build Coastguard Worker   ET_CHECK_MSG(
131*523fa7a6SAndroid Build Coastguard Worker       prof_header->allocator_entries < MEM_PROFILE_MAX_ALLOCATORS,
132*523fa7a6SAndroid Build Coastguard Worker       "Out of allocator tracking space, %d is needed. Increase MEM_PROFILE_MAX_ALLOCATORS and re-compile",
133*523fa7a6SAndroid Build Coastguard Worker       prof_header->allocator_entries);
134*523fa7a6SAndroid Build Coastguard Worker   size_t str_len = strlen(name);
135*523fa7a6SAndroid Build Coastguard Worker   size_t num_allocators = prof_header->allocator_entries;
136*523fa7a6SAndroid Build Coastguard Worker   memset(mem_allocator_arr[num_allocators].name, 0, PROF_NAME_MAX_LEN);
137*523fa7a6SAndroid Build Coastguard Worker   if (str_len > PROF_NAME_MAX_LEN) {
138*523fa7a6SAndroid Build Coastguard Worker     memcpy(mem_allocator_arr[num_allocators].name, name, PROF_NAME_MAX_LEN);
139*523fa7a6SAndroid Build Coastguard Worker   } else {
140*523fa7a6SAndroid Build Coastguard Worker     memcpy(mem_allocator_arr[num_allocators].name, name, str_len);
141*523fa7a6SAndroid Build Coastguard Worker   }
142*523fa7a6SAndroid Build Coastguard Worker   mem_allocator_arr[num_allocators].allocator_id = num_allocators;
143*523fa7a6SAndroid Build Coastguard Worker   return prof_header->allocator_entries++;
144*523fa7a6SAndroid Build Coastguard Worker }
145*523fa7a6SAndroid Build Coastguard Worker 
profiling_create_block(const char * name)146*523fa7a6SAndroid Build Coastguard Worker void profiling_create_block(const char* name) {
147*523fa7a6SAndroid Build Coastguard Worker   // If the current profiling block is not used then continue to use this, if
148*523fa7a6SAndroid Build Coastguard Worker   // not move onto the next block.
149*523fa7a6SAndroid Build Coastguard Worker   if (prof_header->prof_entries != 0 || prof_header->mem_prof_entries != 0 ||
150*523fa7a6SAndroid Build Coastguard Worker       prof_header->allocator_entries != 0 || num_blocks == 0) {
151*523fa7a6SAndroid Build Coastguard Worker     num_blocks += 1;
152*523fa7a6SAndroid Build Coastguard Worker     ET_CHECK_MSG(
153*523fa7a6SAndroid Build Coastguard Worker         num_blocks <= MAX_PROFILE_BLOCKS,
154*523fa7a6SAndroid Build Coastguard Worker         "Only %d blocks are supported and they've all been used up but %d is used. Increment MAX_PROFILE_BLOCKS and re-run",
155*523fa7a6SAndroid Build Coastguard Worker         MAX_PROFILE_BLOCKS,
156*523fa7a6SAndroid Build Coastguard Worker         num_blocks);
157*523fa7a6SAndroid Build Coastguard Worker   }
158*523fa7a6SAndroid Build Coastguard Worker 
159*523fa7a6SAndroid Build Coastguard Worker   // Copy over the name of this profiling block.
160*523fa7a6SAndroid Build Coastguard Worker   size_t str_len =
161*523fa7a6SAndroid Build Coastguard Worker       strlen(name) >= PROF_NAME_MAX_LEN ? PROF_NAME_MAX_LEN : strlen(name);
162*523fa7a6SAndroid Build Coastguard Worker   uintptr_t base = (uintptr_t)prof_buf + (num_blocks - 1) * prof_buf_size;
163*523fa7a6SAndroid Build Coastguard Worker   prof_header = (prof_header_t*)(base + prof_header_offset);
164*523fa7a6SAndroid Build Coastguard Worker   memset(prof_header->name, 0, PROF_NAME_MAX_LEN);
165*523fa7a6SAndroid Build Coastguard Worker   memcpy(prof_header->name, name, str_len);
166*523fa7a6SAndroid Build Coastguard Worker 
167*523fa7a6SAndroid Build Coastguard Worker   // Set profiler version for compatiblity checks in the post-processing
168*523fa7a6SAndroid Build Coastguard Worker   // tool.
169*523fa7a6SAndroid Build Coastguard Worker   prof_header->prof_ver = ET_PROF_VER;
170*523fa7a6SAndroid Build Coastguard Worker   // Set the maximum number of entries that this block can support.
171*523fa7a6SAndroid Build Coastguard Worker   prof_header->max_prof_entries = MAX_PROFILE_EVENTS;
172*523fa7a6SAndroid Build Coastguard Worker   prof_header->max_allocator_entries = MEM_PROFILE_MAX_ALLOCATORS;
173*523fa7a6SAndroid Build Coastguard Worker   prof_header->max_mem_prof_entries = MAX_MEM_PROFILE_EVENTS;
174*523fa7a6SAndroid Build Coastguard Worker   reset_profile_stats();
175*523fa7a6SAndroid Build Coastguard Worker 
176*523fa7a6SAndroid Build Coastguard Worker   // Set the base addresses for the various profiling entries arrays.
177*523fa7a6SAndroid Build Coastguard Worker   prof_arr = (prof_event_t*)(base + prof_events_offset);
178*523fa7a6SAndroid Build Coastguard Worker   mem_allocator_arr = (prof_allocator_t*)(base + prof_mem_alloc_info_offset);
179*523fa7a6SAndroid Build Coastguard Worker   mem_prof_arr = (mem_prof_event_t*)(base + prof_mem_alloc_events_offset);
180*523fa7a6SAndroid Build Coastguard Worker }
181*523fa7a6SAndroid Build Coastguard Worker 
profiler_init(void)182*523fa7a6SAndroid Build Coastguard Worker void profiler_init(void) {
183*523fa7a6SAndroid Build Coastguard Worker   profiling_create_block("default");
184*523fa7a6SAndroid Build Coastguard Worker }
185*523fa7a6SAndroid Build Coastguard Worker 
ExecutorchProfiler(const char * name)186*523fa7a6SAndroid Build Coastguard Worker ExecutorchProfiler::ExecutorchProfiler(const char* name) {
187*523fa7a6SAndroid Build Coastguard Worker   prof_tok = begin_profiling(name);
188*523fa7a6SAndroid Build Coastguard Worker }
189*523fa7a6SAndroid Build Coastguard Worker 
~ExecutorchProfiler()190*523fa7a6SAndroid Build Coastguard Worker ExecutorchProfiler::~ExecutorchProfiler() {
191*523fa7a6SAndroid Build Coastguard Worker   end_profiling(prof_tok);
192*523fa7a6SAndroid Build Coastguard Worker }
193*523fa7a6SAndroid Build Coastguard Worker 
194*523fa7a6SAndroid Build Coastguard Worker } // namespace runtime
195*523fa7a6SAndroid Build Coastguard Worker } // namespace executorch
196