Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

ranj063
Copy link
Collaborator

@ranj063 ranj063 commented Dec 5, 2023

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.

@ranj063 ranj063 force-pushed the fix/get_base_cfg_extn branch 2 times, most recently from 2ed73f7 to 0a7cd2d Compare December 5, 2023 17:06
@ranj063 ranj063 force-pushed the fix/get_base_cfg_extn branch 2 times, most recently from 589eafe to 6b6c154 Compare December 5, 2023 22:32
@ranj063 ranj063 marked this pull request as ready for review December 6, 2023 02:02
@@ -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);
Copy link
Contributor

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.

src/ipc/ipc4/helper.c Show resolved Hide resolved
src/ipc/ipc4/helper.c Outdated Show resolved Hide resolved
@@ -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;
Copy link
Collaborator

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.

Copy link
Member

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).

Copy link
Collaborator Author

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

src/ipc/ipc4/helper.c Outdated Show resolved Hide resolved
src/ipc/ipc4/helper.c Outdated Show resolved Hide resolved
@marcinszkudlinski
Copy link
Contributor

LGTM

Copy link
Member

@lgirdwood lgirdwood left a 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;
Copy link
Member

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).

src/ipc/ipc4/helper.c Show resolved Hide resolved
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,
Copy link
Member

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 ?

Copy link
Collaborator Author

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

Copy link
Collaborator

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>
@udaymb
Copy link
Contributor

udaymb commented Dec 13, 2023

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;
Copy link
Collaborator

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);

Copy link
Contributor

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

Copy link
Collaborator

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);
Copy link
Collaborator

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);
Copy link
Collaborator

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);
Copy link
Collaborator

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,
Copy link
Collaborator

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?

Copy link
Collaborator

@kv2019i kv2019i left a 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);
Copy link
Collaborator

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);

..?

Copy link
Contributor

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.

Copy link
Member

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));
Copy link
Collaborator

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?

Copy link
Contributor

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) +
Copy link
Collaborator

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;
}
Copy link
Collaborator

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.

Copy link
Contributor

@marcinszkudlinski marcinszkudlinski left a 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

@lgirdwood
Copy link
Member

Changes verified om 007, working very well, please proceed with merging

Thanks @marcinszkudlinski for validating !

@ranj063 fyi, some conflicts.

@andyross
Copy link
Contributor

andyross commented Jan 3, 2024

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!

Copy link
Contributor

@andyross andyross left a 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);
Copy link
Contributor

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.

Copy link
Contributor

@marcinszkudlinski marcinszkudlinski Jan 9, 2024

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

@ranj063
Copy link
Collaborator Author

ranj063 commented Jan 10, 2024

replaced by #8685

@ranj063 ranj063 closed this Jan 10, 2024
@ranj063 ranj063 deleted the fix/get_base_cfg_extn branch January 10, 2024 15:56
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.

9 participants