Skip to content

Conversation

@jsarha
Copy link
Contributor

@jsarha jsarha commented Jul 28, 2025

Module memory allocation API functions face lift. Once this is approved I go through the rest of the modules after SRC.

@jsarha jsarha force-pushed the module_heap_api branch from c622f16 to e1f2d1e Compare July 28, 2025 21:01
@jsarha jsarha marked this pull request as ready for review July 29, 2025 12:16
Copilot AI review requested due to automatic review settings July 29, 2025 12:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a module-level memory allocation API to replace direct memory allocation calls, providing better memory management tracking for audio modules. The changes rename and consolidate memory allocation functions to use a standardized module-based approach.

  • Replaced direct rzalloc, rballoc, and rfree calls with new module-based allocation functions
  • Added module-level memory tracking with automatic cleanup
  • Updated function signatures to pass processing modules instead of component devices

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/include/sof/audio/module_adapter/module/generic.h Updates API declarations, replacing old allocation functions with new mod_alloc, mod_zalloc, and mod_free
src/audio/module_adapter/module/generic.c Implements the new module allocation API with memory tracking and adds mod_zalloc function
src/audio/module_adapter/module_adapter.c Adds automatic cleanup of tracked module memory allocations during component free
src/audio/src/*.c Updates SRC audio modules to use new allocation API instead of direct memory calls
src/audio/module_adapter/module/waves/waves.c Migrates Waves audio processing module to use new allocation functions
src/audio/module_adapter/module/cadence.c Updates Cadence codec module to use new memory allocation API
src/audio/codec/dts/dts.c Converts DTS codec to use module-based memory allocation
Comments suppressed due to low confidence (2)

src/audio/module_adapter/module_adapter.c:1232

  • The variable name err_count is misleading as it's counting memory chunks that were properly freed, not errors. Consider renaming to freed_count or chunk_count.
		err_count++;

src/audio/module_adapter/module_adapter.c:1235

  • The variable name err_count is confusing in this context as it's used to warn about successfully freed memory chunks, not errors.
	if (err_count)

@jsarha jsarha force-pushed the module_heap_api branch from e1f2d1e to 4944442 Compare July 29, 2025 13:02
Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just one open.

rfree(mem->ptr);
list_item_del(&mem->mem_list);
rfree(mem);
err_count++;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a bug or is this a feature? I thought that the purpose of this managed allocation was the same as in the Linux kernel - you allocate what you need per "module" and in the end it's all freed automatically when the module is freed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that is upto discussion. Its easy enough to drop the warning message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning removed, and redundant - init failure branch or src_free() calls to mod_free() - removed.

Copy link
Member

@lgirdwood lgirdwood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jsarha changes LGTM, but many CI errors. I think we can merge once passing CI and then follow up and convert remaining modules to use high level API.

@softwarecki the intention here is this "high level" module alloc API will map the allocation request to the correct user heap and memory domain. i.e. the module context will have the domain ID which will be mapped to the heap by the infra.

Jyri Sarha added 4 commits August 3, 2025 23:30
Rename module_allocate_memory and module_free_memory to mod_alloc and
mod_free.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Rename module_free_all_memory() to mod_free_all().

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Container memory should be freed if the requested memory allocation fails.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Add mod_zalloc() function that is otherwise the same as mod_alloc(), but
allocated memory is initialized to zero.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
if (!ptr) {
comp_err(dev, "mod_alloc: failed to allocate memory for comp %x.",
dev_comp_id(dev));
rfree(container);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a proposal for a future improvement: I think we'll be doing lots of module-managed allocating and freeing, so maybe a pool of container objects would make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Reserving only couple of words long containers separately from heap is very inefficient. I'll do that as a follow up

return ret;
}

cd->mem_tabs = mod_alloc(mod, mem_tabs_size, 4);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are all rmalloc() allocations guaranteed to be 4-bytes aligned?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And rballoc, which is the backend used, is aligned to cache line lenght. The shortest cache line I could find from SOF supported platforms was 32 bytes. But still I left the 16 byte alignment in place, but certainly any heap implementation will retun a point at 32-bit word boundary, won't it 😅?

*
* This function is called automatically when the module is unloaded.
*/
void mod_free_all(struct processing_module *mod)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in fact I'm wondering if mod_free_all needs to be exported at all? Modules themselves shouldn't call it, it should only be called by the framework before freeing the actual module

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably yes, but that change can not part of this commit, but that should be done as a separate commmit after "module_adapter: Free all module associated memory module_adapter_free()".

... but no, that is not as easy as one might think. Cadence codec API module uses mod_free_all() in reset() [1] call back. So I'll leave this as it is for the moent.

[1]

module_free_all_memory(mod);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... but no, that is not as easy as one might think. Cadence codec API module uses mod_free_all() in reset() [1] call back. So I'll leave this as it is for the moent.

@jsarha this is interesting... So module and component structures aren't allocated in module-managed memory? If they were and you freed them in .reset() that would seem like a typical self-inflicted foot injury case to me

Copy link
Contributor Author

@jsarha jsarha Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is indeed the case. It uses normal heap allocations for that and mod_alloc() for prepare etc. allocations, so it can just drop them with one call at reset. Need to sort that out at some point, but I leave it for later.

}
EXPORT_SYMBOL(module_adapter_free);

size_t module_adapter_heap_usage(struct comp_dev *dev)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the argument have to be struct comp_dev? This is module-specific, isn't it? And mod_alloc() uses struct processing_module too

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guess not. But it saves some code at the only place that is actually using the function ATM. But in the end ist not big deal, one way or the other.

int module_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_size);
int module_adapter_trigger(struct comp_dev *dev, int cmd);
void module_adapter_free(struct comp_dev *dev);
size_t module_adapter_heap_usage(struct comp_dev *dev);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a good place for this prototype? Prototypes around it belong to the component API, which this function doesn't belong to

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's see if I can find a better place for it.


SHELL_CMD(module_heap_usage, NULL,
"Print heap memory usage of each module\n",
cmd_sof_module_heap_usage),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be good to make it similar to free (1)? Call it e.g. mod_free or modfree and maybe format output a bit similar (at least inspired by) to that of free? Can we print how much heap the modules claim to need?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you be a little more specific on what you'd like to see here? free provides system wide information, but here I was specifically asked to provide per module usage, and nothing more. System wide information does not fall into scope of this PR.

But if you are talking about some per module statistics, then ATM there is no such thing. Once memory is freed its gone and there is not trace or statistics about it. I can add some statistics collection like that (memory high watermark per module or something), but is the wasted cycles and memory really worth it? Most of the modules will anyway only reserve the memory they need and then its all reserved until the module unloads.

But the last request - the topology max heap usage number - should be easy to add. Wonder if I should also add some warning print if any module exceeeds its max heap usage number.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, basically I meant adding maximum size from the topology

{
#if CONFIG_FAST_GET
struct comp_data *cd = module_get_private_data(mod);
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could just move it after line 715/718 below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To do that I may have to use some antihistamine to overcome my allergic reations to mixing code and variable declarations.


if (!size) {
comp_err(dev, "module_allocate_memory: requested allocation of 0 bytes.");
comp_err(dev, "mod_alloc: requested allocation of 0 bytes.");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to include the function name in the error message? Zephyr automatically prefixes log entries with the function name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, but I do not want to mess with this commit that is strictly replace-string operation on the source tree. Maybe I should go through all our modules in another commit, in the next PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, now that we are Zephyr only, we should use LOG(), but this can be another PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lgirdwood didn't we already conclude that no, we want to keep audio specific macros for audio codes that add audio topology information (component and pipe ids) to the log messages. For generic code outside modules, using plain Zephyr LOG is then ok (when not in module context).

Free all module associated memory module_adapter_free() by calling
mod_free_all().

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Jyri Sarha added 3 commits August 4, 2025 21:12
Drop alignment argument from mod_alloc() and introduce
mod_alloc_align() and apply all the necessary changes to mod_alloc()
calls.

Also adds Doxygen documentation to mod_alloc_align, mod_alloc,
mod_zalloc, mod_free, and mod_free_all.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Remove redundant mod_free() and mod_free_all() calls. The calls became
redundant after mod_free_all() was added to module_adapter_free().

This change concerns only the modules that are already exclusively
using mod_alloc() and friends from module API. Namely, Cadence Codec
API (sof/audio/module_adapter/module/cadence.c) was left out even thou
it uses mod_alloc() and friends, since it still also uses direct
rballoc(), rzalloc(), rmalloc(), and rfree() calls. Cadence Codec API
will be dealt with the rest of the modules that do not yet use module
heap API.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Adds exported module_adapter_heap_usage() function that returns current
heap usage of the module in question.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Fix implicit declaration of function 'strtol' by including
stdlib.h.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
@jsarha jsarha force-pushed the module_heap_api branch 2 times, most recently from 534df07 to fae3bfe Compare August 4, 2025 21:40
Jyri Sarha added 2 commits August 5, 2025 00:58
Declare struct comp_dev to avoid warnings if ll_schedule_domain.h is
included before struct comp_dev is defined.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Adds new command to sof sub-command set. The new command,
module_heap_usage, prints out all active component ids, their heap
memory usage allocated through module API, and configured maximum
heap size.

NOTE: For the moment there is nothing preventing a module from
allocating more memory than the configured maximum.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Change all memory allocations to go through module API mod_alloc(),
mod_zalloc(), and mod_free(). The mod_free() calls are dropped form
error handling branches and from src_free() as the memory is anyway
freed as the module should unload shortly.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Copy link
Collaborator

@kv2019i kv2019i left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess ok, but some of the renames are not explained in commit messages and leave me wondering why the commit is done.

Oh, and this changes the module generic.h interface. We are 100% sure there are no external users for this interface? @lgirdwood @abonislawski ?

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 *mod_alloc(struct processing_module *mod, uint32_t size, uint32_t alignment);
int mod_free(struct processing_module *mod, void *ptr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure we don't have out-of-tree modules that use current generic.h naming? Should we add compatibility macros for the old names?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of tree need to adapt.

struct processing_module *mod = mod_void;
struct comp_dev *dev = mod->dev;
void *pMem;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commit doesn't say why these are renamed. Just to make them shorter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, simply to make the names shorter and not to trigger line wrapping storm all around the place when all modules are changed to use module API for memory allocations.

* Author: Kai Vehmanen <kai.vehmanen@linux.intel.com>
*/

#include <rtos/sof.h> /* sof_get() */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could have been a separate PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree (refreshing to have request to drop something out ot this PR instead of including more and more). But still hope this could be merged as one PR.

@lgirdwood
Copy link
Member

I guess ok, but some of the renames are not explained in commit messages and leave me wondering why the commit is done.

Oh, and this changes the module generic.h interface. We are 100% sure there are no external users for this interface? @lgirdwood @abonislawski ?

Any external non upstream usage will have to do the update themselves.

@kv2019i kv2019i merged commit 9fcc269 into thesofproject:main Aug 6, 2025
36 of 45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants