Running real-time audio on a consumer-grade ARM SoC is an exercise in controlled resource contention. The Rockchip RK3288’s four Cortex-A17 cores are shared between MIXXX’s audio engine, the Mali-T76x GPU rendering the skin, the ILI2117 touchscreen driver, Qt’s thread pool, GLib’s mainloop, ALSA DMA, and a dozen other subsystems. A PREEMPT_RT kernel alone is not enough to prevent any of these from briefly pre-empting an audio callback — explicit CPU shielding is required to guarantee stable latency.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/gueritta/primemixxx/llms.txt
Use this file to discover all available pages before exploring further.
Why CPU Shielding Is Necessary
The Prime Go runs kernel6.1.111-inmusic-2024-09-19-rt41 with PREEMPT_RT, which makes the kernel fully preemptible so that high-priority threads are never blocked inside a kernel critical section. However, PREEMPT_RT only controls when threads can be interrupted — it does not prevent unrelated threads from competing for the same CPU cores. Without shielding:
- Mali GPU rendering threads fire on all four cores simultaneously
- Qt’s evdev touchscreen thread wakes on every finger movement
- GLib’s
gmain/gdbusthreads poll at unpredictable intervals - The Qt thread pool spawns work items on whichever core is available
Shielding Strategy
The launcher implements a two-phase approach:Launch on cores 2-3
MIXXX is started with
taskset -c 2,3, so the initial process and all threads it spawns during startup land on the audio-dedicated cores by default.Post-launch thread classification loop
A 12-iteration loop (running for ~12 seconds after launch) inspects every thread in MIXXX’s task group by name. Audio-critical threads are boosted to
SCHED_FIFO 98 and pinned to cores 2–3. All other threads are demoted to SCHED_OTHER and banished to cores 0–1.Main thread assignment
After the loop completes, the main MIXXX process is set to
SCHED_OTHER 0 (normal scheduling) and pinned to cores 0–1. This ensures that any new threads spawned after the classification loop (such as Qt thread pool workers) inherit non-audio affinity by default, rather than landing on the audio-dedicated cores.Thread Classification
Audio-Critical Threads (SCHED_FIFO 98, cores 2–3)
These are the only two threads that must never miss their deadline:| Thread Name | Role |
|---|---|
EngineWorkerSch | Audio engine worker scheduler — drives the mix callback |
EngineSideChain | Sidechain bus for headphone cue and effects |
Non-Audio Threads (SCHED_OTHER, cores 0–1)
Everything else is banished. The full banish list used by the launcher:| Pattern | Subsystem |
|---|---|
mali-* | Mali GPU render threads |
QEvdevTouch | Touchscreen input handler |
CachingReader | MIXXX audio file read-ahead cache |
StatsManager | Internal profiling/metrics |
QDBus | D-Bus bridge for system integration |
VinylControl | Timecode vinyl input processing |
LibraryScanner | Background music library scan |
BrowseThread | File browser backend |
AnalyzerThread | BPM/key analysis worker |
Controller$ | MIDI controller mapping engine |
VSync | Qt vsync notifier |
gmain / gdbus | GLib main loop and D-Bus threads |
Thread (pooled) | Qt generic thread pool workers |
QQuickPixmapRea | Qt Quick image loader |
QQmlThread | QML JavaScript engine thread |
libusb_event | libusb event-handling thread (XMOS controller) |
The Launcher Post-Launch Loop
This is the exact working code frommixxx_launcher.sh:
0x0C taskset mask (binary 1100) pins threads to cores 2–3. The 0x03 mask (binary 0011) pins threads to cores 0–1.
IRQ Affinity
The TKGL bootstrap module pins all non-audio hardware IRQs to CPU 0 at boot before MIXXX launches:- GPU IRQ (Mali-T76x) → CPU 0
- USB IRQ (XMOS audio controller, control surface) → CPU 0
- MMC IRQ (SD card and internal eMMC) → CPU 0
ALSA Buffer Configuration
The audio buffer size directly determines worst-case latency and is the most fragile tuning parameter on this hardware:| Parameter | Value | Notes |
|---|---|---|
| Device | hw:JP11,0 | Direct hardware device, no plughw conversion |
| Format | S32_LE | 32-bit signed little-endian |
| Channels | 4 | Main output (L/R) + booth/headphone |
| Sample rate | 44100 Hz | Fixed — resampling adds CPU load |
latency setting | 5 | Maps to period_size=1024 |
| Period size | 1024 frames | 23.2 ms per period |
| Buffer size | 2048 frames | 46.4 ms total ring buffer |
I/O and VM Tuning
The launcher applies a set of kernel tuning parameters before starting MIXXX to reduce latency variance from I/O and memory management: Block device (MMC/SD):- Scheduler:
none(replaces BFQ) — BFQ’s per-process I/O accounting wastes CPU on flash storage - Read-ahead: 128 KB → 512 KB — reduces sequential read stalls for large audio files
nr_requests: 128 → 64 — limits I/O queue depth to reduce dispatch latency
dirty_background_bytes: set to20480bytes (20 KB) — forces early writeback to prevent large dirty-page flushes stalling the audio threadswappiness: 60 → 1 — no swap device present; prevents pointless page reclaimvfs_cache_pressure: 100 → 200 — aggressively reclaim dentry/inode cache under memory pressurestat_interval: 1 s → 10 s — reduces periodic VM stat collection overhead by 10×
- All
ext4mounts remounted withnoatime,nodiratime,commit=60— eliminates access-time metadata writes; batches journal commits to 60 s intervals
LimitMEMLOCK=infinity— allows audio threads tomlock()buffers into physical RAMLimitRTPRIO=99— allowsSCHED_FIFOpriority up to 99sched_rt_runtime_us=-1— disables the kernel’s RT throttle (default reserves 5% of CPU time for non-RT tasks)
Kernel Limitations
The following limitations exist in the stock
6.1.111-inmusic-2024-09-19-rt41 kernel and cannot be fixed without rebuilding the kernel from source. They cause a small but measurable ~0.1–0.2% CPU steal on audio cores:CONFIG_NO_HZ_FULLnot set — the 1 ms timer tick fires on all four cores including the isolated audio cores 2–3. Full tickless operation would eliminate this.CONFIG_HZ=1000— 1 kHz scheduler tick rate; each tick is ~0.1 ms of overhead per core per second.- No
rcu_nocbs— RCU (Read-Copy-Update) grace-period callbacks are not offloaded and can execute on the audio cores. isolcpus=1-3in kernel cmdline — CPU isolation is set, but without thenohz_fullcompanion parameter it is incomplete; the timer tick still fires.