feat/data-dnd e05cb15

performance.md RawHistoryFolder

Performance

NeferWL uses about 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change.

  • Only changed areas are redrawn. Windows nobody sees get one frame callback per second.
  • Windows are composed as instanced draws, so a frame makes a few Vulkan calls whatever the number of windows.
  • Fullscreen windows go straight to the display (direct scanout), with tearing for games. See render.direct-scanout and render.tearing in Configuration.
  • A full frame at 2560×1600 takes about 0.16 ms on an RX 9070 XT and 3 ms on a Radeon 680M. Measure yours with go test ./internal/adapters/vulkan -bench ComposeFullTarget (NEFERWL_VK_DEVICE picks the GPU).
  • NeferWL runs with GOGC=100 and a 256 MiB soft memory limit. GOGC and GOMEMLIMIT from the environment override them.

VRR

With a fullscreen game under VRR, each game frame is committed at least render.vrr-flip-gap (default 1 ms) after the previous flip. On amdgpu, committing earlier can hold the panel at its slowest refresh rate.

Real-time priority

Output and input threads ask for real-time scheduling, which needs CAP_SYS_NICE. The Arch and Debian packages set it. For a local build:

sudo setcap cap_sys_nice+ep bin/neferwl

performance.realtime = off turns it off. With the capability set, the loader ignores LD_PRELOAD and LD_LIBRARY_PATH, and debuggers need root to attach.

Profiling

Run these from another TTY or over SSH:

# CPU, Go and C frames
perf record -g -p (pgrep -f bin/neferwl) -- sleep 8
perf report --children --percent-limit 1

# Allocations
neferwl --backend=drm --pprof=localhost:6060
go tool pprof -sample_index=alloc_objects -top http://localhost:6060/debug/pprof/heap

# One line per GC cycle
GODEBUG=gctrace=1 neferwl --backend=drm

make tty serves pprof on localhost:6060 by default (make tty PPROF= turns it off).

Logs are in ~/.local/state/neferwl/runs/<backend>/, with latest.log pointing at the newest run. --debug=all enables every category except the noisy drm-flip, input-motion, input-keys, wayland-damage (one client damage entry per client commit) and render-damage (one frame damage entry per rendered frame); name them to turn them on.

Frame stats

Every 10 s, each output logs a stats entry:

Field Meaning
missed_vblanks Frames that flipped more than 1.5 refresh periods late (not counted under VRR)
max_flip_interval_ms Longest gap between two flips
max_commit_delay_ms Longest wait from "frame due" to commit
late_fences Missed vblanks where the GPU finished too late (needs --debug=drm-flip)
redrawn_pixels Pixels drawn

If outputs report flips faster than the display loop reads them, wayland merges them and logs a warning with merged at most every 10 s.

Missed vblanks with late_fences mean the GPU was late. Without late_fences but with a large max_commit_delay_ms, the CPU was late.

source
1# Performance
2
3NeferWL uses about 40–80 MB of RAM with two 4K monitors, and almost no CPU while the screen does not change.
4
5- Only changed areas are redrawn. Windows nobody sees get one frame callback per second.
6- Windows are composed as instanced draws, so a frame makes a few Vulkan calls whatever the number of windows.
7- Fullscreen windows go straight to the display (direct scanout), with tearing for games. See `render.direct-scanout` and `render.tearing` in [Configuration](config.md#keys).
8- A full frame at 2560×1600 takes about 0.16 ms on an RX 9070 XT and 3 ms on a Radeon 680M. Measure yours with `go test ./internal/adapters/vulkan -bench ComposeFullTarget` (`NEFERWL_VK_DEVICE` picks the GPU).
9- NeferWL runs with `GOGC=100` and a 256 MiB soft memory limit. `GOGC` and `GOMEMLIMIT` from the environment override them.
10
11## VRR
12
13With a fullscreen game under VRR, each game frame is committed at least `render.vrr-flip-gap` (default 1 ms) after the previous flip. On amdgpu, committing earlier can hold the panel at its slowest refresh rate.
14
15## Real-time priority
16
17Output and input threads ask for real-time scheduling, which needs `CAP_SYS_NICE`. The Arch and Debian packages set it. For a local build:
18
19```sh
20sudo setcap cap_sys_nice+ep bin/neferwl
21```
22
23`performance.realtime = off` turns it off. With the capability set, the loader ignores `LD_PRELOAD` and `LD_LIBRARY_PATH`, and debuggers need root to attach.
24
25## Profiling
26
27Run these from another TTY or over SSH:
28
29```sh
30# CPU, Go and C frames
31perf record -g -p (pgrep -f bin/neferwl) -- sleep 8
32perf report --children --percent-limit 1
33
34# Allocations
35neferwl --backend=drm --pprof=localhost:6060
36go tool pprof -sample_index=alloc_objects -top http://localhost:6060/debug/pprof/heap
37
38# One line per GC cycle
39GODEBUG=gctrace=1 neferwl --backend=drm
40```
41
42`make tty` serves pprof on `localhost:6060` by default (`make tty PPROF=` turns it off).
43
44Logs are in `~/.local/state/neferwl/runs/<backend>/`, with `latest.log` pointing at the newest run. `--debug=all` enables every category except the noisy `drm-flip`, `input-motion`, `input-keys`, `wayland-damage` (one `client damage` entry per client commit) and `render-damage` (one `frame damage` entry per rendered frame); name them to turn them on.
45
46## Frame stats
47
48Every 10 s, each output logs a `stats` entry:
49
50| Field | Meaning |
51|---|---|
52| `missed_vblanks` | Frames that flipped more than 1.5 refresh periods late (not counted under VRR) |
53| `max_flip_interval_ms` | Longest gap between two flips |
54| `max_commit_delay_ms` | Longest wait from "frame due" to commit |
55| `late_fences` | Missed vblanks where the GPU finished too late (needs `--debug=drm-flip`) |
56| `redrawn_pixels` | Pixels drawn |
57
58If outputs report flips faster than the display loop reads them, wayland merges them and logs a warning with `merged` at most every 10 s.
59
60Missed vblanks with `late_fences` mean the GPU was late. Without `late_fences` but with a large `max_commit_delay_ms`, the CPU was late.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close