Skip to content

Commit c3f1911

Browse files
authored
Merge pull request #10869 from tannewt/zephyr_native_sim_memory_tracking
Add heap stat tracking to native_sim
2 parents f75864d + 860ab98 commit c3f1911

File tree

3 files changed

+138
-7
lines changed

3 files changed

+138
-7
lines changed

ports/zephyr-cp/supervisor/port.c

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <zephyr/autoconf.h>
1717
#include <zephyr/kernel.h>
1818
#include <zephyr/sys/reboot.h>
19+
#include <zephyr/sys/util.h>
1920

2021
#if defined(CONFIG_ARCH_POSIX)
2122
#include <limits.h>
@@ -29,7 +30,16 @@
2930
#include "lib/tlsf/tlsf.h"
3031
#include <zephyr/device.h>
3132

33+
#if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM)
34+
#include "perfetto_encoder.h"
35+
#include <zephyr/sys/mem_stats.h>
36+
#define CIRCUITPY_PERFETTO_TRACK_GROUP_UUID 0x3000ULL
37+
#define CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID 0x3001ULL
38+
#define CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID 0x3002ULL
39+
#endif
40+
3241
static tlsf_t heap;
42+
static size_t tlsf_heap_used = 0;
3343

3444
// Auto generated in pins.c
3545
extern const struct device *const rams[];
@@ -72,12 +82,60 @@ static void native_sim_register_cmdline_opts(void) {
7282
NATIVE_TASK(native_sim_register_cmdline_opts, PRE_BOOT_1, 0);
7383
#endif
7484

85+
#if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM)
86+
static bool perfetto_circuitpython_tracks_emitted;
87+
88+
static void perfetto_emit_outer_heap_stats(void) {
89+
if (!perfetto_start()) {
90+
return;
91+
}
92+
size_t total = tlsf_heap_used;
93+
#if defined(CONFIG_COMMON_LIBC_MALLOC) && defined(CONFIG_SYS_HEAP_RUNTIME_STATS)
94+
extern int malloc_runtime_stats_get(struct sys_memory_stats *stats);
95+
struct sys_memory_stats stats;
96+
if (malloc_runtime_stats_get(&stats) == 0) {
97+
total += stats.allocated_bytes;
98+
}
99+
#endif
100+
perfetto_emit_counter(CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID, (int64_t)total);
101+
Z_SPIN_DELAY(1);
102+
}
103+
104+
static void perfetto_emit_circuitpython_tracks(void) {
105+
if (perfetto_circuitpython_tracks_emitted) {
106+
return;
107+
}
108+
if (!perfetto_start()) {
109+
return;
110+
}
111+
perfetto_emit_track_descriptor(CIRCUITPY_PERFETTO_TRACK_GROUP_UUID,
112+
perfetto_get_process_uuid(),
113+
"CircuitPython");
114+
perfetto_emit_counter_track_descriptor(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID,
115+
CIRCUITPY_PERFETTO_TRACK_GROUP_UUID,
116+
"VM Heap Used",
117+
PERFETTO_COUNTER_UNIT_BYTES);
118+
perfetto_emit_counter_track_descriptor(CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID,
119+
CIRCUITPY_PERFETTO_TRACK_GROUP_UUID,
120+
"Outer Heap Used",
121+
PERFETTO_COUNTER_UNIT_BYTES);
122+
perfetto_circuitpython_tracks_emitted = true;
123+
}
124+
#else
125+
static inline void perfetto_emit_outer_heap_stats(void) {
126+
}
127+
128+
static inline void perfetto_emit_circuitpython_tracks(void) {
129+
}
130+
#endif
131+
75132
static void _tick_function(struct k_timer *timer_id) {
76133
supervisor_tick();
77134
}
78135

79136
safe_mode_t port_init(void) {
80137
k_timer_init(&tick_timer, _tick_function, NULL);
138+
perfetto_emit_circuitpython_tracks();
81139
return SAFE_MODE_NONE;
82140
}
83141

@@ -233,6 +291,7 @@ void port_heap_init(void) {
233291
}
234292
valid_pool_count++;
235293
}
294+
perfetto_emit_outer_heap_stats();
236295
#if !DT_HAS_CHOSEN(zephyr_sram)
237296
#error "No SRAM!"
238297
#endif
@@ -243,30 +302,54 @@ void *port_malloc(size_t size, bool dma_capable) {
243302
if (valid_pool_count > 0) {
244303
block = tlsf_malloc(heap, size);
245304
}
305+
if (block != NULL) {
306+
tlsf_heap_used += tlsf_block_size(block);
307+
}
246308
#ifdef CONFIG_COMMON_LIBC_MALLOC
247309
if (block == NULL) {
248310
block = malloc(size);
249311
}
250312
#endif
313+
if (block != NULL) {
314+
perfetto_emit_outer_heap_stats();
315+
}
251316
return block;
252317
}
253318

254319
void port_free(void *ptr) {
320+
if (ptr == NULL) {
321+
return;
322+
}
255323
if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) {
324+
tlsf_heap_used -= tlsf_block_size(ptr);
256325
tlsf_free(heap, ptr);
257-
return;
326+
} else {
327+
#ifdef CONFIG_COMMON_LIBC_MALLOC
328+
free(ptr);
329+
#endif
258330
}
259-
#ifdef CONFIG_COMMON_LIBC_MALLOC
260-
free(ptr);
261-
#endif
331+
perfetto_emit_outer_heap_stats();
262332
}
263333

264334
void *port_realloc(void *ptr, size_t size, bool dma_capable) {
335+
if (ptr == NULL) {
336+
return port_malloc(size, dma_capable);
337+
}
265338
if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) {
266-
return tlsf_realloc(heap, ptr, size);
339+
size_t old_size = tlsf_block_size(ptr);
340+
void *new_block = tlsf_realloc(heap, ptr, size);
341+
if (new_block != NULL) {
342+
tlsf_heap_used = tlsf_heap_used - old_size + tlsf_block_size(new_block);
343+
perfetto_emit_outer_heap_stats();
344+
}
345+
return new_block;
267346
}
268347
#ifdef CONFIG_COMMON_LIBC_MALLOC
269-
return realloc(ptr, size);
348+
void *new_block = realloc(ptr, size);
349+
if (new_block != NULL) {
350+
perfetto_emit_outer_heap_stats();
351+
}
352+
return new_block;
270353
#endif
271354
return NULL;
272355
}

ports/zephyr-cp/zephyr-config/west.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ manifest:
88
path: modules/bsim_hw_models/nrf_hw_models
99
- name: zephyr
1010
url: https://github.com/adafruit/zephyr
11-
revision: 5351284ac926b1352ab98f5ae692a21f38068beb
11+
revision: 589b2139926017d4d98724bac653ceb30802be9f
1212
clone-depth: 100
1313
import: true

py/gc.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@
3232
#include "py/gc.h"
3333
#include "py/runtime.h"
3434

35+
#if defined(__ZEPHYR__)
36+
#include <zephyr/autoconf.h>
37+
#include <zephyr/kernel.h>
38+
#include <zephyr/sys/util.h>
39+
#endif
40+
3541
#if MICROPY_DEBUG_VALGRIND
3642
#include <valgrind/memcheck.h>
3743
#endif
@@ -45,6 +51,12 @@
4551
#include "shared-module/memorymonitor/__init__.h"
4652
#endif
4753

54+
#if defined(__ZEPHYR__) && defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM)
55+
#include "perfetto_encoder.h"
56+
#define CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID 0x3001ULL
57+
#define CIRCUITPY_PERFETTO_VM_HEAP_MAX_FREE_UUID 0x3002ULL
58+
#endif
59+
4860
#if MICROPY_ENABLE_GC
4961

5062
#if MICROPY_DEBUG_VERBOSE // print debugging info
@@ -158,6 +170,32 @@ void __attribute__ ((noinline)) gc_log_change(uint32_t start_block, uint32_t len
158170
#pragma GCC pop_options
159171
#endif
160172

173+
#if defined(__ZEPHYR__) && defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM)
174+
static void gc_perfetto_emit_heap_stats(void) {
175+
if (!perfetto_start()) {
176+
return;
177+
}
178+
gc_info_t info;
179+
gc_info(&info);
180+
perfetto_emit_counter(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, (int64_t)info.used);
181+
Z_SPIN_DELAY(1);
182+
}
183+
184+
static void gc_perfetto_emit_heap_stopped(void) {
185+
if (!perfetto_start()) {
186+
return;
187+
}
188+
perfetto_emit_counter(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, 0);
189+
Z_SPIN_DELAY(1);
190+
}
191+
#else
192+
static inline void gc_perfetto_emit_heap_stats(void) {
193+
}
194+
195+
static inline void gc_perfetto_emit_heap_stopped(void) {
196+
}
197+
#endif
198+
161199
// Static functions for individual steps of the GC mark/sweep sequence
162200
static void gc_collect_start_common(void);
163201
static void *gc_get_ptr(void **ptrs, int i);
@@ -284,6 +322,7 @@ void gc_init(void *start, void *end) {
284322
#endif
285323

286324
GC_MUTEX_INIT();
325+
gc_perfetto_emit_heap_stats();
287326
}
288327

289328
#if MICROPY_GC_SPLIT_HEAP
@@ -425,6 +464,7 @@ void gc_deinit(void) {
425464
// Run any finalisers before we stop using the heap. This will also free
426465
// any additional heap areas (but not the first.)
427466
gc_sweep_all();
467+
gc_perfetto_emit_heap_stopped();
428468
memset(&MP_STATE_MEM(area), 0, sizeof(MP_STATE_MEM(area)));
429469
}
430470

@@ -654,6 +694,7 @@ void gc_collect_end(void) {
654694
}
655695
MP_STATE_THREAD(gc_lock_depth) &= ~GC_COLLECT_FLAG;
656696
GC_EXIT();
697+
gc_perfetto_emit_heap_stats();
657698
}
658699

659700
static void gc_deal_with_stack_overflow(void) {
@@ -1069,6 +1110,8 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
10691110
memorymonitor_track_allocation(end_block - start_block + 1);
10701111
#endif
10711112

1113+
gc_perfetto_emit_heap_stats();
1114+
10721115
return ret_ptr;
10731116
}
10741117

@@ -1150,6 +1193,7 @@ void gc_free(void *ptr) {
11501193
} while (ATB_GET_KIND(area, block) == AT_TAIL);
11511194

11521195
GC_EXIT();
1196+
gc_perfetto_emit_heap_stats();
11531197

11541198
#if EXTENSIVE_HEAP_PROFILING
11551199
gc_dump_alloc_table(&mp_plat_print);
@@ -1290,6 +1334,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
12901334
memorymonitor_track_allocation(new_blocks);
12911335
#endif
12921336

1337+
gc_perfetto_emit_heap_stats();
1338+
12931339
return ptr_in;
12941340
}
12951341

@@ -1327,6 +1373,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
13271373
memorymonitor_track_allocation(new_blocks);
13281374
#endif
13291375

1376+
gc_perfetto_emit_heap_stats();
1377+
13301378
return ptr_in;
13311379
}
13321380

0 commit comments

Comments
 (0)