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/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/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/include/sof/lib/mm_heap.h b/src/include/sof/lib/mm_heap.h index 4fa5bb02f4b0..7ff15abbefd5 100644 --- a/src/include/sof/lib/mm_heap.h +++ b/src/include/sof/lib/mm_heap.h @@ -86,6 +86,16 @@ 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 + * @param out output variable + * @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/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)}, }, }; diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 62d75cf21ed6..64b10f07a286 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 @@ -796,7 +798,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 +816,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 */ @@ -1281,6 +1283,74 @@ 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) +{ + 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; +} +#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; + } +} + #if CONFIG_DEBUG static int ipc_glb_test_message(uint32_t header) { @@ -1337,7 +1407,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); @@ -1345,6 +1415,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); diff --git a/src/lib/alloc.c b/src/lib/alloc.c index f98c396a148a..2de657941f1d 100644 --- a/src/lib/alloc.c +++ b/src/lib/alloc.c @@ -1069,3 +1069,48 @@ 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(); + 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; +} +#endif