From 743874128f2834f265a333fb1b732ed1ec9ab2f4 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Wed, 2 Sep 2020 12:45:37 +0200 Subject: [PATCH 1/5] alloc: Add possibility to read memory usage in runtime Such a function may be used to monitor memory leaks and system utilization. Signed-off-by: Karol Trzcinski --- src/include/sof/lib/mm_heap.h | 8 +++++++ src/lib/alloc.c | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/include/sof/lib/mm_heap.h b/src/include/sof/lib/mm_heap.h index 4fa5bb02f4b0..8567c677d03a 100644 --- a/src/include/sof/lib/mm_heap.h +++ b/src/include/sof/lib/mm_heap.h @@ -86,6 +86,14 @@ void free_heap(enum mem_zone zone); void heap_trace_all(int force); void heap_trace(struct mm_heap *heap, int size); +/** Fetch runtime information about heap, like used and free memory space + * @param zone to check, see enum mem_zone. + * @param index heap index, eg. cpu core index for any *SYS* zone + * @param out output variable + * @return error code or zero + */ +int heap_info(enum mem_zone zone, int index, struct mm_info *out); + /* retrieve memory map pointer */ static inline struct mm *memmap_get(void) { diff --git a/src/lib/alloc.c b/src/lib/alloc.c index f98c396a148a..51ea617a72b9 100644 --- a/src/lib/alloc.c +++ b/src/lib/alloc.c @@ -1069,3 +1069,46 @@ void init_heap(struct sof *sof) platform_shared_commit(memmap, sizeof(*memmap)); } + +int heap_info(enum mem_zone zone, int index, struct mm_info *out) +{ + struct mm *memmap = memmap_get(); + struct mm_heap *heap; + + if (!out) + goto error; + + switch (zone) { + case SOF_MEM_ZONE_SYS: + if (index >= PLATFORM_HEAP_SYSTEM) + goto error; + heap = memmap->system + index; + break; + case SOF_MEM_ZONE_SYS_RUNTIME: + if (index >= PLATFORM_HEAP_SYSTEM_RUNTIME) + goto error; + heap = memmap->system_runtime + index; + break; + case SOF_MEM_ZONE_RUNTIME: + if (index >= PLATFORM_HEAP_RUNTIME) + goto error; + heap = memmap->runtime + index; + break; + case SOF_MEM_ZONE_BUFFER: + if (index >= PLATFORM_HEAP_BUFFER) + goto error; + heap = memmap->buffer + index; + break; + default: + goto error; + } + + spin_lock(&memmap->lock); + *out = heap->info; + spin_unlock(&memmap->lock); + return 0; +error: + tr_err(&mem_tr, "heap_info(): failed for zone 0x%x index %d out ptr 0x%x", zone, index, + (uint32_t)out); + return -EINVAL; +} From 178c919862ffaf4186008ba0eadf13d62f24986a Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Mon, 7 Sep 2020 12:40:51 +0200 Subject: [PATCH 2/5] ipc: Rename function handling SOF_IPC_GLB_TRACE_MSG Function name should correspond IPC name. Signed-off-by: Karol Trzcinski --- src/ipc/handler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 62d75cf21ed6..5126071e5360 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -796,7 +796,7 @@ static int ipc_trace_filter_update(uint32_t header) return ret; } -static int ipc_glb_debug_message(uint32_t header) +static int ipc_glb_trace_message(uint32_t header) { uint32_t cmd = iCS(header); @@ -814,7 +814,7 @@ static int ipc_glb_debug_message(uint32_t header) } } #else -static int ipc_glb_debug_message(uint32_t header) +static int ipc_glb_trace_message(uint32_t header) { /* traces are disabled - CONFIG_TRACE is not set */ @@ -1337,7 +1337,7 @@ void ipc_cmd(struct sof_ipc_cmd_hdr *hdr) ret = ipc_glb_dai_message(hdr->cmd); break; case SOF_IPC_GLB_TRACE_MSG: - ret = ipc_glb_debug_message(hdr->cmd); + ret = ipc_glb_trace_message(hdr->cmd); break; case SOF_IPC_GLB_GDB_DEBUG: ret = ipc_glb_gdb_debug(hdr->cmd); From 8a9b5bb9ce38759aefcf2c266535da48137ec610 Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Thu, 3 Sep 2020 12:56:34 +0200 Subject: [PATCH 3/5] ipc: debug: Add memory usage probing possibility This feature will be needed to monitor memory utilization and memory leaks. It may be usable also in realese builds, so removed conditional ipc_glb_test_message compilation. Signed-off-by: Karol Trzcinski --- src/include/ipc/debug.h | 39 +++++++++++++++++++++++ src/include/ipc/header.h | 9 ++++++ src/include/kernel/abi.h | 2 +- src/ipc/handler.c | 69 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/include/ipc/debug.h diff --git a/src/include/ipc/debug.h b/src/include/ipc/debug.h new file mode 100644 index 000000000000..cb77c9ca9b03 --- /dev/null +++ b/src/include/ipc/debug.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2020 Intel Corporation. All rights reserved. + * + * Author: Author: Karol Trzcinski + */ + +#ifndef __IPC_DEBUG_H__ +#define __IPC_DEBUG_H__ + +#include +#include + +/** ABI3.18 */ +enum sof_ipc_dbg_mem_zone { + SOF_IPC_MEM_ZONE_SYS = 0, /**< System zone */ + SOF_IPC_MEM_ZONE_SYS_RUNTIME = 1, /**< System-runtime zone */ + SOF_IPC_MEM_ZONE_RUNTIME = 2, /**< Runtime zone */ + SOF_IPC_MEM_ZONE_BUFFER = 3, /**< Buffer zone */ +}; + +/** ABI3.18 */ +struct sof_ipc_dbg_mem_usage_elem { + uint32_t zone; /**< see sof_ipc_dbg_mem_zone */ + uint32_t id; /**< heap index within zone */ + uint32_t used; /**< number of bytes used in zone */ + uint32_t free; /**< number of bytes free to use within zone */ + uint32_t reserved; /**< reserved for future use */ +} __attribute__((packed)); + +/** ABI3.18 */ +struct sof_ipc_dbg_mem_usage { + struct sof_ipc_reply rhdr; /**< generic IPC reply header */ + uint32_t reserved[4]; /**< reserved for future use */ + uint32_t num_elems; /**< elems[] counter */ + struct sof_ipc_dbg_mem_usage_elem elems[]; /**< memory usage information */ +} __attribute__((packed)); + +#endif /* __IPC_DEBUG_H__ */ diff --git a/src/include/ipc/header.h b/src/include/ipc/header.h index f4c5a7715916..000e3134f03b 100644 --- a/src/include/ipc/header.h +++ b/src/include/ipc/header.h @@ -186,6 +186,7 @@ #define SOF_IPC_GLB_GDB_DEBUG SOF_GLB_TYPE(0xAU) #define SOF_IPC_GLB_TEST SOF_GLB_TYPE(0xBU) #define SOF_IPC_GLB_PROBE SOF_GLB_TYPE(0xCU) +#define SOF_IPC_GLB_DEBUG SOF_GLB_TYPE(0xDU) /** @} */ @@ -285,6 +286,14 @@ /** @} */ +/** \name DSP Command: Debug - additional services + * @{ + */ + +#define SOF_IPC_DEBUG_MEM_USAGE SOF_CMD_TYPE(0x001) + +/** @} */ + /** \name DSP Command: Test - Debug build only * @{ */ diff --git a/src/include/kernel/abi.h b/src/include/kernel/abi.h index c7f343f355ef..4eb01a563882 100644 --- a/src/include/kernel/abi.h +++ b/src/include/kernel/abi.h @@ -29,7 +29,7 @@ /** \brief SOF ABI version major, minor and patch numbers */ #define SOF_ABI_MAJOR 3 -#define SOF_ABI_MINOR 17 +#define SOF_ABI_MINOR 18 #define SOF_ABI_PATCH 0 /** \brief SOF ABI version number. Format within 32bit word is MMmmmppp */ diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 5126071e5360..0bea8636510d 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -1281,6 +1283,70 @@ static int ipc_glb_tplg_message(uint32_t header) } } +static int fill_mem_usage_elems(int zone, int elem_number, + struct sof_ipc_dbg_mem_usage_elem *elems) +{ + struct mm_info info; + int ret; + int i; + + for (i = 0; i < elem_number; ++i) { + ret = heap_info(zone, i, &info); + elems[i].zone = zone; + elems[i].id = i; + elems[i].used = ret < 0 ? UINT32_MAX : info.used; + elems[i].free = ret < 0 ? 0 : info.free; + } + + return elem_number; +} + +static int ipc_glb_test_mem_usage(uint32_t header) +{ + /* count number heaps */ + int elem_cnt = PLATFORM_HEAP_SYSTEM + PLATFORM_HEAP_SYSTEM_RUNTIME + + PLATFORM_HEAP_RUNTIME + PLATFORM_HEAP_BUFFER; + size_t size = sizeof(struct sof_ipc_dbg_mem_usage) + + elem_cnt * sizeof(struct sof_ipc_dbg_mem_usage_elem); + struct sof_ipc_dbg_mem_usage_elem *elems; + struct sof_ipc_dbg_mem_usage *mem_usage; + + mem_usage = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, 0, size); + if (!mem_usage) + return -ENOMEM; + + mem_usage->rhdr.hdr.cmd = header; + mem_usage->rhdr.hdr.size = size; + mem_usage->num_elems = elem_cnt; + + /* fill list of elems */ + elems = mem_usage->elems; + elems += fill_mem_usage_elems(SOF_IPC_MEM_ZONE_SYS, PLATFORM_HEAP_SYSTEM, elems); + elems += fill_mem_usage_elems(SOF_IPC_MEM_ZONE_SYS_RUNTIME, PLATFORM_HEAP_SYSTEM_RUNTIME, + elems); + elems += fill_mem_usage_elems(SOF_IPC_MEM_ZONE_RUNTIME, PLATFORM_HEAP_RUNTIME, elems); + elems += fill_mem_usage_elems(SOF_IPC_MEM_ZONE_BUFFER, PLATFORM_HEAP_BUFFER, elems); + + /* write component values to the outbox */ + mailbox_hostbox_write(0, mem_usage, mem_usage->rhdr.hdr.size); + + rfree(mem_usage); + return 1; +} + +static int ipc_glb_debug_message(uint32_t header) +{ + uint32_t cmd = iCS(header); + + switch (cmd) { + case SOF_IPC_DEBUG_MEM_USAGE: + return ipc_glb_test_mem_usage(header); + default: + tr_err(&ipc_tr, "ipc: unknown debug header 0x%x", header); + return -EINVAL; + } +} + #if CONFIG_DEBUG static int ipc_glb_test_message(uint32_t header) { @@ -1345,6 +1411,9 @@ void ipc_cmd(struct sof_ipc_cmd_hdr *hdr) case SOF_IPC_GLB_PROBE: ret = ipc_glb_probe(hdr->cmd); break; + case SOF_IPC_GLB_DEBUG: + ret = ipc_glb_debug_message(hdr->cmd); + break; #if CONFIG_DEBUG case SOF_IPC_GLB_TEST: ret = ipc_glb_test_message(hdr->cmd); From 2e7e5c13409da4aa66ebddb177b9ed903f0b650d Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 29 Sep 2020 14:14:26 +0200 Subject: [PATCH 4/5] ipc: debug: Add KConfig to conditionally compile memory scan feature This feature is not needed to get functional firmware, so may be disabled for platforms with low memory space, like baytrail and cherrytrail. Signed-off-by: Karol Trzcinski --- Kconfig | 8 ++++++++ src/arch/xtensa/configs/baytrail_defconfig | 1 + src/arch/xtensa/configs/baytrail_gcc_defconfig | 1 + src/arch/xtensa/configs/cherrytrail_defconfig | 1 + src/arch/xtensa/configs/cherrytrail_gcc_defconfig | 1 + src/include/sof/lib/mm_heap.h | 2 ++ src/ipc/handler.c | 4 ++++ src/lib/alloc.c | 2 ++ 8 files changed, 20 insertions(+) diff --git a/Kconfig b/Kconfig index 9ea7ff644881..cc333fc393a7 100644 --- a/Kconfig +++ b/Kconfig @@ -181,6 +181,14 @@ config DEBUG_HEAP help Select for enable heap alloc debugging +config DEBUG_MEMORY_USAGE_SCAN + bool "Memory usage scan" + default y + help + It enables memory usage scan at demand in runtime. + This feature does not affect standard memory operations, + especially allocation and deallocation. + config DEBUG_BLOCK_FREE bool "Blocks freeing debug" default n diff --git a/src/arch/xtensa/configs/baytrail_defconfig b/src/arch/xtensa/configs/baytrail_defconfig index d1aafe8ab98f..3068f1ccc8ff 100644 --- a/src/arch/xtensa/configs/baytrail_defconfig +++ b/src/arch/xtensa/configs/baytrail_defconfig @@ -11,3 +11,4 @@ CONFIG_COMP_ASRC=n CONFIG_COMP_TDFB=n CONFIG_OPTIMIZE_FOR_SIZE=y CONFIG_HAVE_AGENT=n +CONFIG_DEBUG_MEMORY_USAGE_SCAN=n diff --git a/src/arch/xtensa/configs/baytrail_gcc_defconfig b/src/arch/xtensa/configs/baytrail_gcc_defconfig index 1d71c1e7e0a6..3ffaf3811431 100644 --- a/src/arch/xtensa/configs/baytrail_gcc_defconfig +++ b/src/arch/xtensa/configs/baytrail_gcc_defconfig @@ -10,3 +10,4 @@ CONFIG_COMP_SRC=n CONFIG_COMP_ASRC=n CONFIG_COMP_TDFB=n CONFIG_HAVE_AGENT=n +CONFIG_DEBUG_MEMORY_USAGE_SCAN=n diff --git a/src/arch/xtensa/configs/cherrytrail_defconfig b/src/arch/xtensa/configs/cherrytrail_defconfig index 4db2949984cb..ed71e7d575f9 100644 --- a/src/arch/xtensa/configs/cherrytrail_defconfig +++ b/src/arch/xtensa/configs/cherrytrail_defconfig @@ -11,3 +11,4 @@ CONFIG_COMP_SRC=n CONFIG_COMP_TDFB=n CONFIG_OPTIMIZE_FOR_SIZE=y CONFIG_HAVE_AGENT=n +CONFIG_DEBUG_MEMORY_USAGE_SCAN=n diff --git a/src/arch/xtensa/configs/cherrytrail_gcc_defconfig b/src/arch/xtensa/configs/cherrytrail_gcc_defconfig index e6255bb01a79..43b203bfa281 100644 --- a/src/arch/xtensa/configs/cherrytrail_gcc_defconfig +++ b/src/arch/xtensa/configs/cherrytrail_gcc_defconfig @@ -10,3 +10,4 @@ CONFIG_COMP_SRC=n CONFIG_COMP_ASRC=n CONFIG_COMP_TDFB=n CONFIG_HAVE_AGENT=n +CONFIG_DEBUG_MEMORY_USAGE_SCAN=n diff --git a/src/include/sof/lib/mm_heap.h b/src/include/sof/lib/mm_heap.h index 8567c677d03a..7ff15abbefd5 100644 --- a/src/include/sof/lib/mm_heap.h +++ b/src/include/sof/lib/mm_heap.h @@ -86,6 +86,7 @@ void free_heap(enum mem_zone zone); void heap_trace_all(int force); void heap_trace(struct mm_heap *heap, int size); +#if CONFIG_DEBUG_MEMORY_USAGE_SCAN /** Fetch runtime information about heap, like used and free memory space * @param zone to check, see enum mem_zone. * @param index heap index, eg. cpu core index for any *SYS* zone @@ -93,6 +94,7 @@ void heap_trace(struct mm_heap *heap, int size); * @return error code or zero */ int heap_info(enum mem_zone zone, int index, struct mm_info *out); +#endif /* retrieve memory map pointer */ static inline struct mm *memmap_get(void) diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 0bea8636510d..64b10f07a286 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -1283,6 +1283,7 @@ static int ipc_glb_tplg_message(uint32_t header) } } +#if CONFIG_DEBUG_MEMORY_USAGE_SCAN static int fill_mem_usage_elems(int zone, int elem_number, struct sof_ipc_dbg_mem_usage_elem *elems) { @@ -1333,14 +1334,17 @@ static int ipc_glb_test_mem_usage(uint32_t header) rfree(mem_usage); return 1; } +#endif static int ipc_glb_debug_message(uint32_t header) { uint32_t cmd = iCS(header); switch (cmd) { +#if CONFIG_DEBUG_MEMORY_USAGE_SCAN case SOF_IPC_DEBUG_MEM_USAGE: return ipc_glb_test_mem_usage(header); +#endif default: tr_err(&ipc_tr, "ipc: unknown debug header 0x%x", header); return -EINVAL; diff --git a/src/lib/alloc.c b/src/lib/alloc.c index 51ea617a72b9..2de657941f1d 100644 --- a/src/lib/alloc.c +++ b/src/lib/alloc.c @@ -1070,6 +1070,7 @@ void init_heap(struct sof *sof) platform_shared_commit(memmap, sizeof(*memmap)); } +#if CONFIG_DEBUG_MEMORY_USAGE_SCAN int heap_info(enum mem_zone zone, int index, struct mm_info *out) { struct mm *memmap = memmap_get(); @@ -1112,3 +1113,4 @@ int heap_info(enum mem_zone zone, int index, struct mm_info *out) (uint32_t)out); return -EINVAL; } +#endif From f64bfb110f4324659a937bedae2669d9ba2a8fec Mon Sep 17 00:00:00 2001 From: Karol Trzcinski Date: Tue, 29 Sep 2020 14:28:00 +0200 Subject: [PATCH 5/5] ext_man: Add information about runtime memory scan possibility This component is conditionally compiled, so passing such an information to driver, allows to check possible scanning failure reason. Signed-off-by: Karol Trzcinski --- src/include/kernel/ext_manifest.h | 1 + src/init/ext_manifest.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/include/kernel/ext_manifest.h b/src/include/kernel/ext_manifest.h index c04db042392a..70cb14dd5587 100644 --- a/src/include/kernel/ext_manifest.h +++ b/src/include/kernel/ext_manifest.h @@ -58,6 +58,7 @@ enum ext_man_elem_type { /* EXT_MAN_ELEM_CONFIG_DATA elements identificators */ enum config_elem_type { EXT_MAN_CONFIG_IPC_MSG_SIZE = 1, + EXT_MAN_CONFIG_MEMORY_USAGE_SCAN = 2, /**< ABI3.18 */ EXT_MAN_CONFIG_LAST_ELEM, /**< keep it at the end of enum list */ }; diff --git a/src/init/ext_manifest.c b/src/init/ext_manifest.c index 7d993337d845..2e9b5b5574f5 100644 --- a/src/init/ext_manifest.c +++ b/src/init/ext_manifest.c @@ -92,5 +92,6 @@ const struct ext_man_config_data ext_man_config EXT_MAN_ALIGN), .elems = { {EXT_MAN_CONFIG_IPC_MSG_SIZE, SOF_IPC_MSG_MAX_SIZE}, + {EXT_MAN_CONFIG_MEMORY_USAGE_SCAN, IS_ENABLED(CONFIG_DEBUG_MEMORY_USAGE_SCAN)}, }, };