[pulseaudio-discuss] Null sink and its monitor cause high CPU usage in headless environment
Tudor Zaharia
tudor at zaharia.ch
Mon Oct 31 18:32:35 UTC 2022
Hello,
<sorry for sending this again; the original message is still awaiting moderation because of the large size caused by rich html format. I can't seem to be able to cancel the moderation anymore>
I'm posting here after reading this thread: https://www.mail-archive.com/pulseaudio-discuss@lists.freedesktop.org/msg21644.html Unfortunately I couldn't find a solution for my case there.
The problem:
I am seeing high CPU usage caused by pulseaudio in a headless environment where the only module that I need is the null sink. Moreover, the high CPU symptom is noticeable even when there is no audio IO performed by the client, i.e. the client app is not reading nor writing anything to/from the null sinks and its monitors.
A. The setup:
1. Pulseaudio:
* client.conf:
default-server = unix:/pa/pulse-socket
autospawn=no
daemon-binary = /bin/true
enable-shm = false
* default.pa:
load-module module-null-sink sink_name=emulator_out sink_properties=device.description=emulator_out format=s16le rate=48000 channels=2 channel_map=front-left,front-right
load-module module-null-sink sink_name=emulator_in sink_properties=device.description=emulator_in format=s16le rate=48000 channels=2 channel_map=front-left,front-right
* daemon.conf:
; daemonize = no
; fail = yes
; allow-module-loading = yes
; allow-exit = yes
; use-pid-file = yes
; system-instance = yes
; local-server-type = user
; enable-shm = yes
; enable-memfd = yes
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
; lock-memory = no
; cpu-limit = no
; high-priority = yes
; nice-level = -11
; realtime-scheduling = yes
; realtime-priority = 5
; exit-idle-time = 20
; scache-idle-time = 20
; dl-search-path = (depends on architecture)
; load-default-script-file = yes
; default-script-file = /etc/pulse/default.pa
; log-target = auto
; log-level = notice
; log-meta = no
; log-time = no
; log-backtrace = 0
; remixing-use-all-sink-channels = yes
; remixing-produce-lfe = no
; remixing-consume-lfe = no
; lfe-crossover-freq = 0
; flat-volumes = no
; rescue-streams = yes
; rlimit-fsize = -1
; rlimit-data = -1
; rlimit-stack = -1
; rlimit-core = -1
; rlimit-as = -1
; rlimit-rss = -1
; rlimit-nproc = -1
; rlimit-nofile = 256
; rlimit-memlock = -1
; rlimit-locks = -1
; rlimit-sigpending = -1
; rlimit-msgqueue = -1
; rlimit-nice = 31
; rlimit-rtprio = 9
; rlimit-rttime = 200000
; default-sample-format = s16le
; default-sample-channels = 2
; default-channel-map = front-left,front-right
; default-fragments = 4
; default-fragment-size-msec = 25
; enable-deferred-volume = yes
deferred-volume-safety-margin-usec = 1
; deferred-volume-extra-delay-usec = 0
; avoid-resampling = true
default-sample-rate = 48000
alternate-sample-rate = 24000
enable-remixing = no
resample-method = trivial
* In order to completely isolate the pulseaudio server, I have made a Docker image based on bitnami/minideb:stretch where I installed pulseaudio. Then I start the container by mapping a volume on the host to enable socket communication between the host and the guest:
$ docker run --name pa --rm --privileged -v /tmp/pa-docker:/pa mypa
2. Start Android Emulator (this is the pulseaudio client that will connect to the above setup server):
$ QEMU_PA_SERVER=unix:/tmp/pa-docker/pulse-socket QEMU_AUDIO_DRV=pa QEMU_PA_SINK=emulator_out QEMU_PA_SOURCE=emulator_in.monitor QEMU_AUDIO_DAC_FIXED_FREQ=48000 QEMU_AUDIO_ADC_FIXED_FREQ=48000 ANDROID_SDK_ROOT=~/Android/Sdk ~/Android/Sdk/emulator/emulator -verbose @Pixel_2_API_29
This runs on the host but connects to the guest through the socket on the mapped volume (QEMU_PA_SERVER).
B. The behavior
The setup above works fine, but pulseaudio uses anywhere between 6% and 15% of the CPU although the emulator is neither outputting any audio, nor reading the virtual microphone. It is basically idle.
$ docker exec -it pa top
Tasks: 2 total, 1 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 3.2 us, 9.8 sy, 0.0 ni, 87.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 65784824 total, 31055920 free, 16851640 used, 17877264 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 47699540 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 9 -11 326868 6896 5892 S 10.3 0.0 0:50.69 pulseaudio
16 root 20 0 43148 3240 2732 R 0.0 0.0 0:00.06 top
Pulseaudio pacmd list output:
$ docker exec -it pa pacmd list
Memory blocks currently allocated: 4, size: 64.1 KiB.
Memory blocks allocated during the whole lifetime: 12667, size: 4.5 MiB.
Memory blocks imported from other processes: 0, size: 0 B.
Memory blocks exported to other processes: 0, size: 0 B.
Total sample cache size: 0 B.
Default sample spec: s16le 2ch 48000Hz
Default channel map: front-left,front-right
Default sink name: emulator_out
Default source name: emulator_out.monitor
Memory blocks of type POOL: 4 allocated/12667 accumulated.
Memory blocks of type POOL_EXTERNAL: 0 allocated/0 accumulated.
Memory blocks of type APPENDED: 0 allocated/0 accumulated.
Memory blocks of type USER: 0 allocated/0 accumulated.
Memory blocks of type FIXED: 0 allocated/0 accumulated.
Memory blocks of type IMPORTED: 0 allocated/0 accumulated.
4 module(s) loaded.
index: 0
name: <module-null-sink>
argument: <sink_name=emulator_out sink_properties=device.description=emulator_out format=s16le rate=48000 channels=2 channel_map=front-left,front-right>
used: 1
load once: no
properties:
module.author = "Lennart Poettering"
module.description = "Clocked NULL sink"
module.version = "10.0"
index: 1
name: <module-null-sink>
argument: <sink_name=emulator_in sink_properties=device.description=emulator_in format=s16le rate=48000 channels=2 channel_map=front-left,front-right>
used: 1
load once: no
properties:
module.author = "Lennart Poettering"
module.description = "Clocked NULL sink"
module.version = "10.0"
index: 2
name: <module-native-protocol-unix>
argument: <auth-anonymous=1 socket=/pa/pulse-socket>
used: -1
load once: no
properties:
module.author = "Lennart Poettering"
module.description = "Native protocol (UNIX sockets)"
module.version = "10.0"
index: 3
name: <module-cli-protocol-unix>
argument: <>
used: -1
load once: no
properties:
module.author = "Lennart Poettering"
module.description = "Command line interface protocol (UNIX sockets)"
module.version = "10.0"
2 sink(s) available.
* index: 0
name: <emulator_out>
driver: <module-null-sink.c>
flags: DECIBEL_VOLUME LATENCY FLAT_VOLUME DYNAMIC_LATENCY
state: RUNNING
suspend cause:
priority: 1000
volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
base volume: 65536 / 100% / 0.00 dB
volume steps: 65537
muted: no
current latency: 0.43 ms
max request: 0 KiB
max rewind: 0 KiB
monitor source: 0
sample spec: s16le 2ch 48000Hz
channel map: front-left,front-right
Stereo
used by: 1
linked by: 1
configured latency: 0.50 ms; range is 0.50 .. 2000.00 ms
module: 0
properties:
device.description = "emulator_out"
device.class = "abstract"
device.icon_name = "audio-card"
index: 1
name: <emulator_in>
driver: <module-null-sink.c>
flags: DECIBEL_VOLUME LATENCY FLAT_VOLUME DYNAMIC_LATENCY
state: IDLE
suspend cause:
priority: 1000
volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
base volume: 65536 / 100% / 0.00 dB
volume steps: 65537
muted: no
current latency: 8.77 ms
max request: 1 KiB
max rewind: 1 KiB
monitor source: 1
sample spec: s16le 2ch 48000Hz
channel map: front-left,front-right
Stereo
used by: 0
linked by: 1
configured latency: 10.00 ms; range is 0.50 .. 2000.00 ms
module: 1
properties:
device.description = "emulator_in"
device.class = "abstract"
device.icon_name = "audio-card"
2 source(s) available.
* index: 0
name: <emulator_out.monitor>
driver: <module-null-sink.c>
flags: DECIBEL_VOLUME LATENCY DYNAMIC_LATENCY
state: IDLE
suspend cause:
priority: 1000
volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
base volume: 65536 / 100% / 0.00 dB
volume steps: 65537
muted: no
current latency: 0.00 ms
max rewind: 0 KiB
sample spec: s16le 2ch 48000Hz
channel map: front-left,front-right
Stereo
used by: 0
linked by: 0
configured latency: 2000.00 ms; range is 0.50 .. 2000.00 ms
monitor_of: 0
module: 0
properties:
device.description = "Monitor of emulator_out"
device.class = "monitor"
device.icon_name = "audio-input-microphone"
index: 1
name: <emulator_in.monitor>
driver: <module-null-sink.c>
flags: DECIBEL_VOLUME LATENCY DYNAMIC_LATENCY
state: IDLE
suspend cause:
priority: 1000
volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
base volume: 65536 / 100% / 0.00 dB
volume steps: 65537
muted: no
current latency: 0.00 ms
max rewind: 1 KiB
sample spec: s16le 2ch 48000Hz
channel map: front-left,front-right
Stereo
used by: 0
linked by: 1
configured latency: 10.00 ms; range is 0.50 .. 2000.00 ms
monitor_of: 1
module: 1
properties:
device.description = "Monitor of emulator_in"
device.class = "monitor"
device.icon_name = "audio-input-microphone"
2 client(s) logged in.
index: 0
driver: <protocol-native.c>
owner module: 2
properties:
application.name = "unix:/tmp/pa-docker/pulse-socket"
native-protocol.peer = "UNIX socket client"
native-protocol.version = "33"
application.process.id = "23931"
application.process.user = "tudor"
application.process.host = "machine"
application.process.binary = "qemu-system-x86_64"
application.language = "C"
window.x11.display = ":1"
application.process.machine_id = "c6ba133539f0416791786992742aa11c"
index: 3
driver: <cli.c>
owner module: 3
properties:
application.name = "UNIX socket client"
0 card(s) available.
1 sink input(s) available.
index: 0
driver: <protocol-native.c>
flags:
state: DRAINED
sink: 0 <emulator_out>
volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
muted: no
current latency: 0.00 ms
requested latency: 0.50 ms
sample spec: s16le 2ch 48000Hz
channel map: front-left,front-right
Stereo
resample method: (null)
module: 2
client: 0 <unix:/tmp/pa-docker/pulse-socket>
properties:
media.name = "qemu"
application.name = "unix:/tmp/pa-docker/pulse-socket"
native-protocol.peer = "UNIX socket client"
native-protocol.version = "33"
application.process.id = "23931"
application.process.user = "tudor"
application.process.host = "machine"
application.process.binary = "qemu-system-x86_64"
application.language = "C"
window.x11.display = ":1"
application.process.machine_id = "c6ba133539f0416791786992742aa11c"
1 source output(s) available.
index: 0
driver: <protocol-native.c>
flags: START_CORKED
state: CORKED
source: 1 <emulator_in.monitor>
volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB
balance 0.00
muted: no
current latency: 0.00 ms
requested latency: 10.00 ms
sample spec: s16le 2ch 48000Hz
channel map: front-left,front-right
Stereo
resample method: (null)
owner module: 2
client: 0 <unix:/tmp/pa-docker/pulse-socket>
properties:
media.name = "qemu"
application.name = "unix:/tmp/pa-docker/pulse-socket"
native-protocol.peer = "UNIX socket client"
native-protocol.version = "33"
application.process.id = "23931"
application.process.user = "tudor"
application.process.host = "machine"
application.process.binary = "qemu-system-x86_64"
application.language = "C"
window.x11.display = ":1"
application.process.machine_id = "c6ba133539f0416791786992742aa11c"
0 cache entrie(s) available.
Other considerations:
In an attempt to try to identify the cause of the problem, I have built pulseaudio from source with valgrind support and run it with the `callgrind` tool. Unfortunately I have reached my limits when trying to correlate that output with the high CPU usage.
Android Emulator is not the only application that I've tried with this setup and seen the same behavior. I used it as an example here because I thought it is easier to understand what is going on.
My system has an i7-9700 CPU with plenty of RAM and running Ubuntu 20.04. And in any case, like I said the emulator is idle concerning audio input/output.
Do you know why I'm seeing this high CPU usage and how I could fix it?
Thanks,
Tudor
More information about the pulseaudio-discuss
mailing list