diff --git a/Documentation/components/drivers/special/segger.rst b/Documentation/components/drivers/special/segger.rst index 29097de3b82ac..e22a420afd6d8 100644 --- a/Documentation/components/drivers/special/segger.rst +++ b/Documentation/components/drivers/special/segger.rst @@ -17,7 +17,7 @@ Supported Segger drivers: Segger SystemView ================= -Steps to enable SystemView support: +1. Steps to enable SystemView support: #. Make sure your architecture supports a high-performance counter. In most cases it will be: @@ -62,3 +62,14 @@ Steps to enable SystemView support: In case SystemView returns buffer overflow errors, you should increase ``CONFIG_NOTE_RTT_BUFFER_SIZE_UP``. + +2. Use SystemView for heap tracing: + +Refer to example configuration at ``stm32f429i-disco/configs/systemview``. +Make sure that ``CONFIG_SCHED_INSTRUMENTATION_HEAP`` is enabled. + +Example of screenshot from SystemView: + +.. image:: sysview.png + :width: 800px + :align: center diff --git a/Documentation/components/drivers/special/sysview.png b/Documentation/components/drivers/special/sysview.png new file mode 100644 index 0000000000000..d5f8709631504 Binary files /dev/null and b/Documentation/components/drivers/special/sysview.png differ diff --git a/arch/sim/src/sim/sim_heap.c b/arch/sim/src/sim/sim_heap.c index a3ccb2bb406c3..e95b559ff1213 100644 --- a/arch/sim/src/sim/sim_heap.c +++ b/arch/sim/src/sim/sim_heap.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "sim_internal.h" @@ -185,6 +186,7 @@ static void mm_delayfree(struct mm_heap_s *heap, void *mem, bool delay) int size = host_mallocsize(mem); atomic_fetch_sub(&heap->aordblks, 1); atomic_fetch_sub(&heap->uordblks, size); + sched_note_heap(NOTE_HEAP_FREE, heap, mem, size, 0); host_free(mem); } } @@ -228,9 +230,37 @@ struct mm_heap_s *mm_initialize(const char *name, procfs_register_meminfo(&heap->mm_procfs); #endif + sched_note_heap(NOTE_HEAP_ADD, heap, heap_start, heap_size, 0); return heap; } +/**************************************************************************** + * Name: mm_uninitialize + * + * Description: + * Uninitialize the selected heap data structures + * + * Input Parameters: + * heap - The selected heap + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +void mm_uninitialize(struct mm_heap_s *heap) +{ + sched_note_heap(NOTE_HEAP_REMOVE, heap, NULL, 0, 0); + +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MEMINFO) + procfs_unregister_meminfo(&heap->mm_procfs); +#endif + mm_free_delaylist(heap); + host_free(heap); +} + /**************************************************************************** * Name: mm_addregion * @@ -339,6 +369,7 @@ void *mm_realloc(struct mm_heap_s *heap, void *oldmem, int uordblks; int usmblks; int newsize; + int oldsize; free_delaylist(heap, false); @@ -348,13 +379,23 @@ void *mm_realloc(struct mm_heap_s *heap, void *oldmem, return NULL; } - atomic_fetch_sub(&heap->uordblks, host_mallocsize(oldmem)); + oldsize = host_mallocsize(oldmem); + atomic_fetch_sub(&heap->uordblks, oldsize); mem = host_realloc(oldmem, size); atomic_fetch_add(&heap->aordblks, oldmem == NULL && mem != NULL); newsize = host_mallocsize(mem ? mem : oldmem); atomic_fetch_add(&heap->uordblks, newsize); usmblks = atomic_load(&heap->usmblks); + if (mem != NULL) + { + if (oldmem != NULL) + { + sched_note_heap(NOTE_HEAP_FREE, heap, oldmem, oldsize, 0); + } + + sched_note_heap(NOTE_HEAP_ALLOC, heap, mem, newsize, 0); + } do { @@ -445,6 +486,7 @@ void *mm_memalign(struct mm_heap_s *heap, size_t alignment, size_t size) } size = host_mallocsize(mem); + sched_note_heap(NOTE_HEAP_ALLOC, heap, mem, size, 0); atomic_fetch_add(&heap->aordblks, 1); atomic_fetch_add(&heap->uordblks, size); usmblks = atomic_load(&heap->usmblks); diff --git a/boards/arm/stm32/stm32f429i-disco/configs/systemview/defconfig b/boards/arm/stm32/stm32f429i-disco/configs/systemview/defconfig index 075534e939ea8..adb3a67086eec 100644 --- a/boards/arm/stm32/stm32f429i-disco/configs/systemview/defconfig +++ b/boards/arm/stm32/stm32f429i-disco/configs/systemview/defconfig @@ -38,6 +38,7 @@ CONFIG_RAM_START=0x20000000 CONFIG_RAW_BINARY=y CONFIG_RR_INTERVAL=200 CONFIG_SCHED_INSTRUMENTATION=y +CONFIG_SCHED_INSTRUMENTATION_HEAP=y CONFIG_SCHED_INSTRUMENTATION_IRQHANDLER=y CONFIG_SCHED_INSTRUMENTATION_SWITCH=y CONFIG_SEGGER_SYSVIEW=y diff --git a/drivers/note/note_driver.c b/drivers/note/note_driver.c index cee07d3b9a79b..74141665420fc 100644 --- a/drivers/note/note_driver.c +++ b/drivers/note/note_driver.c @@ -92,6 +92,8 @@ #define note_irqhandler(drv, irq, handler, enter) \ ((drv)->ops->irqhandler && \ ((drv)->ops->irqhandler(drv, irq, handler, enter), true)) +#define note_heap(drv, event, data, mem, size, used) \ + ((drv)->ops->heap && ((drv)->ops->heap(drv, event, data, mem, size, used), true)) #define note_string(drv, ip, buf) \ ((drv)->ops->string && ((drv)->ops->string(drv, ip, buf), true)) #define note_event(drv, ip, event, buf, len) \ @@ -1352,6 +1354,51 @@ void sched_note_irqhandler(int irq, FAR void *handler, bool enter) } #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP +void sched_note_heap(uint8_t event, FAR void *heap, FAR void *mem, + size_t size, size_t used) +{ + FAR struct note_driver_s **driver; + struct note_heap_s note; + bool formatted = false; + FAR struct tcb_s *tcb = this_task(); + +#ifdef CONFIG_SCHED_INSTRUMENTATION_FILTER + if (!note_isenabled()) + { + return; + } +#endif + + for (driver = g_note_drivers; *driver; driver++) + { + if (note_heap(*driver, event, heap, mem, size, used)) + { + continue; + } + + if ((*driver)->ops->add == NULL) + { + continue; + } + + if (!formatted) + { + formatted = true; + note_common(tcb, ¬e.nmm_cmn, sizeof(note), event); + note.heap = heap; + note.mem = mem; + note.size = size; + note.used = used; + } + + /* Add the note to circular buffer */ + + note_add(*driver, ¬e, sizeof(note)); + } +} +#endif + #ifdef CONFIG_SCHED_INSTRUMENTATION_DUMP void sched_note_string_ip(uint32_t tag, uintptr_t ip, FAR const char *buf) { diff --git a/drivers/note/noteram_driver.c b/drivers/note/noteram_driver.c index f095445010cd9..e9b60333ab015 100644 --- a/drivers/note/noteram_driver.c +++ b/drivers/note/noteram_driver.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -419,6 +420,7 @@ static int noteram_open(FAR struct file *filep) int noteram_close(FAR struct file *filep) { FAR struct noteram_dump_context_s *ctx = filep->f_priv; + kmm_free(ctx); return OK; } @@ -621,11 +623,12 @@ static void noteram_dump_init_context(FAR struct noteram_dump_context_s *ctx) } /**************************************************************************** - * Name: get_task_name + * Name: get_taskname ****************************************************************************/ static const char *get_taskname(pid_t pid) { +#if CONFIG_DRIVERS_NOTE_TASKNAME_BUFSIZE > 0 FAR const char *taskname; taskname = note_get_taskname(pid); @@ -633,6 +636,7 @@ static const char *get_taskname(pid_t pid) { return taskname; } +#endif return ""; } @@ -1015,7 +1019,27 @@ static int noteram_dump_one(FAR uint8_t *p, FAR struct lib_outstream_s *s, } break; #endif - +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP + case NOTE_HEAP_ADD: + case NOTE_HEAP_REMOVE: + case NOTE_HEAP_ALLOC: + case NOTE_HEAP_FREE: + { + FAR struct note_heap_s *nmm = (FAR struct note_heap_s *)p; + FAR const char *name[] = + { + "add", "remove", "malloc", "free" + }; + + ret += noteram_dump_header(s, &nmm->nmm_cmn, ctx); + ret += lib_sprintf(s, "tracing_mark_write: C|%d|Heap Usage|%d|%s" + ": heap: %p size:%" PRIiPTR ", address: %p\n", + pid, nmm->used, + name[note->nc_type - NOTE_HEAP_ADD], + nmm->heap, nmm->size, nmm->mem); + } + break; +#endif default: break; } diff --git a/drivers/segger/Make.defs b/drivers/segger/Make.defs index 424c0f7206676..162cd4e3958b6 100644 --- a/drivers/segger/Make.defs +++ b/drivers/segger/Make.defs @@ -69,7 +69,7 @@ endif ifneq ($(CONFIG_SEGGER_RTT)$(CONFIG_SEGGER_SYSVIEW),) CFLAGS += ${INCDIR_PREFIX}segger$(DELIM)SystemView$(DELIM)SEGGER - SYSVIEW_VERSION ?= 354 + SYSVIEW_VERSION ?= 356 SYSVIEW_ZIP = SystemView_Src_V$(SYSVIEW_VERSION).zip # Download and unpack tarball if no git repo found diff --git a/drivers/segger/note_sysview.c b/drivers/segger/note_sysview.c index 1b221fff5a19e..95ded2b2ebcb6 100644 --- a/drivers/segger/note_sysview.c +++ b/drivers/segger/note_sysview.c @@ -23,6 +23,7 @@ ****************************************************************************/ #include +#include #include #include @@ -73,6 +74,11 @@ static void note_sysview_syscall_enter(FAR struct note_driver_s *drv, static void note_sysview_syscall_leave(FAR struct note_driver_s *drv, int nr, uintptr_t result); #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP +static void note_sysview_heap(FAR struct note_driver_s *drv, + uint8_t event, FAR void *heap, FAR void *mem, + size_t size, size_t curused); +#endif /**************************************************************************** * Private Data @@ -113,6 +119,9 @@ static const struct note_driver_ops_s g_note_sysview_ops = #ifdef CONFIG_SCHED_INSTRUMENTATION_IRQHANDLER note_sysview_irqhandler, /* irqhandler */ #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP + note_sysview_heap, /* heap */ +#endif }; static struct note_sysview_driver_s g_note_sysview_driver = @@ -319,6 +328,64 @@ static void note_sysview_syscall_leave(FAR struct note_driver_s *drv, } #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP +static void note_sysview_heap(FAR struct note_driver_s *drv, + uint8_t event, FAR void *heap, FAR void *mem, + size_t size, size_t curused) +{ + switch (event) + { + case NOTE_HEAP_ALLOC: + case NOTE_HEAP_FREE: + { + U32 value = (U32)curused; + const SEGGER_SYSVIEW_DATA_SAMPLE data = + { + .ID = (U32)(uintptr_t)heap, + .pU32_Value = &value, + }; + + SEGGER_SYSVIEW_SampleData(&data); + if (event == NOTE_HEAP_ALLOC) + { + SEGGER_SYSVIEW_HeapAlloc(heap, mem, size); + } + else + { + SEGGER_SYSVIEW_HeapFree(heap, mem); + } + + break; + } + + case NOTE_HEAP_ADD: + { + char name[32]; + SEGGER_SYSVIEW_DATA_REGISTER data = + { + .ID = (U32)(uintptr_t)heap, + .DataType = SEGGER_SYSVIEW_TYPE_U32, + .Offset = 0, + .RangeMin = 0, + .RangeMax = 0, + .ScalingFactor = 1.f, + .sUnit = "B", + .sName = name, + }; + + snprintf(name, sizeof(name), "Heap%p", heap); + + SEGGER_SYSVIEW_RegisterData(&data); + SEGGER_SYSVIEW_HeapDefine(heap, mem, size, 0); + break; + } + + default: + break; + } +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/include/nuttx/note/note_driver.h b/include/nuttx/note/note_driver.h index fae9b0685c8e8..7dc67e3dcda6b 100644 --- a/include/nuttx/note/note_driver.h +++ b/include/nuttx/note/note_driver.h @@ -91,6 +91,11 @@ struct note_driver_ops_s CODE void (*irqhandler)(FAR struct note_driver_s *drv, int irq, FAR void *handler, bool enter); #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP + CODE void (*heap)(FAR struct note_driver_s *drv, uint8_t event, + FAR void *heap, FAR void *mem, size_t size, + size_t curused); +#endif #ifdef CONFIG_SCHED_INSTRUMENTATION_DUMP CODE void (*string)(FAR struct note_driver_s *drv, uintptr_t ip, FAR const char *buf); diff --git a/include/nuttx/sched_note.h b/include/nuttx/sched_note.h index 6b0d3c845883a..b87b66369af4f 100644 --- a/include/nuttx/sched_note.h +++ b/include/nuttx/sched_note.h @@ -166,34 +166,41 @@ enum note_type_e { - NOTE_START = 0, - NOTE_STOP = 1, - NOTE_SUSPEND = 2, - NOTE_RESUME = 3, - NOTE_CPU_START = 4, - NOTE_CPU_STARTED = 5, - NOTE_CPU_PAUSE = 6, - NOTE_CPU_PAUSED = 7, - NOTE_CPU_RESUME = 8, - NOTE_CPU_RESUMED = 9, - NOTE_PREEMPT_LOCK = 10, - NOTE_PREEMPT_UNLOCK = 11, - NOTE_CSECTION_ENTER = 12, - NOTE_CSECTION_LEAVE = 13, - NOTE_SPINLOCK_LOCK = 14, - NOTE_SPINLOCK_LOCKED = 15, - NOTE_SPINLOCK_UNLOCK = 16, - NOTE_SPINLOCK_ABORT = 17, - NOTE_SYSCALL_ENTER = 18, - NOTE_SYSCALL_LEAVE = 19, - NOTE_IRQ_ENTER = 20, - NOTE_IRQ_LEAVE = 21, - NOTE_DUMP_STRING = 22, - NOTE_DUMP_BINARY = 23, - NOTE_DUMP_BEGIN = 24, - NOTE_DUMP_END = 25, - NOTE_DUMP_MARK = 28, - NOTE_DUMP_COUNTER = 29, + NOTE_START, + NOTE_STOP, + NOTE_SUSPEND, + NOTE_RESUME, + NOTE_CPU_START, + NOTE_CPU_STARTED, + NOTE_CPU_PAUSE, + NOTE_CPU_PAUSED, + NOTE_CPU_RESUME, + NOTE_CPU_RESUMED, + NOTE_PREEMPT_LOCK, + NOTE_PREEMPT_UNLOCK, + NOTE_CSECTION_ENTER, + NOTE_CSECTION_LEAVE, + NOTE_SPINLOCK_LOCK, + NOTE_SPINLOCK_LOCKED, + NOTE_SPINLOCK_UNLOCK, + NOTE_SPINLOCK_ABORT, + NOTE_SYSCALL_ENTER, + NOTE_SYSCALL_LEAVE, + NOTE_IRQ_ENTER, + NOTE_IRQ_LEAVE, + NOTE_HEAP_ADD, + NOTE_HEAP_REMOVE, + NOTE_HEAP_ALLOC, + NOTE_HEAP_FREE, + NOTE_DUMP_STRING, + NOTE_DUMP_BINARY, + NOTE_DUMP_BEGIN, + NOTE_DUMP_END, + NOTE_DUMP_MARK, + NOTE_DUMP_COUNTER, + + /* Always last */ + NOTE_TYPE_LAST }; @@ -379,6 +386,15 @@ struct note_irqhandler_s uint8_t nih_irq; /* IRQ number */ }; +struct note_heap_s +{ + struct note_common_s nmm_cmn; /* Common note parameters */ + FAR void *heap; + FAR void *mem; + size_t size; + size_t used; +}; + struct note_string_s { struct note_common_s nst_cmn; /* Common note parameters */ @@ -541,6 +557,13 @@ void sched_note_irqhandler(int irq, FAR void *handler, bool enter); # define sched_note_irqhandler(i,h,e) #endif +#ifdef CONFIG_SCHED_INSTRUMENTATION_HEAP +void sched_note_heap(uint8_t event, FAR void *heap, FAR void *mem, + size_t size, size_t used); +#else +# define sched_note_heap(e,h,m,s,c) +#endif + #ifdef CONFIG_SCHED_INSTRUMENTATION_DUMP void sched_note_string_ip(uint32_t tag, uintptr_t ip, FAR const char *buf); void sched_note_event_ip(uint32_t tag, uintptr_t ip, uint8_t event, diff --git a/mm/mm_heap/mm_free.c b/mm/mm_heap/mm_free.c index ab3cda0eae62f..6848ad3ab8bea 100644 --- a/mm/mm_heap/mm_free.c +++ b/mm/mm_heap/mm_free.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "mm_heap/mm.h" @@ -99,11 +100,12 @@ void mm_delayfree(FAR struct mm_heap_s *heap, FAR void *mem, bool delay) return; } + nodesize = mm_malloc_size(heap, mem); #ifdef CONFIG_MM_FILL_ALLOCATIONS - memset(mem, MM_FREE_MAGIC, mm_malloc_size(heap, mem)); + memset(mem, MM_FREE_MAGIC, nodesize); #endif - kasan_poison(mem, mm_malloc_size(heap, mem)); + kasan_poison(mem, nodesize); if (delay) { @@ -126,6 +128,7 @@ void mm_delayfree(FAR struct mm_heap_s *heap, FAR void *mem, bool delay) /* Update heap statistics */ heap->mm_curused -= nodesize; + sched_note_heap(NOTE_HEAP_FREE, heap, mem, nodesize, heap->mm_curused); /* Check if the following node is free and, if so, merge it */ diff --git a/mm/mm_heap/mm_initialize.c b/mm/mm_heap/mm_initialize.c index 0ae00b04e0120..6dd2f3dbf5902 100644 --- a/mm/mm_heap/mm_initialize.c +++ b/mm/mm_heap/mm_initialize.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -202,6 +203,9 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart, mm_addfreechunk(heap, node); heap->mm_curused += 2 * MM_SIZEOF_ALLOCNODE; mm_unlock(heap); + + sched_note_heap(NOTE_HEAP_ADD, heap, heapstart, heapsize, + heap->mm_curused); } /**************************************************************************** @@ -367,6 +371,9 @@ void mm_uninitialize(FAR struct mm_heap_s *heap) for (i = 0; i < CONFIG_MM_REGIONS; i++) { kasan_unregister(heap->mm_heapstart[i]); + sched_note_heap(NOTE_HEAP_REMOVE, heap, heap->mm_heapstart[i], + (uintptr_t)heap->mm_heapend[i] - + (uintptr_t)heap->mm_heapstart[i], heap->mm_curused); } #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MEMINFO) diff --git a/mm/mm_heap/mm_malloc.c b/mm/mm_heap/mm_malloc.c index 96adef1a48501..3d15c326ac354 100644 --- a/mm/mm_heap/mm_malloc.c +++ b/mm/mm_heap/mm_malloc.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "mm_heap/mm.h" @@ -306,7 +307,8 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) /* Update heap statistics */ - heap->mm_curused += MM_SIZEOF_NODE(node); + nodesize = MM_SIZEOF_NODE(node); + heap->mm_curused += nodesize; if (heap->mm_curused > heap->mm_maxused) { heap->mm_maxused = heap->mm_curused; @@ -324,7 +326,9 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) if (ret) { MM_ADD_BACKTRACE(heap, node); - ret = kasan_unpoison(ret, mm_malloc_size(heap, ret)); + ret = kasan_unpoison(ret, nodesize - MM_ALLOCNODE_OVERHEAD); + sched_note_heap(NOTE_HEAP_ALLOC, heap, ret, nodesize, + heap->mm_curused); #ifdef CONFIG_MM_FILL_ALLOCATIONS memset(ret, MM_ALLOC_MAGIC, alignsize - MM_ALLOCNODE_OVERHEAD); #endif diff --git a/mm/mm_heap/mm_memalign.c b/mm/mm_heap/mm_memalign.c index 0aa449f29605f..aa0621889fece 100644 --- a/mm/mm_heap/mm_memalign.c +++ b/mm/mm_heap/mm_memalign.c @@ -30,6 +30,7 @@ #include #include +#include #include "mm_heap/mm.h" @@ -267,7 +268,8 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, /* Update heap statistics */ - heap->mm_curused += MM_SIZEOF_NODE(node); + size = MM_SIZEOF_NODE(node); + heap->mm_curused += size; if (heap->mm_curused > heap->mm_maxused) { heap->mm_maxused = heap->mm_curused; @@ -277,10 +279,10 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, MM_ADD_BACKTRACE(heap, node); - alignedchunk = (uintptr_t)kasan_unpoison - ((FAR const void *)alignedchunk, - mm_malloc_size(heap, - (FAR void *)alignedchunk)); + alignedchunk = (uintptr_t)kasan_unpoison((FAR const void *)alignedchunk, + size - MM_ALLOCNODE_OVERHEAD); + sched_note_heap(NOTE_HEAP_ALLOC, heap, (FAR void *)alignedchunk, size, + heap->mm_curused); DEBUGASSERT(alignedchunk % alignment == 0); return (FAR void *)alignedchunk; diff --git a/mm/mm_heap/mm_realloc.c b/mm/mm_heap/mm_realloc.c index 7125a71f04cea..13fc849541866 100644 --- a/mm/mm_heap/mm_realloc.c +++ b/mm/mm_heap/mm_realloc.c @@ -34,6 +34,7 @@ #include #include +#include #include "mm_heap/mm.h" @@ -382,10 +383,15 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, heap->mm_maxused = heap->mm_curused; } + sched_note_heap(NOTE_HEAP_FREE, heap, oldmem, oldsize, + heap->mm_curused - newsize); + sched_note_heap(NOTE_HEAP_ALLOC, heap, newmem, newsize, + heap->mm_curused); mm_unlock(heap); MM_ADD_BACKTRACE(heap, (FAR char *)newmem - MM_SIZEOF_ALLOCNODE); - newmem = kasan_unpoison(newmem, mm_malloc_size(heap, newmem)); + newmem = kasan_unpoison(newmem, MM_SIZEOF_NODE(oldnode) - + MM_ALLOCNODE_OVERHEAD); if (kasan_reset_tag(newmem) != kasan_reset_tag(oldmem)) { /* Now we have to move the user contents 'down' in memory. memcpy diff --git a/mm/tlsf/mm_tlsf.c b/mm/tlsf/mm_tlsf.c index 4c60f419bf507..ff32de3726250 100644 --- a/mm/tlsf/mm_tlsf.c +++ b/mm/tlsf/mm_tlsf.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "tlsf/tlsf.h" @@ -492,15 +493,12 @@ static void mm_delayfree(FAR struct mm_heap_s *heap, FAR void *mem, { if (mm_lock(heap) == 0) { + size_t size = mm_malloc_size(heap, mem); #ifdef CONFIG_MM_FILL_ALLOCATIONS - memset(mem, MM_FREE_MAGIC, mm_malloc_size(heap, mem)); + memset(mem, MM_FREE_MAGIC, size); #endif - kasan_poison(mem, mm_malloc_size(heap, mem)); - - /* Update heap statistics */ - - heap->mm_curused -= mm_malloc_size(heap, mem); + kasan_poison(mem, size); /* Pass, return to the tlsf pool */ @@ -510,6 +508,10 @@ static void mm_delayfree(FAR struct mm_heap_s *heap, FAR void *mem, } else { + /* Update heap statistics */ + + heap->mm_curused -= size; + sched_note_heap(NOTE_HEAP_FREE, heap, mem, size, heap->mm_curused); tlsf_free(heap->mm_tlsf, mem); } @@ -598,6 +600,9 @@ void mm_addregion(FAR struct mm_heap_s *heap, FAR void *heapstart, tlsf_add_pool(heap->mm_tlsf, heapstart, heapsize); mm_unlock(heap); + + sched_note_heap(NOTE_HEAP_ADD, heap, heapstart, heapsize, + heap->mm_curused); } /**************************************************************************** @@ -1134,6 +1139,7 @@ size_t mm_malloc_size(FAR struct mm_heap_s *heap, FAR void *mem) FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) { + size_t nodesize; FAR void *ret; /* In case of zero-length allocations allocate the minimum size object */ @@ -1168,7 +1174,8 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) ret = tlsf_malloc(heap->mm_tlsf, size); #endif - heap->mm_curused += mm_malloc_size(heap, ret); + nodesize = mm_malloc_size(heap, ret); + heap->mm_curused += nodesize; if (heap->mm_curused > heap->mm_maxused) { heap->mm_maxused = heap->mm_curused; @@ -1179,11 +1186,14 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) if (ret) { #if CONFIG_MM_BACKTRACE >= 0 - FAR struct memdump_backtrace_s *buf = ret + mm_malloc_size(heap, ret); + FAR struct memdump_backtrace_s *buf = ret + nodesize; memdump_backtrace(heap, buf); #endif - ret = kasan_unpoison(ret, mm_malloc_size(heap, ret)); + + ret = kasan_unpoison(ret, nodesize); + sched_note_heap(NOTE_HEAP_ALLOC, heap, ret, nodesize, + heap->mm_curused); #ifdef CONFIG_MM_FILL_ALLOCATIONS memset(ret, 0xaa, nodesize); @@ -1218,6 +1228,7 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, size_t size) { + size_t nodesize; FAR void *ret; #ifdef CONFIG_MM_HEAP_MEMPOOL @@ -1245,7 +1256,8 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, ret = tlsf_memalign(heap->mm_tlsf, alignment, size); #endif - heap->mm_curused += mm_malloc_size(heap, ret); + nodesize = mm_malloc_size(heap, ret); + heap->mm_curused += nodesize; if (heap->mm_curused > heap->mm_maxused) { heap->mm_maxused = heap->mm_curused; @@ -1256,11 +1268,13 @@ FAR void *mm_memalign(FAR struct mm_heap_s *heap, size_t alignment, if (ret) { #if CONFIG_MM_BACKTRACE >= 0 - FAR struct memdump_backtrace_s *buf = ret + mm_malloc_size(heap, ret); + FAR struct memdump_backtrace_s *buf = ret + nodesize; memdump_backtrace(heap, buf); #endif - ret = kasan_unpoison(ret, mm_malloc_size(heap, ret)); + ret = kasan_unpoison(ret, nodesize); + sched_note_heap(NOTE_HEAP_ALLOC, heap, ret, nodesize, + heap->mm_curused); } #if CONFIG_MM_FREE_DELAYCOUNT_MAX > 0 @@ -1302,6 +1316,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, size_t size) { FAR void *newmem; + size_t oldsize; + size_t newsize; /* If oldmem is NULL, then realloc is equivalent to malloc */ @@ -1361,7 +1377,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, /* Allocate from the tlsf pool */ DEBUGVERIFY(mm_lock(heap)); - heap->mm_curused -= mm_malloc_size(heap, oldmem); + oldsize = mm_malloc_size(heap, oldmem); + heap->mm_curused -= oldsize; #if CONFIG_MM_BACKTRACE >= 0 newmem = tlsf_realloc(heap->mm_tlsf, oldmem, size + sizeof(struct memdump_backtrace_s)); @@ -1369,7 +1386,8 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, newmem = tlsf_realloc(heap->mm_tlsf, oldmem, size); #endif - heap->mm_curused += mm_malloc_size(heap, newmem ? newmem : oldmem); + newsize = mm_malloc_size(heap, newmem); + heap->mm_curused += newmem ? newsize : oldsize; if (heap->mm_curused > heap->mm_maxused) { heap->mm_maxused = heap->mm_curused; @@ -1377,20 +1395,23 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem, mm_unlock(heap); -#if CONFIG_MM_BACKTRACE >= 0 if (newmem) { - FAR struct memdump_backtrace_s *buf = - newmem + mm_malloc_size(heap, newmem); - +#if CONFIG_MM_BACKTRACE >= 0 + FAR struct memdump_backtrace_s *buf = newmem + newsize; memdump_backtrace(heap, buf); - } #endif + sched_note_heap(NOTE_HEAP_FREE, heap, oldmem, oldsize, + heap->mm_curused - newsize); + sched_note_heap(NOTE_HEAP_ALLOC, heap, newmem, newsize, + heap->mm_curused); + } + #if CONFIG_MM_FREE_DELAYCOUNT_MAX > 0 /* Try again after free delay list */ - if (newmem == NULL && free_delaylist(heap, true)) + else if (free_delaylist(heap, true)) { return mm_realloc(heap, oldmem, size); } @@ -1425,6 +1446,9 @@ void mm_uninitialize(FAR struct mm_heap_s *heap) for (i = 0; i < CONFIG_MM_REGIONS; i++) { kasan_unregister(heap->mm_heapstart[i]); + sched_note_heap(NOTE_HEAP_REMOVE, heap, heap->mm_heapstart[i], + (uintptr_t)heap->mm_heapend[i] - + (uintptr_t)heap->mm_heapstart[i], heap->mm_curused); } #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MEMINFO) diff --git a/sched/Kconfig b/sched/Kconfig index f7a10612fdbcc..a4c5110c6f7ee 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -1284,6 +1284,14 @@ config SCHED_INSTRUMENTATION_IRQHANDLER void sched_note_irqhandler(int irq, FAR void *handler, bool enter); +config SCHED_INSTRUMENTATION_HEAP + bool "Heap monitor hooks" + default n + ---help--- + Enables additional hooks for heap allocation. + + void sched_note_heap(uint8_t event, FAR void* heap, FAR void *mem, size_t size, size_t curused); + config SCHED_INSTRUMENTATION_DUMP bool "Use note dump for instrumentation" default n diff --git a/tools/nxstyle.c b/tools/nxstyle.c index f886497360aac..4e27d179996c7 100644 --- a/tools/nxstyle.c +++ b/tools/nxstyle.c @@ -304,12 +304,19 @@ static const char *g_white_content_list[] = * drivers/segger/note_sysview.c */ + "DataType", + "Offset", + "Prio", + "pU32_Value", + "RangeMax", + "RangeMin", "SEGGER_SYSVIEW", - "TaskID", + "ScalingFactor", "sName", - "Prio", + "sUnit", "StackBase", "StackSize", + "TaskID", /* Ref: * drivers/segger/syslog_rtt.c