diff --git a/src/audio/codec/dts/dts.c b/src/audio/codec/dts/dts.c index 83a112ab0ae3..cdda17b78d66 100644 --- a/src/audio/codec/dts/dts.c +++ b/src/audio/codec/dts/dts.c @@ -25,7 +25,7 @@ static void *dts_effect_allocate_codec_memory(void *mod_void, unsigned int lengt comp_dbg(dev, "dts_effect_allocate_codec_memory() start"); - pMem = module_allocate_memory(mod, (uint32_t)length, (uint32_t)alignment); + pMem = mod_alloc_align(mod, (uint32_t)length, (uint32_t)alignment); if (pMem == NULL) comp_err(dev, @@ -42,10 +42,10 @@ static void dts_effect_free_codec_memory(void *mod_void, void *pMem) comp_dbg(dev, "dts_effect_free_codec_memory() start"); - int ret = module_free_memory(mod, pMem); + int ret = mod_free(mod, pMem); if (ret) - comp_err(dev, "dts_effect_free_codec_memory() module_free_memory failed %d", ret); + comp_err(dev, "dts_effect_free_codec_memory() mod_free failed %d", ret); comp_dbg(dev, "dts_effect_free_codec_memory() done"); } @@ -405,8 +405,6 @@ static int dts_codec_free(struct processing_module *mod) if (ret) comp_err(dev, "dts_codec_free() failed %d %d", ret, dts_result); - module_free_all_memory(mod); - comp_dbg(dev, "dts_codec_free() done"); return ret; diff --git a/src/audio/module_adapter/module/cadence.c b/src/audio/module_adapter/module/cadence.c index 87ee611eb19f..c854fc2fb85b 100644 --- a/src/audio/module_adapter/module/cadence.c +++ b/src/audio/module_adapter/module/cadence.c @@ -519,7 +519,7 @@ static int init_memory_tables(struct processing_module *mod) goto err; } /* Allocate memory for this type, taking alignment into account */ - ptr = module_allocate_memory(mod, mem_size, mem_alignment); + ptr = mod_alloc_align(mod, mem_size, mem_alignment); if (!ptr) { comp_err(dev, "init_memory_tables() error %x: failed to allocate memory for %d", ret, mem_type); @@ -563,13 +563,13 @@ static int init_memory_tables(struct processing_module *mod) return 0; err: if (scratch) - module_free_memory(mod, scratch); + mod_free(mod, scratch); if (persistent) - module_free_memory(mod, persistent); + mod_free(mod, persistent); if (codec->mpd.in_buff) - module_free_memory(mod, codec->mpd.in_buff); + mod_free(mod, codec->mpd.in_buff); if (codec->mpd.out_buff) - module_free_memory(mod, codec->mpd.out_buff); + mod_free(mod, codec->mpd.out_buff); return ret; } @@ -688,7 +688,7 @@ static int cadence_codec_prepare(struct processing_module *mod, return ret; } - cd->mem_tabs = module_allocate_memory(mod, mem_tabs_size, 4); + cd->mem_tabs = mod_alloc(mod, mem_tabs_size); if (!cd->mem_tabs) { comp_err(dev, "cadence_codec_prepare() error: failed to allocate space for memtabs"); return -ENOMEM; @@ -732,7 +732,7 @@ static int cadence_codec_prepare(struct processing_module *mod, comp_dbg(dev, "cadence_codec_prepare() done"); return 0; free: - module_free_memory(mod, cd->mem_tabs); + mod_free(mod, cd->mem_tabs); return ret; } @@ -847,7 +847,7 @@ static int cadence_codec_reset(struct processing_module *mod) * So, free all memory associated with runtime params. These will be reallocated during * prepare. */ - module_free_all_memory(mod); + mod_free_all(mod); /* reset to default params */ API_CALL(cd, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL, ret); @@ -867,7 +867,7 @@ static int cadence_codec_free(struct processing_module *mod) struct cadence_codec_data *cd = module_get_private_data(mod); rfree(cd->setup_cfg.data); - module_free_all_memory(mod); + mod_free_all(mod); rfree(cd->self); rfree(cd); return 0; diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index f7983cf67d53..b755de0adf16 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -110,14 +110,23 @@ int module_init(struct processing_module *mod) return 0; } -void *module_allocate_memory(struct processing_module *mod, uint32_t size, uint32_t alignment) +/** + * Allocates aligned memory block for module. + * @param mod Pointer to the module this memory block is allocatd for. + * @param bytes Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * The allocated memory is automatically freed when the module is unloaded. + */ +void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t alignment) { struct comp_dev *dev = mod->dev; struct module_memory *container; void *ptr; if (!size) { - comp_err(dev, "module_allocate_memory: requested allocation of 0 bytes."); + comp_err(dev, "mod_alloc: requested allocation of 0 bytes."); return NULL; } @@ -125,7 +134,7 @@ void *module_allocate_memory(struct processing_module *mod, uint32_t size, uint3 container = rzalloc(SOF_MEM_FLAG_USER, sizeof(struct module_memory)); if (!container) { - comp_err(dev, "module_allocate_memory: failed to allocate memory container."); + comp_err(dev, "mod_alloc: failed to allocate memory container."); return NULL; } @@ -136,18 +145,60 @@ void *module_allocate_memory(struct processing_module *mod, uint32_t size, uint3 ptr = rballoc(SOF_MEM_FLAG_USER, size); if (!ptr) { - comp_err(dev, "module_allocate_memory: failed to allocate memory for comp %x.", + comp_err(dev, "mod_alloc: failed to allocate memory for comp %x.", dev_comp_id(dev)); + rfree(container); return NULL; } /* Store reference to allocated memory */ container->ptr = ptr; + container->size = size; list_item_prepend(&container->mem_list, &mod->priv.memory.mem_list); return ptr; } +EXPORT_SYMBOL(mod_alloc_align); + +/** + * Allocates memory block for module. + * @param mod Pointer to module this memory block is allocated for. + * @param bytes Size in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * Like mod_alloc_align() but the alignment can not be specified. However, + * rballoc() will always aligns the memory to PLATFORM_DCACHE_ALIGN. + */ +void *mod_alloc(struct processing_module *mod, uint32_t size) +{ + return mod_alloc_align(mod, size, 0); +} +EXPORT_SYMBOL(mod_alloc); -int module_free_memory(struct processing_module *mod, void *ptr) +/** + * Allocates memory block for module and initializes it to zero. + * @param mod Pointer to module this memory block is allocated for. + * @param bytes Size in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * Like mod_alloc() but the allocated memory is initialized to zero. + */ +void *mod_zalloc(struct processing_module *mod, uint32_t size) +{ + void *ret = mod_alloc(mod, size); + + if (ret) + memset(ret, 0, size); + + return ret; +} +EXPORT_SYMBOL(mod_zalloc); + +/** + * Frees the memory block removes it from module's book keeping. + * @param mod Pointer to module this memory block was allocated for. + * @param ptr Pointer to the memory block. + */ +int mod_free(struct processing_module *mod, void *ptr) { struct module_memory *mem; struct list_item *mem_list; @@ -167,11 +218,12 @@ int module_free_memory(struct processing_module *mod, void *ptr) } } - comp_err(mod->dev, "module_free_memory: error: could not find memory pointed by %p", + comp_err(mod->dev, "mod_free: error: could not find memory pointed by %p", ptr); return -EINVAL; } +EXPORT_SYMBOL(mod_free); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, @@ -343,7 +395,13 @@ int module_reset(struct processing_module *mod) return 0; } -void module_free_all_memory(struct processing_module *mod) +/** + * Frees all the memory allocated for this module + * @param mod Pointer to module this memory block was allocated for. + * + * This function is called automatically when the module is unloaded. + */ +void mod_free_all(struct processing_module *mod) { struct module_memory *mem; struct list_item *mem_list; @@ -357,6 +415,7 @@ void module_free_all_memory(struct processing_module *mod) rfree(mem); } } +EXPORT_SYMBOL(mod_free_all); int module_free(struct processing_module *mod) { diff --git a/src/audio/module_adapter/module/waves/waves.c b/src/audio/module_adapter/module/waves/waves.c index d384b2b15334..94151a0f8a6d 100644 --- a/src/audio/module_adapter/module/waves/waves.c +++ b/src/audio/module_adapter/module/waves/waves.c @@ -200,7 +200,7 @@ static int waves_effect_allocate(struct processing_module *mod) return -EINVAL; } - waves_codec->effect = (MaxxEffect_t *)module_allocate_memory(mod, + waves_codec->effect = (MaxxEffect_t *)mod_alloc_align(mod, waves_codec->effect_size, 16); if (!waves_codec->effect) { @@ -376,7 +376,7 @@ static int waves_effect_buffers(struct processing_module *mod) comp_dbg(dev, "waves_effect_buffers() start"); - i_buffer = module_allocate_memory(mod, waves_codec->buffer_bytes, 16); + i_buffer = mod_alloc_align(mod, waves_codec->buffer_bytes, 16); if (!i_buffer) { comp_err(dev, "waves_effect_buffers() failed to allocate %d bytes for i_buffer", waves_codec->buffer_bytes); @@ -384,7 +384,7 @@ static int waves_effect_buffers(struct processing_module *mod) goto err; } - o_buffer = module_allocate_memory(mod, waves_codec->buffer_bytes, 16); + o_buffer = mod_alloc_align(mod, waves_codec->buffer_bytes, 16); if (!o_buffer) { comp_err(dev, "waves_effect_buffers() failed to allocate %d bytes for o_buffer", waves_codec->buffer_bytes); @@ -407,9 +407,9 @@ static int waves_effect_buffers(struct processing_module *mod) err: if (i_buffer) - module_free_memory(mod, i_buffer); + mod_free(mod, i_buffer); if (o_buffer) - module_free_memory(mod, o_buffer); + mod_free(mod, o_buffer); return ret; } @@ -475,13 +475,13 @@ static int waves_effect_save_config_blob_to_cache(struct processing_module *mod, /* release old cached config blob*/ if (waves_codec->config_blob && size != waves_codec->config_blob_size) { comp_info(dev, "waves_effect_save_config_blob_to_cache() release blob"); - module_free_memory(mod, waves_codec->config_blob); + mod_free(mod, waves_codec->config_blob); waves_codec->config_blob = NULL; waves_codec->config_blob_size = 0; } if (!waves_codec->config_blob) { - waves_codec->config_blob = module_allocate_memory(mod, size, 16); + waves_codec->config_blob = mod_alloc_align(mod, size, 16); if (!waves_codec->config_blob) { comp_err(dev, "waves_effect_save_config_blob_to_cache() failed to allocate %d bytes for config blob", @@ -497,7 +497,7 @@ static int waves_effect_save_config_blob_to_cache(struct processing_module *mod, comp_err(dev, "waves_effect_save_config_blob_to_cache(): failed to copy config blob %d", ret); - module_free_memory(mod, waves_codec->config_blob); + mod_free(mod, waves_codec->config_blob); waves_codec->config_blob = NULL; waves_codec->config_blob_size = 0; return ret; @@ -668,7 +668,7 @@ static int waves_codec_init(struct processing_module *mod) comp_dbg(dev, "waves_codec_init() start"); - waves_codec = module_allocate_memory(mod, sizeof(struct waves_codec_data), 16); + waves_codec = mod_alloc_align(mod, sizeof(struct waves_codec_data), 16); if (!waves_codec) { comp_err(dev, "waves_codec_init() failed to allocate %d bytes for waves_codec_data", sizeof(struct waves_codec_data)); @@ -677,10 +677,8 @@ static int waves_codec_init(struct processing_module *mod) memset(waves_codec, 0, sizeof(struct waves_codec_data)); codec->private = waves_codec; ret = waves_effect_allocate(mod); - if (ret) { - module_free_memory(mod, waves_codec); + if (ret) codec->private = NULL; - } } if (ret) { @@ -696,7 +694,7 @@ static int waves_codec_init(struct processing_module *mod) return -EINVAL; } - response = module_allocate_memory(mod, waves_codec->response_max_bytes, 16); + response = mod_alloc_align(mod, waves_codec->response_max_bytes, 16); if (!response) { comp_err(dev, "waves_codec_init() failed to allocate %d bytes for response", waves_codec->response_max_bytes); @@ -850,10 +848,10 @@ static int waves_codec_reset(struct processing_module *mod) comp_err(dev, "waves_codec_reset() failed %d", ret); if (codec->mpd.in_buff) - module_free_memory(mod, codec->mpd.in_buff); + mod_free(mod, codec->mpd.in_buff); if (codec->mpd.out_buff) - module_free_memory(mod, codec->mpd.out_buff); + mod_free(mod, codec->mpd.out_buff); waves_codec->initialized = false; comp_dbg(dev, "waves_codec_reset() done"); @@ -862,7 +860,6 @@ static int waves_codec_reset(struct processing_module *mod) static int waves_codec_free(struct processing_module *mod) { - module_free_all_memory(mod); comp_dbg(mod->dev, "waves_codec_free()"); return 0; } diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 45dab7b02e19..0f2b624e0431 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -1223,6 +1223,8 @@ void module_adapter_free(struct comp_dev *dev) buffer_free(buffer); } + mod_free_all(mod); + #if CONFIG_IPC_MAJOR_4 rfree(mod->priv.cfg.input_pins); #endif @@ -1232,6 +1234,21 @@ void module_adapter_free(struct comp_dev *dev) } EXPORT_SYMBOL(module_adapter_free); +size_t module_adapter_heap_usage(struct processing_module *mod) +{ + struct list_item *mem_list, *_mem_list; + size_t size = 0; + + list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { + struct module_memory *mem = container_of(mem_list, struct module_memory, mem_list); + + size += mem->size; + } + + return size; +} +EXPORT_SYMBOL(module_adapter_heap_usage); + /* * \brief Get DAI hw params * \param[in] dev - component device pointer diff --git a/src/audio/src/src.c b/src/audio/src/src.c index c891e97fae4d..7f744f64d43d 100644 --- a/src/audio/src/src.c +++ b/src/audio/src/src.c @@ -60,7 +60,7 @@ static int src_prepare(struct processing_module *mod, if (ret < 0) return ret; - ret = src_allocate_copy_stages(mod->dev, a, + ret = src_allocate_copy_stages(mod, a, src_table1[a->idx_out][a->idx_in], src_table2[a->idx_out][a->idx_in]); if (ret < 0) diff --git a/src/audio/src/src_common.c b/src/audio/src/src_common.c index 120077f5763b..37e0b6585765 100644 --- a/src/audio/src/src_common.c +++ b/src/audio/src/src_common.c @@ -531,9 +531,9 @@ int src_params_general(struct processing_module *mod, } /* free any existing delay lines. TODO reuse if same size */ - rfree(cd->delay_lines); + mod_free(mod, cd->delay_lines); - cd->delay_lines = rballoc(SOF_MEM_FLAG_USER, delay_lines_size); + cd->delay_lines = mod_alloc(mod, delay_lines_size); if (!cd->delay_lines) { comp_err(dev, "src_params(): failed to alloc cd->delay_lines, delay_lines_size = %zu", delay_lines_size); @@ -594,7 +594,7 @@ int src_param_set(struct comp_dev *dev, struct comp_data *cd) return 0; } -int src_allocate_copy_stages(struct comp_dev *dev, struct src_param *prm, +int src_allocate_copy_stages(struct processing_module *mod, struct src_param *prm, const struct src_stage *stage_src1, const struct src_stage *stage_src2) { @@ -607,10 +607,9 @@ int src_allocate_copy_stages(struct comp_dev *dev, struct src_param *prm, size_t tap_size = sizeof(int32_t); #endif - stage_dst = rmalloc(SOF_MEM_FLAG_USER, - 2 * sizeof(*stage_dst)); + stage_dst = mod_alloc(mod, 2 * sizeof(*stage_dst)); if (!stage_dst) { - comp_err(dev, "failed to allocate stages"); + comp_err(mod->dev, "failed to allocate stages"); return -ENOMEM; } @@ -622,10 +621,9 @@ int src_allocate_copy_stages(struct comp_dev *dev, struct src_param *prm, coef_size[1] = tap_size * stage_src2->filter_length; if (coef_size[0] == 0 || coef_size[1] == 0) { - comp_err(dev, + comp_err(mod->dev, "illegal zero coefficient vector size for unsupported conversion request %d to %d", prm->in_fs[prm->idx_in], prm->out_fs[prm->idx_out]); - rfree(stage_dst); return -EINVAL; } @@ -633,9 +631,8 @@ int src_allocate_copy_stages(struct comp_dev *dev, struct src_param *prm, stage_dst[1].coefs = fast_get(stage_src2->coefs, coef_size[1]); if (!stage_dst[0].coefs || !stage_dst[1].coefs) { - comp_err(dev, "failed to allocate coefficients"); + comp_err(mod->dev, "failed to allocate coefficients"); fast_put(stage_dst[0].coefs); - rfree(stage_dst); return -ENOMEM; } @@ -707,21 +704,16 @@ int src_reset(struct processing_module *mod) __cold int src_free(struct processing_module *mod) { - struct comp_data *cd = module_get_private_data(mod); - assert_can_be_cold(); comp_info(mod->dev, "src_free()"); - /* Free dynamically reserved buffers for SRC algorithm */ - rfree(cd->delay_lines); #if CONFIG_FAST_GET + struct comp_data *cd = module_get_private_data(mod); if (cd->param.stage1) { fast_put(cd->param.stage1->coefs); fast_put(cd->param.stage2->coefs); } - rfree((void *)cd->param.stage1); #endif - rfree(cd); return 0; } diff --git a/src/audio/src/src_common.h b/src/audio/src/src_common.h index 56b07a0b03a2..6a8028662ffd 100644 --- a/src/audio/src/src_common.h +++ b/src/audio/src/src_common.h @@ -215,7 +215,7 @@ static inline int src_fallback(struct comp_data *cd, return 0; } -int src_allocate_copy_stages(struct comp_dev *dev, struct src_param *prm, +int src_allocate_copy_stages(struct processing_module *mod, struct src_param *prm, const struct src_stage *stage_src1, const struct src_stage *stage_src2); int src_rate_check(const void *spec); diff --git a/src/audio/src/src_ipc3.c b/src/audio/src/src_ipc3.c index 93b0348ba462..75b74d1e257f 100644 --- a/src/audio/src/src_ipc3.c +++ b/src/audio/src/src_ipc3.c @@ -178,7 +178,7 @@ int src_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; diff --git a/src/audio/src/src_ipc4.c b/src/audio/src/src_ipc4.c index 76ef1a50175c..0786ced3306b 100644 --- a/src/audio/src/src_ipc4.c +++ b/src/audio/src/src_ipc4.c @@ -209,7 +209,7 @@ __cold int src_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = mod_zalloc(mod, sizeof(*cd)); if (!cd) return -ENOMEM; @@ -240,7 +240,6 @@ __cold int src_init(struct processing_module *mod) default: comp_err(dev, "src_init(): Illegal sample depth %d", cd->ipc_config.base.audio_fmt.depth); - rfree(cd); return -EINVAL; } diff --git a/src/audio/src/src_lite.c b/src/audio/src/src_lite.c index 75f664ec262d..4cbedea76ad2 100644 --- a/src/audio/src/src_lite.c +++ b/src/audio/src/src_lite.c @@ -43,7 +43,7 @@ static int src_lite_prepare(struct processing_module *mod, if (ret < 0) return ret; - ret = src_allocate_copy_stages(mod->dev, a, + ret = src_allocate_copy_stages(mod, a, src_table1[a->idx_out][a->idx_in], src_table2[a->idx_out][a->idx_in]); if (ret < 0) diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index bff6aa420629..395fe771da39 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -122,6 +122,7 @@ struct module_param { struct module_memory { void *ptr; /**< A pointr to particular memory block */ struct list_item mem_list; /**< list of memory allocated by module */ + size_t size; }; /** @@ -153,9 +154,11 @@ struct module_processing_data { /*****************************************************************************/ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size); int module_init(struct processing_module *mod); -void *module_allocate_memory(struct processing_module *mod, uint32_t size, uint32_t alignment); -int module_free_memory(struct processing_module *mod, void *ptr); -void module_free_all_memory(struct processing_module *mod); +void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t alignment); +void *mod_alloc(struct processing_module *mod, uint32_t size); +void *mod_zalloc(struct processing_module *mod, uint32_t size); +int mod_free(struct processing_module *mod, void *ptr); +void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks); @@ -217,6 +220,8 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd); void module_adapter_free(struct comp_dev *dev); int module_adapter_reset(struct comp_dev *dev); +size_t module_adapter_heap_usage(struct processing_module *mod); + #if CONFIG_IPC_MAJOR_3 static inline int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value) diff --git a/src/include/sof/schedule/ll_schedule_domain.h b/src/include/sof/schedule/ll_schedule_domain.h index be8dcb477ce8..5fc7691e3b13 100644 --- a/src/include/sof/schedule/ll_schedule_domain.h +++ b/src/include/sof/schedule/ll_schedule_domain.h @@ -35,6 +35,7 @@ struct dma; struct ll_schedule_domain; struct task; struct timer; +struct comp_dev; struct ll_schedule_domain_ops { int (*domain_register)(struct ll_schedule_domain *domain, diff --git a/zephyr/sof_shell.c b/zephyr/sof_shell.c index d36344b1b3fe..60785c4eb5c4 100644 --- a/zephyr/sof_shell.c +++ b/zephyr/sof_shell.c @@ -7,11 +7,14 @@ #include /* sof_get() */ #include +#include #include #include #include +#include + #define SOF_TEST_INJECT_SCHED_GAP_USEC 1500 static int cmd_sof_test_inject_sched_gap(const struct shell *sh, @@ -39,11 +42,39 @@ static int cmd_sof_test_inject_sched_gap(const struct shell *sh, return 0; } +static int cmd_sof_module_heap_usage(const struct shell *sh, + size_t argc, char *argv[]) +{ + struct ipc *ipc = sof_get()->ipc; + struct list_item *clist, *_clist; + struct ipc_comp_dev *icd; + + if (!ipc) { + shell_print(sh, "No IPC"); + return 0; + } + + list_for_item_safe(clist, _clist, &ipc->comp_list) { + icd = container_of(clist, struct ipc_comp_dev, list); + if (icd->type != COMP_TYPE_COMPONENT) + continue; + + shell_print(sh, "comp id 0x%08x\t%8zu bytes\t(%zu max)", icd->id, + module_adapter_heap_usage(comp_mod(icd->cd)), + comp_mod(icd->cd)->priv.cfg.heap_bytes); + } + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE(sof_commands, SHELL_CMD(test_inject_sched_gap, NULL, "Inject a gap to audio scheduling\n", cmd_sof_test_inject_sched_gap), + SHELL_CMD(module_heap_usage, NULL, + "Print heap memory usage of each module\n", + cmd_sof_module_heap_usage), + SHELL_SUBCMD_SET_END );