Skip to content

Commit

Permalink
dp_queue: change buf calculation size and cosmetic changes
Browse files Browse the repository at this point in the history
buf calculation size has been changed to be always 2xmax(IBS,OBS)
to allow free read/write in various data chunk sizes
and execution periods (of course in/out data rates must be same)

example:
  Consumer reads 3bytes each 3 cycles (IBS = 3)
  producer writes 5bytes every 5 cycles (OBS = 5)
 *    - cycle0 produce 3 bytes (buf occupation = 3)
 *    - cycle3 produce 3 bytes (buf occupation = 6)
 *    - cycle5 consume 5 bytes (buf occupation = 1)
 *    - cycle6 produce 3 bytes (buf occupation = 4)
 *    - cycle9 produce 3 bytes (buf occupation = 7)
 *    - cycle10 consume 5 bytes (buf occupation = 2)
 *    - cycle12 produce 3 bytes (buf occupation = 5)
 *    - cycle15 (producer goes first) produce 3 bytes (buf occupation = 8)
     	 	consume 5 bytes (buf occupation = 3)
 at this point the situation is identical as in cycle 0

 ===> max buf occupation = 8

even in case of IBS=OBS and equal periods of
consumer/producer the buffer must be 2*MAX(IBS,OBS)
as we do not know who goes first - consumer or producer,
especially when both are located on separate cores and
EDF scheduling is used

example:
  Consumer reads 5 bytes every cycle (IBS = 5)
  producer writes 5 bytes every cycle (OBS = 5)
 *    - cycle0 consumer goes first - must wait (buf occupation = 0)
 *		producer produce 5 bytes (buf occupation = 5)
 *    - cycle1 producer goes first - produce 5 bytes (buf occupation = 10)
 *		consumer consumes 5 bytes (buf occupation = 5)

===> max buf occupation = 10

Signed-off-by: Marcin Szkudlinski <[email protected]>
  • Loading branch information
marcinszkudlinski committed Sep 15, 2023
1 parent a0c48e5 commit 3cc9d82
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 17 deletions.
21 changes: 9 additions & 12 deletions src/audio/dp_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ static inline void dp_queue_writeback_shared(struct dp_queue *dp_queue,
}

static inline
uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, uint32_t offset)
uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, size_t offset)
{
/* check if offset is not in "double area"
* lines below do a quicker version of offset %= dp_queue->data_buffer_size;
Expand All @@ -84,7 +84,7 @@ uint8_t __sparse_cache *dp_queue_get_pointer(struct dp_queue *dp_queue, uint32_t
}

static inline
uint32_t dp_queue_inc_offset(struct dp_queue *dp_queue, uint32_t offset, uint32_t inc)
size_t dp_queue_inc_offset(struct dp_queue *dp_queue, size_t offset, size_t inc)
{
assert(inc <= dp_queue->data_buffer_size);
offset += inc;
Expand Down Expand Up @@ -161,20 +161,20 @@ static int dp_queue_get_data(struct sof_source *source, size_t req_size,
void const **data_ptr, void const **buffer_start, size_t *buffer_size)
{
struct dp_queue *dp_queue = dp_queue_from_source(source);
__sparse_cache void *_data_ptr;
__sparse_cache void *data_ptr_c;

CORE_CHECK_STRUCT(dp_queue);
if (req_size > dp_queue_get_data_available(source))
return -ENODATA;

_data_ptr = dp_queue_get_pointer(dp_queue, dp_queue->_read_offset);
data_ptr_c = dp_queue_get_pointer(dp_queue, dp_queue->_read_offset);

/* clean cache in provided data range */
dp_queue_invalidate_shared(dp_queue, _data_ptr, req_size);
dp_queue_invalidate_shared(dp_queue, data_ptr_c, req_size);

*buffer_start = (__sparse_force void *)dp_queue->_data_buffer;
*buffer_size = dp_queue->data_buffer_size;
*data_ptr = (__sparse_force void *)_data_ptr;
*data_ptr = (__sparse_force void *)data_ptr_c;

return 0;
}
Expand Down Expand Up @@ -272,14 +272,11 @@ struct dp_queue *dp_queue_create(size_t ibs, size_t obs, uint32_t flags)
sink_set_obs(&dp_queue->_sink_api, obs);
source_set_ibs(&dp_queue->_source_api, ibs);

uint32_t max_ibs_obs = MAX(ibs, obs);
uint32_t min_ibs_obs = MIN(ibs, obs);
size_t max_ibs_obs = MAX(ibs, obs);
size_t min_ibs_obs = MIN(ibs, obs);

/* calculate required buffer size */
if (max_ibs_obs % min_ibs_obs == 0)
dp_queue->data_buffer_size = 2 * max_ibs_obs;
else
dp_queue->data_buffer_size = 3 * max_ibs_obs;
dp_queue->data_buffer_size = 2 * max_ibs_obs;

/* allocate data buffer - always in cached memory alias */
dp_queue->data_buffer_size = ALIGN_UP(dp_queue->data_buffer_size, PLATFORM_DCACHE_ALIGN);
Expand Down
37 changes: 32 additions & 5 deletions src/include/sof/audio/dp_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,36 @@
* 1) incoming and outgoing data rate MUST be the same
* 2) Both data consumer and data producer declare max chunk sizes they want to use (IBS/OBS)
*
* required Buffer size:
* - 2*MAX(IBS,OBS) if the larger of IBS/OBS is multiplication of smaller
* - 3*MAX(IBS,OBS) otherwise
* required Buffer size is 2*MAX(IBS,OBS) to allow free read/write in various data chunk sizes
* and execution periods (of course in/out data rates must be same)
* example:
* Consumer reads 3bytes each 3 cycles (IBS = 3)
* producer writes 5bytes every 5 cycles (OBS = 5)
* - cycle0 produce 3 bytes (buf occupation = 3)
* - cycle3 produce 3 bytes (buf occupation = 6)
* - cycle5 consume 5 bytes (buf occupation = 1)
* - cycle6 produce 3 bytes (buf occupation = 4)
* - cycle9 produce 3 bytes (buf occupation = 7)
* - cycle10 consume 5 bytes (buf occupation = 2)
* - cycle12 produce 3 bytes (buf occupation = 5)
* - cycle15 (producer goes first) produce 3 bytes (buf occupation = 8)
* consume 5 bytes (buf occupation = 3)
* at this point the situation is identical as in cycle 0
*
* ===> max buf occupation = 8
*
* even in case of IBS=OBS and equal periods of consumer/producer the buffer must be 2*MAX(IBS,OBS)
* as we do not know who goes first - consumer or producer, especially when both are located on
* separate cores and EDF scheduling is used
*
* Consumer reads 5 bytes every cycle (IBS = 5)
* producer writes 5 bytes every cycle (OBS = 5)
* - cycle0 consumer goes first - must wait (buf occupation = 0)
* producer produce 5 bytes (buf occupation = 5)
* - cycle1 producer goes first - produce 5 bytes (buf occupation = 10)
* consumer consumes 5 bytes (buf occupation = 5)
* ===> max buf occupation = 10
*
*
* The queue may work in 2 modes
* 1) local mode
Expand Down Expand Up @@ -91,8 +118,8 @@ struct dp_queue {
uint32_t _flags; /* DP_QUEUE_MODE_* */

uint8_t __sparse_cache *_data_buffer;
uint32_t _write_offset; /* private: to be modified by data producer using API */
uint32_t _read_offset; /* private: to be modified by data consumer using API */
size_t _write_offset; /* private: to be modified by data producer using API */
size_t _read_offset; /* private: to be modified by data consumer using API */

bool _hw_params_configured;
};
Expand Down

0 comments on commit 3cc9d82

Please sign in to comment.