[alsa-devel] Measuring Device Throughput - MMAP vs. RW
Hi, Gathering data for USB async gadget feedback ( https://mailman.alsa-project.org/pipermail/alsa-devel/2019-August/154819.htm... ) requires measuring average data rate to/from a device. For testing I added measuring/averaging code to methods snd_pcm_hw_writei, snd_pcm_hw_readi, and snd_pcm_hw_mmap_commit in https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm_hw.c . In all cases I take the parameter "size" of all the three methods as the number of samples written/read.
RW: The averaging works very well for R/W access (hw:X) for playback and capture, I get same values on the same device (playback/capture timed by one clock).
MMAP: When mmap is used (e.g. plughw:X + sample format conversion), I get very stable results for MMAP playback on all soundcards I have tested. But for capture I get identical results to playback for one soundcard (PCI Envy24), while the averaged rate calculated from "size" in snd_pcm_hw_mmap_commit fluctuates for capture on Intel HDA.
The averaging is simply summing "size" in every call of the method and dividing by passed nanosecs every approx 10 seconds:
Working OK (Infrasonic Quartet, and all soundcards for read/write mode): Playback MMAP Time: 19440.900391, averaged samplerate: 48000.511829 MMAP Time: 19451.140625, averaged samplerate: 48000.360218 MMAP Time: 19461.380859, averaged samplerate: 48000.176846 MMAP Time: 19471.619141, averaged samplerate: 48000.664570 MMAP Time: 19481.861328, averaged samplerate: 48000.199970 MMAP Time: 19492.101562, averaged samplerate: 48000.589854 MMAP Time: 19502.341797, averaged samplerate: 48000.288977 MMAP Time: 19512.580078, averaged samplerate: 48000.516104 MMAP Time: 19522.820312, averaged samplerate: 48000.225282
Capture: MMAP Time: 19454.578125, averaged samplerate: 48000.430766 MMAP Time: 19464.818359, averaged samplerate: 48000.397611 MMAP Time: 19475.056641, averaged samplerate: 48000.400049 MMAP Time: 19485.296875, averaged samplerate: 48000.293275 MMAP Time: 19495.539062, averaged samplerate: 48000.549048 MMAP Time: 19505.779297, averaged samplerate: 48000.445214 MMAP Time: 19516.017578, averaged samplerate: 48000.417299 MMAP Time: 19526.257812, averaged samplerate: 48000.376264 MMAP Time: 19536.498047, averaged samplerate: 48000.422957 MMAP Time: 19546.738281, averaged samplerate: 48000.538619 MMAP Time: 19556.976562, averaged samplerate: 48000.241647 MMAP Time: 19567.216797, averaged samplerate: 48000.447243
Fluctuating Capture (Intel HDA): Playback - OK: MMAP Time: 19574.498047, averaged samplerate: 47998.971874 MMAP Time: 19584.568359, averaged samplerate: 47998.871734 MMAP Time: 19594.636719, averaged samplerate: 47998.929850 MMAP Time: 19604.707031, averaged samplerate: 47998.972555 MMAP Time: 19614.775391, averaged samplerate: 47998.925531 MMAP Time: 19624.845703, averaged samplerate: 47998.893351 MMAP Time: 19634.916016, averaged samplerate: 47998.949489 MMAP Time: 19644.986328, averaged samplerate: 47998.593678 MMAP Time: 19655.056641, averaged samplerate: 47999.230857 MMAP Time: 19665.125000, averaged samplerate: 47998.777034 MMAP Time: 19675.195312, averaged samplerate: 47999.177460 MMAP Time: 19685.263672, averaged samplerate: 47998.798503
Capture - fluctuating, clearly some samples are not counted: MMAP Time: 19539.853516, averaged samplerate: 47191.039837 MMAP Time: 19549.923828, averaged samplerate: 46369.921890 MMAP Time: 19559.994141, averaged samplerate: 47998.831508 MMAP Time: 19570.148438, averaged samplerate: 47190.998307 MMAP Time: 19580.302734, averaged samplerate: 47191.275432 MMAP Time: 19590.373047, averaged samplerate: 47998.894343 MMAP Time: 19600.443359, averaged samplerate: 47998.906779 MMAP Time: 19610.511719, averaged samplerate: 47999.174771 MMAP Time: 19620.582031, averaged samplerate: 47998.747971 MMAP Time: 19630.650391, averaged samplerate: 47998.881964 MMAP Time: 19640.722656, averaged samplerate: 47998.999974 MMAP Time: 19650.791016, averaged samplerate: 47998.769240
I suspect the size parameter of snd_pcm_hw_mmap_commit is not the actual amount of samples read during the MMAP capture. Please how to calculate the number of samples read from the variables available in that method?
Thanks a lot.
Pavel.
On Sun, Sep 8, 2019 at 5:23 PM Pavel Hofman pavhofman@gmail.com wrote:
Hi, Gathering data for USB async gadget feedback ( https://mailman.alsa-project.org/pipermail/alsa-devel/2019-August/154819.htm... ) requires measuring average data rate to/from a device. For testing I added measuring/averaging code to methods snd_pcm_hw_writei, snd_pcm_hw_readi, and snd_pcm_hw_mmap_commit in https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm_hw.c . In all cases I take the parameter "size" of all the three methods as the number of samples written/read.
MMAP: When mmap is used (e.g. plughw:X + sample format conversion), I get very stable results for MMAP playback on all soundcards I have tested. But for capture I get identical results to playback for one soundcard (PCI Envy24), while the averaged rate calculated from "size" in snd_pcm_hw_mmap_commit fluctuates for capture on Intel HDA.
I suspect the size parameter of snd_pcm_hw_mmap_commit is not the actual amount of samples read during the MMAP capture. Please how to calculate the number of samples read from the variables available in that method?
The mmap fluctuations seem to be fixed by using increases in hardware pointer pcm->hw.ptr values instead of frames variable. Please do these values wrap up or do they grow to max long? Still contiguous after 10 minutes of running.
I see the hw.ptr gets zeroed at XRUN. If I do not check for xruns ( snd_pcm_state(snd_pcm_t *pcm)?), can I just monitor continuity of hw.ptr and restart the averaging if the new hw.ptr is lower than the previous one, or are there any quirks to watch out?
Thanks a lot,
Pavel.
On Mon, 09 Sep 2019 18:30:14 +0200, Pavel Hofman wrote:
On Sun, Sep 8, 2019 at 5:23 PM Pavel Hofman pavhofman@gmail.com wrote:
Hi, Gathering data for USB async gadget feedback ( https://mailman.alsa-project.org/pipermail/alsa-devel/2019-August/154819.htm... ) requires measuring average data rate to/from a device. For testing I added measuring/averaging code to methods snd_pcm_hw_writei, snd_pcm_hw_readi, and snd_pcm_hw_mmap_commit in https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm_hw.c . In all cases I take the parameter "size" of all the three methods as the number of samples written/read.
MMAP: When mmap is used (e.g. plughw:X + sample format conversion), I get very stable results for MMAP playback on all soundcards I have tested. But for capture I get identical results to playback for one soundcard (PCI Envy24), while the averaged rate calculated from "size" in snd_pcm_hw_mmap_commit fluctuates for capture on Intel HDA.
I suspect the size parameter of snd_pcm_hw_mmap_commit is not the actual amount of samples read during the MMAP capture. Please how to calculate the number of samples read from the variables available in that method?
The mmap fluctuations seem to be fixed by using increases in hardware pointer pcm->hw.ptr values instead of frames variable. Please do these values wrap up or do they grow to max long? Still contiguous after 10 minutes of running.
Could you elaborate the requirement? The description isn't clear to me.
I see the hw.ptr gets zeroed at XRUN. If I do not check for xruns ( snd_pcm_state(snd_pcm_t *pcm)?), can I just monitor continuity of hw.ptr and restart the averaging if the new hw.ptr is lower than the previous one, or are there any quirks to watch out?
You should be able to skip XRUN check by changing the stop_threshold. Setting it to the boundary size essentially means skipping XRUN checks.
In anyway, I put Pierre to Cc, as he's done some works in the past for the accurate position reporting on HD-audio and USB-audio devices. He can give a better hint in this regard.
thanks,
Takashi
On Mon, Sep 9, 2019 at 7:44 PM Takashi Iwai tiwai@suse.de wrote:
The mmap fluctuations seem to be fixed by using increases in hardware pointer pcm->hw.ptr values instead of frames variable. Please do these values wrap up or do they grow to max long? Still contiguous after 10 minutes of running.
Could you elaborate the requirement? The description isn't clear to me.
I need to slave EP OUT of asynchronous USB-audio gadget (i.e. device) to another (output) soundcard in the system so that adaptive resampling in the chain "USB gadget -> processing -> output soundcard" is avoided. For that I need to measure average throughput to/from alsa hw:X devices, to gather data for the feedback endpoint implemented by the gadget driver. I do not have any control over configuration of the devices, the feedback must run independently of the rest of the chain, of the applications used.
In snd_pcm_hw_mmap_commit I subtract the advancement of pcm->hw.ptr from value approx. 10 seconds ago, divided by passed nanosecs measured by clock_gettime(CLOCK_MONOTONIC). For that I need the pcm->hw.ptr either to be monotonic, or I just reset the averaging if a non-monotony is detected (hw pointer in previous (n-1) call of snd_pcm_hw_mmap_commit was higher than current value).
For better precision, would it make sense to update the pcm->hw.ptr with snd_pcm_avail call in that method? It may not be even possible in that method due to some locking, I really do not know. But my precision requirements are not very strict since I can average over long time (minutes) for the feedback (the clock difference is usually very small).
You should be able to skip XRUN check by changing the stop_threshold. Setting it to the boundary size essentially means skipping XRUN checks.
Actually if xruns could be detected by discontinuity of the hw pointer, I would not need any other method.
In anyway, I put Pierre to Cc, as he's done some works in the past for the accurate position reporting on HD-audio and USB-audio devices. He can give a better hint in this regard.
Thanks a lot, I very much appreciate your help. I do not know these low-level alsa details. But I will gladly learn.
Pavel.
On Mon, 09 Sep 2019 21:31:49 +0200, Pavel Hofman wrote:
On Mon, Sep 9, 2019 at 7:44 PM Takashi Iwai tiwai@suse.de wrote:
> The mmap fluctuations seem to be fixed by using increases in hardware > pointer pcm->hw.ptr values instead of frames variable. Please do these > values wrap up or do they grow to max long? Still contiguous after 10 > minutes of running. Could you elaborate the requirement? The description isn't clear to me.
I need to slave EP OUT of asynchronous USB-audio gadget (i.e. device) to another (output) soundcard in the system so that adaptive resampling in the chain "USB gadget -> processing -> output soundcard" is avoided. For that I need to measure average throughput to/from alsa hw:X devices, to gather data for the feedback endpoint implemented by the gadget driver. I do not have any control over configuration of the devices, the feedback must run independently of the rest of the chain, of the applications used.
In snd_pcm_hw_mmap_commit I subtract the advancement of pcm->hw.ptr from value approx. 10 seconds ago, divided by passed nanosecs measured by clock_gettime (CLOCK_MONOTONIC). For that I need the pcm->hw.ptr either to be monotonic, or I just reset the averaging if a non-monotony is detected (hw pointer in previous (n-1) call of snd_pcm_hw_mmap_commit was higher than current value).
For better precision, would it make sense to update the pcm->hw.ptr with snd_pcm_avail call in that method? It may not be even possible in that method due to some locking, I really do not know. But my precision requirements are not very strict since I can average over long time (minutes) for the feedback (the clock difference is usually very small).
The value read from snd_pcm_status() should give the accurate pair of the position and the timestamp. You need to check the delay count as well, which compensates the in-flight samples.
Takashi
You should be able to skip XRUN check by changing the stop_threshold. Setting it to the boundary size essentially means skipping XRUN checks.
Actually if xruns could be detected by discontinuity of the hw pointer, I would not need any other method.
In anyway, I put Pierre to Cc, as he's done some works in the past for the accurate position reporting on HD-audio and USB-audio devices. He can give a better hint in this regard.
Thanks a lot, I very much appreciate your help. I do not know these low-level alsa details. But I will gladly learn.
Pavel.
On Tue, Sep 10, 2019 at 9:18 AM Takashi Iwai tiwai@suse.de wrote:
The value read from snd_pcm_status() should give the accurate pair of the position and the timestamp.
Thanks. IIUC, if I call snd_pcm_status() in that mmap_commit method, get data between e.g. 10 seconds, and divide the increase of status._ptr https://github.com/michaelwu/alsa-lib/blob/afb2fbd0e554e42e51325c3197a176ea9... by increase of status.tstamp, I should get the the most precise available soundcard rate estimate referenced to system time.
You need to check the delay count as well, which compensates the in-flight samples.
I need just the rate at which the soundcard consumes/produces samples, I do not care about time at which the sound is being produced. I do not know exact meaning of the delay field. Is it involved in this calculation? Please is there any exact detailed description of the status fields?
Thanks.
Pavel.
divide the increase of status._ptr https://github.com/michaelwu/alsa-lib/blob/afb2fbd0e554e42e51325c3197a176ea9...
Of course meant the hw_ptr https://github.com/michaelwu/alsa-lib/blob/afb2fbd0e554e42e51325c3197a176ea9... , sorry
On Tue, Sep 10, 2019 at 9:48 AM Pavel Hofman pavhofman@gmail.com wrote:
Thanks. IIUC, if I call snd_pcm_status() in that mmap_commit method, get data between e.g. 10 seconds, and divide the increase of status._ptr https://github.com/michaelwu/alsa-lib/blob/afb2fbd0e554e42e51325c3197a176ea9... by increase of status.tstamp, I should get the the most precise available soundcard rate estimate referenced to system time.
Upon hard-coding params->tstamp_mode = SND_PCM_TSTAMP_ENABLE in snd_pcm_hw_sw_params, the snd_pcm_hw_status method started returning hw_ptr and tstamp. The variance of the rate calculated by these values is perfectly acceptable for my purpose, I will use this method. 10 sec averages of the previously "jittery" mmap arecord:
STATUS MMAP: time: 6679.12, card = 1, device = 0, averaged samplerate: 191995.485933 STATUS MMAP: time: 6689.14, card = 1, device = 0, averaged samplerate: 191995.833616 STATUS MMAP: time: 6699.17, card = 1, device = 0, averaged samplerate: 191995.589371 STATUS MMAP: time: 6709.20, card = 1, device = 0, averaged samplerate: 191995.647669 STATUS MMAP: time: 6719.22, card = 1, device = 0, averaged samplerate: 191995.740024 STATUS MMAP: time: 6729.25, card = 1, device = 0, averaged samplerate: 191995.709675 STATUS MMAP: time: 6739.28, card = 1, device = 0, averaged samplerate: 191995.588850 STATUS MMAP: time: 6749.30, card = 1, device = 0, averaged samplerate: 191995.706994 STATUS MMAP: time: 6759.33, card = 1, device = 0, averaged samplerate: 191995.641393 STATUS MMAP: time: 6769.36, card = 1, device = 0, averaged samplerate: 191995.530104 STATUS MMAP: time: 6779.38, card = 1, device = 0, averaged samplerate: 191995.764419
Do you think there is any chance a code generating the average throughput into some file identified with card/device IDs, all of that enabled by some environment variable, would be acceptable into upstream pcm_hw.c? It will be a key part of the working async usb gadget. The current version https://github.com/torvalds/linux/blob/master/drivers/usb/gadget/function/f_... does not comply with USB-audio v. 2 specs due to the missing async feedback endpoint, and works only for the adaptive mode (requires resampling).
Thanks,
Pavel.
Thanks.
Pavel.
participants (2)
-
Pavel Hofman
-
Takashi Iwai