detached 1d8bbbe

test(core): benchmark refreshShown with 26 rect motions on 24 windows

Records the per-frame cost of matching motions to the layout (about 5 µs,
33 allocations, all from the layout rebuild) before any change to it.
commit
1d8bbbe96dd2593f6dcfa4e2124c7dfbc179b567
author
brice · · 2026-10-05 01:59 UTC
parent
dfa298b
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +61 -0
A internal/core/refresh_bench_test.go +61 -0
@@ -0,0 +1,61 @@
1+package core
2+
3+import (
4+ "testing"
5+ "time"
6+
7+ "github.com/bnema/neferwl/internal/ports"
8+)
9+
10+// BenchmarkRefreshShown is one publish's layout build on a screen of 24
11+// windows, 20 of them with a rect motion and 6 more leaving: the cost of
12+// matching the motions to the layout every frame.
13+func BenchmarkRefreshShown(b *testing.B) {
14+ var cfg ports.Config
15+ cfg.Keyboard.CmdKey = "super"
16+ cfg.Layout.MaxColumns = 4
17+ cfg.Animations.On = true
18+ cfg.Animations.Slowdown = 10
19+ c, err := New(cfg, Channels{Scenes: make(chan []ports.Scene, 1), Commands: make(chan ports.ClientCommand, 64)})
20+ if err != nil {
21+ b.Fatal(err)
22+ }
23+ c.addScreen(ports.OutputInfo{Name: "A", Width: 3000, Height: 2000})
24+ sc := c.cur()
25+ for id := WindowID(1); id <= 30; id++ {
26+ sc.mon.AddWindow(id)
27+ }
28+ sc.arrange()
29+ c.refreshShown()
30+ t0 := time.Now()
31+ sc.rects = make(map[WindowID]rectMotion, 26)
32+ sp := viewSpring(100, 0)
33+ for i, p := range sc.settledLayout {
34+ if i >= 20 {
35+ break
36+ }
37+ sc.rects[p.ID] = rectMotion{
38+ x: c.spring(sp, t0), y: c.spring(sp, t0), w: c.spring(sp, t0), h: c.spring(sp, t0),
39+ dx: 100, dy: 100, dw: 100, dh: 100,
40+ fade: c.spring(viewSpring(0.5, 0), t0), df: 0.5, scale: true,
41+ }
42+ }
43+ for i, p := range sc.settledLayout[24:] {
44+ sc.mon.RemoveWindow(p.ID)
45+ c.leave(sc, p, t0)
46+ _ = i
47+ }
48+ sc.rectsWS = sc.mon.Current()
49+ c.refreshShown()
50+ if len(sc.rects) != 26 {
51+ b.Fatalf("rects %d", len(sc.rects))
52+ }
53+ b.ReportAllocs()
54+ b.ResetTimer()
55+ for range b.N {
56+ c.refreshShown()
57+ }
58+ if len(sc.rects) != 26 {
59+ b.Fatalf("rects %d after", len(sc.rects))
60+ }
61+}
@@ -0,0 +1,61 @@
1+package core
2+
3+import (
4+ "testing"
5+ "time"
6+
7+ "github.com/bnema/neferwl/internal/ports"
8+)
9+
10+// BenchmarkRefreshShown is one publish's layout build on a screen of 24
11+// windows, 20 of them with a rect motion and 6 more leaving: the cost of
12+// matching the motions to the layout every frame.
13+func BenchmarkRefreshShown(b *testing.B) {
14+ var cfg ports.Config
15+ cfg.Keyboard.CmdKey = "super"
16+ cfg.Layout.MaxColumns = 4
17+ cfg.Animations.On = true
18+ cfg.Animations.Slowdown = 10
19+ c, err := New(cfg, Channels{Scenes: make(chan []ports.Scene, 1), Commands: make(chan ports.ClientCommand, 64)})
20+ if err != nil {
21+ b.Fatal(err)
22+ }
23+ c.addScreen(ports.OutputInfo{Name: "A", Width: 3000, Height: 2000})
24+ sc := c.cur()
25+ for id := WindowID(1); id <= 30; id++ {
26+ sc.mon.AddWindow(id)
27+ }
28+ sc.arrange()
29+ c.refreshShown()
30+ t0 := time.Now()
31+ sc.rects = make(map[WindowID]rectMotion, 26)
32+ sp := viewSpring(100, 0)
33+ for i, p := range sc.settledLayout {
34+ if i >= 20 {
35+ break
36+ }
37+ sc.rects[p.ID] = rectMotion{
38+ x: c.spring(sp, t0), y: c.spring(sp, t0), w: c.spring(sp, t0), h: c.spring(sp, t0),
39+ dx: 100, dy: 100, dw: 100, dh: 100,
40+ fade: c.spring(viewSpring(0.5, 0), t0), df: 0.5, scale: true,
41+ }
42+ }
43+ for i, p := range sc.settledLayout[24:] {
44+ sc.mon.RemoveWindow(p.ID)
45+ c.leave(sc, p, t0)
46+ _ = i
47+ }
48+ sc.rectsWS = sc.mon.Current()
49+ c.refreshShown()
50+ if len(sc.rects) != 26 {
51+ b.Fatalf("rects %d", len(sc.rects))
52+ }
53+ b.ReportAllocs()
54+ b.ResetTimer()
55+ for range b.N {
56+ c.refreshShown()
57+ }
58+ if len(sc.rects) != 26 {
59+ b.Fatalf("rects %d after", len(sc.rects))
60+ }
61+}

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 23

Tags 10

↑↓ moveenter openesc close