-
Notifications
You must be signed in to change notification settings - Fork 318
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
module: Add support for saving and retrieving the base config extension #8575
Conversation
2ed73f7
to
0a7cd2d
Compare
589eafe
to
6b6c154
Compare
@@ -392,7 +392,7 @@ static int google_rtc_audio_processing_init(struct processing_module *mod) | |||
#if CONFIG_IPC_MAJOR_4 | |||
const struct ipc4_base_module_extended_cfg *base_cfg = md->cfg.init_data; | |||
struct ipc4_input_pin_format reference_fmt, output_fmt; | |||
const size_t size = sizeof(struct ipc4_input_pin_format); | |||
size_t size = sizeof(struct ipc4_input_pin_format); |
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 suggest with input_size and output_size, and use input_size and output_size related line 409
sizeof(struct ipc4_input_pin_format)
sizeof(struct ipc4_output_pin_format)
use variable will not make code lose performance( no matter you use or not, compiler will do this), it can make code more easy to read.
@@ -216,31 +217,59 @@ struct get_attribute_remote_payload { | |||
static inline int comp_ipc4_get_attribute_remote(struct comp_dev *dev, uint32_t type, | |||
void *value) | |||
{ | |||
struct ipc4_base_module_cfg *base_cfg; | |||
struct ipc4_base_module_cfg_ext *basecfg_ext = NULL; | |||
struct ipc4_base_module_cfg *base_cfg = NULL; |
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.
you never need both pointers, right? So you could just use one, the only difference is the size, otherwise you'd reuse the same code.
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.
two pointers does help with type correctness, in case we ever have to deref. however, I cant see from here if one struct is embedded in the other (then 1 ptr makes sense).
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 they're not embedded. i will move the free's to the respective switches and remove the inits here
LGTM |
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.
Just some minor questions from me.
@@ -216,31 +217,59 @@ struct get_attribute_remote_payload { | |||
static inline int comp_ipc4_get_attribute_remote(struct comp_dev *dev, uint32_t type, | |||
void *value) | |||
{ | |||
struct ipc4_base_module_cfg *base_cfg; | |||
struct ipc4_base_module_cfg_ext *basecfg_ext = NULL; | |||
struct ipc4_base_module_cfg *base_cfg = NULL; |
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.
two pointers does help with type correctness, in case we ever have to deref. however, I cant see from here if one struct is embedded in the other (then 1 ptr makes sense).
struct ipc4_input_pin_format in_fmt; | ||
size_t input_fmt_offset; | ||
|
||
sink_basecfg_ext = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, |
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, if these are always copied and freed (in the same func), why not just have on the 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.
because basecfg_ext structure contains a flexible array member for the number of pin formats
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 we add a component method to get a pin format?
Modules are bound with one another with a buffer in between. Today, this buffer's size is based on the source module's base config obs and sink module's base config ibs. But this is incorrect because this assumes that the connection is always from output pin 0 of the source module and input pin 0 of the sink module. To determine the buffer size correctly, the buffer size should be based on the pin-based obs/ibs of the source/sink module. To allow this, save the base config extension for the module during init so that it can be retrieved during module binding to get the obs/ibs based on the source/sink pin ID. Modify the google rtc and smart amp modules to save the base config extension during their init. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
6b6c154
to
09ace5c
Compare
This patch is verified on Chrome rex system and is working without issue |
|
||
/* save the base config extension */ | ||
size = base_cfg->base_cfg_ext.nb_input_pins * in_fmt_size + | ||
base_cfg->base_cfg_ext.nb_output_pins * out_fmt_size; |
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.
nitpick: you could have
size = base_cfg->base_cfg_ext.nb_input_pins * in_fmt_size +
base_cfg->base_cfg_ext.nb_output_pins * out_fmt_size +
sizeof(struct ipc4_base_module_cfg_ext);
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 , no , see line 416, extra struct size are added when rzalloc
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.
@btian1 that's exactly why I'm proposing that
} | ||
|
||
size = basecfg_ext->nb_input_pins * sizeof(struct ipc4_input_pin_format) + | ||
basecfg_ext->nb_output_pins * sizeof(struct ipc4_output_pin_format); |
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.
similar here with size
rfree(base_cfg); | ||
break; | ||
case COMP_ATTR_BASE_CONFIG_EXT: | ||
memcpy_s(value, size, basecfg_ext, size); |
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.
here without sizeof(*basecfg_ext)
, right?
if (!src_basecfg_ext) | ||
return IPC4_OUT_OF_MEMORY; | ||
|
||
ret = comp_get_attribute(source, COMP_ATTR_BASE_CONFIG_EXT, src_basecfg_ext); |
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 looks scary... Can we add a size
argument to comp_get_attribute()
?
struct ipc4_input_pin_format in_fmt; | ||
size_t input_fmt_offset; | ||
|
||
sink_basecfg_ext = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, |
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 we add a component method to get a pin format?
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.
Please check the one functional comment. Multiple minor ones, but not necessary to address in this PR.
&base_cfg->base_cfg_ext.pin_formats[in_fmt_size], in_fmt_size); | ||
memcpy_s(&output_fmt, in_fmt_size, | ||
&base_cfg->base_cfg_ext.pin_formats[in_fmt_size * GOOGLE_RTC_NUM_INPUT_PINS], | ||
in_fmt_size); |
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.
Shouldn't this copy output-sized format? I.e.
memcpy_s(&output_fmt, out_fmt_size, , out_fmt_size);
..?
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.
and since size is same, I would prefer use memcpy(dst, src, size) to reduce one parameters.
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.
yeah, the array index [in_fmt_size], looks like copy paste error (even though its replacing a similar size/index bit of code) ?
|
||
memcpy_s(md->cfg.basecfg_ext, size + sizeof(struct ipc4_base_module_cfg_ext), | ||
&base_cfg->base_cfg_ext, | ||
size + sizeof(struct ipc4_base_module_cfg_ext)); |
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.
nitpick: "size + sizeof(struct ipc4_base_module_cfg_ext)" is repeated three times, maybe use a local variable for readability?
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 is not a complex operation, we should make code more straightforward to read.
total_size = size + sizeof(struct ipc4_base_module_cfg_ext);
struct ipc4_base_module_cfg *base_cfg; | ||
struct get_attribute_remote_payload payload = {}; | ||
struct idc_msg msg = { IDC_MSG_GET_ATTRIBUTE, | ||
IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, | ||
sizeof(payload), &payload}; | ||
size_t size = MODULE_MAX_SINKS * sizeof(struct ipc4_output_pin_format) + |
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.
minor: I found "size" a too generic as it's only used for one type of attributes. I.e. size of what? "ext_size"
} | ||
|
||
ibs = sink_src_cfg.ibs; | ||
} |
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.
Another minor note: would be nice to split out into subfunctions somehow, this function is getting very, very long.
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.
Changes verified om 007, working very well, please proceed with merging
Thanks @marcinszkudlinski for validating ! @ranj063 fyi, some conflicts. |
It's probably way too disruptive for me to -1 this given that it's already been pushed into mtl-007-drop-stable, but see #8685 for a different take on the same problem that IMHO is a lot cleaner long-term. Basically: I... kinda really, really hate the API picked here: Module code (literally every module that might in principle be connected to more than two other components) needs to make a copy of raw IPC memory that it finds in the module_config, set it back on a different field in module_config (for the benefit of ibs/obs buffer sizing, which it can't control), and then set that metadata back onto the connected buffers at prepare time. Literally none of those steps should be the responsibility of module code. Module code is written by dumb third party people like me who don't understand the module_adapter internals! |
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.
Actually I did find a spot with an actual bug, so -1. But not because of the dueling solutions, I swear. :)
I actually hit coherency issues in my version, which does basically the same copy but at a different place with different timing. It's presumably benign here, but these bugs can lurk for a long time before becoming traps.
FWIW, just to pontificate a little: SOF's cached-by-default heap really seems likely to be a reliability problem as more stuff gets moved out into DP-world. It might be worth thinking about e.g. changing "MEM_ZONE_RUNTIME" to be uncached and then auditing components to see (1) which ones are using heap blocks inside their copy/process routines and (2) decide on strategies for making those usages coherence-safe.
base_cfg->base_cfg_ext.nb_output_pins * out_fmt_size; | ||
|
||
md->cfg.basecfg_ext = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, | ||
sizeof(struct ipc4_base_module_cfg_ext) + size); |
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 needs to be SOF_MEM_ZONE_RUNTIME_SHARED or else to have SOF_MEM_CAPS_COHERENT. By default you get cached memory from the heap, and this code is running in a DP component on another core. Globally-shared data like module config either needs to be uncached or to be accessed via a cache-aware wrapper API.
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.
@andyross that is not true in this case.
All operations - create/configure/run/delete/whatever will be performed by a core the module is bound to. No exceptions. Using cached structures is safe
replaced by #8685 |
Modules are bound with one another with a buffer in between. Today, this buffer's size is based on the source module's base config obs and sink module's base config ibs. But this is incorrect because this assumes that the connection is always from output pin 0 of the source module and input pin 0 of the sink module.
To determine the buffer size correctly, the buffer size should be based on the pin-based obs/ibs of the source/sink module. To allow this, save the base config extension for the module during init so that it can be retrieved during module binding to get the obs/ibs based on the source/sink pin ID.
Modify the google rtc and smart amp modules to save the base config extension during their init.