aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-05-11 11:50:49 -0400
committerTakashi Iwai <tiwai@suse.de>2012-05-11 13:05:12 -0400
commit0910c216f78d1097a4ac6dcc83b38809dea94160 (patch)
tree906b3beea4baea0c31062ff2ebc1714fedc48a62 /sound/core
parentb2522f9262539fc328b4b9344f8a2f7ef2cb18d5 (diff)
ALSA: pcm - Optimize the call of snd_pcm_update_hw_ptr() in read/write loop
In the PCM read/write loop, the driver calls snd_pcm_update_hw_ptr() at each time at the beginning of the loop. Russell King reported that this hogs CPU significantly. The current code assumes that the pointer callback is very fast and cheap, also not too much fine grained. It's not true in all cases. When the pointer advances short samples while the read/write copy has been performed, the driver updates the hw_ptr and gets avail > 0 again. Then it tries to read/write these small chunks. This repeats until the avail really gets to zero. For avoiding this situation, a simple workaround is to call snd_pcm_update_hw_ptr() only once at starting the loop, assuming that the read/write copy is performed fast enough. If the available count becomes short, it goes to snd_pcm_wait_avail() anyway, and this processes right. Tested-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/pcm_lib.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 4d18941178e6..faedb1481b24 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,
1894 struct snd_pcm_runtime *runtime = substream->runtime; 1894 struct snd_pcm_runtime *runtime = substream->runtime;
1895 snd_pcm_uframes_t xfer = 0; 1895 snd_pcm_uframes_t xfer = 0;
1896 snd_pcm_uframes_t offset = 0; 1896 snd_pcm_uframes_t offset = 0;
1897 snd_pcm_uframes_t avail;
1897 int err = 0; 1898 int err = 0;
1898 1899
1899 if (size == 0) 1900 if (size == 0)
@@ -1917,13 +1918,12 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1917 } 1918 }
1918 1919
1919 runtime->twake = runtime->control->avail_min ? : 1; 1920 runtime->twake = runtime->control->avail_min ? : 1;
1921 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
1922 snd_pcm_update_hw_ptr(substream);
1923 avail = snd_pcm_playback_avail(runtime);
1920 while (size > 0) { 1924 while (size > 0) {
1921 snd_pcm_uframes_t frames, appl_ptr, appl_ofs; 1925 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1922 snd_pcm_uframes_t avail;
1923 snd_pcm_uframes_t cont; 1926 snd_pcm_uframes_t cont;
1924 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
1925 snd_pcm_update_hw_ptr(substream);
1926 avail = snd_pcm_playback_avail(runtime);
1927 if (!avail) { 1927 if (!avail) {
1928 if (nonblock) { 1928 if (nonblock) {
1929 err = -EAGAIN; 1929 err = -EAGAIN;
@@ -1971,6 +1971,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
1971 offset += frames; 1971 offset += frames;
1972 size -= frames; 1972 size -= frames;
1973 xfer += frames; 1973 xfer += frames;
1974 avail -= frames;
1974 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && 1975 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
1975 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { 1976 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
1976 err = snd_pcm_start(substream); 1977 err = snd_pcm_start(substream);
@@ -2111,6 +2112,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2111 struct snd_pcm_runtime *runtime = substream->runtime; 2112 struct snd_pcm_runtime *runtime = substream->runtime;
2112 snd_pcm_uframes_t xfer = 0; 2113 snd_pcm_uframes_t xfer = 0;
2113 snd_pcm_uframes_t offset = 0; 2114 snd_pcm_uframes_t offset = 0;
2115 snd_pcm_uframes_t avail;
2114 int err = 0; 2116 int err = 0;
2115 2117
2116 if (size == 0) 2118 if (size == 0)
@@ -2141,13 +2143,12 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2141 } 2143 }
2142 2144
2143 runtime->twake = runtime->control->avail_min ? : 1; 2145 runtime->twake = runtime->control->avail_min ? : 1;
2146 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2147 snd_pcm_update_hw_ptr(substream);
2148 avail = snd_pcm_capture_avail(runtime);
2144 while (size > 0) { 2149 while (size > 0) {
2145 snd_pcm_uframes_t frames, appl_ptr, appl_ofs; 2150 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2146 snd_pcm_uframes_t avail;
2147 snd_pcm_uframes_t cont; 2151 snd_pcm_uframes_t cont;
2148 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2149 snd_pcm_update_hw_ptr(substream);
2150 avail = snd_pcm_capture_avail(runtime);
2151 if (!avail) { 2152 if (!avail) {
2152 if (runtime->status->state == 2153 if (runtime->status->state ==
2153 SNDRV_PCM_STATE_DRAINING) { 2154 SNDRV_PCM_STATE_DRAINING) {
@@ -2202,6 +2203,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
2202 offset += frames; 2203 offset += frames;
2203 size -= frames; 2204 size -= frames;
2204 xfer += frames; 2205 xfer += frames;
2206 avail -= frames;
2205 } 2207 }
2206 _end_unlock: 2208 _end_unlock:
2207 runtime->twake = 0; 2209 runtime->twake = 0;