Skip to content

Commit 3cd2527

Browse files
serhiy-katsyuba-intellgirdwood
authored andcommitted
kpb: Avoid long seizure of EDF scheduler thread.
The draining task could run for quite a long time (e.g., a few seconds). It is implemented as an EDF scheduler task. While working, it blocks other EDF scheduler tasks: the IPC processing task and the mtrace logging task. The fix replaces the while loop in the draining task with a return SOF_TASK_STATE_RESCHEDULE, so other EDF scheduler tasks can have CPU time. Signed-off-by: Serhiy Katsyuba <serhiy.katsyuba@intel.com>
1 parent b4da02f commit 3cd2527

2 files changed

Lines changed: 84 additions & 56 deletions

File tree

src/audio/kpb.c

Lines changed: 79 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,19 @@ static void devicelist_reset(struct device_list *devlist, bool remove_items);
160160

161161
static uint64_t kpb_task_deadline(void *data)
162162
{
163+
#ifndef __ZEPHYR__
163164
return SOF_TASK_DEADLINE_ALMOST_IDLE;
165+
#else
166+
struct draining_data *dd = (struct draining_data *)data;
167+
uint64_t now;
168+
169+
if (dd->next_copy_time == 0)
170+
return 0; /* run immediately */
171+
172+
now = sof_cycle_get_64();
173+
return dd->next_copy_time > now ?
174+
k_uptime_ticks() + k_cyc_to_ticks_near64(dd->next_copy_time - now) : 0;
175+
#endif
164176
}
165177

166178
#if CONFIG_AMS
@@ -1684,9 +1696,13 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli)
16841696
kpb->draining_task_data.sink = kpb->host_sink;
16851697
kpb->draining_task_data.hb = buff;
16861698
kpb->draining_task_data.drain_req = drain_req;
1699+
kpb->draining_task_data.drained = 0;
16871700
kpb->draining_task_data.sample_width = sample_width;
16881701
kpb->draining_task_data.drain_interval = drain_interval;
1702+
kpb->draining_task_data.period_copy_start = 0;
16891703
kpb->draining_task_data.pb_limit = period_bytes_limit;
1704+
kpb->draining_task_data.period_bytes = 0;
1705+
kpb->draining_task_data.next_copy_time = 0;
16901706
kpb->draining_task_data.dev = dev;
16911707
kpb->draining_task_data.sync_mode_on = kpb->sync_draining_mode;
16921708

@@ -1701,6 +1717,16 @@ static void kpb_init_draining(struct comp_dev *dev, struct kpb_client *cli)
17011717
/* Pause selector copy. */
17021718
comp_buffer_get_sink_component(kpb->sel_sink)->state = COMP_STATE_PAUSED;
17031719

1720+
if (!pm_runtime_is_active(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID))
1721+
pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
1722+
1723+
comp_info(dev, "Scheduling draining task");
1724+
1725+
/* Change KPB internal state to DRAINING */
1726+
kpb_change_state(kpb, KPB_STATE_DRAINING);
1727+
1728+
kpb->draining_task_data.draining_time_start = sof_cycle_get_64();
1729+
17041730
/* Schedule draining task */
17051731
schedule_task(&kpb->draining_task, 0, 0);
17061732
}
@@ -1719,23 +1745,16 @@ static enum task_state kpb_draining_task(void *arg)
17191745
struct draining_data *draining_data = (struct draining_data *)arg;
17201746
struct comp_buffer *sink = draining_data->sink;
17211747
struct history_buffer *buff = draining_data->hb;
1722-
size_t drain_req = draining_data->drain_req;
17231748
size_t sample_width = draining_data->sample_width;
17241749
size_t avail;
17251750
size_t size_to_copy;
1726-
uint32_t drained = 0;
1727-
uint64_t draining_time_start;
17281751
uint64_t draining_time_end;
17291752
uint64_t draining_time_ms;
17301753
uint64_t drain_interval = draining_data->drain_interval;
1731-
uint64_t next_copy_time = 0;
1732-
size_t period_bytes = 0;
17331754
size_t period_bytes_limit = draining_data->pb_limit;
1734-
uint64_t period_copy_start;
17351755
size_t *rt_stream_update = &draining_data->buffered_while_draining;
17361756
struct comp_data *kpb = comp_get_drvdata(draining_data->dev);
17371757
bool sync_mode_on = draining_data->sync_mode_on;
1738-
bool pm_is_active;
17391758

17401759
/*
17411760
* WORKAROUND: The code below accesses KPB sink buffer and calls comp_copy() on
@@ -1748,66 +1767,53 @@ static enum task_state kpb_draining_task(void *arg)
17481767
k_sched_lock();
17491768
#endif
17501769

1751-
comp_cl_info(&comp_kpb, "kpb_draining_task(), start.");
1752-
1753-
pm_is_active = pm_runtime_is_active(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
1754-
1755-
if (!pm_is_active)
1756-
pm_runtime_disable(PM_RUNTIME_DSP, PLATFORM_PRIMARY_CORE_ID);
1757-
1758-
/* Change KPB internal state to DRAINING */
1759-
kpb_change_state(kpb, KPB_STATE_DRAINING);
1770+
comp_cl_dbg(&comp_kpb, "kpb_draining_task()");
17601771

1761-
draining_time_start = sof_cycle_get_64();
1762-
period_copy_start = draining_time_start;
1772+
/* Have we received reset request? */
1773+
if (kpb->state == KPB_STATE_RESETTING) {
1774+
kpb_change_state(kpb, KPB_STATE_RESET_FINISHING);
1775+
kpb_reset(draining_data->dev);
1776+
draining_data->drain_req = 0;
1777+
goto out;
1778+
}
17631779

1764-
while (drain_req > 0) {
1765-
/*
1766-
* Draining task usually runs for quite a lot of time (could be few seconds).
1767-
* LL should not be blocked for such a long time.
1780+
if (draining_data->drain_req > 0) {
1781+
/* Are we ready to drain further or host still need some time
1782+
* to read the data already provided?
17681783
*/
1784+
if (sync_mode_on && draining_data->next_copy_time > sof_cycle_get_64()) {
1785+
/* Restore original EDF thread priority */
17691786
#ifdef __ZEPHYR__
1770-
k_sched_unlock();
1771-
k_yield();
1772-
k_sched_lock();
1787+
k_sched_unlock();
17731788
#endif
1774-
1775-
/* Have we received reset request? */
1776-
if (kpb->state == KPB_STATE_RESETTING) {
1777-
kpb_change_state(kpb, KPB_STATE_RESET_FINISHING);
1778-
kpb_reset(draining_data->dev);
1779-
goto out;
1789+
return SOF_TASK_STATE_RESCHEDULE;
17801790
}
1781-
/* Are we ready to drain further or host still need some time
1782-
* to read the data already provided?
1783-
*/
1784-
if (sync_mode_on &&
1785-
next_copy_time > sof_cycle_get_64()) {
1786-
period_bytes = 0;
1787-
period_copy_start = sof_cycle_get_64();
1788-
continue;
1789-
} else if (next_copy_time == 0) {
1790-
period_copy_start = sof_cycle_get_64();
1791+
1792+
if (draining_data->period_copy_start == 0) {
1793+
/* starting new draining period */
1794+
draining_data->period_copy_start = sof_cycle_get_64();
1795+
draining_data->period_bytes = 0;
17911796
}
17921797

17931798
avail = (uintptr_t)buff->end_addr - (uintptr_t)buff->r_ptr;
17941799
size_to_copy = MIN(avail,
1795-
MIN(drain_req, audio_stream_get_free_bytes(&sink->stream)));
1800+
MIN(draining_data->drain_req,
1801+
audio_stream_get_free_bytes(&sink->stream)));
17961802

17971803
kpb_drain_samples(buff->r_ptr, &sink->stream, size_to_copy,
17981804
sample_width);
17991805

18001806
buff->r_ptr = (char *)buff->r_ptr + (uint32_t)size_to_copy;
1801-
drain_req -= size_to_copy;
1802-
drained += size_to_copy;
1803-
period_bytes += size_to_copy;
1807+
draining_data->drain_req -= size_to_copy;
1808+
draining_data->drained += size_to_copy;
1809+
draining_data->period_bytes += size_to_copy;
18041810
kpb->hd.free += MIN(kpb->hd.buffer_size -
18051811
kpb->hd.free, size_to_copy);
18061812

18071813
/* no data left in the current buffer -- switch to the next buffer */
18081814
if (size_to_copy == avail) {
18091815
buff->r_ptr = buff->start_addr;
1810-
buff = buff->next;
1816+
draining_data->hb = buff->next;
18111817
}
18121818

18131819
if (size_to_copy) {
@@ -1821,20 +1827,25 @@ static enum task_state kpb_draining_task(void *arg)
18211827
comp_copy(comp_buffer_get_sink_component(sink));
18221828
}
18231829

1824-
if (sync_mode_on && period_bytes >= period_bytes_limit)
1825-
next_copy_time = period_copy_start + drain_interval;
1830+
if (sync_mode_on && draining_data->period_bytes >= period_bytes_limit) {
1831+
draining_data->next_copy_time = draining_data->period_copy_start +
1832+
drain_interval;
1833+
draining_data->period_copy_start = 0;
1834+
} else {
1835+
draining_data->next_copy_time = 0;
1836+
}
18261837

1827-
if (drain_req == 0) {
1838+
if (draining_data->drain_req == 0) {
18281839
/* We have finished draining of requested data however
18291840
* while we were draining real time stream could provided
18301841
* new data which needs to be copy to host.
18311842
*/
18321843
comp_cl_info(&comp_kpb, "kpb: update drain_req by %zu",
18331844
*rt_stream_update);
18341845
kpb_lock(kpb);
1835-
drain_req += *rt_stream_update;
1846+
draining_data->drain_req += *rt_stream_update;
18361847
*rt_stream_update = 0;
1837-
if (!drain_req && kpb->state == KPB_STATE_DRAINING) {
1848+
if (!draining_data->drain_req && kpb->state == KPB_STATE_DRAINING) {
18381849
/* Draining is done. Now switch KPB to copy real time
18391850
* stream to client's sink. This state is called
18401851
* "draining on demand"
@@ -1848,6 +1859,17 @@ static enum task_state kpb_draining_task(void *arg)
18481859
}
18491860

18501861
out:
1862+
if (draining_data->drain_req > 0) {
1863+
/* Restore original EDF thread priority */
1864+
#ifdef __ZEPHYR__
1865+
k_sched_unlock();
1866+
#endif
1867+
1868+
/* continue drainig on next task iteration */
1869+
return SOF_TASK_STATE_RESCHEDULE;
1870+
}
1871+
1872+
/* finished drainig */
18511873
draining_time_end = sof_cycle_get_64();
18521874

18531875
/* Reset host-sink copy mode back to its pre-draining value.
@@ -1860,13 +1882,14 @@ static enum task_state kpb_draining_task(void *arg)
18601882
else
18611883
comp_cl_err(&comp_kpb, "Failed to restore host copy mode!");
18621884

1863-
draining_time_ms = k_cyc_to_ms_near64(draining_time_end - draining_time_start);
1885+
draining_time_ms = k_cyc_to_ms_near64(draining_time_end -
1886+
draining_data->draining_time_start);
18641887
if (draining_time_ms <= UINT_MAX)
1865-
comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %u drained in %u ms",
1866-
drained, (unsigned int)draining_time_ms);
1888+
comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %zu drained in %u ms",
1889+
draining_data->drained, (unsigned int)draining_time_ms);
18671890
else
1868-
comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %u drained in > %u ms",
1869-
drained, UINT_MAX);
1891+
comp_cl_info(&comp_kpb, "KPB: kpb_draining_task(), done. %zu drained in > %u ms",
1892+
draining_data->drained, UINT_MAX);
18701893

18711894
/* Restore original EDF thread priority */
18721895
#ifdef __ZEPHYR__

src/include/sof/audio/kpb.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,16 @@ struct draining_data {
146146
struct comp_buffer *sink;
147147
struct history_buffer *hb;
148148
size_t drain_req;
149+
size_t drained;
149150
uint8_t is_draining_active;
150151
size_t sample_width;
151152
size_t buffered_while_draining;
153+
uint64_t draining_time_start;
152154
size_t drain_interval;
155+
uint64_t period_copy_start;
153156
size_t pb_limit; /**< Period bytes limit */
157+
size_t period_bytes;
158+
uint64_t next_copy_time;
154159
struct comp_dev *dev;
155160
bool sync_mode_on;
156161
enum comp_copy_type copy_type;

0 commit comments

Comments
 (0)