All of lore.kernel.org
 help / color / mirror / Atom feed
* ALSA calling pcm_pointer excessively?
@ 2012-05-10 16:06 Russell King - ARM Linux
  2012-05-10 16:29 ` Russell King - ARM Linux
                   ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-10 16:06 UTC (permalink / raw)
  To: alsa-devel, Mark Brown

I'm wondering what is causing ALSA to behave as follows - I have a 64KiB
buffer, which is divided up into 4 16KiB periods.  The log below is from
my soc-dmaengine.c code which supports audio on the Assabet (as we don't
have cyclic DMA support there yet.)

I'm just trying to sort out the DMA engine tx_status residue code, and
am using this as proof that its working.

However, it seems that ALSA for whatever reason likes to hammer away at
the pcm_pointer callback from time to time:

soc_dmaengine_pointer: index 3 stat 1 residue 0018 cookie 3cfe pos 10000 bytes ffe8
soc_dmaengine_pointer: index 3 stat 1 residue 0008 cookie 3cfe pos 10000 bytes fff8
soc_dmaengine_callback: complete
soc_dmaengine_pointer: index 0 stat 1 residue 3ff0 cookie 3cff pos 4000 bytes 0010
soc_dmaengine_submit: submitting index 3 size 4000 cookie 3d02
soc_dmaengine_pointer: index 0 stat 1 residue 3fd0 cookie 3cff pos 4000 bytes 0030
soc_dmaengine_pointer: index 0 stat 1 residue 17b8 cookie 3cff pos 4000 bytes 2848
soc_dmaengine_pointer: index 0 stat 1 residue 1770 cookie 3cff pos 4000 bytes 2890
soc_dmaengine_pointer: index 0 stat 1 residue 1768 cookie 3cff pos 4000 bytes 2898
soc_dmaengine_pointer: index 0 stat 1 residue 1758 cookie 3cff pos 4000 bytes 28a8
soc_dmaengine_pointer: index 0 stat 1 residue 1748 cookie 3cff pos 4000 bytes 28b8
soc_dmaengine_pointer: index 0 stat 1 residue 1740 cookie 3cff pos 4000 bytes 28c0
soc_dmaengine_pointer: index 0 stat 1 residue 1730 cookie 3cff pos 4000 bytes 28d0
soc_dmaengine_pointer: index 0 stat 1 residue 1720 cookie 3cff pos 4000 bytes 28e0
soc_dmaengine_pointer: index 0 stat 1 residue 1718 cookie 3cff pos 4000 bytes 28e8
...
soc_dmaengine_pointer: index 0 stat 1 residue 0018 cookie 3cff pos 4000 bytes 3fe8
soc_dmaengine_pointer: index 0 stat 1 residue 0008 cookie 3cff pos 4000 bytes 3ff8
soc_dmaengine_callback: complete
soc_dmaengine_pointer: index 1 stat 1 residue 3ff0 cookie 3d00 pos 8000 bytes 4010
soc_dmaengine_submit: submitting index 0 size 4000 cookie 3d03
soc_dmaengine_pointer: index 1 stat 1 residue 3fd0 cookie 3d00 pos 8000 bytes 4030
soc_dmaengine_pointer: index 1 stat 1 residue 3b28 cookie 3d00 pos 8000 bytes 44d8
soc_dmaengine_pointer: index 1 stat 1 residue 3b10 cookie 3d00 pos 8000 bytes 44f0
soc_dmaengine_pointer: index 1 stat 1 residue 3b00 cookie 3d00 pos 8000 bytes 4500

'pos' is the end of the current DMA buffer ((index + 1) * period_byte_size)
'residue' is the value returned from tx_status
'bytes' is the value passed into bytes_to_frames() to return from my
pcm_pointer function.

The question is - what would cause ALSA to hammer away at the buffer
like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
seeing around 75% system CPU time, which really isn't good.

The above was captured while aplay was running, with no apparant audio
corruption.

Any ideas?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 16:06 ALSA calling pcm_pointer excessively? Russell King - ARM Linux
@ 2012-05-10 16:29 ` Russell King - ARM Linux
  2012-05-10 17:05   ` Clemens Ladisch
  2012-05-10 16:34 ` Trent Piepho
  2012-05-10 17:00 ` Jassi Brar
  2 siblings, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-10 16:29 UTC (permalink / raw)
  To: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 05:06:01PM +0100, Russell King - ARM Linux wrote:
> I'm wondering what is causing ALSA to behave as follows - I have a 64KiB
> buffer, which is divided up into 4 16KiB periods.  The log below is from
> my soc-dmaengine.c code which supports audio on the Assabet (as we don't
> have cyclic DMA support there yet.)
> 
> I'm just trying to sort out the DMA engine tx_status residue code, and
> am using this as proof that its working.
> 
> However, it seems that ALSA for whatever reason likes to hammer away at
> the pcm_pointer callback from time to time:
> 
> soc_dmaengine_pointer: index 3 stat 1 residue 0018 cookie 3cfe pos 10000 bytes ffe8
> soc_dmaengine_pointer: index 3 stat 1 residue 0008 cookie 3cfe pos 10000 bytes fff8
> soc_dmaengine_callback: complete
> soc_dmaengine_pointer: index 0 stat 1 residue 3ff0 cookie 3cff pos 4000 bytes 0010
> soc_dmaengine_submit: submitting index 3 size 4000 cookie 3d02
> soc_dmaengine_pointer: index 0 stat 1 residue 3fd0 cookie 3cff pos 4000 bytes 0030
> soc_dmaengine_pointer: index 0 stat 1 residue 17b8 cookie 3cff pos 4000 bytes 2848
> soc_dmaengine_pointer: index 0 stat 1 residue 1770 cookie 3cff pos 4000 bytes 2890
> soc_dmaengine_pointer: index 0 stat 1 residue 1768 cookie 3cff pos 4000 bytes 2898
> soc_dmaengine_pointer: index 0 stat 1 residue 1758 cookie 3cff pos 4000 bytes 28a8
> soc_dmaengine_pointer: index 0 stat 1 residue 1748 cookie 3cff pos 4000 bytes 28b8
> soc_dmaengine_pointer: index 0 stat 1 residue 1740 cookie 3cff pos 4000 bytes 28c0
> soc_dmaengine_pointer: index 0 stat 1 residue 1730 cookie 3cff pos 4000 bytes 28d0
> soc_dmaengine_pointer: index 0 stat 1 residue 1720 cookie 3cff pos 4000 bytes 28e0
> soc_dmaengine_pointer: index 0 stat 1 residue 1718 cookie 3cff pos 4000 bytes 28e8
> ...
> soc_dmaengine_pointer: index 0 stat 1 residue 0018 cookie 3cff pos 4000 bytes 3fe8
> soc_dmaengine_pointer: index 0 stat 1 residue 0008 cookie 3cff pos 4000 bytes 3ff8
> soc_dmaengine_callback: complete
> soc_dmaengine_pointer: index 1 stat 1 residue 3ff0 cookie 3d00 pos 8000 bytes 4010
> soc_dmaengine_submit: submitting index 0 size 4000 cookie 3d03
> soc_dmaengine_pointer: index 1 stat 1 residue 3fd0 cookie 3d00 pos 8000 bytes 4030
> soc_dmaengine_pointer: index 1 stat 1 residue 3b28 cookie 3d00 pos 8000 bytes 44d8
> soc_dmaengine_pointer: index 1 stat 1 residue 3b10 cookie 3d00 pos 8000 bytes 44f0
> soc_dmaengine_pointer: index 1 stat 1 residue 3b00 cookie 3d00 pos 8000 bytes 4500
> 
> 'pos' is the end of the current DMA buffer ((index + 1) * period_byte_size)
> 'residue' is the value returned from tx_status
> 'bytes' is the value passed into bytes_to_frames() to return from my
> pcm_pointer function.
> 
> The question is - what would cause ALSA to hammer away at the buffer
> like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
> seeing around 75% system CPU time, which really isn't good.
> 
> The above was captured while aplay was running, with no apparant audio
> corruption.
> 
> Any ideas?

bash-2.05a# cat /proc/asound/card0/pcm0p/sub0/sw_params 
tstamp_mode: NONE
period_step: 1
avail_min: 4096
start_threshold: 16384
stop_threshold: 16384
silence_threshold: 0
silence_size: 0
boundary: 1073741824

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.  That implies that I have to purposely reduce the granularity
that I report the current DMA position which isn't a sane thing to do.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 16:06 ALSA calling pcm_pointer excessively? Russell King - ARM Linux
  2012-05-10 16:29 ` Russell King - ARM Linux
@ 2012-05-10 16:34 ` Trent Piepho
  2012-05-10 16:42   ` Russell King - ARM Linux
  2012-05-10 17:00 ` Jassi Brar
  2 siblings, 1 reply; 21+ messages in thread
From: Trent Piepho @ 2012-05-10 16:34 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 12:06 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> The question is - what would cause ALSA to hammer away at the buffer
> like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
> seeing around 75% system CPU time, which really isn't good.
>
> The above was captured while aplay was running, with no apparant audio
> corruption.

I've had this happen, but not with aplay.  I sent something to the
list a few months ago about it.

The problem is triggered when writing to ALSA with writes that are
unequal to the period size and using sampling rate conversion in an
ALSA plugin.  Code in alsa-lib will get into a loop calling poll() on
the pcm fd, and ALSA's poll() calls the pointer method to figure out
if there is enough buffer space free to return or if it poll() should
block.

That is all fine, but rather than write more data when poll() returns,
alsa-lib decides to call poll() again.  So it's stuck in a tight loop
calling poll() which isn't blocking.  Eventually there will be enough
space in the buffer that alsa will write some data and poll() will
block.

Basically poll() will return when there is at least X bytes available
in the buffer.  X = avail_min.  ALSA will only write more data when
there is at least Y bytes free in the buffer.  The bug is X < Y.  This
only happens when sample rate conversion and only if the app doesn't
call snd_pcm_writei() with full periods.  While the available space in
the buffer is > X and < Y, ALSA is in a tight loop calling poll()
which calls the PCM's pointer method.  If X == Y, then this would
never happen.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 16:34 ` Trent Piepho
@ 2012-05-10 16:42   ` Russell King - ARM Linux
  0 siblings, 0 replies; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-10 16:42 UTC (permalink / raw)
  To: Trent Piepho; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 12:34:19PM -0400, Trent Piepho wrote:
> On Thu, May 10, 2012 at 12:06 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > The question is - what would cause ALSA to hammer away at the buffer
> > like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
> > seeing around 75% system CPU time, which really isn't good.
> >
> > The above was captured while aplay was running, with no apparant audio
> > corruption.
> 
> I've had this happen, but not with aplay.  I sent something to the
> list a few months ago about it.
> 
> The problem is triggered when writing to ALSA with writes that are
> unequal to the period size and using sampling rate conversion in an
> ALSA plugin.

I'm not using any plugins, and there's definitely no sample rate
conversion going on.  I'm basically piping a raw S16_LE stereo file
into "aplay -c2 -r48000 -fS16_LE" and that's the only format the
hardware supports:

Playing raw data 'stdin' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Plug PCM: Hardware PCM card 0 'Assabet' device 0 subdevice 0

Its setup is:
stream       : PLAYBACK
access       : RW_INTERLEAVED
format       : S16_LE
subformat    : STD
channels     : 2
rate         : 48000
exact rate   : 48000 (48000/1)
msbits       : 16
buffer_size  : 16384
period_size  : 4096
period_time  : 85333
tick_time    : 0
tstamp_mode  : NONE
period_step  : 1
sleep_min    : 0
avail_min    : 4096
xfer_align   : 4096
start_threshold  : 16384
stop_threshold   : 16384
silence_threshold: 0
silence_size : 0
boundary     : 1073741824

Note that this is not using mmap, as ARM is not cache coherent.

Interestingly, if I use -M to aplay to force it to use mmap, things get
a _lot_ better and I only get a lot fewer calls to the pcm_pointer()
method per period.  I've included in this log the DMA engine output
(which shows the raw DMA address - the buffer is 64K aligned) and where
the pcm_pointer() method was called from.

tx_status: addr:c0f14010
soc_dmaengine_pointer: index 1 stat 1 residue 3ff0 cookie 1792 pos 8000 bytes 4010
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_submit: submitting index 0 size 4000 cookie 1795
tx_status: addr:c0f14060
soc_dmaengine_pointer: index 1 stat 1 residue 3fa0 cookie 1792 pos 8000 bytes 4060
snd_pcm_update_hw_ptr0+0x30/0x24c
tx_status: addr:c0f14130
soc_dmaengine_pointer: index 1 stat 1 residue 3ed0 cookie 1792 pos 8000 bytes 4130
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_callback: complete
tx_status: addr:c0f18010
soc_dmaengine_pointer: index 2 stat 1 residue 3ff0 cookie 1793 pos c000 bytes 8010
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_submit: submitting index 1 size 4000 cookie 1796
tx_status: addr:c0f18060
soc_dmaengine_pointer: index 2 stat 1 residue 3fa0 cookie 1793 pos c000 bytes 8060
snd_pcm_update_hw_ptr0+0x30/0x24c
tx_status: addr:c0f18150
soc_dmaengine_pointer: index 2 stat 1 residue 3eb0 cookie 1793 pos c000 bytes 8150
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_callback: complete
tx_status: addr:c0f1c010
soc_dmaengine_pointer: index 3 stat 1 residue 3ff0 cookie 1794 pos 10000 bytes c010
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_submit: submitting index 2 size 4000 cookie 1797
tx_status: addr:c0f1c060
soc_dmaengine_pointer: index 3 stat 1 residue 3fa0 cookie 1794 pos 10000 bytes c060
snd_pcm_update_hw_ptr0+0x30/0x24c
tx_status: addr:c0f1c130
soc_dmaengine_pointer: index 3 stat 1 residue 3ed0 cookie 1794 pos 10000 bytes c130
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_callback: complete
tx_status: addr:c0f10068
soc_dmaengine_pointer: index 0 stat 1 residue 3f98 cookie 1795 pos 4000 bytes 0068
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_submit: submitting index 3 size 4000 cookie 1798
tx_status: addr:c0f100f0
soc_dmaengine_pointer: index 0 stat 1 residue 3f10 cookie 1795 pos 4000 bytes 00f0
snd_pcm_update_hw_ptr0+0x30/0x24c
tx_status: addr:c0f101c8
soc_dmaengine_pointer: index 0 stat 1 residue 3e38 cookie 1795 pos 4000 bytes 01c8
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_callback: complete
tx_status: addr:c0f14010
soc_dmaengine_pointer: index 1 stat 1 residue 3ff0 cookie 1796 pos 8000 bytes 4010
snd_pcm_update_hw_ptr0+0x30/0x24c
soc_dmaengine_submit: submitting index 0 size 4000 cookie 1799
tx_status: addr:c0f14060
soc_dmaengine_pointer: index 1 stat 1 residue 3fa0 cookie 1796 pos 8000 bytes 4060
snd_pcm_update_hw_ptr0+0x30/0x24c
tx_status: addr:c0f14130
soc_dmaengine_pointer: index 1 stat 1 residue 3ed0 cookie 1796 pos 8000 bytes 4130
snd_pcm_update_hw_ptr0+0x30/0x24c

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 16:06 ALSA calling pcm_pointer excessively? Russell King - ARM Linux
  2012-05-10 16:29 ` Russell King - ARM Linux
  2012-05-10 16:34 ` Trent Piepho
@ 2012-05-10 17:00 ` Jassi Brar
  2012-05-10 17:04   ` Trent Piepho
  2012-05-10 17:04   ` Russell King - ARM Linux
  2 siblings, 2 replies; 21+ messages in thread
From: Jassi Brar @ 2012-05-10 17:00 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 9:36 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
>
> The question is - what would cause ALSA to hammer away at the buffer
> like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
> seeing around 75% system CPU time, which really isn't good.
>
> The above was captured while aplay was running, with no apparant audio
> corruption.
>
> Any ideas?
>
I believe it's because the pcm's write tries to keep the data in ring
buffer filled
upto brim and keeps polling the dma position till it keeps reporting
some progress.

I think if you could avoid that behavior if your driver carefully
keeps negligible
progresses to itself and report only considerable ones. Basically, core would
stop polling and wait on queue when two pointer calls return same value i.e no
progress.
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:00 ` Jassi Brar
@ 2012-05-10 17:04   ` Trent Piepho
  2012-05-10 17:04   ` Russell King - ARM Linux
  1 sibling, 0 replies; 21+ messages in thread
From: Trent Piepho @ 2012-05-10 17:04 UTC (permalink / raw)
  To: Jassi Brar; +Cc: alsa-devel, Mark Brown, Russell King - ARM Linux

On Thu, May 10, 2012 at 1:00 PM, Jassi Brar <jassisinghbrar@gmail.com> wrote:
> On Thu, May 10, 2012 at 9:36 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
>>
>> The question is - what would cause ALSA to hammer away at the buffer
>> like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
>> seeing around 75% system CPU time, which really isn't good.
>>
>> The above was captured while aplay was running, with no apparant audio
>> corruption.
>>
>> Any ideas?
>>
> I believe it's because the pcm's write tries to keep the data in ring
> buffer filled
> upto brim and keeps polling the dma position till it keeps reporting
> some progress.

Seems like it should sleep until avail_min frames are empty?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:00 ` Jassi Brar
  2012-05-10 17:04   ` Trent Piepho
@ 2012-05-10 17:04   ` Russell King - ARM Linux
  2012-05-10 17:18     ` Jassi Brar
  1 sibling, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-10 17:04 UTC (permalink / raw)
  To: Jassi Brar; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 10:30:44PM +0530, Jassi Brar wrote:
> On Thu, May 10, 2012 at 9:36 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> >
> > The question is - what would cause ALSA to hammer away at the buffer
> > like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
> > seeing around 75% system CPU time, which really isn't good.
> >
> > The above was captured while aplay was running, with no apparant audio
> > corruption.
> >
> > Any ideas?
> >
> I believe it's because the pcm's write tries to keep the data in ring
> buffer filled
> upto brim and keeps polling the dma position till it keeps reporting
> some progress.
> 
> I think if you could avoid that behavior if your driver carefully
> keeps negligible
> progresses to itself and report only considerable ones. Basically, core would
> stop polling and wait on queue when two pointer calls return same value i.e no
> progress.

You _could_ but why should drivers work around silly behaviour in the
ALSA core?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 16:29 ` Russell King - ARM Linux
@ 2012-05-10 17:05   ` Clemens Ladisch
  2012-05-10 17:13     ` Clemens Ladisch
                       ` (2 more replies)
  0 siblings, 3 replies; 21+ messages in thread
From: Clemens Ladisch @ 2012-05-10 17:05 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown

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;

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:05   ` Clemens Ladisch
@ 2012-05-10 17:13     ` Clemens Ladisch
  2012-05-10 18:18       ` Russell King - ARM Linux
  2012-05-10 17:47     ` Jassi Brar
  2012-05-11 13:31     ` Takashi Iwai
  2 siblings, 1 reply; 21+ messages in thread
From: Clemens Ladisch @ 2012-05-10 17:13 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown

I wrote:
> This (untested) patch tries to avoid too many busy looping.

Oops, off-by-one error (avail == avail_min should not wait).


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_nowait_min;
 		snd_pcm_uframes_t cont;
+
+		if (busy_loops < 5)
+			avail_nowait_min = 1;
+		else
+			avail_nowait_min = 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_nowait_min) {
 			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;

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:04   ` Russell King - ARM Linux
@ 2012-05-10 17:18     ` Jassi Brar
  0 siblings, 0 replies; 21+ messages in thread
From: Jassi Brar @ 2012-05-10 17:18 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 10:34 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Thu, May 10, 2012 at 10:30:44PM +0530, Jassi Brar wrote:
>> On Thu, May 10, 2012 at 9:36 PM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>> >
>> > The question is - what would cause ALSA to hammer away at the buffer
>> > like that - checking it every 16 or 8 DMA bytes transferred?  I'm also
>> > seeing around 75% system CPU time, which really isn't good.
>> >
>> > The above was captured while aplay was running, with no apparant audio
>> > corruption.
>> >
>> > Any ideas?
>> >
>> I believe it's because the pcm's write tries to keep the data in ring
>> buffer filled
>> upto brim and keeps polling the dma position till it keeps reporting
>> some progress.
>>
>> I think if you could avoid that behavior if your driver carefully
>> keeps negligible
>> progresses to itself and report only considerable ones. Basically, core would
>> stop polling and wait on queue when two pointer calls return same value i.e no
>> progress.
>
> You _could_ but why should drivers work around silly behaviour in the
> ALSA core?
>
One reason I could think of is to save us from under-runs for as long
as possible.
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:05   ` Clemens Ladisch
  2012-05-10 17:13     ` Clemens Ladisch
@ 2012-05-10 17:47     ` Jassi Brar
  2012-05-11 13:31     ` Takashi Iwai
  2 siblings, 0 replies; 21+ messages in thread
From: Jassi Brar @ 2012-05-10 17:47 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, Mark Brown, Russell King - ARM Linux

On Thu, May 10, 2012 at 10:35 PM, Clemens Ladisch <clemens@ladisch.de> wrote:
>
> --- 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;
>
Hi Clemens,

If we really want to change the behavior of play, wouldn't we want to do that
for capture(snd_pcm_lib_read1) as well ?
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:13     ` Clemens Ladisch
@ 2012-05-10 18:18       ` Russell King - ARM Linux
  2012-05-10 18:43         ` Clemens Ladisch
  0 siblings, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-10 18:18 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 07:13:59PM +0200, Clemens Ladisch wrote:
> I wrote:
> > This (untested) patch tries to avoid too many busy looping.
> 
> Oops, off-by-one error (avail == avail_min should not wait).

This is better - it now sits around 2-14% system time.  I guess the
five loops is rather arbitary?

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 18:18       ` Russell King - ARM Linux
@ 2012-05-10 18:43         ` Clemens Ladisch
  2012-05-10 23:09           ` Russell King - ARM Linux
  0 siblings, 1 reply; 21+ messages in thread
From: Clemens Ladisch @ 2012-05-10 18:43 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown

Russell King - ARM Linux wrote:
> On Thu, May 10, 2012 at 07:13:59PM +0200, Clemens Ladisch wrote:
>> I wrote:
>>> This (untested) patch tries to avoid too many busy looping.
>>
>> Oops, off-by-one error (avail == avail_min should not wait).
>
> This is better - it now sits around 2-14% system time.  I guess the
> five loops is rather arbitary?

Yes.  The minimum loop limit is two (to handle wraparound at the end of
the buffer); more than that probably does not actually make sense.

Jassi Brar wrote:
> If we really want to change the behavior of play, wouldn't we want to do that
> for capture(snd_pcm_lib_read1) as well ?

Indeed.  And we'd want to reuse the twake calculation.


Regards,
Clemens

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 18:43         ` Clemens Ladisch
@ 2012-05-10 23:09           ` Russell King - ARM Linux
  0 siblings, 0 replies; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-10 23:09 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, Mark Brown

On Thu, May 10, 2012 at 08:43:40PM +0200, Clemens Ladisch wrote:
> Russell King - ARM Linux wrote:
> > On Thu, May 10, 2012 at 07:13:59PM +0200, Clemens Ladisch wrote:
> >> I wrote:
> >>> This (untested) patch tries to avoid too many busy looping.
> >>
> >> Oops, off-by-one error (avail == avail_min should not wait).
> >
> > This is better - it now sits around 2-14% system time.  I guess the
> > five loops is rather arbitary?
> 
> Yes.  The minimum loop limit is two (to handle wraparound at the end of
> the buffer); more than that probably does not actually make sense.

Ok, I'll test with two there tomorrow.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-10 17:05   ` Clemens Ladisch
  2012-05-10 17:13     ` Clemens Ladisch
  2012-05-10 17:47     ` Jassi Brar
@ 2012-05-11 13:31     ` Takashi Iwai
  2012-05-11 14:02       ` Russell King - ARM Linux
  2 siblings, 1 reply; 21+ messages in thread
From: Takashi Iwai @ 2012-05-11 13:31 UTC (permalink / raw)
  To: Clemens Ladisch; +Cc: alsa-devel, Mark Brown, Russell King - ARM Linux

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@alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-11 13:31     ` Takashi Iwai
@ 2012-05-11 14:02       ` Russell King - ARM Linux
  2012-05-11 14:17         ` Takashi Iwai
  0 siblings, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-11 14:02 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Mark Brown, Clemens Ladisch

On Fri, May 11, 2012 at 03:31:08PM +0200, Takashi Iwai wrote:
> 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.

It's exaclty as I explained.  Lets take avail_min = 4096, as it is in my
case.

In snd_pcm_lib_write1(), we loop - here's the simplified version:

        while (size > 0) {
                if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
                        snd_pcm_update_hw_ptr(substream);
                avail = snd_pcm_playback_avail(runtime);
                if (!avail) {
			/* Sleep until avail >= avail_min */
		}
		/* Transfer up to max(avail,size) bytes to buffer */
	}

The problem is this.  On entry to the loop, say, we calculate that we
can transfer 4096 bytes into the buffer, and we do that.  While we're
transferring those bytes, the hardware DMA position has advanced.

So, the second time around the loop, avail will be non-zero - let's
say that the DMA position has advanced 32 bytes.  So avail will be
32 bytes, and we transfer 32 bytes.  Again, while transferring those
bytes, the DMA position has advanced, but not as far.  Let's say 8
bytes.

So, we repeat the loop, and again, we find avail is non-zero.  We
omit sleeping, instead, dropping through to transfer 8 bytes.

Meanwhile, the DMA position has advanced another 8 bytes.

Repeat, endlessly, wasting lots of CPU cycles transferring very small
sets of sample data to the buffer.

That happens because of the requirement for the above code to sleep is
that there has been _no_ advancement of the DMA position while copying
data to the buffer.  Unfortunately, that's not always a realistic
expectation, especially if you have a high data rate.

At no point in the above scenario does avail_min come into it, until
we're lucky enough that we copy data into the buffer without the DMA
position changing.  At that point, we're then allowed to sleep.  The
decision to sleep is based purely upon there being _zero_ bytes of
available buffer space.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-11 14:02       ` Russell King - ARM Linux
@ 2012-05-11 14:17         ` Takashi Iwai
  2012-05-11 15:04           ` Russell King - ARM Linux
  0 siblings, 1 reply; 21+ messages in thread
From: Takashi Iwai @ 2012-05-11 14:17 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown, Clemens Ladisch

At Fri, 11 May 2012 15:02:37 +0100,
Russell King - ARM Linux wrote:
> 
> On Fri, May 11, 2012 at 03:31:08PM +0200, Takashi Iwai wrote:
> > 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.
> 
> It's exaclty as I explained.  Lets take avail_min = 4096, as it is in my
> case.
> 
> In snd_pcm_lib_write1(), we loop - here's the simplified version:
> 
>         while (size > 0) {
>                 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
>                         snd_pcm_update_hw_ptr(substream);
>                 avail = snd_pcm_playback_avail(runtime);
>                 if (!avail) {
> 			/* Sleep until avail >= avail_min */
> 		}
> 		/* Transfer up to max(avail,size) bytes to buffer */
> 	}
> 
> The problem is this.  On entry to the loop, say, we calculate that we
> can transfer 4096 bytes into the buffer, and we do that.  While we're
> transferring those bytes, the hardware DMA position has advanced.
> 
> So, the second time around the loop, avail will be non-zero - let's
> say that the DMA position has advanced 32 bytes.  So avail will be
> 32 bytes, and we transfer 32 bytes.  Again, while transferring those
> bytes, the DMA position has advanced, but not as far.  Let's say 8
> bytes.
> 
> So, we repeat the loop, and again, we find avail is non-zero.  We
> omit sleeping, instead, dropping through to transfer 8 bytes.
> 
> Meanwhile, the DMA position has advanced another 8 bytes.
> 
> Repeat, endlessly, wasting lots of CPU cycles transferring very small
> sets of sample data to the buffer.
> 
> That happens because of the requirement for the above code to sleep is
> that there has been _no_ advancement of the DMA position while copying
> data to the buffer.  Unfortunately, that's not always a realistic
> expectation, especially if you have a high data rate.
> 
> At no point in the above scenario does avail_min come into it, until
> we're lucky enough that we copy data into the buffer without the DMA
> position changing.  At that point, we're then allowed to sleep.  The
> decision to sleep is based purely upon there being _zero_ bytes of
> available buffer space.

Ah, thanks for clearing, now I got it.

Actually the call of snd_pcm_update_hw_ptr() at the loop entry doesn't
have to be done at each time, supposing the process of the loop
(without wait_for_avail()) is fast enough.

How about the patch below?


Takashi

---
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 4d18941..faedb14 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1894,6 +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;
+	snd_pcm_uframes_t avail;
 	int err = 0;
 
 	if (size == 0)
@@ -1917,13 +1918,12 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 	}
 
 	runtime->twake = runtime->control->avail_min ? : 1;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+		snd_pcm_update_hw_ptr(substream);
+	avail = snd_pcm_playback_avail(runtime);
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t cont;
-		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			snd_pcm_update_hw_ptr(substream);
-		avail = snd_pcm_playback_avail(runtime);
 		if (!avail) {
 			if (nonblock) {
 				err = -EAGAIN;
@@ -1971,6 +1971,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
 		offset += frames;
 		size -= frames;
 		xfer += frames;
+		avail -= frames;
 		if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
 		    snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
 			err = snd_pcm_start(substream);
@@ -2111,6 +2112,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	snd_pcm_uframes_t xfer = 0;
 	snd_pcm_uframes_t offset = 0;
+	snd_pcm_uframes_t avail;
 	int err = 0;
 
 	if (size == 0)
@@ -2141,13 +2143,12 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 	}
 
 	runtime->twake = runtime->control->avail_min ? : 1;
+	if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+		snd_pcm_update_hw_ptr(substream);
+	avail = snd_pcm_capture_avail(runtime);
 	while (size > 0) {
 		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
-		snd_pcm_uframes_t avail;
 		snd_pcm_uframes_t cont;
-		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
-			snd_pcm_update_hw_ptr(substream);
-		avail = snd_pcm_capture_avail(runtime);
 		if (!avail) {
 			if (runtime->status->state ==
 			    SNDRV_PCM_STATE_DRAINING) {
@@ -2202,6 +2203,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
 		offset += frames;
 		size -= frames;
 		xfer += frames;
+		avail -= frames;
 	}
  _end_unlock:
 	runtime->twake = 0;

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-11 14:17         ` Takashi Iwai
@ 2012-05-11 15:04           ` Russell King - ARM Linux
  2012-05-11 16:31             ` Takashi Iwai
  0 siblings, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-11 15:04 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Mark Brown, Clemens Ladisch

On Fri, May 11, 2012 at 04:17:50PM +0200, Takashi Iwai wrote:
> Actually the call of snd_pcm_update_hw_ptr() at the loop entry doesn't
> have to be done at each time, supposing the process of the loop
> (without wait_for_avail()) is fast enough.
> 
> How about the patch below?

This too seems to work fine on playback.  Thanks.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-11 15:04           ` Russell King - ARM Linux
@ 2012-05-11 16:31             ` Takashi Iwai
  2012-05-11 16:38               ` Russell King - ARM Linux
  0 siblings, 1 reply; 21+ messages in thread
From: Takashi Iwai @ 2012-05-11 16:31 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown, Clemens Ladisch

At Fri, 11 May 2012 16:04:50 +0100,
Russell King - ARM Linux wrote:
> 
> On Fri, May 11, 2012 at 04:17:50PM +0200, Takashi Iwai wrote:
> > Actually the call of snd_pcm_update_hw_ptr() at the loop entry doesn't
> > have to be done at each time, supposing the process of the loop
> > (without wait_for_avail()) is fast enough.
> > 
> > How about the patch below?
> 
> This too seems to work fine on playback.  Thanks.

Good to hear.  I queued it for linux-next now.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-11 16:31             ` Takashi Iwai
@ 2012-05-11 16:38               ` Russell King - ARM Linux
  2012-05-11 17:07                 ` Takashi Iwai
  0 siblings, 1 reply; 21+ messages in thread
From: Russell King - ARM Linux @ 2012-05-11 16:38 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Mark Brown, Clemens Ladisch

On Fri, May 11, 2012 at 06:31:53PM +0200, Takashi Iwai wrote:
> At Fri, 11 May 2012 16:04:50 +0100,
> Russell King - ARM Linux wrote:
> > 
> > On Fri, May 11, 2012 at 04:17:50PM +0200, Takashi Iwai wrote:
> > > Actually the call of snd_pcm_update_hw_ptr() at the loop entry doesn't
> > > have to be done at each time, supposing the process of the loop
> > > (without wait_for_avail()) is fast enough.
> > > 
> > > How about the patch below?
> > 
> > This too seems to work fine on playback.  Thanks.
> 
> Good to hear.  I queued it for linux-next now.

Please ensure that it gets:

Tested-by: Russell King <rmk+kernel@arm.linux.org.uk>

and not with this address.  Thanks.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: ALSA calling pcm_pointer excessively?
  2012-05-11 16:38               ` Russell King - ARM Linux
@ 2012-05-11 17:07                 ` Takashi Iwai
  0 siblings, 0 replies; 21+ messages in thread
From: Takashi Iwai @ 2012-05-11 17:07 UTC (permalink / raw)
  To: Russell King - ARM Linux; +Cc: alsa-devel, Mark Brown, Clemens Ladisch

At Fri, 11 May 2012 17:38:44 +0100,
Russell King - ARM Linux wrote:
> 
> On Fri, May 11, 2012 at 06:31:53PM +0200, Takashi Iwai wrote:
> > At Fri, 11 May 2012 16:04:50 +0100,
> > Russell King - ARM Linux wrote:
> > > 
> > > On Fri, May 11, 2012 at 04:17:50PM +0200, Takashi Iwai wrote:
> > > > Actually the call of snd_pcm_update_hw_ptr() at the loop entry doesn't
> > > > have to be done at each time, supposing the process of the loop
> > > > (without wait_for_avail()) is fast enough.
> > > > 
> > > > How about the patch below?
> > > 
> > > This too seems to work fine on playback.  Thanks.
> > 
> > Good to hear.  I queued it for linux-next now.
> 
> Please ensure that it gets:
> 
> Tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
> 
> and not with this address.  Thanks.

I didn't add your tested-by tag since it wasn't explicitly given, but
now added with the right address.  Thanks.


Takashi

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2012-05-11 17:07 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-10 16:06 ALSA calling pcm_pointer excessively? Russell King - ARM Linux
2012-05-10 16:29 ` Russell King - ARM Linux
2012-05-10 17:05   ` Clemens Ladisch
2012-05-10 17:13     ` Clemens Ladisch
2012-05-10 18:18       ` Russell King - ARM Linux
2012-05-10 18:43         ` Clemens Ladisch
2012-05-10 23:09           ` Russell King - ARM Linux
2012-05-10 17:47     ` Jassi Brar
2012-05-11 13:31     ` Takashi Iwai
2012-05-11 14:02       ` Russell King - ARM Linux
2012-05-11 14:17         ` Takashi Iwai
2012-05-11 15:04           ` Russell King - ARM Linux
2012-05-11 16:31             ` Takashi Iwai
2012-05-11 16:38               ` Russell King - ARM Linux
2012-05-11 17:07                 ` Takashi Iwai
2012-05-10 16:34 ` Trent Piepho
2012-05-10 16:42   ` Russell King - ARM Linux
2012-05-10 17:00 ` Jassi Brar
2012-05-10 17:04   ` Trent Piepho
2012-05-10 17:04   ` Russell King - ARM Linux
2012-05-10 17:18     ` Jassi Brar

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.