From 467d69c5bc1533a51e784423c73068fbff844ebc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 22 Apr 2005 16:36:13 +0000 Subject: [PATCH] Fix CPU hog with combination of rate plugin Fix CPU hog with some apps (e.g. artsd) when rate plugin is used together with dmix (or possible hw). --- src/pcm/pcm_direct.c | 6 +-- src/pcm/pcm_dmix.c | 3 ++ src/pcm/pcm_rate.c | 107 ++++++++++++++++++------------------------- 3 files changed, 51 insertions(+), 65 deletions(-) diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 5ec13e73..e49df24c 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -447,7 +447,7 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in events = pfds[0].revents; if (events & POLLIN) { snd_pcm_uframes_t avail; - int empty = 0; + int empty; snd_pcm_avail_update(pcm); if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { events |= POLLOUT; @@ -457,10 +457,10 @@ int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned in avail = snd_pcm_mmap_capture_avail(pcm); } empty = avail < pcm->avail_min; - if (empty) + if (empty) { snd_pcm_direct_clear_timer_queue(dmix); - if (empty) events &= ~(POLLOUT|POLLIN); + } } switch (snd_pcm_state(dmix->spcm)) { case SND_PCM_STATE_XRUN: diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 88cf5d1d..4813b8a2 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -627,6 +627,9 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, /* ok, we commit the changes after the validation of area */ /* it's intended, although the result might be crappy */ snd_pcm_dmix_sync_area(pcm, size); + /* clear timer queue to avoid a bogus return from poll */ + if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min) + snd_pcm_direct_clear_timer_queue(dmix); } return size; } diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index 4c8fb2e0..77f96b04 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -69,6 +69,7 @@ struct _snd_pcm_rate { snd_pcm_generic_t gen; snd_atomic_write_t watom; snd_pcm_uframes_t appl_ptr, hw_ptr; + snd_pcm_uframes_t last_commit_ptr; snd_pcm_uframes_t orig_avail_min; snd_pcm_sw_params_t sw_params; enum rate_type type; @@ -759,6 +760,7 @@ static int snd_pcm_rate_init(snd_pcm_t *pcm) default: assert(0); } + rate->last_commit_ptr = 0; return 0; } @@ -831,7 +833,10 @@ static inline snd_pcm_sframes_t snd_pcm_rate_move_applptr(snd_pcm_t *pcm, snd_pc diff = -((slave->boundary - orig_appl_ptr) + rate->appl_ptr); } if (frames < 0) - return -diff; + diff = -diff; + + rate->last_commit_ptr = rate->appl_ptr - rate->appl_ptr % pcm->period_size; + return diff; } @@ -842,6 +847,9 @@ static inline void snd_pcm_rate_sync_hwptr(snd_pcm_t *pcm) if (pcm->stream != SND_PCM_STREAM_PLAYBACK) return; + /* FIXME: boundary overlap of slave hw_ptr isn't evaluated here! + * e.g. if slave rate is small... + */ rate->hw_ptr = (slave_hw_ptr / rate->gen.slave->period_size) * pcm->period_size + snd_pcm_rate_client_frames(pcm, slave_hw_ptr % rate->gen.slave->period_size); @@ -1168,82 +1176,56 @@ static int snd_pcm_rate_grab_next_period(snd_pcm_t *pcm, snd_pcm_uframes_t hw_of return 1; } -static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm, - snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, - snd_pcm_uframes_t size) +static int snd_pcm_rate_sync_playback_area(snd_pcm_t *pcm, snd_pcm_uframes_t appl_ptr) { snd_pcm_rate_t *rate = pcm->private_data; snd_pcm_t *slave = rate->gen.slave; - snd_pcm_uframes_t appl_offset, xfer; + snd_pcm_uframes_t xfer; snd_pcm_sframes_t slave_size; int err; - if (size == 0) - return 0; - if (pcm->stream == SND_PCM_STREAM_CAPTURE) { - snd_atomic_write_begin(&rate->watom); - snd_pcm_mmap_appl_forward(pcm, size); - snd_atomic_write_end(&rate->watom); - return size; - } slave_size = snd_pcm_avail_update(slave); if (slave_size < 0) return slave_size; - xfer = rate->appl_ptr % pcm->period_size; - appl_offset = (rate->appl_ptr - xfer) % pcm->buffer_size; - xfer = pcm->period_size - xfer; - if (xfer >= size) { - if (xfer == size && (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { - err = snd_pcm_rate_commit_next_period(pcm, appl_offset); - if (err < 0) - return err; - if (err == 0) - return 0; - } - snd_atomic_write_begin(&rate->watom); - snd_pcm_mmap_appl_forward(pcm, size); - snd_atomic_write_end(&rate->watom); - return size; - } else { - if ((snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { - err = snd_pcm_rate_commit_next_period(pcm, appl_offset); - if (err < 0) - return err; - if (err == 0) - return 0; - } - snd_atomic_write_begin(&rate->watom); - snd_pcm_mmap_appl_forward(pcm, xfer); - snd_atomic_write_end(&rate->watom); - appl_offset += pcm->period_size; - appl_offset %= pcm->buffer_size; - size -= xfer; - slave_size -= rate->gen.slave->period_size; - } - while ((snd_pcm_uframes_t)size >= pcm->period_size && + + if (appl_ptr < rate->last_commit_ptr) + xfer = appl_ptr - rate->last_commit_ptr + pcm->boundary; + else + xfer = appl_ptr - rate->last_commit_ptr; + while (xfer >= pcm->period_size && (snd_pcm_uframes_t)slave_size >= rate->gen.slave->period_size) { - err = snd_pcm_rate_commit_next_period(pcm, appl_offset); + err = snd_pcm_rate_commit_next_period(pcm, rate->last_commit_ptr % pcm->buffer_size); if (err == 0) - return xfer; + break; if (err < 0) - return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; - xfer += pcm->period_size; - size -= pcm->period_size; + return err; + xfer -= pcm->period_size; slave_size -= rate->gen.slave->period_size; - appl_offset += pcm->period_size; - appl_offset %= pcm->buffer_size; - snd_atomic_write_begin(&rate->watom); - snd_pcm_mmap_appl_forward(pcm, pcm->period_size); - snd_atomic_write_end(&rate->watom); + rate->last_commit_ptr += pcm->period_size; + if (rate->last_commit_ptr >= pcm->boundary) + rate->last_commit_ptr = 0; } - size %= pcm->period_size; - if (size > 0) { - snd_atomic_write_begin(&rate->watom); - snd_pcm_mmap_appl_forward(pcm, size); - snd_atomic_write_end(&rate->watom); - xfer += size; + return 0; +} + +static snd_pcm_sframes_t snd_pcm_rate_mmap_commit(snd_pcm_t *pcm, + snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, + snd_pcm_uframes_t size) +{ + snd_pcm_rate_t *rate = pcm->private_data; + int err; + + if (size == 0) + return 0; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + err = snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr + size); + if (err < 0) + return err; } - return xfer; + snd_atomic_write_begin(&rate->watom); + snd_pcm_mmap_appl_forward(pcm, size); + snd_atomic_write_end(&rate->watom); + return size; } static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) @@ -1258,6 +1240,7 @@ static snd_pcm_sframes_t snd_pcm_rate_avail_update(snd_pcm_t *pcm) snd_atomic_write_begin(&rate->watom); snd_pcm_rate_sync_hwptr(pcm); snd_atomic_write_end(&rate->watom); + snd_pcm_rate_sync_playback_area(pcm, rate->appl_ptr); return snd_pcm_mmap_avail(pcm); _capture: { snd_pcm_uframes_t xfer, hw_offset, size; -- 2.47.1