Tuning Linux on Raspberry Pi for Audio

Tuning Linux on Raspberry Pi for Audio

Introduction

This article attempts to be a compendium of techniques for optimizing Linux on Raspberry Pi hardware when used as an audio source. Of course, not all tweaks are universal; many will not make sense for different hardware versions; some items may be subtlely different depending on the Linux distribution. Unless otherwise noted, these were all done on a Raspberry Pi 2, running DietPi.

Here's my /etc/os-release file for reference:

root@DietPi:~# cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 8 (jessie)"
NAME="Raspbian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

HOWTO

CPU Isolation

Overview:

  • Isolate core 3 from the CPU scheduler
  • Pin mpd to core 3

The Linux kernel can "migrate" processes from one CPU core to another. Typically this happens so quickly that the user doesn't notice. But for those of us who seek to eliminate any possible source of jitter in our audio stream, we must eliminate opportunities for the CPU scheduler to migrate our most critical application, i.e. mpd.

  1. Isolate core 3 from the CPU scheduler. Append " isolcpus=3" to the end of /boot/cmdline.txt (note the space).

  2. Pin mpd to core 3 and assign real-time priority. Here's my /etc/systemd/system/mpd.service file:

    [Unit]
    Description=Music Player Daemon
    After=network.target sound.target
    
    [Service]
    EnvironmentFile=/etc/default/mpd
    ExecStart=/usr/bin/mpd --no-daemon $MPDCONF
    Nice=-15
    LimitNice=-15
    CPUAffinity=3
    
    [Install]
    WantedBy=multi-user.target
    

    Then do something like this:

    # systemctl daemon-reload
    # systemctl disable mpd
    # systemctl enable mpd
    
  3. Verification. Reboot your system ("systemctl reboot"). Check to make sure your CPU isolation is working:

    root@DietPi:~# dmesg | grep isol
    [    0.000000] Kernel command line: bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=720 bcm2708_fb.fbdepth=16 bcm2708_fb.fbswap=1 vc_mem.mem_base=0x3ea00000 vc_mem.mem_size=0x3f000000 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=PARTUUID=ee614650-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait isolcpus=3
    

    If you don't see "isolcpus=3" in there (i.e. the "dmesg | grep isol" command returns nothing), then a mistake has been made.

    Ensure mpd is pinned to core 3:

    root@DietPi:~# taskset -cp $( pidof mpd )
    pid 1720's current affinity list: 3
    

    Check that mpd is running with realtime priority (set to -15 in the example above, anything between -1 and -20 is considered realtime, with -20 being the highest). The easiest way I've found to do this is to check the output of htop, and look for the mpd line:

    mpd       -15  0.0  2.7  0:01.61 /usr/bin/mpd --no-daemon
    

    That -15 in the second column is the "nice" value, which we set to be -15 in the systemd unit file above. So it checks out!

    NOTE: As of this writing, neither CPU pinning nor priority setting seem to work on reboot. But if I manually do a "systemctl restart mpd", then these things work. Not yet sure what's causing this.

CPU Fixed Frequency