End of life — September 2026. SolarFlare is no longer maintained and this site is kept for reference only. No further releases, updates, bug fixes, or security patches will be published. Users are encouraged to migrate to Slipstream, the successor project, which remains actively maintained.

On this page
OptimizationLow Latency

Performance & Latency Tuning

System-level optimizations for Linux kernels, GPU governors, CPU pinning, and network transport.

7 min readUpdated August 2026

Ready-made profiles#

Copy one profile into ~/.config/sunshine/sunshine.conf, then tune Moonlight bitrate to the link. Measure with the client overlay before changing more keys.

Wired NVIDIA, 1080p120 or 1440p120.

ini
busy_poll_us = 50
rate_cap_pct = 90
enet_4mib_buffer = true
dscp_qos = true
cpu_pinning = true
gpu_governor = true
latency_mode = aggressive
pipewire_latency_ms = 4
nvenc_tuning_preset = 0

CPU Frequency Governor & Pinning#

For 120 FPS + 4K streaming, verify your CPU governor is set to performance and enable SolarFlare CPU pinning:

cpu_pinning = true elevates the capture worker to SCHED_RR real-time policy and pins the thread to a non-IRQ core, bypassing general OS context-switch overhead.

bash
# Check current scaling governor
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# Set all cores to performance
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

GPU Clocks & Power Governors#

  • AMD GPUs: Setting gpu_governor = true in sunshine.conf forces power_dpm_force_performance_level to performance during active streaming.
  • NVIDIA GPUs: Prevent GPU down-clocking during video capture using clock locking (nvidia-smi -lgc <boost_clock>).
bash
# Query maximum graphics boost clock
nvidia-smi --query-gpu=clocks.max.graphics --format=csv,noheader

# Lock GPU clock to boost frequency (e.g. 2100 MHz)
sudo nvidia-smi -lgc 2100,2100

Network Buffers & Low-Latency Polling#

Wi-Fi and high-bitrate LAN links benefit from expanded socket buffers and busy-polling:

enet_4mib_buffer = true
Networkdefault: true

Expands socket buffers so 50+ Mbps bursts do not get dropped in kernel send queues.

busy_poll_us = 50
Networkdefault: 50

Enables kernel SO_BUSY_POLL for instant UDP wakeup without burning full CPU cores.

dscp_qos = true
Networkdefault: true

Marks streaming packets with DSCP CS3 so QoS-enabled routers prioritize stream traffic.

Recommended Kernel sysctls#

Add the following tweaks to /etc/sysctl.d/99-streaming.conf:

ini
# Increase socket max buffer sizes for 4K streaming
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 4194304
net.core.wmem_default = 4194304

# Enable BBR congestion control
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

Latency deep-dive: measure first#

Read the Moonlight overlay (decode + network + render) next to host GET /api/stream/latency (capture_ms, encode_ms, network_total_ms, network_queue_dwell_ms, rtt_ms) and GET /api/stream/telemetry (CPU/GPU/RAM pressure). If capture_ms is high, suspect the compositor or CPU pinning; if encode_ms is high, drop a preset level or resolution; if network/rtt dominates, run iperf3 UDP at the Moonlight bitrate and keep loss under 5% with jitter under 1 ms before touching knobs.

bash
iperf3 -s
iperf3 -c <host> -u -b 80M -t 10
ping -c 100 <host> | tail -3
curl -sk -H "Authorization: Bearer $TOK" https://localhost:47990/api/stream/latency | jq .capture_ms,.encode_ms,.rtt_ms

Vendor & link profiles#

Start from the closest profile, then A/B one knob at a time and re-measure:

ini
encoder = vaapi
capture = kms
latency_mode = safe
pipewire_latency_ms = 8

HDR streaming chain#

HDR needs the whole chain: KMS capture, an HDR compositor (Plasma 6, Gamescope), a 10-bit encoder (hevc_mode or av1_mode 3+), HDR enabled in host OS and Moonlight client, and an EDID emulator or HDR display on the host. Washed-out output means something fell back to SDR — check the colorspace lines in the log and the IsHdrSupported negotiation.

Symptom to knob table#

SymptomCheckKnob
KMS black + Probably not permittedgetcap, /dev/dri permssetcap; video group
vainfo failslibva driver presentInstall driver or encoder = software
No monitorxrandr --listmonitorsVIRTUAL1 or headless_mode
No sinkpactl/wpctl sinksaudio_sink = name
Loss over 5%iperf3 UDPrate_cap_pct down; adaptive on
401 from APICredentialssunshine --creds reset
403 from APIScope / origin / CSRFToken scope; origin_web_ui_allowed; X-CSRF-Token
Update stuck waiting_idleGET /api/sessionsEnd stream or cancel