[alsa-devel] ALSA calling pcm_pointer excessively?

Clemens Ladisch clemens at ladisch.de
Thu May 10 19:05:56 CEST 2012


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.


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 avail, avail_wait_max;
 		snd_pcm_uframes_t cont;
+
+		if (busy_loops < 5)
+			avail_wait_max = 0;
+		else
+			avail_wait_max = min(runtime->control->avail_min, size);
 		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
 			snd_pcm_update_hw_ptr(substream);
 		avail = snd_pcm_playback_avail(runtime);
-		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 {
+			busy_loops++;
 		}
 		frames = size > avail ? avail : size;
 		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;


More information about the Alsa-devel mailing list