audio: pipeline: change locking strategy for user LL builds#10957
audio: pipeline: change locking strategy for user LL builds#10957kv2019i wants to merge 3 commits into
Conversation
|
Keeping as drafts until dependencies are marged and will then update this PR and mark as ready for review. |
f1b280d to
1998a42
Compare
|
V2 pushed:
|
There was a problem hiding this comment.
Pull request overview
This PR changes how mutual exclusion is enforced between the IPC thread and the low-latency (LL) pipeline scheduling path when SOF is built to run LL pipelines in Zephyr user-space, aiming to simplify locking and reduce syscall overhead.
Changes:
- Keep the LL scheduler mutex held while executing LL tasks in user-space LL builds, shifting protection to a single scheduler-level lock.
- Introduce
user_ll_lock_sched()/user_ll_unlock_sched()as a shared locking API for IPC-side operations that must exclude the LL thread. - Remove the per-component list mutex and update IPC/pipeline graph operations to use the LL scheduler lock instead.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/schedule/zephyr_ll.c | Holds the scheduler lock while running LL tasks in user-space builds; adds exported scheduler lock/unlock helpers. |
| src/ipc/ipc4/helper.c | Uses the scheduler lock to protect pipeline/module free and updates LL blocking macros to accept src/dst cores. |
| src/ipc/ipc-helper.c | Uses the scheduler lock (user-space builds) instead of IRQ disable/enable when freeing components and manipulating buffer lists. |
| src/include/sof/schedule/ll_schedule_domain.h | Declares the new user_ll_lock_sched() / user_ll_unlock_sched() APIs. |
| src/include/sof/audio/component.h | Removes the user-space-only per-component list mutex. |
| src/audio/pipeline/pipeline-stream.c | Adds scheduler locking around pipeline_copy() in user-space LL builds. |
| src/audio/pipeline/pipeline-graph.c | Switches connect/disconnect list protection to the scheduler lock (or IRQ disable in kernel builds). |
0705e81 to
cb4edfd
Compare
|
V2 and V3 pushed:
|
| #include <stdbool.h> | ||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
| #include <sof/schedule/ll_schedule_domain.h> |
| assert(ret == 0); \ | ||
| } while (0) | ||
| #define PPL_LOCK(x) user_ll_assert_locked(x) | ||
| #define PPL_UNLOCK(x) |
There was a problem hiding this comment.
so PPL_UNLOCK() doesn't need the argument?
There was a problem hiding this comment.
Hmm, yes, stricly not needed. Can drop in next version. UPDATE: done in V4.
| #define ll_unblock(cross_core_bind, flags) irq_local_enable(flags) | ||
| #if CONFIG_SOF_USERSPACE_LL | ||
| /* note: cross-core streams are disabled in the build in this branch, | ||
| * so we can safely use 'src_core' only */ |
There was a problem hiding this comment.
could explicitly add a comment that src_core == dst_core
| #else | ||
| static inline void zephyr_ll_lock_acquired(int core) { (void)core; } | ||
| static inline void zephyr_ll_lock_releasing(int core) { (void)core; } | ||
| #endif /* CONFIG_ASSERT */ |
There was a problem hiding this comment.
to the commit description - sorry, couldn't quite follow how it describes this commit. Could you point out where the lock is taken for the whole duration of the LL tick processing? That's what the commit description is saying, right?
There was a problem hiding this comment.
@lyakh ack, I should merge patches 2 and 3. The actual lock is taken in patch 2, should be merged. Will fix.
There was a problem hiding this comment.
Actually, I kept these as separate patches (one for scheduler, one for audio pipeline code), but reworded the text in 3rd commit. So 2nd patch changes locking strategy in ll scheduler, 3rd patch removes the now unnecessary locks in audio pipeline level. Changed in V4.
cb4edfd to
a57c14b
Compare
|
V4 pushed:
|
Add new functions to lock/unlock the LL scheduler for a given core. This is intended for audio application code that needs to modify the audio pipelines and needs an interface to get exclusive access to the pipelines on a particular core. This interface is specific to SOF builds with CONFIG_SOF_USERSPACE_LL. If LL scheduler is running in kernel space, there is option to disable interrupts for similar effect. For now these code paths are kept separate. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
In user-space LL builds (CONFIG_SOF_USERSPACE_LL), the IPC user thread cannot block interrupts while making modifications to the audio graph. To workaround this limitation, one could either protect each pipeline object with locks, or keep the LL level lock held while executing LL tasks. This patch implements support for the latter approach. If building SOF for user LL, do not release the lock when running a task. This will help to reduce number of syscalls during a LL iteration, while still allowing to safely implement IPC handlers that need to modify the audio graph. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
a57c14b to
2a36aba
Compare
|
V5 pushed:
|
| #include <sof/audio/module_adapter/module/generic.h> | ||
| #include <sof/audio/pipeline.h> | ||
| #include <sof/ipc/msg.h> | ||
| #include <sof/schedule/ll_schedule_domain.h> |
There was a problem hiding this comment.
CONFIG_SOF_USERS_SPACE in commit description seems to be wrong
| /* Assert that the calling context already holds the LL lock for 'core'. */ | ||
| void user_ll_assert_locked(int core); | ||
| #else | ||
| static inline void user_ll_assert_locked(int core) { (void)core; } |
There was a problem hiding this comment.
could be ARG_UNUSED(), not important
There was a problem hiding this comment.
True, this is a Zephyr'ism, but given CONFIG_SOF_USERSPACE_LL is only built with Zephyr, I can use ARG_UNUSED here...
| #if CONFIG_SOF_USERSPACE_LL | ||
| /* note: cross-core streams are disabled so src_core==dst_core */ | ||
| #define ll_block(src_core, dst_core, flags) do { user_ll_lock_sched(src_core); (void)flags; } while(0) | ||
| #define ll_unblock(src_core, dst_core, flags) do { user_ll_unlock_sched(src_core) ; (void)flags; } while(0) |
There was a problem hiding this comment.
also ARG_UNUSED() and also unimportant
There was a problem hiding this comment.
I need to push anyway, so addressing this as well.
| #ifdef CONFIG_SOF_USERSPACE_LL | ||
| ppl_core = icd->core; | ||
| user_ll_lock_sched(ppl_core); | ||
| #endif |
There was a problem hiding this comment.
currently this is working with no locking at all, right? Theoretically this could race against pipeline streaming if we have a forking graph where one branch is stopped and freed while the other one is still running, correct? So I suppose we have a guard in place that would prevent the streaming loop from entering the stopped branch safely somehow?
There was a problem hiding this comment.
@lyakh In kernel-LL build, pipeline_disconnect() will disable local irqs to protect this. It's a good question whether that is sufficient for all cases, but at least has been in the code for a while like this. In user-LL, with higher cost taken with each mutex, taking the lock higher here, outside the loop in pipeline_module_free().
Modify the locking approach for CONFIG_SOF_USERSPACE_LL builds. Kernel LL implementation heavily relies on ability to disable interrupts when IPC handler is modifying the graph. This ensures a new LL tick and execution of a new graph cycle does not start before the graph modifications done by IPC handler are complete. In user-space, this approach is not available as user-space thread cannot disable interrupts. In commit 1e59ce2 ("pipeline: protect component connections with a mutex"), a sys_mutex based locking was implemented to protect the component list and modifications to it. This approach does not scale in the end as this would require taking the mutex for each component of each pipeline, and take the locks on every LL cycle tick. This results in significant system call overhead. Additionally Zephyr sys_mutex does not work correctly if the lock object is put into dynamically allocated user memory. The LL scheduler logic was changed to keep the LL lock when building with CONFIG_SOF_USERSPACE_LL. A single lock is used to protect the whole LL graph, and the lock is taken at start of LL tick. Take benefit of this in audio pipeline code and remove redundant locking. The patch only changes behaviour for userspace LL SOF builds. If LL scheduling is kept in kernel, locking is done as before. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
2a36aba to
7fc285f
Compare
|
V6 pushed:
|
A set of patches to change the locking approach for LL audio pipeline scheduling when SOF is built to run all LL pipelines in user-space. The target is to simplify the design and decrease the syscall overhead during typical audio use-cases.
Tested as part of #10558