Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Documentation/components/drivers/special/segger.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 43 additions & 1 deletion arch/sim/src/sim/sim_heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <nuttx/atomic.h>
#include <nuttx/fs/procfs.h>
#include <nuttx/mm/mm.h>
#include <nuttx/sched_note.h>

#include "sim_internal.h"

Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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);

Expand All @@ -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
{
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 47 additions & 0 deletions drivers/note/note_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down Expand Up @@ -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, &note.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, &note, sizeof(note));
}
}
#endif

#ifdef CONFIG_SCHED_INSTRUMENTATION_DUMP
void sched_note_string_ip(uint32_t tag, uintptr_t ip, FAR const char *buf)
{
Expand Down
28 changes: 26 additions & 2 deletions drivers/note/noteram_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include <nuttx/spinlock.h>
#include <nuttx/sched.h>
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -621,18 +623,20 @@ 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);
if (taskname != NULL)
{
return taskname;
}
#endif

return "<noname>";
}
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion drivers/segger/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 67 additions & 0 deletions drivers/segger/note_sysview.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
****************************************************************************/

#include <stddef.h>
#include <stdio.h>
#include <syslog.h>

#include <nuttx/clock.h>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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
****************************************************************************/
Expand Down
5 changes: 5 additions & 0 deletions include/nuttx/note/note_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading