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

Dp shadow as a part of comp_buffer / audio_stream #9106

Merged

Conversation

marcinszkudlinski
Copy link
Contributor

@marcinszkudlinski marcinszkudlinski commented May 7, 2024

This is a follow up to #9063 and a bugfix

The PR is connecting shadow dp_queue tightly with comp_buffer/audio_stream.

  1. it is more natural way, after changes comp_buffer is exposing either its own sink/src API or one provided by dp_queue
  2. race prevention. In internal tests there was a race condition found during frequent binding/unbinding DP to a running pipeline
  3. less code in heavy module_adapter

@marcinszkudlinski marcinszkudlinski added dp_scheduler bug Something isn't working as expected labels May 7, 2024
src/audio/audio_stream.c Outdated Show resolved Hide resolved
src/audio/audio_stream.c Outdated Show resolved Hide resolved
src/include/sof/audio/buffer.h Outdated Show resolved Hide resolved
src/audio/module_adapter/module_adapter.c Outdated Show resolved Hide resolved
src/ipc/ipc4/helper.c Outdated Show resolved Hide resolved
src/ipc/ipc4/helper.c Outdated Show resolved Hide resolved
as agreed some time ago, parts of structures
that should not be modified or accessed directly
("private") should be marked with _ prefix
thesofproject#8100

Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
@marcinszkudlinski marcinszkudlinski changed the title Dp shadow part of stream Dp shadow as a part of comp_buffer / audio_stream May 8, 2024
@marcinszkudlinski marcinszkudlinski marked this pull request as ready for review May 8, 2024 08:45
@marcinszkudlinski
Copy link
Contributor Author

I generally don't agree with "superfluous parentheses", Code "obviously correct" is always better than "correct".
And all ( ) make reading easier, don't matter at all for the compiler
anyway, removed because checkpatch was yelling


return audio_stream_get_free_bytes(audio_stream);
}

static int audio_stream_get_buffer(struct sof_sink *sink, size_t req_size,
void **data_ptr, void **buffer_start, size_t *buffer_size)
{
struct audio_stream *audio_stream = container_of(sink, struct audio_stream, sink_api);
struct audio_stream *audio_stream = container_of(sink, struct audio_stream, _sink_api);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you could take this 1 step further in the future by having a static inline accessor API that wraps container_of()

src/audio/buffer.c Show resolved Hide resolved
@marcinszkudlinski
Copy link
Contributor Author

Internal CI failed, checking...

Connection between LL and DP component is implemented bu using
double buffering - between comp_buffer and DP component there's
additional "shadow" dp_queue

Currently shadow buffers are created in module adapter in "prepare"
handler and freed in "reset" handler. It may lead to races when there
are bind/unbind operation between a components in separate pipelienes,
especially when one of the pipelines is already running

The commit makes shadow dp_queue to be a part of comp_buffer. When
shadow is created, it replaces source or sink interface of audio_stream
allowing the module connected to it using all properties of dp_queue,
like lockless cross-core connection.

Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
Instead of creating dp_queue in module adapter, use shadow
buffering provided by comp_bufer

It simplifies the code and makes it more race-resistant

Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
Dp queues are no longer kept as a list of objects,
remove unused list maintenance code and data

Signed-off-by: Marcin Szkudlinski <marcin.szkudlinski@intel.com>
@marcinszkudlinski
Copy link
Contributor Author

Fixed, there was a crash if a bind module wasn't using a module adapter.

Copy link
Collaborator

@lyakh lyakh 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 nit-picking, only if you do end up making another revision. Feel free to ignore otherwise

*/
data_src = &buffer->stream._source_api;
data_dst = dp_queue_get_sink(buffer->stream.dp_queue_source);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line

size_t to_copy = MIN(MIN(data_available, free_size), limit);

err = source_to_sink_copy(data_src, data_dst, true, to_copy);
return err;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return source_to_sink_copy(data_src, data_dst, true, to_copy); and remove err

return &audio_stream->_source_api;
}
struct sof_source *
audio_stream_get_source(struct audio_stream *audio_stream);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one line should do, same below

@@ -159,6 +159,8 @@ struct dp_queue *dp_queue_create(size_t min_available, size_t min_free_space, ui
static inline
void dp_queue_free(struct dp_queue *dp_queue)
{
if (!dp_queue)
return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in principle it's probably good, since this makes the function compatible with free(), rfree(), etc., but just wondering - can this actually happen? Do we ever have a chance of calling it with NULL?

Copy link
Contributor Author

@marcinszkudlinski marcinszkudlinski May 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it can, very often when changes from this PR are applied:

#if CONFIG_ZEPHYR_DP_SCHEDULER
	dp_queue_free(buffer->stream.dp_queue_sink);
	dp_queue_free(buffer->stream.dp_queue_source);
#endif /* CONFIG_ZEPHYR_DP_SCHEDULER */

there's no condition if freed pointers are not null, and those will be nulls every time the buffer is not shadowed (so - in most cases). More - there may be only one shadow, so one of those will always be null

@marcinszkudlinski
Copy link
Contributor Author

just some nit-picking, only if you do end up making another revision. Feel free to ignore otherwise

first time in the history there are 100% checks passed, so better don't update ;)

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.

Thanks @marcinszkudlinski for the follow-up. This is clean solution.

@kv2019i kv2019i merged commit 618bdbd into thesofproject:main May 13, 2024
45 checks passed
@marcinszkudlinski marcinszkudlinski deleted the dp_shadow_part_of_stream branch May 13, 2024 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working as expected dp_scheduler
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants