From 9281f900d0c46229928043194c1837fd9b7a5165 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 11 Aug 2025 01:30:13 +0300 Subject: [PATCH 01/13] modules: Allocate memory containers in chunks Do not allocate module memory containers one by one, but allocate them in chunks. The bookkeeping of allocated resources is done using containers that are allocated from heap. This effectively doubles the amount of heap allocations. This is not very efficient especially since the containers are only 20 bytes in size. This commit changes the allocation of containers so that they are always allocated in chunks of 16 containers, or what is selected with MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE Kconfig option. The unused containers are not freed when the associated resource is freed. Instead the unused containers are kept in free containers list. All the containers are freed when mod_free_all() is called, for instance when the module unloads. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/Kconfig | 10 +++ src/audio/module_adapter/module/generic.c | 89 ++++++++++++++----- src/audio/module_adapter/module_adapter.c | 3 +- src/include/module/module/base.h | 2 +- .../sof/audio/module_adapter/module/generic.h | 14 ++- 5 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/audio/module_adapter/Kconfig b/src/audio/module_adapter/Kconfig index bb9081812271..ad7f879d7049 100644 --- a/src/audio/module_adapter/Kconfig +++ b/src/audio/module_adapter/Kconfig @@ -3,6 +3,16 @@ menu "Processing modules" visible if COMP_MODULE_ADAPTER + config MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE + int "Number of memory containers to allocate at once" + default 16 + help + The per module resource containers are allocated in + chunks. The unused containers are kept in free + list. When the free list is empty the amount of + containers to allocate at once is selected by this + config option. + config CADENCE_CODEC bool "Cadence codec" default n diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 03a345552f71..b78f27059e13 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -92,7 +92,9 @@ int module_init(struct processing_module *mod) } /* Init memory list */ - list_init(&md->memory.mem_list); + list_init(&md->resources.mem_list); + list_init(&md->resources.free_cont_list); + list_init(&md->resources.cont_chunk_list); /* Now we can proceed with module specific initialization */ ret = interface->init(mod); @@ -110,6 +112,42 @@ int module_init(struct processing_module *mod) return 0; } +struct container_chunk { + struct list_item chunk_list; + struct module_memory containers[CONFIG_MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE]; +}; + +static struct module_memory *container_get(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct module_memory *container; + + if (list_is_empty(&res->free_cont_list)) { + struct container_chunk *chunk = rzalloc(SOF_MEM_FLAG_USER, sizeof(*chunk)); + int i; + + if (!chunk) { + comp_err(mod->dev, "allocating more containers failed"); + return NULL; + } + + list_item_append(&chunk->chunk_list, &res->cont_chunk_list); + for (i = 0; i < ARRAY_SIZE(chunk->containers); i++) + list_item_append(&chunk->containers[i].mem_list, &res->free_cont_list); + } + + container = list_first_item(&res->free_cont_list, struct module_memory, mem_list); + list_item_del(&container->mem_list); + return container; +} + +static void container_put(struct processing_module *mod, struct module_memory *container) +{ + struct module_resources *res = &mod->priv.resources; + + list_item_append(&container->mem_list, &res->free_cont_list); +} + /** * Allocates aligned memory block for module. * @param mod Pointer to the module this memory block is allocatd for. @@ -121,20 +159,16 @@ int module_init(struct processing_module *mod) */ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t alignment) { - struct comp_dev *dev = mod->dev; - struct module_memory *container; + struct module_memory *container = container_get(mod); + struct module_resources *res = &mod->priv.resources; void *ptr; - if (!size) { - comp_err(dev, "mod_alloc: requested allocation of 0 bytes."); + if (!container) return NULL; - } - /* Allocate memory container */ - container = rzalloc(SOF_MEM_FLAG_USER, - sizeof(struct module_memory)); - if (!container) { - comp_err(dev, "mod_alloc: failed to allocate memory container."); + if (!size) { + comp_err(mod->dev, "mod_alloc: requested allocation of 0 bytes."); + container_put(mod, container); return NULL; } @@ -145,15 +179,15 @@ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t ali ptr = rballoc(SOF_MEM_FLAG_USER, size); if (!ptr) { - comp_err(dev, "mod_alloc: failed to allocate memory for comp %x.", - dev_comp_id(dev)); - rfree(container); + comp_err(mod->dev, "mod_alloc: failed to allocate memory for comp %x.", + dev_comp_id(mod->dev)); + container_put(mod, 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); + list_item_prepend(&container->mem_list, &res->mem_list); return ptr; } @@ -200,6 +234,7 @@ EXPORT_SYMBOL(mod_zalloc); */ int mod_free(struct processing_module *mod, void *ptr) { + struct module_resources *res = &mod->priv.resources; struct module_memory *mem; struct list_item *mem_list; struct list_item *_mem_list; @@ -208,12 +243,12 @@ int mod_free(struct processing_module *mod, void *ptr) return 0; /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { + list_for_item_safe(mem_list, _mem_list, &res->mem_list) { mem = container_of(mem_list, struct module_memory, mem_list); if (mem->ptr == ptr) { rfree(mem->ptr); list_item_del(&mem->mem_list); - rfree(mem); + container_put(mod, mem); return 0; } } @@ -403,16 +438,24 @@ int module_reset(struct processing_module *mod) */ void mod_free_all(struct processing_module *mod) { - struct module_memory *mem; - struct list_item *mem_list; - struct list_item *_mem_list; + struct module_resources *res = &mod->priv.resources; + struct list_item *list; + struct list_item *_list; /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { - mem = container_of(mem_list, struct module_memory, mem_list); + list_for_item_safe(list, _list, &res->mem_list) { + struct module_memory *mem = container_of(list, struct module_memory, mem_list); + rfree(mem->ptr); list_item_del(&mem->mem_list); - rfree(mem); + } + + list_for_item_safe(list, _list, &res->cont_chunk_list) { + struct container_chunk *chunk = + container_of(list, struct container_chunk, chunk_list); + + list_item_del(&chunk->chunk_list); + rfree(chunk); } } EXPORT_SYMBOL(mod_free_all); diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index da0353d892ab..5fb8dc990218 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -1291,10 +1291,11 @@ EXPORT_SYMBOL(module_adapter_free); size_t module_adapter_heap_usage(struct processing_module *mod) { + struct module_resources *res = &mod->priv.resources; struct list_item *mem_list, *_mem_list; size_t size = 0; - list_for_item_safe(mem_list, _mem_list, &mod->priv.memory.mem_list) { + list_for_item_safe(mem_list, _mem_list, &res->mem_list) { struct module_memory *mem = container_of(mem_list, struct module_memory, mem_list); size += mem->size; diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index 2371d77124f5..881e74a2d108 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -59,7 +59,7 @@ struct module_data { enum module_state state; size_t new_cfg_size; /**< size of new module config data */ void *runtime_params; - struct module_memory memory; /**< memory allocated by module */ + struct module_resources resources; /**< resources allocated by module */ struct module_processing_data mpd; /**< shared data comp <-> module */ #endif /* SOF_MODULE_PRIVATE */ }; diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 1001c4ba450c..c63f98dbd9c2 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -117,7 +117,19 @@ struct module_param { /** * \struct module_memory - * \brief module memory block - used for every memory allocated by module + * \brief module resources block - used for module allocation records + * The allocations are recorded so that they can be automatically freed + * when the module unloads. + */ +struct module_resources { + struct list_item mem_list; /**< Allocad memory containers */ + struct list_item free_cont_list; /**< Unused memory containers */ + struct list_item cont_chunk_list; /**< Memory container chunks */ +}; + +/** + * \struct module_memory + * \brief module memory container - used for every memory allocated by module */ struct module_memory { void *ptr; /**< A pointr to particular memory block */ From 6576498b4b4029aa7d71753977368066edb5a0b5 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 12 Aug 2025 00:16:13 +0300 Subject: [PATCH 02/13] modules: Add high water mark to module_adapter_heap_usage() Add heap usage high water mark to module_adapter_heap_usage() and shell's "sof module_heap_usage" command. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module/generic.c | 7 +++++++ src/audio/module_adapter/module_adapter.c | 13 ++++--------- .../sof/audio/module_adapter/module/generic.h | 4 +++- zephyr/sof_shell.c | 8 +++++--- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index b78f27059e13..27892af025b1 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -95,6 +95,8 @@ int module_init(struct processing_module *mod) list_init(&md->resources.mem_list); list_init(&md->resources.free_cont_list); list_init(&md->resources.cont_chunk_list); + md->resources.heap_usage = 0; + md->resources.heap_high_water_mark = 0; /* Now we can proceed with module specific initialization */ ret = interface->init(mod); @@ -189,6 +191,10 @@ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t ali container->size = size; list_item_prepend(&container->mem_list, &res->mem_list); + res->heap_usage += size; + if (res->heap_usage > res->heap_high_water_mark) + res->heap_high_water_mark = res->heap_usage; + return ptr; } EXPORT_SYMBOL(mod_alloc_align); @@ -247,6 +253,7 @@ int mod_free(struct processing_module *mod, void *ptr) mem = container_of(mem_list, struct module_memory, mem_list); if (mem->ptr == ptr) { rfree(mem->ptr); + res->heap_usage -= mem->size; list_item_del(&mem->mem_list); container_put(mod, mem); return 0; diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 5fb8dc990218..10f722fd9bbd 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -1289,19 +1289,14 @@ void module_adapter_free(struct comp_dev *dev) } EXPORT_SYMBOL(module_adapter_free); -size_t module_adapter_heap_usage(struct processing_module *mod) +size_t module_adapter_heap_usage(struct processing_module *mod, size_t *hwm) { struct module_resources *res = &mod->priv.resources; - struct list_item *mem_list, *_mem_list; - size_t size = 0; - list_for_item_safe(mem_list, _mem_list, &res->mem_list) { - struct module_memory *mem = container_of(mem_list, struct module_memory, mem_list); + if (hwm) + *hwm = res->heap_high_water_mark; - size += mem->size; - } - - return size; + return res->heap_usage; } EXPORT_SYMBOL(module_adapter_heap_usage); diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index c63f98dbd9c2..eeac83cc438d 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -125,6 +125,8 @@ struct module_resources { struct list_item mem_list; /**< Allocad memory containers */ struct list_item free_cont_list; /**< Unused memory containers */ struct list_item cont_chunk_list; /**< Memory container chunks */ + size_t heap_usage; + size_t heap_high_water_mark; }; /** @@ -235,7 +237,7 @@ 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); +size_t module_adapter_heap_usage(struct processing_module *mod, size_t *hwm); #if CONFIG_IPC_MAJOR_3 static inline diff --git a/zephyr/sof_shell.c b/zephyr/sof_shell.c index 60785c4eb5c4..f10a2c9275b5 100644 --- a/zephyr/sof_shell.c +++ b/zephyr/sof_shell.c @@ -55,13 +55,15 @@ static int cmd_sof_module_heap_usage(const struct shell *sh, } list_for_item_safe(clist, _clist, &ipc->comp_list) { + size_t usage, hwm; + 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); + usage = module_adapter_heap_usage(comp_mod(icd->cd), &hwm); + shell_print(sh, "comp id 0x%08x%9zu usage%9zu hwm %9zu max\tbytes", + icd->id, usage, hwm, comp_mod(icd->cd)->priv.cfg.heap_bytes); } return 0; } From 781301c112dcc45a0e3dd0a483035eff37a643f4 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 14 Aug 2025 15:23:08 +0300 Subject: [PATCH 03/13] cmocka: Fix mixer test before it breaks due to blob handler dependency Add src/audio/data_blob.c to mixer cmocka test sources to fix the dependency problem from adding comp_data_blob_handler_new_ext() to audio/module_adapter/module/generic.c. Signed-off-by: Jyri Sarha --- test/cmocka/src/audio/mixer/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cmocka/src/audio/mixer/CMakeLists.txt b/test/cmocka/src/audio/mixer/CMakeLists.txt index 723cb091ff61..ea8cad0bd79e 100644 --- a/test/cmocka/src/audio/mixer/CMakeLists.txt +++ b/test/cmocka/src/audio/mixer/CMakeLists.txt @@ -25,6 +25,7 @@ cmocka_test(mixer ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-schedule.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-stream.c ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-xrun.c + ${PROJECT_SOURCE_DIR}/src/audio/data_blob.c ${PROJECT_SOURCE_DIR}/src/module/audio/source_api.c ${PROJECT_SOURCE_DIR}/src/module/audio/sink_api.c ${PROJECT_SOURCE_DIR}/src/math/numbers.c From 41ff293255d065a453ead9b230d8deb8bff30b44 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 12 Aug 2025 15:02:40 +0300 Subject: [PATCH 04/13] modules: Add mod_data_blob_handler_new() to module API Add mod_data_blob_handler_new() to module API. The function is otherwise the same as comp_data_blob_handler_new(), but it takes a module pointer as the first argument, and the blob handler is automatically freed when the module unloads. The handler allocated with mod_data_blob_handler_new() should not be freed with comp_data_blob_handler_free(), mod_data_blob_handler_free() should be used. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module/generic.c | 123 +++++++++++++----- .../sof/audio/module_adapter/module/generic.h | 30 +++-- 2 files changed, 116 insertions(+), 37 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 27892af025b1..4fcf2606f109 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -14,6 +14,7 @@ #include #include +#include LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); @@ -92,7 +93,7 @@ int module_init(struct processing_module *mod) } /* Init memory list */ - list_init(&md->resources.mem_list); + list_init(&md->resources.res_list); list_init(&md->resources.free_cont_list); list_init(&md->resources.cont_chunk_list); md->resources.heap_usage = 0; @@ -116,13 +117,13 @@ int module_init(struct processing_module *mod) struct container_chunk { struct list_item chunk_list; - struct module_memory containers[CONFIG_MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE]; + struct module_resource containers[CONFIG_MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE]; }; -static struct module_memory *container_get(struct processing_module *mod) +static struct module_resource *container_get(struct processing_module *mod) { struct module_resources *res = &mod->priv.resources; - struct module_memory *container; + struct module_resource *container; if (list_is_empty(&res->free_cont_list)) { struct container_chunk *chunk = rzalloc(SOF_MEM_FLAG_USER, sizeof(*chunk)); @@ -135,19 +136,19 @@ static struct module_memory *container_get(struct processing_module *mod) list_item_append(&chunk->chunk_list, &res->cont_chunk_list); for (i = 0; i < ARRAY_SIZE(chunk->containers); i++) - list_item_append(&chunk->containers[i].mem_list, &res->free_cont_list); + list_item_append(&chunk->containers[i].list, &res->free_cont_list); } - container = list_first_item(&res->free_cont_list, struct module_memory, mem_list); - list_item_del(&container->mem_list); + container = list_first_item(&res->free_cont_list, struct module_resource, list); + list_item_del(&container->list); return container; } -static void container_put(struct processing_module *mod, struct module_memory *container) +static void container_put(struct processing_module *mod, struct module_resource *container) { struct module_resources *res = &mod->priv.resources; - list_item_append(&container->mem_list, &res->free_cont_list); + list_item_append(&container->list, &res->free_cont_list); } /** @@ -161,7 +162,7 @@ static void container_put(struct processing_module *mod, struct module_memory *c */ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t alignment) { - struct module_memory *container = container_get(mod); + struct module_resource *container = container_get(mod); struct module_resources *res = &mod->priv.resources; void *ptr; @@ -189,7 +190,8 @@ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t ali /* Store reference to allocated memory */ container->ptr = ptr; container->size = size; - list_item_prepend(&container->mem_list, &res->mem_list); + container->type = MOD_RES_HEAP; + list_item_prepend(&container->list, &res->res_list); res->heap_usage += size; if (res->heap_usage > res->heap_high_water_mark) @@ -233,30 +235,84 @@ void *mod_zalloc(struct processing_module *mod, uint32_t size) } EXPORT_SYMBOL(mod_zalloc); +/** + * Creates a blob handler and releases it when the module is unloaded + * @param mod Pointer to module this memory block is allocated for. + * @return Pointer to the created data blob handler + * + * Like comp_data_blob_handler_new() but the handler is automatically freed. + */ +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler * +mod_data_blob_handler_new(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container = container_get(mod); + struct comp_data_blob_handler *bhp; + + if (!container) + return NULL; + + bhp = comp_data_blob_handler_new_ext(mod->dev, false, NULL, NULL); + if (!bhp) { + container_put(mod, container); + return NULL; + } + + container->bhp = bhp; + container->size = 0; + container->type = MOD_RES_BLOB_HANDLER; + list_item_prepend(&container->list, &res->res_list); + + return bhp; +} +EXPORT_SYMBOL(mod_data_blob_handler_new); +#endif + +static int free_contents(struct processing_module *mod, struct module_resource *container) +{ + struct module_resources *res = &mod->priv.resources; + + switch (container->type) { + case MOD_RES_HEAP: + rfree(container->ptr); + res->heap_usage -= container->size; + return 0; +#if CONFIG_COMP_BLOB + case MOD_RES_BLOB_HANDLER: + comp_data_blob_handler_free(container->bhp); + return 0; +#endif + default: + comp_err(mod->dev, "Unknown resource type: %d", container->type); + } + return -EINVAL; +} + /** * 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) +int mod_free(struct processing_module *mod, const void *ptr) { struct module_resources *res = &mod->priv.resources; - struct module_memory *mem; - struct list_item *mem_list; - struct list_item *_mem_list; + struct module_resource *container; + struct list_item *res_list; + struct list_item *_res_list; if (!ptr) return 0; /* Find which container keeps this memory */ - list_for_item_safe(mem_list, _mem_list, &res->mem_list) { - mem = container_of(mem_list, struct module_memory, mem_list); - if (mem->ptr == ptr) { - rfree(mem->ptr); - res->heap_usage -= mem->size; - list_item_del(&mem->mem_list); - container_put(mod, mem); - return 0; + list_for_item_safe(res_list, _res_list, &res->res_list) { + container = container_of(res_list, struct module_resource, list); + if (container->ptr == ptr) { + int ret = free_contents(mod, container); + + list_item_del(&container->list); + container_put(mod, container); + return ret; } } @@ -267,6 +323,14 @@ int mod_free(struct processing_module *mod, void *ptr) } EXPORT_SYMBOL(mod_free); +#if CONFIG_COMP_BLOB +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh) +{ + mod_free(mod, (void *)dbh); +} +EXPORT_SYMBOL(mod_data_blob_handler_free); +#endif + int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -438,8 +502,8 @@ int module_reset(struct processing_module *mod) } /** - * Frees all the memory allocated for this module - * @param mod Pointer to module this memory block was allocated for. + * Frees all the resources registered for this module + * @param mod Pointer to module that should have its resource freed. * * This function is called automatically when the module is unloaded. */ @@ -450,11 +514,12 @@ void mod_free_all(struct processing_module *mod) struct list_item *_list; /* Find which container keeps this memory */ - list_for_item_safe(list, _list, &res->mem_list) { - struct module_memory *mem = container_of(list, struct module_memory, mem_list); + list_for_item_safe(list, _list, &res->res_list) { + struct module_resource *container = + container_of(list, struct module_resource, list); - rfree(mem->ptr); - list_item_del(&mem->mem_list); + free_contents(mod, container); + list_item_del(&container->list); } list_for_item_safe(list, _list, &res->cont_chunk_list) { diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index eeac83cc438d..735bdc6c89f9 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -116,27 +116,37 @@ struct module_param { }; /** - * \struct module_memory + * \struct module_resources * \brief module resources block - used for module allocation records * The allocations are recorded so that they can be automatically freed * when the module unloads. */ struct module_resources { - struct list_item mem_list; /**< Allocad memory containers */ + struct list_item res_list; /**< Allocad resource containers */ struct list_item free_cont_list; /**< Unused memory containers */ struct list_item cont_chunk_list; /**< Memory container chunks */ size_t heap_usage; size_t heap_high_water_mark; }; +enum mod_resource_type { + MOD_RES_UNINITIALIZED = 0, + MOD_RES_HEAP, + MOD_RES_BLOB_HANDLER, +}; + /** - * \struct module_memory + * \struct module_resource * \brief module memory container - used for every memory allocated by module */ -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; +struct module_resource { + union { + void *ptr; /**< Pointer to heap allocated memory */ + struct comp_data_blob_handler *bhp; /**< Blob handler ptr */ + }; + struct list_item list; /**< list element */ + size_t size; /**< Size of allocated heap memory, 0 if not from heap */ + enum mod_resource_type type; /**< Resource type */ }; /** @@ -171,7 +181,11 @@ int module_init(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); +int mod_free(struct processing_module *mod, const void *ptr); +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod); +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh); +#endif void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, From 60fe4145d0d5c2e3e13ab5f4a8fda47fa565ece0 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Tue, 26 Aug 2025 00:06:30 +0300 Subject: [PATCH 05/13] modules: Add mod_fast_get() and mod_fast_put() Add module API versions of fast_get() and fast_put(). The SRAM copies reserved with mod_fast_get() are released automatically when the module unloads, and those SRAM copies should not be freed with the regular fast_put(). The sram-copy allocated with mod_fast_get() should not be freed with regular fast_put(), but mod_fast_put() should be used. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module/generic.c | 47 +++++++++++++++++++ .../sof/audio/module_adapter/module/generic.h | 6 +++ 2 files changed, 53 insertions(+) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 4fcf2606f109..6e78747601c6 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -15,6 +15,7 @@ #include #include +#include LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); @@ -269,6 +270,39 @@ mod_data_blob_handler_new(struct processing_module *mod) EXPORT_SYMBOL(mod_data_blob_handler_new); #endif +/** + * Make a module associated shared SRAM copy of DRAM read-only data. + * @param mod Pointer to module this copy is allocated for. + * @return Pointer to the SRAM copy. + * + * Like fast_get() but the handler is automatically freed. + */ +#if CONFIG_FAST_GET +const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container = container_get(mod); + const void *ptr; + + if (!container) + return NULL; + + ptr = fast_get(dram_ptr, size); + if (!ptr) { + container_put(mod, container); + return NULL; + } + + container->sram_ptr = ptr; + container->size = 0; + container->type = MOD_RES_FAST_GET; + list_item_prepend(&container->list, &res->res_list); + + return ptr; +} +EXPORT_SYMBOL(mod_fast_get); +#endif + static int free_contents(struct processing_module *mod, struct module_resource *container) { struct module_resources *res = &mod->priv.resources; @@ -282,6 +316,11 @@ static int free_contents(struct processing_module *mod, struct module_resource * case MOD_RES_BLOB_HANDLER: comp_data_blob_handler_free(container->bhp); return 0; +#endif +#if CONFIG_FAST_GET + case MOD_RES_FAST_GET: + fast_put(container->sram_ptr); + return 0; #endif default: comp_err(mod->dev, "Unknown resource type: %d", container->type); @@ -331,6 +370,14 @@ void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_ EXPORT_SYMBOL(mod_data_blob_handler_free); #endif +#if CONFIG_FAST_GET +void mod_fast_put(struct processing_module *mod, const void *sram_ptr) +{ + mod_free(mod, sram_ptr); +} +EXPORT_SYMBOL(mod_fast_put); +#endif + int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 735bdc6c89f9..f0cee2370290 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -133,6 +133,7 @@ enum mod_resource_type { MOD_RES_UNINITIALIZED = 0, MOD_RES_HEAP, MOD_RES_BLOB_HANDLER, + MOD_RES_FAST_GET, }; /** @@ -143,6 +144,7 @@ struct module_resource { union { void *ptr; /**< Pointer to heap allocated memory */ struct comp_data_blob_handler *bhp; /**< Blob handler ptr */ + const void *sram_ptr; /**< SRAM ptr from fast_get() */ }; struct list_item list; /**< list element */ size_t size; /**< Size of allocated heap memory, 0 if not from heap */ @@ -186,6 +188,10 @@ int mod_free(struct processing_module *mod, const void *ptr); struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod); void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh); #endif +#if CONFIG_FAST_GET +const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size); +void mod_fast_put(struct processing_module *mod, const void *sram_ptr); +#endif void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, From a5cafd84b9f88c7c3fe8c1c31e27450496e74f04 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 15 Aug 2025 12:18:44 +0300 Subject: [PATCH 06/13] modules: Add safeguard to mod_alloc() and friends Add safeguard to mod_alloc() and friends that checks that they are always called from the same thread (e.g. no locking needed). The checking code has to be also behind defined(__ZEPHYR__) to keep cmocka tests working. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/Kconfig | 11 +++++++++++ src/audio/module_adapter/module/generic.c | 17 ++++++++++++++++- .../sof/audio/module_adapter/module/generic.h | 8 ++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/audio/module_adapter/Kconfig b/src/audio/module_adapter/Kconfig index ad7f879d7049..3c762c73f7f8 100644 --- a/src/audio/module_adapter/Kconfig +++ b/src/audio/module_adapter/Kconfig @@ -13,6 +13,17 @@ menu "Processing modules" containers to allocate at once is selected by this config option. + config MODULE_MEMORY_API_DEBUG + bool "Turn on memory API thread safety checks" + default y if DEBUG + help + The Module Memory API structures are not protected + by locks. This is because the initialization, + allocation, and freeing of resources should always + be done in the same thread. This option adds an + assert to make sure no other thread makes such + operations. + config CADENCE_CODEC bool "Cadence codec" default n diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 6e78747601c6..b822f4ed3606 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -17,6 +17,14 @@ #include #include +/* The __ZEPHYR__ condition is to keep cmocka tests working */ +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) +#define MEM_API_CHECK_THREAD(res) __ASSERT((res)->rsrc_mngr == k_current_get(), \ + "Module memory API operation from wrong thread") +#else +#define MEM_API_CHECK_THREAD(res) +#endif + LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) @@ -99,7 +107,9 @@ int module_init(struct processing_module *mod) list_init(&md->resources.cont_chunk_list); md->resources.heap_usage = 0; md->resources.heap_high_water_mark = 0; - +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) + md->resources.rsrc_mngr = k_current_get(); +#endif /* Now we can proceed with module specific initialization */ ret = interface->init(mod); if (ret) { @@ -167,6 +177,7 @@ void *mod_alloc_align(struct processing_module *mod, uint32_t size, uint32_t ali struct module_resources *res = &mod->priv.resources; void *ptr; + MEM_API_CHECK_THREAD(res); if (!container) return NULL; @@ -251,6 +262,7 @@ mod_data_blob_handler_new(struct processing_module *mod) struct module_resource *container = container_get(mod); struct comp_data_blob_handler *bhp; + MEM_API_CHECK_THREAD(res); if (!container) return NULL; @@ -284,6 +296,7 @@ const void *mod_fast_get(struct processing_module *mod, const void * const dram_ struct module_resource *container = container_get(mod); const void *ptr; + MEM_API_CHECK_THREAD(res); if (!container) return NULL; @@ -340,6 +353,7 @@ int mod_free(struct processing_module *mod, const void *ptr) struct list_item *res_list; struct list_item *_res_list; + MEM_API_CHECK_THREAD(res); if (!ptr) return 0; @@ -560,6 +574,7 @@ void mod_free_all(struct processing_module *mod) struct list_item *list; struct list_item *_list; + MEM_API_CHECK_THREAD(res); /* Find which container keeps this memory */ list_for_item_safe(list, _list, &res->res_list) { struct module_resource *container = diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index f0cee2370290..ced9fc710b11 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -19,6 +19,11 @@ #include #include "module_interface.h" +/* The __ZEPHYR__ condition is to keep cmocka tests working */ +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) +#include +#endif + /* * helpers to determine processing type * Needed till all the modules use PROCESSING_MODE_SINK_SOURCE @@ -127,6 +132,9 @@ struct module_resources { struct list_item cont_chunk_list; /**< Memory container chunks */ size_t heap_usage; size_t heap_high_water_mark; +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) + k_tid_t rsrc_mngr; +#endif }; enum mod_resource_type { From 70b3d56b5b33daa9a18a41678c33a258a5cd591a Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Mon, 25 Aug 2025 19:14:25 +0300 Subject: [PATCH 07/13] modules: Use list_for_item() instead of list_for_item_safe() in mod_free() Use list_for_item() instead of list_for_item_safe() in mod_free(). There is no need for *_safe() version when loop is not continued after an element is removed from the list. Signed-off-by: Jyri Sarha --- src/audio/module_adapter/module/generic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index b822f4ed3606..cb4ea2e3d5ae 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -351,14 +351,13 @@ int mod_free(struct processing_module *mod, const void *ptr) struct module_resources *res = &mod->priv.resources; struct module_resource *container; struct list_item *res_list; - struct list_item *_res_list; MEM_API_CHECK_THREAD(res); if (!ptr) return 0; /* Find which container keeps this memory */ - list_for_item_safe(res_list, _res_list, &res->res_list) { + list_for_item(res_list, &res->res_list) { container = container_of(res_list, struct module_resource, list); if (container->ptr == ptr) { int ret = free_contents(mod, container); From 289efb13b581b06bed7b6cd4a88e530314128548 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 13 Aug 2025 00:37:08 +0300 Subject: [PATCH 08/13] Audio: SRC: Take mod_fast_get() and mod_fast_put() into use Take mod_fast_get() and mod_fast_put() into use. Signed-off-by: Jyri Sarha --- src/audio/src/src_common.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/audio/src/src_common.c b/src/audio/src/src_common.c index f96b3bc6e358..6331a6b9180e 100644 --- a/src/audio/src/src_common.c +++ b/src/audio/src/src_common.c @@ -627,12 +627,11 @@ int src_allocate_copy_stages(struct processing_module *mod, struct src_param *pr return -EINVAL; } - stage_dst[0].coefs = fast_get(stage_src1->coefs, coef_size[0]); - stage_dst[1].coefs = fast_get(stage_src2->coefs, coef_size[1]); + stage_dst[0].coefs = mod_fast_get(mod, stage_src1->coefs, coef_size[0]); + stage_dst[1].coefs = mod_fast_get(mod, stage_src2->coefs, coef_size[1]); if (!stage_dst[0].coefs || !stage_dst[1].coefs) { comp_err(mod->dev, "failed to allocate coefficients"); - fast_put(stage_dst[0].coefs); return -ENOMEM; } @@ -708,12 +707,5 @@ __cold int src_free(struct processing_module *mod) comp_info(mod->dev, "src_free()"); -#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); - } -#endif return 0; } From 5ef37a3b7e78bad3390746de166345555a3632f3 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 21 Aug 2025 22:32:55 +0300 Subject: [PATCH 09/13] Math: Make mod_alloc() versions of all heap using functions Make mod_alloc() versions of all heap using functions. The new functions are simple copy-paste versions of the original, just using mod_alloc() and friend instead of rmalloc() friends. The idea is to get rid off the original versions once all the modules are converted to module API heap usage and the cmocka math tests have been fixed to work with mod_alloc() versions. Signed-off-by: Jyri Sarha --- src/include/sof/math/auditory.h | 2 + src/include/sof/math/dct.h | 1 + src/include/sof/math/fft.h | 4 + src/include/sof/math/matrix.h | 15 ++++ src/math/auditory/auditory.c | 126 ++++++++++++++++++++++++++++++++ src/math/dct.c | 48 ++++++++++++ src/math/fft/fft_common.c | 59 +++++++++++++++ 7 files changed, 255 insertions(+) diff --git a/src/include/sof/math/auditory.h b/src/include/sof/math/auditory.h index eef073092e22..0e082335f764 100644 --- a/src/include/sof/math/auditory.h +++ b/src/include/sof/math/auditory.h @@ -77,6 +77,8 @@ int16_t psy_mel_to_hz(int16_t mel); * \return Zero when success, otherwise error code. */ int psy_get_mel_filterbank(struct psy_mel_filterbank *mel_fb); +struct processing_module; +int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); /** * \brief Convert linear complex spectra from FFT into Mel band energies in desired diff --git a/src/include/sof/math/dct.h b/src/include/sof/math/dct.h index bb3aca81b202..c1c5caa808a6 100644 --- a/src/include/sof/math/dct.h +++ b/src/include/sof/math/dct.h @@ -30,5 +30,6 @@ struct dct_plan_16 { }; int dct_initialize_16(struct dct_plan_16 *dct); +int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct); #endif /* __SOF_MATH_DCT_H__ */ diff --git a/src/include/sof/math/fft.h b/src/include/sof/math/fft.h index 504465401cad..16ae9ca97669 100644 --- a/src/include/sof/math/fft.h +++ b/src/include/sof/math/fft.h @@ -53,8 +53,12 @@ struct fft_plan { /* interfaces of the library */ struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits); +struct processing_module; +struct fft_plan *mod_fft_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits); void fft_execute_16(struct fft_plan *plan, bool ifft); void fft_execute_32(struct fft_plan *plan, bool ifft); void fft_plan_free(struct fft_plan *plan16); +void mod_fft_plan_free(struct processing_module *mod, struct fft_plan *plan16); #endif /* __SOF_FFT_H__ */ diff --git a/src/include/sof/math/matrix.h b/src/include/sof/math/matrix.h index 74899371038a..f48f1ca4960d 100644 --- a/src/include/sof/math/matrix.h +++ b/src/include/sof/math/matrix.h @@ -10,6 +10,7 @@ #ifndef __SOF_MATH_MATRIX_H__ #define __SOF_MATH_MATRIX_H__ +#include #include #include #include @@ -44,6 +45,20 @@ static inline struct mat_matrix_16b *mat_matrix_alloc_16b(int16_t rows, int16_t return mat; } +static inline struct mat_matrix_16b *mod_mat_matrix_alloc_16b(struct processing_module *mod, + int16_t rows, int16_t columns, + int16_t fractions) +{ + struct mat_matrix_16b *mat; + const int mat_size = sizeof(int16_t) * rows * columns + sizeof(struct mat_matrix_16b); + + mat = mod_zalloc(mod, mat_size); + if (mat) + mat_init_16b(mat, rows, columns, fractions); + + return mat; +} + static inline void mat_copy_from_linear_16b(struct mat_matrix_16b *mat, const int16_t *lin_data) { size_t bytes = sizeof(int16_t) * mat->rows * mat->columns; diff --git a/src/math/auditory/auditory.c b/src/math/auditory/auditory.c index dbfe47b1699c..a10d13bbfc99 100644 --- a/src/math/auditory/auditory.c +++ b/src/math/auditory/auditory.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo +#include #include #include #include @@ -210,3 +211,128 @@ int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) fb->scratch_data2, sizeof(int16_t) * fb->data_length); return 0; } + +int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *fb) +{ + int32_t up_slope; + int32_t down_slope; + int32_t slope; + int32_t scale = ONE_Q16; + int32_t scale_inv = ONE_Q16; + int16_t *mel; + int16_t mel_start; + int16_t mel_end; + int16_t mel_step; + int16_t left_mel; + int16_t center_mel; + int16_t right_mel; + int16_t delta_cl; + int16_t delta_rc; + int16_t left_hz; + int16_t right_hz; + int16_t f; + int segment; + int i, j, idx; + int base_idx = 0; + int start_bin = 0; + int end_bin = 0; + + if (!fb) + return -ENOMEM; + + if (!fb->scratch_data1 || !fb->scratch_data2) + return -ENOMEM; + + /* Log power can be log, or log10 or dB, get multiply coef to convert + * log to desired format. + */ + switch (fb->mel_log_scale) { + case MEL_LOG: + fb->log_mult = ONE_OVER_LOG2E_Q29; + break; + case MEL_LOG10: + fb->log_mult = ONE_OVER_LOG2TEN_Q29; + break; + case MEL_DB: + fb->log_mult = TEN_OVER_LOG2TEN_Q29; + break; + default: + return -EINVAL; + } + + /* Use scratch area to hold vector of Mel values for each FFT frequency */ + if (fb->scratch_length1 < fb->half_fft_bins) + return -ENOMEM; + + fb->scale_log2 = 0; + + mel = fb->scratch_data1; + for (i = 0; i < fb->half_fft_bins; i++) { + f = fb->samplerate * i / fb->fft_bins; + mel[i] = psy_hz_to_mel(f); + } + + mel_start = psy_hz_to_mel(fb->start_freq); + mel_end = psy_hz_to_mel(fb->end_freq); + mel_step = (mel_end - mel_start) / (fb->mel_bins + 1); + for (i = 0; i < fb->mel_bins; i++) { + left_mel = mel_start + i * mel_step; + center_mel = mel_start + (i + 1) * mel_step; + right_mel = mel_start + (i + 2) * mel_step; + delta_cl = center_mel - left_mel; + delta_rc = right_mel - center_mel; + segment = 0; + idx = base_idx + 3; /* start of filter weight values */ + if (fb->slaney_normalize) { + left_hz = psy_mel_to_hz(left_mel); + right_hz = psy_mel_to_hz(right_mel); + scale = Q_SHIFT_RND(TWO_Q29 / (right_hz - left_hz), 29, 16); /* Q16.16*/ + if (i == 0) { + scale_inv = Q_SHIFT_LEFT(ONE_Q30 / scale, 14, 16); + fb->scale_log2 = base2_logarithm((uint32_t)scale) - LOG2_2P16; + } + + scale = Q_MULTSR_32X32((int64_t)scale, scale_inv, 16, 16, 16); + } + for (j = 0; j < fb->half_fft_bins; j++) { + up_slope = (((int32_t)mel[j] - left_mel) << 15) / delta_cl; /* Q17.15 */ + down_slope = (((int32_t)right_mel - mel[j]) << 15) / delta_rc; /* Q17.15 */ + slope = MIN(up_slope, down_slope); + slope = Q_MULTSR_32X32((int64_t)slope, scale, 15, 16, 15); + if (segment == 1 && slope <= 0) { + end_bin = j - 1; + break; + } + + if (segment == 0 && slope > 0) { + start_bin = j; + segment = 1; + } + + if (segment == 1) { + if (idx >= fb->scratch_length2) + return -EINVAL; + + fb->scratch_data2[idx++] = sat_int16(slope); + } + } + + if (idx + 2 >= fb->scratch_length2) + return -EINVAL; + + fb->scratch_data2[base_idx] = idx; /* index to next */ + fb->scratch_data2[base_idx + 1] = start_bin; + fb->scratch_data2[base_idx + 2] = end_bin - start_bin + 1; /* length */ + base_idx = idx; + } + + fb->data_length = &fb->scratch_data2[base_idx] - &fb->scratch_data2[0]; + fb->data = mod_zalloc(mod, sizeof(int16_t) * fb->data_length); + if (!fb->data) + return -ENOMEM; + + /* Copy the exact triangles data size to allocated buffer */ + memcpy_s(fb->data, sizeof(int16_t) * fb->data_length, + fb->scratch_data2, sizeof(int16_t) * fb->data_length); + return 0; +} diff --git a/src/math/dct.c b/src/math/dct.c index 15d23b67c7f9..db2d96525eea 100644 --- a/src/math/dct.c +++ b/src/math/dct.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo +#include #include #include #include @@ -77,3 +78,50 @@ int dct_initialize_16(struct dct_plan_16 *dct) return 0; } + +int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct) +{ + int16_t dct_val; + int32_t arg; + int32_t cos; + int32_t c1; + int16_t c2; + int16_t nk; + int n; + int k; + + if (dct->type != DCT_II || dct->ortho != true) + return -EINVAL; + + if (dct->num_in < 1 || dct->num_out < 1) + return -EINVAL; + + if (dct->num_in > DCT_MATRIX_SIZE_MAX || dct->num_out > DCT_MATRIX_SIZE_MAX) + return -EINVAL; + + dct->matrix = mod_mat_matrix_alloc_16b(mod, dct->num_in, dct->num_out, 15); + if (!dct->matrix) + return -ENOMEM; + + c1 = PI_Q29 / dct->num_in; + arg = Q_SHIFT_RND(TWO_Q29 / dct->num_in, 29, 12); + c2 = sqrt_int16(arg); /* Q4.12 */ + for (n = 0; n < dct->num_in; n++) { + for (k = 0; k < dct->num_out; k++) { + /* Note: Current int16_t nk works up to DCT_MATRIX_SIZE_MAX = 91 */ + nk = (Q_SHIFT_LEFT(n, 0, 1) + HALF_Q1) * Q_SHIFT_LEFT(k, 0, 1); /*Q14.2 */ + arg = Q_MULTSR_32X32((int64_t)c1, nk, 29, 2, 24); /* Q8.24 */ + /* Note: Q8.24 works up to DCT_MATRIX_SIZE_MAX = 42 */ + arg %= TWO_PI_Q24; + cos = cos_fixed_32b(Q_SHIFT_LEFT(arg, 24, 28)); /* Q1.31 */ + dct_val = Q_MULTSR_32X32((int64_t)cos, c2, 31, 12, 15); /* Q1.15 */ + if (k == 0) + dct_val = Q_MULTSR_32X32((int64_t)dct_val, + ONE_OVER_SQRT_TWO, 15, 31, 15); + + mat_set_scalar_16b(dct->matrix, n, k, dct_val); + } + } + + return 0; +} diff --git a/src/math/fft/fft_common.c b/src/math/fft/fft_common.c index a2afd09cf127..182bbb623078 100644 --- a/src/math/fft/fft_common.c +++ b/src/math/fft/fft_common.c @@ -5,6 +5,7 @@ // Author: Amery Song // Keyon Jie +#include #include #include #include @@ -63,6 +64,55 @@ struct fft_plan *fft_plan_new(void *inb, void *outb, uint32_t size, int bits) return plan; } +struct fft_plan *mod_fft_plan_new(struct processing_module *mod, void *inb, + void *outb, uint32_t size, int bits) +{ + struct fft_plan *plan; + int lim = 1; + int len = 0; + int i; + + if (!inb || !outb) + return NULL; + + plan = mod_zalloc(mod, sizeof(struct fft_plan)); + if (!plan) + return NULL; + + switch (bits) { + case 16: + plan->inb16 = inb; + plan->outb16 = outb; + break; + case 32: + plan->inb32 = inb; + plan->outb32 = outb; + break; + default: + return NULL; + } + + /* calculate the exponent of 2 */ + while (lim < size) { + lim <<= 1; + len++; + } + + plan->size = lim; + plan->len = len; + + plan->bit_reverse_idx = mod_zalloc(mod, plan->size * sizeof(uint16_t)); + if (!plan->bit_reverse_idx) + return NULL; + + /* set up the bit reverse index */ + for (i = 1; i < plan->size; ++i) + plan->bit_reverse_idx[i] = (plan->bit_reverse_idx[i >> 1] >> 1) | + ((i & 1) << (len - 1)); + + return plan; +} + void fft_plan_free(struct fft_plan *plan) { if (!plan) @@ -71,3 +121,12 @@ void fft_plan_free(struct fft_plan *plan) rfree(plan->bit_reverse_idx); rfree(plan); } + +void mod_fft_plan_free(struct processing_module *mod, struct fft_plan *plan) +{ + if (!plan) + return; + + mod_free(mod, plan->bit_reverse_idx); + mod_free(mod, plan); +} From 73e325716b8d4742a9db6dd79f91b25ebf420a1e Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 21 Aug 2025 23:16:17 +0300 Subject: [PATCH 10/13] Audio: mfcc: Memory, blob, and fast_get allocs to module API Allocate all memory, blob handlers, and fast_get() buffers through module API mod_alloc() and friends and remove all redundant rfree(), comp_data_blob_handler_free(), and fast_put() calls from module unload functions and init error branches. Signed-off-by: Jyri Sarha --- src/audio/mfcc/mfcc.c | 22 ++------ src/audio/mfcc/mfcc_setup.c | 77 ++++++++++---------------- src/include/sof/audio/mfcc/mfcc_comp.h | 2 +- 3 files changed, 34 insertions(+), 67 deletions(-) diff --git a/src/audio/mfcc/mfcc.c b/src/audio/mfcc/mfcc.c index 6437c187e29e..547e86850213 100644 --- a/src/audio/mfcc/mfcc.c +++ b/src/audio/mfcc/mfcc.c @@ -88,44 +88,32 @@ static int mfcc_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; /* Handler for configuration data */ md->private = cd; - cd->model_handler = comp_data_blob_handler_new(dev); + cd->model_handler = mod_data_blob_handler_new(mod); if (!cd->model_handler) { comp_err(dev, "comp_data_blob_handler_new() failed."); - ret = -ENOMEM; - goto err; + return -ENOMEM; } /* Get configuration data */ ret = comp_init_data_blob(cd->model_handler, bs, cfg->init_data); if (ret < 0) { comp_err(mod->dev, "comp_init_data_blob() failed."); - goto err_init; + return ret; } return 0; - -err_init: - comp_data_blob_handler_free(cd->model_handler); - -err: - rfree(cd); - return ret; } static int mfcc_free(struct processing_module *mod) { - struct mfcc_comp_data *cd = module_get_private_data(mod); - comp_info(mod->dev, "mfcc_free()"); - comp_data_blob_handler_free(cd->model_handler); - mfcc_free_buffers(cd); - rfree(cd); + mfcc_free_buffers(mod); return 0; } diff --git a/src/audio/mfcc/mfcc_setup.c b/src/audio/mfcc/mfcc_setup.c index 802ea058bb6f..33d6577f9d38 100644 --- a/src/audio/mfcc/mfcc_setup.c +++ b/src/audio/mfcc/mfcc_setup.c @@ -65,7 +65,7 @@ static int mfcc_get_window(struct mfcc_state *state, enum sof_mfcc_fft_window_ty * coef[i] = 1.0 + 0.5 * lifter * sin(pi * i / lifter), i = 0 to num_ceps-1 */ -static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) +static int mfcc_get_cepstral_lifter(struct processing_module *mod, struct mfcc_cepstral_lifter *cl) { int32_t inv_cepstral_lifter; int32_t val; @@ -75,7 +75,7 @@ static int mfcc_get_cepstral_lifter(struct mfcc_cepstral_lifter *cl) if (cl->num_ceps > DCT_MATRIX_SIZE_MAX) return -EINVAL; - cl->matrix = mat_matrix_alloc_16b(1, cl->num_ceps, 9); /* Use Q7.9 */ + cl->matrix = mod_mat_matrix_alloc_16b(mod, 1, cl->num_ceps, 9); /* Use Q7.9 */ if (!cl->matrix) return -ENOMEM; @@ -171,12 +171,10 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i comp_info(dev, "mfcc_setup(), buffer_size = %d, prev_size = %d", state->buffer_size, state->prev_data_size); - state->buffers = rzalloc(SOF_MEM_FLAG_USER, - state->sample_buffers_size); + state->buffers = mod_zalloc(mod, state->sample_buffers_size); if (!state->buffers) { comp_err(dev, "Failed buffer allocate"); - ret = -ENOMEM; - goto exit; + return -ENOMEM; } mfcc_init_buffer(&state->buf, state->buffers, state->buffer_size); @@ -189,29 +187,26 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i #else fft->fft_buffer_size = fft->fft_padded_size * sizeof(struct icomplex32); #endif - fft->fft_buf = rzalloc(SOF_MEM_FLAG_USER, fft->fft_buffer_size); + fft->fft_buf = mod_zalloc(mod, fft->fft_buffer_size); if (!fft->fft_buf) { comp_err(dev, "Failed FFT buffer allocate"); - ret = -ENOMEM; - goto free_buffers; + return -ENOMEM; } - fft->fft_out = rzalloc(SOF_MEM_FLAG_USER, fft->fft_buffer_size); + fft->fft_out = mod_zalloc(mod, fft->fft_buffer_size); if (!fft->fft_out) { comp_err(dev, "Failed FFT output allocate"); - ret = -ENOMEM; - goto free_fft_buf; + return -ENOMEM; } fft->fft_fill_start_idx = 0; /* From config pad_type */ /* Setup FFT */ - fft->fft_plan = fft_plan_new(fft->fft_buf, fft->fft_out, fft->fft_padded_size, - MFCC_FFT_BITS); + fft->fft_plan = mod_fft_plan_new(mod, fft->fft_buf, fft->fft_out, fft->fft_padded_size, + MFCC_FFT_BITS); if (!fft->fft_plan) { comp_err(dev, "Failed FFT init"); - ret = -EINVAL; - goto free_fft_out; + return -EINVAL; } comp_info(dev, "mfcc_setup(), window = %d, num_mel_bins = %d, num_ceps = %d, norm = %d", @@ -223,7 +218,7 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i ret = mfcc_get_window(state, config->window); if (ret < 0) { comp_err(dev, "Failed Window function"); - goto free_fft_out; + return ret; } /* Setup Mel auditory filterbank. FFT input and output buffers are used @@ -242,10 +237,10 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i fb->scratch_data2 = (int16_t *)fft->fft_out; fb->scratch_length1 = fft->fft_buffer_size / sizeof(int16_t); fb->scratch_length2 = fft->fft_buffer_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(fb); + ret = mod_psy_get_mel_filterbank(mod, fb); if (ret < 0) { comp_err(dev, "Failed Mel filterbank"); - goto free_fft_out; + return ret; } /* Setup DCT */ @@ -253,18 +248,18 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i dct->num_out = config->num_ceps; dct->type = (enum dct_type)config->dct; dct->ortho = true; - ret = dct_initialize_16(dct); + ret = mod_dct_initialize_16(mod, dct); if (ret < 0) { comp_err(dev, "Failed DCT init"); - goto free_melfb_data; + return ret; } state->lifter.num_ceps = config->num_ceps; state->lifter.cepstral_lifter = config->cepstral_lifter; /* Q7.9 max 64.0*/ - ret = mfcc_get_cepstral_lifter(&state->lifter); + ret = mfcc_get_cepstral_lifter(mod, &state->lifter); if (ret < 0) { comp_err(dev, "Failed cepstral lifter"); - goto free_dct_matrix; + return ret; } /* Scratch overlay during runtime @@ -297,33 +292,17 @@ int mfcc_setup(struct processing_module *mod, int max_frames, int sample_rate, i comp_dbg(dev, "mfcc_setup(), done"); return 0; - -free_dct_matrix: - rfree(state->dct.matrix); - -free_melfb_data: - rfree(fb->data); - -free_fft_out: - rfree(fft->fft_out); - -free_fft_buf: - rfree(fft->fft_buf); - -free_buffers: - rfree(state->buffers); - -exit: - return ret; } -void mfcc_free_buffers(struct mfcc_comp_data *cd) +void mfcc_free_buffers(struct processing_module *mod) { - fft_plan_free(cd->state.fft.fft_plan); - rfree(cd->state.fft.fft_buf); - rfree(cd->state.fft.fft_out); - rfree(cd->state.buffers); - rfree(cd->state.melfb.data); - rfree(cd->state.dct.matrix); - rfree(cd->state.lifter.matrix); + struct mfcc_comp_data *cd = module_get_private_data(mod); + + mod_fft_plan_free(mod, cd->state.fft.fft_plan); + mod_free(mod, cd->state.fft.fft_buf); + mod_free(mod, cd->state.fft.fft_out); + mod_free(mod, cd->state.buffers); + mod_free(mod, cd->state.melfb.data); + mod_free(mod, cd->state.dct.matrix); + mod_free(mod, cd->state.lifter.matrix); } diff --git a/src/include/sof/audio/mfcc/mfcc_comp.h b/src/include/sof/audio/mfcc/mfcc_comp.h index bbc01030e157..ec5cc90eb40c 100644 --- a/src/include/sof/audio/mfcc/mfcc_comp.h +++ b/src/include/sof/audio/mfcc/mfcc_comp.h @@ -154,7 +154,7 @@ static inline int16_t *mfcc_buffer_wrap(struct mfcc_buffer *buffer, int16_t *ptr int mfcc_setup(struct processing_module *mod, int max_frames, int rate, int channels); -void mfcc_free_buffers(struct mfcc_comp_data *cd); +void mfcc_free_buffers(struct processing_module *mod); void mfcc_s16_default(struct processing_module *mod, struct input_stream_buffer *bsource, struct output_stream_buffer *bsink, int frames); From 9ed49116ae3839945e8213a03aa198e2739c69da Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 22 Aug 2025 12:19:03 +0300 Subject: [PATCH 11/13] cmocka: Add mocks for mod_alloc(), mod_zalloc(), and mod_free() Add mocks for mod_alloc(), mod_zalloc(), and mod_free(). These dummy versions do not keep track of the allocated memory. They just forward the calls to reqular malloc() and free(). Signed-off-by: Jyri Sarha --- test/cmocka/src/common_mocks.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/test/cmocka/src/common_mocks.c b/test/cmocka/src/common_mocks.c index 3d844b803268..44b632997c7a 100644 --- a/test/cmocka/src/common_mocks.c +++ b/test/cmocka/src/common_mocks.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,39 @@ void WEAK rfree(void *ptr) free(ptr); } +void WEAK *mod_alloc(struct processing_module *mod, uint32_t size) +{ + void *ret; + (void)mod; + + ret = malloc(size); + + assert(ret); + + return ret; +} + +void WEAK *mod_zalloc(struct processing_module *mod, uint32_t size) +{ + void *ret; + (void)mod; + + ret = malloc(size); + + assert(ret); + + memset(ret, 0, size); + + return ret; +} + +int WEAK mod_free(struct processing_module *mod, const void *ptr) +{ + (void)mod; + free((void *)ptr); + return 0; +} + int WEAK memcpy_s(void *dest, size_t dest_size, const void *src, size_t count) { From 256ae88ba3200c2cb3bf1e50ec1a4907523e7725 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sat, 23 Aug 2025 12:04:18 +0300 Subject: [PATCH 12/13] cmocka: math: Test using module memory API math function Convert auditory, dct, fft, and matrix math tests to use module heap API functions instead of the old version using rmalloc() and friends directly. Signed-off-by: Jyri Sarha --- test/cmocka/src/math/auditory/auditory.c | 7 +++++-- test/cmocka/src/math/dct/dct.c | 4 +++- test/cmocka/src/math/fft/fft.c | 23 +++++++++++++---------- test/cmocka/src/math/matrix/matrix.c | 9 ++++++--- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/test/cmocka/src/math/auditory/auditory.c b/test/cmocka/src/math/auditory/auditory.c index 1e3e903fb5fb..65be2e0dcfce 100644 --- a/test/cmocka/src/math/auditory/auditory.c +++ b/test/cmocka/src/math/auditory/auditory.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "ref_hz_to_mel.h" @@ -38,6 +39,8 @@ #undef DEBUGFILES /* Change this to #define to get output data files for debugging */ +struct processing_module dummy; + static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, const int16_t *ref_mel_log, int num_fft_bins, int num_mel_bins, int norm_slaney, @@ -87,7 +90,7 @@ static void filterbank_16_test(const int16_t *fft_real, const int16_t *fft_imag, fb.scratch_data2 = (int16_t *)fft_out; fb.scratch_length1 = fft_size / sizeof(int16_t); fb.scratch_length2 = fft_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(&fb); + ret = mod_psy_get_mel_filterbank(&dummy, &fb); if (ret < 0) { fprintf(stderr, "Failed Mel filterbank\n"); goto err_get_filterbank; @@ -190,7 +193,7 @@ static void filterbank_32_test(const int32_t *fft_real, const int32_t *fft_imag, fb.scratch_data2 = (int16_t *)fft_out; fb.scratch_length1 = fft_size / sizeof(int16_t); fb.scratch_length2 = fft_size / sizeof(int16_t); - ret = psy_get_mel_filterbank(&fb); + ret = mod_psy_get_mel_filterbank(&dummy, &fb); if (ret < 0) { fprintf(stderr, "Failed Mel filterbank\n"); goto err_get_filterbank; diff --git a/test/cmocka/src/math/dct/dct.c b/test/cmocka/src/math/dct/dct.c index 4cfe38ef803b..fd7b2f64d0b5 100644 --- a/test/cmocka/src/math/dct/dct.c +++ b/test/cmocka/src/math/dct/dct.c @@ -22,6 +22,8 @@ #define MATRIX_MULT_16_MAX_ERROR_ABS 2.5 #define MATRIX_MULT_16_MAX_ERROR_RMS 1.1 +struct processing_module dummy; + static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, enum dct_type type, bool ortho) { @@ -41,7 +43,7 @@ static void dct_matrix_16_test(const int16_t *ref, int num_in, int num_out, dct.num_out = num_out; dct.type = type; dct.ortho = ortho; - ret = dct_initialize_16(&dct); + ret = mod_dct_initialize_16(&dummy, &dct); if (ret) { fprintf(stderr, "Failed to initialize DCT.\n"); exit(EXIT_FAILURE); diff --git a/test/cmocka/src/math/fft/fft.c b/test/cmocka/src/math/fft/fft.c index 7c3279c96b57..92ac9380f0e7 100644 --- a/test/cmocka/src/math/fft/fft.c +++ b/test/cmocka/src/math/fft/fft.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,8 @@ #define MIN_SNR_512 125.0 #define MIN_SNR_1024 119.0 +struct processing_module dummy; + /** * \brief Doing Fast Fourier Transform (FFT) for mono real input buffers. * \param[in] src - pointer to input buffer. @@ -68,7 +71,7 @@ static void fft_real(struct comp_buffer *src, struct comp_buffer *dst, uint32_t if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -85,7 +88,7 @@ static void fft_real(struct comp_buffer *src, struct comp_buffer *dst, uint32_t *((int32_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -123,7 +126,7 @@ static void ifft_complex(struct comp_buffer *src, struct comp_buffer *dst, uint3 if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -140,7 +143,7 @@ static void ifft_complex(struct comp_buffer *src, struct comp_buffer *dst, uint3 *((int32_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -181,7 +184,7 @@ static void fft_real_2(struct comp_buffer *src, struct comp_buffer *dst1, if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 32); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 32); if (!plan) goto err_plan; @@ -210,7 +213,7 @@ static void fft_real_2(struct comp_buffer *src, struct comp_buffer *dst1, (outb[size - i].real - outb[i].real) / 2; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -498,7 +501,7 @@ static void fft_real_16(struct comp_buffer *src, struct comp_buffer *dst, uint32 if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 16); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 16); if (!plan) goto err_plan; @@ -515,7 +518,7 @@ static void fft_real_16(struct comp_buffer *src, struct comp_buffer *dst, uint32 *((int16_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); @@ -553,7 +556,7 @@ static void ifft_complex_16(struct comp_buffer *src, struct comp_buffer *dst, ui if (!outb) goto err_outb; - plan = fft_plan_new(inb, outb, size, 16); + plan = mod_fft_plan_new(&dummy, inb, outb, size, 16); if (!plan) goto err_plan; @@ -570,7 +573,7 @@ static void ifft_complex_16(struct comp_buffer *src, struct comp_buffer *dst, ui *((int16_t *)dst->stream.addr + 2 * i + 1) = outb[i].imag; } - fft_plan_free(plan); + mod_fft_plan_free(&dummy, plan); err_plan: rfree(outb); diff --git a/test/cmocka/src/math/matrix/matrix.c b/test/cmocka/src/math/matrix/matrix.c index 66200bc3e632..8806344dce09 100644 --- a/test/cmocka/src/math/matrix/matrix.c +++ b/test/cmocka/src/math/matrix/matrix.c @@ -4,6 +4,7 @@ // // Author: Seppo Ingalsuo +#include #include #include #include @@ -23,6 +24,8 @@ #define MATRIX_MULT_16_MAX_ERROR_ABS 1.5 #define MATRIX_MULT_16_MAX_ERROR_RMS 0.5 +struct processing_module dummy; + static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, const int16_t *c_ref, int elementwise, int a_rows, int a_columns, int b_rows, int b_columns, int c_rows, int c_columns, @@ -38,17 +41,17 @@ static void matrix_mult_16_test(const int16_t *a_ref, const int16_t *b_ref, cons int16_t x; int i, j, k; - a_matrix = mat_matrix_alloc_16b(a_rows, a_columns, a_frac); + a_matrix = mod_mat_matrix_alloc_16b(&dummy, a_rows, a_columns, a_frac); if (!a_matrix) exit(EXIT_FAILURE); - b_matrix = mat_matrix_alloc_16b(b_rows, b_columns, b_frac); + b_matrix = mod_mat_matrix_alloc_16b(&dummy, b_rows, b_columns, b_frac); if (!b_matrix) { free(a_matrix); exit(EXIT_FAILURE); } - c_matrix = mat_matrix_alloc_16b(c_rows, c_columns, c_frac); + c_matrix = mod_mat_matrix_alloc_16b(&dummy, c_rows, c_columns, c_frac); if (!c_matrix) { free(a_matrix); free(b_matrix); From 028a1e139407b5a27894bef8c22ede82300a0b22 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Sun, 24 Aug 2025 21:10:07 +0300 Subject: [PATCH 13/13] Math: Remove directly heap using math functions Both unit tests and modules should now use the module API heap allocation functions, so we can now remove the directly heap using versions. Signed-off-by: Jyri Sarha --- src/include/sof/math/auditory.h | 1 - src/include/sof/math/dct.h | 1 - src/math/auditory/auditory.c | 126 -------------------------------- src/math/dct.c | 47 ------------ 4 files changed, 175 deletions(-) diff --git a/src/include/sof/math/auditory.h b/src/include/sof/math/auditory.h index 0e082335f764..997c1a6c4a58 100644 --- a/src/include/sof/math/auditory.h +++ b/src/include/sof/math/auditory.h @@ -76,7 +76,6 @@ int16_t psy_mel_to_hz(int16_t mel); * filter coefficients. * \return Zero when success, otherwise error code. */ -int psy_get_mel_filterbank(struct psy_mel_filterbank *mel_fb); struct processing_module; int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *mel_fb); diff --git a/src/include/sof/math/dct.h b/src/include/sof/math/dct.h index c1c5caa808a6..21cdd8ba817f 100644 --- a/src/include/sof/math/dct.h +++ b/src/include/sof/math/dct.h @@ -29,7 +29,6 @@ struct dct_plan_16 { bool ortho; }; -int dct_initialize_16(struct dct_plan_16 *dct); int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct); #endif /* __SOF_MATH_DCT_H__ */ diff --git a/src/math/auditory/auditory.c b/src/math/auditory/auditory.c index a10d13bbfc99..56cd6f99a24e 100644 --- a/src/math/auditory/auditory.c +++ b/src/math/auditory/auditory.c @@ -86,132 +86,6 @@ int16_t psy_mel_to_hz(int16_t mel) return hz; } -int psy_get_mel_filterbank(struct psy_mel_filterbank *fb) -{ - int32_t up_slope; - int32_t down_slope; - int32_t slope; - int32_t scale = ONE_Q16; - int32_t scale_inv = ONE_Q16; - int16_t *mel; - int16_t mel_start; - int16_t mel_end; - int16_t mel_step; - int16_t left_mel; - int16_t center_mel; - int16_t right_mel; - int16_t delta_cl; - int16_t delta_rc; - int16_t left_hz; - int16_t right_hz; - int16_t f; - int segment; - int i, j, idx; - int base_idx = 0; - int start_bin = 0; - int end_bin = 0; - - if (!fb) - return -ENOMEM; - - if (!fb->scratch_data1 || !fb->scratch_data2) - return -ENOMEM; - - /* Log power can be log, or log10 or dB, get multiply coef to convert - * log to desired format. - */ - switch (fb->mel_log_scale) { - case MEL_LOG: - fb->log_mult = ONE_OVER_LOG2E_Q29; - break; - case MEL_LOG10: - fb->log_mult = ONE_OVER_LOG2TEN_Q29; - break; - case MEL_DB: - fb->log_mult = TEN_OVER_LOG2TEN_Q29; - break; - default: - return -EINVAL; - } - - /* Use scratch area to hold vector of Mel values for each FFT frequency */ - if (fb->scratch_length1 < fb->half_fft_bins) - return -ENOMEM; - - fb->scale_log2 = 0; - - mel = fb->scratch_data1; - for (i = 0; i < fb->half_fft_bins; i++) { - f = fb->samplerate * i / fb->fft_bins; - mel[i] = psy_hz_to_mel(f); - } - - mel_start = psy_hz_to_mel(fb->start_freq); - mel_end = psy_hz_to_mel(fb->end_freq); - mel_step = (mel_end - mel_start) / (fb->mel_bins + 1); - for (i = 0; i < fb->mel_bins; i++) { - left_mel = mel_start + i * mel_step; - center_mel = mel_start + (i + 1) * mel_step; - right_mel = mel_start + (i + 2) * mel_step; - delta_cl = center_mel - left_mel; - delta_rc = right_mel - center_mel; - segment = 0; - idx = base_idx + 3; /* start of filter weight values */ - if (fb->slaney_normalize) { - left_hz = psy_mel_to_hz(left_mel); - right_hz = psy_mel_to_hz(right_mel); - scale = Q_SHIFT_RND(TWO_Q29 / (right_hz - left_hz), 29, 16); /* Q16.16*/ - if (i == 0) { - scale_inv = Q_SHIFT_LEFT(ONE_Q30 / scale, 14, 16); - fb->scale_log2 = base2_logarithm((uint32_t)scale) - LOG2_2P16; - } - - scale = Q_MULTSR_32X32((int64_t)scale, scale_inv, 16, 16, 16); - } - for (j = 0; j < fb->half_fft_bins; j++) { - up_slope = (((int32_t)mel[j] - left_mel) << 15) / delta_cl; /* Q17.15 */ - down_slope = (((int32_t)right_mel - mel[j]) << 15) / delta_rc; /* Q17.15 */ - slope = MIN(up_slope, down_slope); - slope = Q_MULTSR_32X32((int64_t)slope, scale, 15, 16, 15); - if (segment == 1 && slope <= 0) { - end_bin = j - 1; - break; - } - - if (segment == 0 && slope > 0) { - start_bin = j; - segment = 1; - } - - if (segment == 1) { - if (idx >= fb->scratch_length2) - return -EINVAL; - - fb->scratch_data2[idx++] = sat_int16(slope); - } - } - - if (idx + 2 >= fb->scratch_length2) - return -EINVAL; - - fb->scratch_data2[base_idx] = idx; /* index to next */ - fb->scratch_data2[base_idx + 1] = start_bin; - fb->scratch_data2[base_idx + 2] = end_bin - start_bin + 1; /* length */ - base_idx = idx; - } - - fb->data_length = &fb->scratch_data2[base_idx] - &fb->scratch_data2[0]; - fb->data = rzalloc(SOF_MEM_FLAG_USER, - sizeof(int16_t) * fb->data_length); - if (!fb->data) - return -ENOMEM; - - /* Copy the exact triangles data size to allocated buffer */ - memcpy_s(fb->data, sizeof(int16_t) * fb->data_length, - fb->scratch_data2, sizeof(int16_t) * fb->data_length); - return 0; -} - int mod_psy_get_mel_filterbank(struct processing_module *mod, struct psy_mel_filterbank *fb) { int32_t up_slope; diff --git a/src/math/dct.c b/src/math/dct.c index db2d96525eea..192846e6a082 100644 --- a/src/math/dct.c +++ b/src/math/dct.c @@ -32,53 +32,6 @@ * multiply with the returned matrix. * \param[in,out] dct In input provide DCT type and size, in output the DCT matrix */ -int dct_initialize_16(struct dct_plan_16 *dct) -{ - int16_t dct_val; - int32_t arg; - int32_t cos; - int32_t c1; - int16_t c2; - int16_t nk; - int n; - int k; - - if (dct->type != DCT_II || dct->ortho != true) - return -EINVAL; - - if (dct->num_in < 1 || dct->num_out < 1) - return -EINVAL; - - if (dct->num_in > DCT_MATRIX_SIZE_MAX || dct->num_out > DCT_MATRIX_SIZE_MAX) - return -EINVAL; - - dct->matrix = mat_matrix_alloc_16b(dct->num_in, dct->num_out, 15); - if (!dct->matrix) - return -ENOMEM; - - c1 = PI_Q29 / dct->num_in; - arg = Q_SHIFT_RND(TWO_Q29 / dct->num_in, 29, 12); - c2 = sqrt_int16(arg); /* Q4.12 */ - for (n = 0; n < dct->num_in; n++) { - for (k = 0; k < dct->num_out; k++) { - /* Note: Current int16_t nk works up to DCT_MATRIX_SIZE_MAX = 91 */ - nk = (Q_SHIFT_LEFT(n, 0, 1) + HALF_Q1) * Q_SHIFT_LEFT(k, 0, 1); /*Q14.2 */ - arg = Q_MULTSR_32X32((int64_t)c1, nk, 29, 2, 24); /* Q8.24 */ - /* Note: Q8.24 works up to DCT_MATRIX_SIZE_MAX = 42 */ - arg %= TWO_PI_Q24; - cos = cos_fixed_32b(Q_SHIFT_LEFT(arg, 24, 28)); /* Q1.31 */ - dct_val = Q_MULTSR_32X32((int64_t)cos, c2, 31, 12, 15); /* Q1.15 */ - if (k == 0) - dct_val = Q_MULTSR_32X32((int64_t)dct_val, - ONE_OVER_SQRT_TWO, 15, 31, 15); - - mat_set_scalar_16b(dct->matrix, n, k, dct_val); - } - } - - return 0; -} - int mod_dct_initialize_16(struct processing_module *mod, struct dct_plan_16 *dct) { int16_t dct_val;