At Thu, 10 May 2012 19:05:56 +0200, Clemens Ladisch wrote:
Russell King - ARM Linux wrote:
I think what's happening is that snd_pcm_lib_write1() is looping, and each time it updates the hardware position, it finds that it can transfer 8 or 16 bytes to the buffer. Once it's transferred that, it re-updates the hardware position which has now advanced by another 8 or 16 bytes. Repeat, and you find that snd_pcm_lib_write1() spends a lot of time inefficiently copying the buffer.
It seems that it will only sleep if the hardware pointer stops making progress.
I'd guess that most existing hardware is fast enough to transfer samples and has a big enough granularity (typically 32 byte bursts for PCI) that the pointer doesn't change in consecutive loop iterations.
This (untested) patch tries to avoid too many busy looping.
Hmm... I still can't follow why such a busy loop happens when avail_min > 1. If avail_min = 1, a busy loop can't be avoided. But if avail_min is set (typically equal with period_size), runtime->twake is either the rest size or the period size, and wait_for_avail() should wait until that sufficiently.
Russell, which avail_min value is used in your test case? (I thought aplay uses avail_min = period_size as default, but just to be sure.)
thanks,
Takashi
Regards, Clemens
--- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -1894,7 +1894,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0;
- int err = 0;
int busy_loops = 0, err = 0;
if (size == 0) return 0;
@@ -1919,12 +1919,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, runtime->twake = runtime->control->avail_min ? : 1; while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t avail;
snd_pcm_uframes_t cont;snd_pcm_uframes_t avail, avail_wait_max;
if (busy_loops < 5)
avail_wait_max = 0;
else
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) snd_pcm_update_hw_ptr(substream); avail = snd_pcm_playback_avail(runtime);avail_wait_max = min(runtime->control->avail_min, size);
if (!avail) {
if (avail <= avail_wait_max) { if (nonblock) { err = -EAGAIN; goto _end_unlock;
@@ -1934,6 +1939,9 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, err = wait_for_avail(substream, &avail); if (err < 0) goto _end_unlock;
busy_loops = 0;
} else {
} frames = size > avail ? avail : size; cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;busy_loops++;
Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel