[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