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 Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· 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 | + | } | |||