-
Notifications
You must be signed in to change notification settings - Fork 349
Audio: template_comp: Add a new SOF template component #9952
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
Conversation
| *y = *(x + cd->channels_order[ch]); | ||
| y++; | ||
| } | ||
| x += cd->channels; |
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.
maybe in a follow-up - should we add template-generic.c and template-hifi5.c with different versions of these functions? Then also a template_comp.h header becomes justified, otherwise it isn't really needed?
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 need to complete this task quickly for coming power-on and move on to other critical things, so I'd like to postpone the HiFi5 version. But sure it makes sense, and shows how to use the Xtensa version helper macros.
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.
Also per my own experience the xt-clang compiler for HiFi5 is good, it's hard to beat the performance of good C code (e.g. hot code loops unrolled by four or eight) with hand written intrinsics. Intrinsics are good for saturated math with rounding that is not efficient with C but otherwise the gain can be low.
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.
@singalsu I think we can move this functions now into a file name template-generic.c. It doesn't pollute the template_comp.c code and makes everything easier to read.
| return NULL; | ||
| } | ||
|
|
||
| static int template_comp_process(struct processing_module *mod, |
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 strongly suggest using sink/source in the template for new modules
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've converted it now to sink/source. But as not experienced with it, not sure if the best way for everything. Some things look now a bit more complex than before. Can you please check again this!
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.
@marcinszkudlinski has your request been addressed correctly? Should your request for change be dropped?
61de80a to
5f3c2c4
Compare
|
Into this version I fixed the rimage .toml for ACE platforms, it loads and runs now. @marcinszkudlinski Thanks for suggestion, good idea! I'll update next this to sink/source api. |
|
@singalsu we already have similar component Looks good. I'm working on a presentation for EOSS/ZDS on how to add a new component to SOF and I could use this PR as an example. Is this component working only with IPC4? |
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.
The code and topology look fine (we need the kcontrol logic), but we need
- comments everywhere ! This should be like a book on how to create a module, AI should be able to understand it.
- Based on all the files changes in this PR, can we add a Readme.md file that lists all the setpc needed (based on the steps taken in this PR.
| */ | ||
| SOF_DEFINE_REG_UUID(template_comp); | ||
|
|
||
| DECLARE_TR_CTX(template_comp_tr, SOF_UUID(template_comp_uuid), LOG_LEVEL_INFO); |
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.
Can we comment everything ! e.g. what is it for, why needed, how to use etc etc.
| @@ -0,0 +1,21 @@ | |||
| #ifndef LOAD_TYPE | |||
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 also put a lot cf comments in here too.
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.
Unfortunately I don't know the meaning of these. We have a document start in https://github.com/thesofproject/sof-docs/pull/451/files but it was never merged to sof-docs where it should be described.
abonislawski
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.
Definitely need more comments, this template seems quite complicated
| return 0; | ||
| } | ||
|
|
||
| __cold static int template_comp_free(struct processing_module *mod) |
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.
e.g. here a short comment on why __cold
5f3c2c4 to
19822f1
Compare
| if (cd->enable) { | ||
| /* Process the data with the channels | ||
| * swap example function | ||
| */ |
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.
can this comment just fit on a single line?
|
@singalsu I left some comments. Would it also be possible to add IPC3 support? |
Thanks! Yes I could add (control handling is main difference), but I'm not able to test it. Also need a topology. Could it be another PR after this? |
| struct template_comp_comp_data { | ||
| template_comp_func template_comp_func; /**< processing function */ | ||
| int channels_order[PLATFORM_MAX_CHANNELS]; /**< channels ordering */ | ||
| int source_format; /**< audio format for input */ |
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 forgot to remove this, not used.
Ok, could be a separate PR. I can help test it. |
Yep, testing help and topology for IPC3 platform would be great. For Intel builds we can't have IPC3 and sink/source api without tricky back-porting. |
@dbaluta @singalsu can we then split this into |
9f24b39 to
99720e6
Compare
| struct template_comp_comp_data *cd = module_get_private_data(mod); | ||
| int16_t *x, *x_start, *x_end; | ||
| int16_t *y, *y_start, *y_end; | ||
| size_t size; | ||
| int x_size, y_size; | ||
| int source_samples_without_wrap; | ||
| int samples_without_wrap; | ||
| int samples = frames * cd->channels; | ||
| int bytes = frames * cd->frame_bytes; | ||
| int ret; | ||
| int ch; | ||
| int i; | ||
|
|
||
| ret = source_get_data(source, bytes, (void const **)&x, (void const **)&x_start, &size); | ||
| x_size = size >> 1; /* Bytes to number of s16 samples */ | ||
| if (ret) | ||
| return ret; | ||
|
|
||
| ret = sink_get_buffer(sink, bytes, (void **)&y, (void **)&y_start, &size); | ||
| y_size = size >> 1; /* Bytes to number of s16 samples */ | ||
| if (ret) | ||
| return ret; | ||
|
|
||
| x_end = x_start + x_size; | ||
| y_end = y_start + y_size; | ||
| while (samples) { | ||
| source_samples_without_wrap = x_end - x; | ||
| samples_without_wrap = y_end - y; | ||
| samples_without_wrap = MIN(samples_without_wrap, source_samples_without_wrap); | ||
| samples_without_wrap = MIN(samples_without_wrap, samples); |
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.
@singalsu can you have a comment for each step as this is a learning module. I'm good to merge if you can give a good commentry in the module and I can come back and add more context on the infra.
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.
Yep, I added comments to things happening in processing function.
99720e6 to
c95ce87
Compare
| * as defined in array channels_order[]. | ||
| */ | ||
| for (ch = 0; ch < cd->channels; ch++) { | ||
| *y = *(x + cd->channels_order[ch]); |
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.
isn't it similar to channel mapping in some other components, would channel_map be a better name for it?
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'm changing it since you prefer it, though this is not the same. Channels map elsewhere is an enum describing the stream, e.g. stereo or 5.1.
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.
Adding, yes you are right, there's in IPC4 copiers usage a channel map vector.
| ret = source_get_data(source, bytes, (void const **)&x, (void const **)&x_start, &size); | ||
| x_size = size >> 1; /* Bytes to number of s16 samples */ | ||
| if (ret) | ||
| return ret; |
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.
would be better to put if (ret) return ret; directly after line 50, before x_size calculation. Particularly since this is a template, so a copy-paste 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.
OK, though I tried to make more compact looking code this way.
| ret = sink_get_buffer(sink, bytes, (void **)&y, (void **)&y_start, &size); | ||
| y_size = size >> 1; /* Bytes to number of s16 samples */ | ||
| if (ret) | ||
| return ret; |
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.
ditto, and in other formats below too of course
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.
Yep, fixed now.
| comp_err(dev, "Illegal switch control num_elems = %d.", | ||
| cdata->num_elems); | ||
| return -EINVAL; | ||
| } |
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.
also a nitpick, but since this is a template:
if (cdata->num_elems != 1) {
comp_err(dev, "Illegal switch control num_elems = %d.",
cdata->num_elems);
return -EINVAL;
}
cd->enable = cdata->chanv[0].value;
comp_info(dev, "Setting enable = %d.", cd->enable);
i.e. check and return in case invalid, then process with standard processing without an else
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.
Yep, good idea.
| } else { | ||
| comp_err(dev, "Illegal switch control index = %d.", cdata->index); | ||
| return -EINVAL; | ||
| } |
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.
ditto - you also save 2 levels of indentation
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.
Yep, good finding. Note that I wanted to keep index != 0 to make it obvious these are numbers assigned for controls in topology. I trust the compiler to find the best instructions to handle it.
src/audio/template_comp/template.c
Outdated
| frames = MIN(frames, sink_frames); | ||
| if (cd->enable) { | ||
| /* Process the data with the channels swap example function. */ | ||
| ret = cd->template_comp_func(mod, source, sink, frames); |
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.
could do return cd->template_comp_func(...); and remove the else below and the ret variable
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.
Yep
src/audio/template_comp/template.c
Outdated
| enum sof_ipc_frame source_format; | ||
| int i; | ||
|
|
||
| comp_info(dev, "template_comp_prepare()"); |
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.
we don't even make .prepare() functions __cold because they should run reasonably fast. Better make this comp_dbg()
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.
Yep
src/audio/template_comp/template.c
Outdated
| { | ||
| struct template_comp_comp_data *cd = module_get_private_data(mod); | ||
|
|
||
| comp_info(mod->dev, "template_comp_reset()"); |
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.
ditto
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.
OK
src/audio/template_comp/template.c
Outdated
|
|
||
| assert_can_be_cold(); | ||
|
|
||
| comp_info(mod->dev, "template_comp_free()"); |
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.
even in __cold functions I'd make these comp_dbg() - sometimes these are useful, e.g. to see which component ID is which type, but IMHO if we do this in all modules - that would be too much. At least would be good to have them consistent. Maybe use comp_info() in all .init() and comp_dbg() in all others
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.
OK but hesitating a bit with this -- can no more see the life cycle of component from normal trace.
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.
maybe we should make a decision - how we log .init(), .free(), .set_config() and follow that consistently. Of course for debugging the more the better - if it all were captured perfectly with no negative effects on system performance, but unfortunately both happen: (1) if too much is logged, the logging subsystem will drop log entries automatically, and it can then drop important ones, and (2) performance can suffer
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.
Yep, the init, free, set_config would be my preference as minimum. The components are not causing as much traces traffic as the other framework.
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.
Yep, the init, free, set_config would be my preference as minimum. The components are not causing as much traces traffic as the other framework.
@singalsu I wouldn't be against this in principle, if we really weren't already hitting a margin, where adding just a couple more logs triggers Zephyr to drop some. E.g. looking at mtrace in https://sof-ci.01.org/sofpr/PR9952/build12397/devicetest/index.html?model=PTLH_RVP_NOCODEC&testcase=check-playback-all-formats which is good because it runs 1 stream at a time. A stream there begins with
[ 588.396178] <inf> ipc: ipc_cmd: rx : 0x44000000|0x3060004c
which is MOD_LARGE_CONFIG_SET. This doesn't yet belong to the actual streaming but the next IPC
[ 588.398488] <inf> ipc: ipc_cmd: rx : 0x11000005|0x0
is already GLB_CREATE_PIPELINE. The last log entry, that belongs to stream configuration before starting streaming is
[ 588.421185] <wrn> host_comp: host_get_copy_bytes_normal: comp:0 0x3 no bytes to copy, available samples: 0, free_samples: 192
which is less than 3ms later. In this time we generate 66 log entries. And - again - this is just one stream. If we do init-free-set_config for each component, in this case we have 7 components in 2 pipelines, would be 14 lines alone (.free() isn't called during construction, but might interfere if we run multiple streams). Of those 66 lines 22 lines are IPCs (I think we do need these, I find them very useful), 12 "pipe: pipeline_connect:" lines (also rather useful IMHO), 6 "buffer_new: buffer new size ..." lines (do we need these?)... So 14 lines more seems a rather significant addition. But you can of course make such a test PR and we'll see what mtrace logs will look like there
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 prefer the simple human readable traces, I've unless desperate never tried to decode in my mind the ipx rx/tx hex commands. We also see those IPC hex dumps in kernel messages.
This patch contains all needed to add a new minimal SOF component to FW build for TGL and more recent platforms plus sof-testbench4 simulation. the component name is template_comp and it is easy to duplicate for new component development from scratch. The component supports one switch kcontrol. When enabled the component swaps or reverses the channels order if there are two or more channels. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
This patch adds the template_comp widget class to topology2 and provides three topologies with word lengths 16/24/32 bits to test the component in playback and capture. The topologies are built to development directory with names sof-hda-benchmark-template_comp<16/24/32>.tplg. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
c95ce87 to
ef5b0ba
Compare
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 OK, just minor suggestion for comments regarding multiple inputs/outputs
|
|
||
| comp_dbg(dev, "template_comp_prepare()"); | ||
|
|
||
| if (num_of_sources != 1 || num_of_sinks != 1) |
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.
add a comment - there may be more than 1 input and/or output.
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.
@singalsu can you update incrementally, will merge this.
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.
Yep, I'll do another PR to address Marcin's additions.
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.
| { | ||
| struct template_comp_comp_data *cd = module_get_private_data(mod); | ||
| struct comp_dev *dev = mod->dev; | ||
| struct sof_source *source = sources[0]; |
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.
ditto
No description provided.