Skip to content

Per pipeline vregions/mod_alloc_ctx - #11164

Open
jsarha wants to merge 2 commits into
thesofproject:mainfrom
jsarha:per_pipeline_vregions
Open

Per pipeline vregions/mod_alloc_ctx#11164
jsarha wants to merge 2 commits into
thesofproject:mainfrom
jsarha:per_pipeline_vregions

Conversation

@jsarha

@jsarha jsarha commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

This is the last PR from my vregions proto PR: #10783

This move all low latency module allocations within a pipeline to a pipeline specific vregion. This should help with memory fragmentation as the whole vregion can freed when the pipeline is closed and freed. The later commit will put the vregion behind struct mod_alloc_ctx.

While reviewing this my self, the pipeline->heep looks now a bit redundant. There maybe room for one more PR, that would get rid of pipeline->heap and replacing its usage with mod_alloc_ctx.

Copilot AI lite review requested due to automatic review settings September 3, 2026 13:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

There are confirmed allocator/ownership bugs in module_adapter_mem_free() that can free memory with the wrong allocator and potentially free a pipeline-owned alloc context on early error paths.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR introduces a pipeline-scoped allocation context (mod_alloc_ctx) so that low-latency (LL) modules within the same pipeline can allocate from a pipeline-specific vregion (when available), reducing fragmentation and enabling bulk release when the pipeline is torn down.

Changes:

  • Add a shared per-pipeline allocation context pointer to struct pipeline.
  • Create and manage an optional pipeline vregion during pipeline lifecycle (create/free) and switch allocations to interim mode on pipeline_complete().
  • Update module adapter allocation to use the pipeline’s alloc context for LL modules (falling back to heap when no vregion is present).
File summaries
File Description
src/include/sof/audio/pipeline.h Adds a pipeline-level mod_alloc_ctx *alloc pointer for shared module allocations.
src/audio/pipeline/pipeline-graph.c Creates/frees the pipeline alloc context and optional vregion; switches vregion to interim on pipeline completion.
src/audio/module_adapter/module_adapter.c Routes LL module allocations/frees through the pipeline alloc context when available.
Review details

Suppressed comments (1)

src/audio/module_adapter/module_adapter.c:227

  • alloc is allocated via sof_heap_alloc(mod_heap, ...) (when not using the pipeline alloc context), but here it is freed with rfree(). Mixing allocators can corrupt heap state; free it with sof_heap_free(alloc->heap, alloc) instead.
	} else if (alloc->vreg) {
		if (!vregion_put(alloc->vreg))
			rfree(alloc);
	} else {
		rfree(alloc);
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/audio/module_adapter/module_adapter.c

@lyakh lyakh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

not a complete review yet, but I think at least this should be rearranged into 3 commits: (1) add mod_alloc_ctx to pipeline and move heap to it (part of your current second commit), (2) allocate vregion when needed (your current first commit), (3) move module allocations to pipeline vregion (the rest of your second commit)

vregion_free(mod_vreg, mod);
if (!vregion_put(mod_vreg))
if (!vregion_put(mod_vreg) || proc_domain == COMP_PROCESSING_DOMAIN_LL)
sof_heap_free(alloc->heap, alloc);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

are you sure this is symmetric? IIUC you only allocate LL pipeline memory on vregion if certain particular conditions are satisfied (certain extended init parameters are set). But here you free it unconditionally for all LL pipelines

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, I am sure. If we have no memory data for the pipeline, we do not create the vregion at all, and everything works through a regular heap. And we can call vregion_get(NULL) and vregion_put(NULL) as much as we want.

Comment thread src/audio/module_adapter/module_adapter.c Outdated
Comment thread src/audio/pipeline/pipeline-graph.c
Comment thread src/audio/pipeline/pipeline-graph.c Outdated
@intel-sofci

intel-sofci commented Sep 3, 2026

Copy link
Copy Markdown

PR 11164: test results

Run date: 2026-09-03 21:39 UTC

Tested commit: 6407e81546647d9dddf6310425669e6d07212e3c

mtl pass rate lnl pass rate ptl pass rate wcl pass rate nvl pass rate

@jsarha

jsarha commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

This at least fails in ll-userspace setup. I'll fix those issues first. I'll then see about rearranging the commits in completely new order.

Jyri Sarha added 2 commits September 3, 2026 20:35
Replace the bare k_heap pointer in struct pipeline with a
mod_alloc_ctx object. The context is created in pipeline_new()
and freed symmetrically in pipeline_free(). No vregion is
associated with this context yet, so allocation behavior is
unchanged: sof_ctx_alloc()/sof_ctx_zalloc()/sof_ctx_free() fall
back to the plain heap when the context has no vregion.

Update all remaining pipeline->heap consumers, including the
pipeline and trigger task allocations in pipeline-schedule.c, to
go through the alloc context instead of the heap pointer
directly.

Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Create a per-pipeline vregion in pipeline_new() when the IPC4 pipeline
extension payload specifies the required heap size, and attach it to
the pipeline's alloc context. LL modules on a pipeline with a vregion
use it as their allocation backend via vregion_get(), instead of the
driver's default heap, and share the pipeline's mod_alloc_ctx. A
use_ppl_alloc flag gates the sharing to LL modules only, so DP modules
continue to create their own vregion and alloc context as before. Also
the behaviour in the case the where ppl_alloc is not available remains
unchanged.

module_adapter_mem_free() detects whether a module's alloc belongs
to its pipeline and either just releases the vregion reference
(ppl_alloc case) or tears down the module's own alloc. Setting of
dev->pipeline is moved earlier in module_adapter_new_ext() so that
we can still use module_adapter_mem_free() in its error handling.

Call vregion_set_interim() for the pipeline vregion in
pipeline_complete() to switch the allocator to interim mode after
all lifetime allocations are done, and release it in
pipeline_free(), warning if the refcount does not reach zero.

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

jsarha commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

All suggestios from @lyakh applied. The new first commit now adds struct mod_alloc_ctx *alloc to struct pipeline and removes the old struct k_heap heap. After this commit I felt that adding extraneous vreg object to struct pipeline is kind of backwards and dropped that intermediate step and I added the vreg directly to the pipeline->alloc .

/* show heap status */
heap_trace_all(0);

alloc = sof_heap_alloc(heap, SOF_MEM_FLAG_USER, sizeof(*alloc), 0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think in the original version alloc was allocated using rmalloc(), i.e. only accessible to the kernel. I think that this version is correct and the previous one would have problems with userspace LL. Could you confirm?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that is why I changed it.

ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id,
IPC_COMP_IGNORE_REMOTE);
if (ipc_pipe && ipc_pipe->pipeline)
ppl_alloc = ipc_pipe->pipeline->alloc;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is it actually valid to have ipc_pipe == NULL? And why do we ignore remote pipelines? I suppose remote pipelines are only possible with DP, is that the intention here? But DP on the same core we accept. I think you want IPC_COMP_ALL here. And ipc_pipe shouldn't be NULL even for chain DMA, right? So if it's NULL, it's an error? And ipc_pipe->pipeline should be non-NULL too? Also the allocation context must be there too. So in practice ppl_alloc is always non-NULL?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is now indeed true.

uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ?
SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER;
bool use_ppl_alloc = ppl_alloc &&
config->proc_domain == COMP_PROCESSING_DOMAIN_LL;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

if my comment below is correct, ppl_alloc != NULL always, so this is true for all LL components.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, indeed. There should always be a mod_alloc_ctx. The both the heap and vreg may be NULL, but that does not matter.


if (IS_ENABLED(CONFIG_SOF_VREGIONS) && IS_ENABLED(CONFIG_USERSPACE) &&
!IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP) &&
config->proc_domain == COMP_PROCESSING_DOMAIN_DP) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

if my other comments are correct, then you only enter this else branch for DP components, so this condition is always true. If that's right let's remove that check here and add comments that the if branch is for all LL components, and here it's only DP. And let's rename the use_ppl_alloc variable then into something like ll_domain or ll_sched_dom or similar.

In fact you can do even better: keep the original if in old lines 96-97. Since it checks for DP, you're guaranteed, that your current use_ppl_alloc is false in that case. Then replace else in old line 108 with else if (use_ppl_alloc) or just else if (config->proc_domain == COMP_PROCESSING_DOMAIN_LL) and then use the last else branch - an equivalent to the present one. That way the diff will be much smaller and easier to review.

alloc = sof_heap_alloc(mod_heap, flags, sizeof(*alloc), 0);
if (!alloc) {
vregion_put(mod_vreg);
return NULL;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

use goto edev instead, optionally add an error message

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

mod_vreg is not defined outside the else branch, but I'll add an error message.

sof_heap_free(mod_heap, mod->dev);
sof_heap_free(mod_heap, mod);
sof_heap_free(mod_heap, alloc);
rfree(alloc);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is unclear now. Is this possible? If it is - you entered this function with valid non-NULL mod and mod->dev, what happens to them now? If this is invalid, then this should be made clear.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Oh, the rfree() is obviously wrong and should be sof_heap_free(alloc->heap, alloc), but what else are you suggesting?

I am not sure I am following your question. Are you talking about the final else-branch? That is needed in case alloc->vreg == NULL, like in non userspace dp case. Then there is no reason to delay the freeing of alloc ctx.

@lyakh

lyakh commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

@jsarha looks much better now! Much easier to understand now.

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.

4 participants