-
Notifications
You must be signed in to change notification settings - Fork 349
DP thread - start early #10150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DP thread - start early #10150
Conversation
lgirdwood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just some questions.
| pdata->mod = mod; | ||
| *task = &task_memory->task; | ||
|
|
||
| /* create a zephyr thread for the task */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be worth stating why we create it here in the comment, i.e. to do this and that etc. Next PR would then take stack size from topology i.e. stack_size = topology->stack_size ? topology->stack_size : DEFAULT_DP_STACK_SIZE;
| mod->dev = dev; | ||
| dev->mod = mod; | ||
|
|
||
| #if CONFIG_ZEPHYR_DP_SCHEDULER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw - I guess this will always be true now ? if so can be a later optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no legacy platforms with no DP? IPC3?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would say no non Zephyr platforms now. Everything should be Zephyr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this Kconfig already exists and it isn't about Zephyr, it is about DP. We could at some point remove "ZEPHYR" from SOF Kconfig names at toms point though, but that would be another task for our automation
| comp_dbg(dev, "start"); | ||
|
|
||
| if (dev->task) | ||
| schedule_task_cancel(dev->task); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need a sync() version here ? i.e. will this return after thread is stopped
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, the thread should be stopped at this point by exit from dp_thread_fn.
This call is "just in case"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dp thread should be released after calling the free method in the module.
marcinszkudlinski
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good,
i would double check it with Google AEC pipelines,
|
We need to start the DP thread earlier, before creating |
| ca_copy_from_module_to_sink(const struct audio_stream *sink, | ||
| void *buff, size_t bytes) | ||
| static void ca_copy_from_module_to_sink(const struct audio_stream *sink, | ||
| void *buff, size_t bytes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
align to open bracket
| struct comp_buffer **sinks) | ||
| static uint32_t module_single_sink_setup(struct comp_dev *dev, | ||
| struct comp_buffer **source, | ||
| struct comp_buffer **sinks) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
align to open bracket
| struct comp_buffer **source, | ||
| struct comp_buffer **sinks) | ||
| static uint32_t module_single_source_setup(struct comp_dev *dev, | ||
| struct comp_buffer **source, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
align to open bracket
| ca_copy_from_source_to_module(const struct audio_stream *source, | ||
| void *buff, uint32_t buff_size, size_t bytes) | ||
| static void ca_copy_from_source_to_module(const struct audio_stream *source, | ||
| void *buff, uint32_t buff_size, size_t bytes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
align to open bracket
|
|
||
| /* success, fill the structures */ | ||
| task_memory->task.priv_data = &task_memory->pdata; | ||
| task_memory->pdata.p_stack = p_stack; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The stack_size is no longer needed in pdata.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| comp_dbg(dev, "start"); | ||
|
|
||
| if (dev->task) | ||
| schedule_task_cancel(dev->task); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dp thread should be released after calling the free method in the module.
the freeing is done later in a newer version of this patch, as for the entry - maybe we can make that optional, at least with LLEXT we should be able to easily enough get rid of it and just get ops directly from an ELF section |
fa3e265 to
8b45418
Compare
lgirdwood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lyakh can we split this PR into 2 PRs, one for thread move and teh other for RTIO. That way we can test the thread move in CI whilst RTIO is still WIP.
|
|
||
| /* success, fill the structures */ | ||
| task_memory->task.priv_data = &task_memory->pdata; | ||
| task_memory->pdata.p_stack = p_stack; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
one general comment Using DP thread to other tasks but data processing is a bit risky - may lead to starvation
Theory of EDF scheduling says it may utilize CPU in 100%, lets not spoil it. I would strongly recommend using a separate thread for IPC for DP - AFAIK a thread may be switched from one user space to another, so a single worker, properly switched from one user space to another - will be enough and won;t consume too much resources. It will save a lot of problems |
@marcinszkudlinski we don't have 100ms long DP modules so far, looks like ATM we aren't expecting any that could run longer than 20ms. If we ever get such slow modules, then yes, then we can consider adding support for a separate thread. |
|
why not now? Less complicated that future refactoring. Are there advantages to re-use of DP thread vs 1 common thread - except for one less stack in RAM? |
@marcinszkudlinski Are we sure that we'll ever need that? I'd prefer to first enable the simpler version if we don't know if we ever need the more complex one. Besides I personally don't find the concept of switching memory domains particularly elegant. And the alternative would be at least an additional thread per "trust circle" (vendor / module interface), which is then not one but potentially several such proxy threads |
We need to move IPC processing for DP scheduled components into their thread context. For that the thread has to be started early. Create it immediately when creating DP task context. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
We need to run all module callbacks in DP thread context, for this the thread has to be started early - before the first module callback is called. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
DP processing threads should have as long as life time as possible to process all the relevant IPCs in the thread context. Move thread termination to be called immediately before freeing module data. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
|
With this state SRC can be run in DP mode and all its hooks will run on the SRC DP thread, no SRC code will execute in "base firmware" context. In fact that isn't quite right when SRC is built as an LLEXT module - then a one-line entry function will be called by the base firmware directly. Fixing that in the next step. |
a36778e to
f33ab73
Compare
We should be able to run DP threads in user-space mode, for this we need to move audio and IPC signalling to RTIO. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
src_set_config() and src_get_config() aren't used, they would return an error if ever called. It's easier to just remove them. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The current library loading API prescribes that all modules should have entry functions whose only role in fact (in case of LLEXT at least) is returning an interface operations popinter. LLEXT modules don't need that, they can store that pointer directly in module manifest. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
I think we are fine today (as the 1st step) with the single thread (since we dont have long period DP configs today), but adding the IPC thread can come next as a topology flag i.e. DP module configured for long period, pls fork a second thread for module IPC. I think we also need to look at IPC serialization too, it seems we can have improvements to support multiple messages per doorbell ring and more concurrency. Wont help us today though, but it is possible as future improvements. |
One separate worker will certainly be simpler.
Since we only have one IPC thread, one worker will suffice. Having multiple workers and the concept of "trust circle" is pointless. |
@softwarecki Modules shouldn't be allowed to access each other's memory, so you cannot run code of module A while being allowed to access memory of module B. So if you have a single user-space IPC helper thread, you'd need to switch its permissions / domain every time you need it to execute on behalf of a different module. This supposedly means reconfiguring the MMU context / reloading page tables. |
This is the beginning of the user-space SOF work. To enable DP threads to run in user-space we want to start them early to also call all callbacks from their modules in the thread context. This PR does that - starts the thread early to prepare for the context conversion