[alsa-devel] ALSA calling pcm_pointer excessively?

Takashi Iwai tiwai at suse.de
Fri May 11 15:31:08 CEST 2012


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 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;
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 


More information about the Alsa-devel mailing list