Skip to content

Conversation

@jsarha
Copy link
Contributor

@jsarha jsarha commented Sep 8, 2025

The message bellow is mostly obsolete.

It appears that virtual heap is not able to cope with all module allcations, so move away from using rballoc() and friends to avoid moving all the module allocations to virtual heap. Use rmalloc() friends in stead. To do this rmalloc() family needs to be extended with rmallloc_aling(). Adding new function requires some additions to cmocka and testbench. Then there is also couple of minor fixes at the end of series.

This is the first split of this huge PR: #10195

The older already merged PR on the same subject is here: #10164

Copilot AI review requested due to automatic review settings September 8, 2025 15:17
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 new aligned memory allocation function rmalloc_align() to replace rballoc() usage in the module API, avoiding virtual heap allocations. The change extends the rmalloc family with alignment support and includes corresponding test infrastructure updates.

  • Adds rmalloc_align() function with alignment parameter support
  • Updates module allocation to use rmalloc_align() instead of rballoc() functions
  • Improves error message formatting to use hexadecimal display for component IDs

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
zephyr/lib/alloc.c Implements rmalloc_align() and refactors rmalloc() to use it
zephyr/include/rtos/alloc.h Adds function declaration and documentation for rmalloc_align()
test/cmocka/src/common_mocks.c Adds mock implementations for testing framework
src/platform/library/lib/alloc.c Adds testbench implementation of rmalloc_align()
src/ipc/ipc4/helper.c Updates error message formatting to use hexadecimal IDs
src/audio/module_adapter/module/generic.c Replaces rballoc() usage with rmalloc_align()
posix/include/rtos/alloc.h Adds POSIX header declaration for rmalloc_align()

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

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 think we need to clarify rmalloc()/rballoc() semantics before continuing.


void *rmalloc_align(uint32_t flags, size_t bytes, uint32_t alignment)
{
return malloc(bytes);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm. I wonder if we should clarify rmalloc() and rballoc() semantics first. Originally in SOF, rballoc() was used to allocate 1k aligned buffers, but it was changed by this commit 50f7b0e from @lgirdwood . The documentation was never clarified explicitly, both calls are used to allocate buffers of memory. Now in practise, the audio components have continued to use rballoc() while OS and driver code has used rmalloc() UNLESS alignment has been needed.

As you note, there's really no difference with the alignment anymore, and most recently, since completing transition to Zephyr and addition of virtual heaps in commit 3932884 , only differences betwen rmalloc() and rballoc() are:

  • whether alignment can be passed (which is really a no-op as this commit shows)
  • virtual heap is only used for rballoc() (you take benefit of this in second patch)

I don't think this serves much purpose anymore and we might just as well clarify that heap interfaces we offer to apps. Any reason to keep both rmalloc() and rballoc()? If the virtual heap is the only difference and we want to keep this option, should the interface be renamed? Or atleast this needs to be documented better. @softwarecki can you comment on the rationale why virtual heap is only plugged to rballoc()?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@kv2019i I didn't want to switch the entire SOF to virtual heap usage all at once - the idea was to do it gradually, starting with components that benefit most from it. That's why it's currently only used in rballoc().

The second reason is that the virtual heap has some implementation limitations. Buffer sizes must be powers of two, and each group of buffers must be aligned to the page size (4KB). These constraints make it unsuitable for general-purpose allocations, which is why rmalloc() still uses the traditional heap.

We need the virtual heap mainly to support deep buffering. That mechanism relies on allocating the largest possible buffer from a predefined set of sizes. Without slot-based allocation, a single request could consume all available memory, blocking further allocations. Additionally, virtual heap helps reduce fragmentation and allows power savings by mapping only the used memory pages - unused memory banks can be powered down.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Excellent, thank you @softwarecki , that helps a lot. I think we should merge rmalloc and rballoc and have some flag to hint the allocator that virtual heap should/may be used. Current calls to rballoc() are good places to use this new flag as these have been prove to work with the virtual heap. Sounds good? @jsarha and @lgirdwood ?

Copy link
Collaborator

@lyakh lyakh Sep 11, 2025

Choose a reason for hiding this comment

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

We need the virtual heap mainly to support deep buffering. That mechanism relies on allocating the largest possible buffer from a predefined set of sizes.

@softwarecki then maybe static_hp_buffers could be tuned for this even better? Maybe most rballoc() users should be converted to use rmalloc() and the VMH should be used exclusively for audio buffers?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@lyakh I think we should aim to have as many users of the virtual heap as possible to fully benefit from its advantages:

  • reduced memory fragmentation
  • power savings by powering down unused memory banks
  • predictable allocation behavior thanks to fixed-size slots

Deep buffering just happens to leverage these properties, but it's not the reason virtual heap was introduced.

Copy link
Collaborator

@lyakh lyakh Sep 12, 2025

Choose a reason for hiding this comment

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

@softwarecki sure, and we should weigh those against VMH drawbacks:

  • inefficient memory use - memory is wasted because any allocation takes up a whole slot
  • high likelihood of allocation failure with growing number of small allocations
  • hard-coded and manually empirically optimised slot configuration
  • additional significant code size and complexity
  • general confusion of multiple (two) memory allocators

Copy link
Member

Choose a reason for hiding this comment

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

@jsarha @softwarecki @lyakh both VMH and Zephyr heap have benefits and drawbacks today, I've asked @jsarha to add a Kconfig to select the heap implementation at build time. i.e. all the alloc() calls will either go to VMH or Zephyr heap via a Kconfig selection. This way we keep both heaps as options and can continually fix/improve heaps and pick the correct heap per target/use case.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@lgirdwood Isn't this what CONFIG_VIRTUAL_HEAP=y does. Yes "y", rballoc() uses virtual heap, if 'n', it's not used anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even if we set CONFIG_VIRTUAL_HEAP=y vheap is not used for anything but rballoc. Now there is an extra option whether or not mod_alloc should use rmalloc (default) or rballoc, effectively directing all memory allocation done by processing modules (this does not include pipleline and other audio routing code), to virtual heap.

comp_err(mod->dev, "mod_alloc: requested allocation of 0 bytes.");
container_put(mod, container);
return NULL;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

This effectively cuts virtual heap from any use and we lose the user intent whether a piece of code wanted to allocate with potentially virtual heap in used, versus doing allocations in a way where virtual heap is ensured never to be used (see my comment to commit 1).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Processing module allocations in the system are not all allocations. In fact they of the audio buffer allocations they hardly play a role. The audio buffers are mostly allocated by the pipeline code which does not use module API.

@lgirdwood
Copy link
Member

I think we need to clarify rmalloc()/rballoc() semantics before continuing.

rballoc() to be deleted - can be done in this PR if possible.
rmalloc() and mod_alloc() will then map to correct heap implementation (either virt heap or zephyr heap) via the Kconfigs we have today.

@softwarecki softwarecki requested review from serhiy-katsyuba-intel and tmleman and removed request for dabekjakub September 10, 2025 15:44
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.

Seems consensus is to merge rballoc() and rmalloc() so let me remove my -1. I'll let others chime in how to sequence the rballoc/rmalloc merge w.r.t. this PR

@jsarha
Copy link
Contributor Author

jsarha commented Sep 11, 2025

Added one more commit on top, to allow Kconfig selection for mod_alloc() to use either rballoc or rmalloc, effectively giving choice whether to use virtual heap or not.

Copy link
Collaborator

@lyakh lyakh left a comment

Choose a reason for hiding this comment

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

mostly good. Let's just clarify compile-time vs. run-time rballoc() use before merging not to have to remove a Kconfig option again later

(void)flags;
(void)alignment;

return malloc(bytes);
Copy link
Collaborator

Choose a reason for hiding this comment

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

this works, right? So no cmocka test actually cares about alignment

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, with my full PR #10195 that includes cmocka memory leak fixes, all the cmocka tests pass without error from valgrind.

comp_err(mod->dev, "mod_alloc: failed to allocate memory for comp %x.",
dev_comp_id(mod->dev));
comp_err(mod->dev, "Failed to alloc %d bytes %d alignment for comp %x.",
size, alignment, dev_comp_id(mod->dev));
Copy link
Collaborator

Choose a reason for hiding this comment

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

unrelated to this commit: can we change size and alignment parameters of mod_alloc() and friends to size_t? Doesn't need to be a part of this PR, in fact I have this change already in my tree, so I can push it myself at some point

#else
ptr = rmalloc_align(SOF_MEM_FLAG_USER, size, alignment);

#endif
Copy link
Collaborator

Choose a reason for hiding this comment

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

we could also make it run-time by adding flags to mod_alloc_...() arguments. It will anyway be needed for uncached allocations

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, they could of course be added, but @lgirdwood specifically asked me to get rid of them.

Copy link
Member

Choose a reason for hiding this comment

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

It should only be infra that needs to use uncached memory. i.e. the user needs to convert to uncache and perform any synchronization. Modules will always be cached, yes there may be exceptions but these would be implemented by IP vendors.

@jsarha jsarha force-pushed the module_api_no_virtual_and_fixes branch from 495861d to 389e7e1 Compare September 12, 2025 14:08
Copy link
Collaborator

@softwarecki softwarecki left a comment

Choose a reason for hiding this comment

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

The Kconfig-based approach to selecting the heap implementation is not sufficient. Compile-time configuration removes the ability to express allocation intent per allocation site, which is essential for cases like audio buffers that benefit from virtual heap properties.
Instead of relying on global build-time switches, I propose extending the allocation API with a flag - for example SOF_MEM_FLAG_BUFFER - that can be set at the call site to indicate that the allocation is intended for buffer use and should leverage the virtual heap.
This preserves clarity of intent, avoids coupling allocation behavior to global configuration, and enables more targeted use of VMH where its benefits (fragmentation reduction, power savings, slot-based predictability) are most relevant.

@jsarha
Copy link
Contributor Author

jsarha commented Sep 16, 2025

The Kconfig-based approach to selecting the heap implementation is not sufficient. Compile-time configuration removes the ability to express allocation intent per allocation site, which is essential for cases like audio buffers that benefit from virtual heap properties. Instead of relying on global build-time switches, I propose extending the allocation API with a flag - for example SOF_MEM_FLAG_BUFFER - that can be set at the call site to indicate that the allocation is intended for buffer use and should leverage the virtual heap. This preserves clarity of intent, avoids coupling allocation behavior to global configuration, and enables more targeted use of VMH where its benefits (fragmentation reduction, power savings, slot-based predictability) are most relevant.

@softwarecki why is it relevant to the allocator if the memory is used as audio buffer?

BTW, I don't think any of the processing modules allocate audio buffers as such (that is pipeline infrastructure's job, isn't it?), but some of the memory allocated resembless audio buffers a bit, like filter memories.

@softwarecki
Copy link
Collaborator

@jsarha You're right that pipeline infrastructure handles most audio buffer allocations, but some modules still allocates buffers. The Kconfig-based approach to selecting the heap implementation is not sufficient. Compile-time configuration removes the ability to express allocation intent per call site. Currently, modules use both rzalloc() and rballoc() depending on context. Replacing these with a single mod_alloc() call simplifies the interface, but risks losing the original distinction between different allocation types. A flag restores that expressiveness without complicating the API. Even if the distinction between buffer and non-buffer memory isn't relevant today, it has been relevant in the past and may become important again. New platforms may introduce significant changes in memory architecture, and having a flexible, extensible API will help us adapt without needing invasive refactoring.

@lyakh
Copy link
Collaborator

lyakh commented Sep 19, 2025

A flag restores that expressiveness without complicating the API.

however, adding such a flag only makes sense if there's significant common processing taking place for both cases - with flag on and off. We shouldn't add a

int do_it_all(enum action x)
{
    switch (x) {
    case A:
        return do_a();
    case B:
        return do_b();
    case C:
        return do_c();
    }
    return -EINVAL;
}

if callers always know exactly which action they need, i.e. all (or most) calls to this function look like do_it_all(A) - in such cases the caller can just call do_a() directly. So if rballoc() and rmalloc() have no or very little common code and we need them both selectable at run-time, I'd rather have two functions, then a flag.

@softwarecki
Copy link
Collaborator

I don't mind whether we keep this as a separate function or use a flag for this purpose. For userspace modules, we'll want to use a different heap, so it might be better to have a single allocation function to avoid duplicating code. Regardless of the chosen approach, it will be necessary to fix the rballoc call, which was replaced with mod_alloc in commit 9fcc269 .

@jsarha jsarha force-pushed the module_api_no_virtual_and_fixes branch from 389e7e1 to 5b4a2ac Compare September 28, 2025 21:15
@jsarha
Copy link
Contributor Author

jsarha commented Sep 28, 2025

@softwarecki , I dropped the ifdef and added mod_balloc() and mod_balloc_align, that use rballoc as backend.

@jsarha jsarha force-pushed the module_api_no_virtual_and_fixes branch from 5b4a2ac to 8ed5133 Compare September 29, 2025 20:38
{
return mod_balloc_align(mod, size, 0);
}
EXPORT_SYMBOL(mod_balloc);
Copy link
Collaborator

Choose a reason for hiding this comment

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

is there actually any specific reason to make these wrappers proper external and exported functions instead of just trivial inlines, which would very likely have zero overhead when inlined? I'm planning some such changes in my user-space work e.g. lyakh@a4a975f and lyakh@dceb1b2 . If you like - feel free to take those two commits and make a separate PR with them

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really. Thou performance wise on extra function call hardly make a difference with a complex operation like heap allocation, and there is already quite a few calls after this. But then again I can make the change myself too, to this PR, if you wish.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only reason is that the rmalloc() and rballoc() + friends are implemented in the same manner in zepjhyr/lib/alloc.c. The main purpose of these API additions was not to be complete, but to not to cause regression when combined with conversion of the modules (#10195 ). The further development is easier and makes more sense, when the modules are actually using this API, and possible bugs are caught by CI.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not really. Thou performance wise on extra function call hardly make a difference with a complex operation like heap allocation, and there is already quite a few calls after this. But then again I can make the change myself too, to this PR, if you wish.

@jsarha This PR already has 11 commits in it, that's why I proposed a separate one

@jsarha jsarha force-pushed the module_api_no_virtual_and_fixes branch from 8ed5133 to d7262eb Compare September 30, 2025 14:59
@jsarha jsarha changed the title Module api: Do not use rballoc() and friends to avoid virtal heap usage. Module api: various fixes and developments Sep 30, 2025
Jyri Sarha added 8 commits September 30, 2025 18:40
Add rmalloc_align() function. The alignment is present in all alloc
implementations used by rmalloc() so there is no reason not to provide
it in the API.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Prepare cmocka tests for rmalloc() and rmalloc_align().

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Prepare for rmalloc_align() usage.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Forward mod_alloc() calls to rmalloc() instead of rbmalloc(). rballoc()
calls are forwarded to virtual heap if it is enabled, but rmalloc()
calls are not. The commit also removes if (alignment) condition, as
rmalloc() will eventually end up to rmalloc_align() with zero alignment.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Remove the remains of function name from the prints and in case of
heap allocation failure, print all available related parameters.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Print all module IDs hex for better readability.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Change mod_alloc_align and friends size and alignment parameters type
to size_t.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Add mod_balloc() and mod_balloc_aling() to enable also automatically
freed buffer memory allocations. The difference at the moment is that
"buffers" are allocated from virtual heap, using rballoc() as a
back-end, and other things are allocated from Zephyr heap assigned for
user space shared memory, using rmalloc() as a back-end.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
@jsarha jsarha force-pushed the module_api_no_virtual_and_fixes branch from d7262eb to beeb4d6 Compare September 30, 2025 16:12
Jyri Sarha added 3 commits September 30, 2025 19:13
Move container_get() after MEM_API_CHECK_THREAD(). This change may
help debugging if container_get() crashes when memory API functions
are called from wrong thread.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Make mod_balloc() and mod_alloc() inline functions.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Make mod_zalloc() inline function.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
@jsarha jsarha force-pushed the module_api_no_virtual_and_fixes branch from beeb4d6 to dbe5520 Compare September 30, 2025 16:15
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 Can we make this PR add the APIs, but lets keep the rballoc() usage atm as we work through VMH updates. This way there should be no allocation differences, once VMH updates are complete we can transition rballoc() users and retain the VMH allocations.

ptr = rballoc_align(SOF_MEM_FLAG_USER, size, alignment);
else
ptr = rballoc(SOF_MEM_FLAG_USER, size);
ptr = rmalloc_align(SOF_MEM_FLAG_USER, size, alignment);
Copy link
Member

Choose a reason for hiding this comment

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

Can we keep the rballoc() atm whilst VMH is updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is now also mod_balloc() which uses rballoc as a backend. Going to rballoc() alone will break the CI if conbined with module conversions. Its only a oneliner the change the backend when we are ready for it.

@lgirdwood
Copy link
Member

The Kconfig-based approach to selecting the heap implementation is not sufficient. Compile-time configuration removes the ability to express allocation intent per allocation site, which is essential for cases like audio buffers that benefit from virtual heap properties. Instead of relying on global build-time switches, I propose extending the allocation API with a flag - for example SOF_MEM_FLAG_BUFFER - that can be set at the call site to indicate that the allocation is intended for buffer use and should leverage the virtual heap. This preserves clarity of intent, avoids coupling allocation behavior to global configuration, and enables more targeted use of VMH where its benefits (fragmentation reduction, power savings, slot-based predictability) are most relevant.

I'm going to rework VMH as its "doing the right thing" today, but needs cleanup and better resilience when PHY pages are sparse. Once we are happy with VMH updates, we can remove rballoc() and keep its users with VMH and then add additional VMH users as incremental PRs.

Copy link
Collaborator

@softwarecki softwarecki left a comment

Choose a reason for hiding this comment

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

rballoc remains separated, so there's no reason to keep blocking this any further.

@softwarecki softwarecki self-requested a review October 3, 2025 15:14
@softwarecki softwarecki dismissed their stale review October 7, 2025 13:50

rballoc remains separated, so there's no reason to keep blocking this any further.

@jsarha
Copy link
Contributor Author

jsarha commented Oct 7, 2025

SOFCI TEST

@kv2019i
Copy link
Collaborator

kv2019i commented Oct 7, 2025

Thanks all, this is now ready to go in!

@kv2019i kv2019i merged commit 4da059e into thesofproject:main Oct 7, 2025
33 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