zgx

Results

zgx against GPUI Fast, MyGo and Rune on one Mac, in one session, the same four scenes built from the same workload code.

zgx uses the least CPU in 10 of 10 tests and the least GPU power in 9, against GPUI Fast, MyGo and Rune, and none of its frames run long.

macOS · 2026-10-25 · zgx at c3c0dc9 · lower is better throughout

CPU, heavy dashboard (both)
9.0%
GPUI Fast 43% lessMyGo 48% lessRune 59% less
GPU power, heavy dashboard (both)
154 mW
GPUI Fast 7% lessMyGo 32% lessRune 68% less
Long frames (over 25 ms)
0%
GPUI Fast, MyGo and Rune: up to 20.6%
CPU while idle
0.00%
GPUI Fast 0.37%MyGo 0.00%Rune 0.00%

GPUI Fast is Zed’s GPUI with its fast-path optimizations, as apps ship it. MyGo is a Go desktop framework, measured through its GPU-drawn native UI. Rune is built on Rust, wgpu, Taffy and Parley. Every figure on this page is read at build time from the run that scripts/build_site.py accepted, after it recomputed each median and range from the trials and checked them against the run’s summaries.

Heavy dashboard

A 1280×800 dashboard: 6 tiles, 30 cards of 26 sparkline bars, a status table and a log. Most values change 60 times a second; the table scrolls. 50 trials. Raw data

CPU% of one core
ModeFrameworkMedian (range)
Idlezgx
0.00
GPUI Fast
0.37
MyGo
0.00
Rune
0.00
Streamingzgx
8.5(trials 8.5 to 8.7)
GPUI Fast
14.9(trials 14.5 to 15.8)
MyGo
16.2(trials 16.0 to 16.5)
Rune
19.9(trials 19.9 to 20.8)
Scrollingzgx
2.9(trials 2.9 to 3.0)
GPUI Fast
8.1(trials 7.1 to 9.1)
MyGo
13.5(trials 12.4 to 13.6)
Rune
19.8(trials 18.9 to 20.5)
Bothzgx
9.0(trials 8.0 to 9.3)
GPUI Fast
15.9(trials 14.4 to 17.2)
MyGo
17.4(trials 17.2 to 17.8)
Rune
22.2(trials 21.8 to 22.3)
GPU powermW, the whole GPU (the window server's compositing included), less the desktop alone
ModeFrameworkMedian (range)
Streamingzgx
128.6(trials 128.0 to 129.6)
GPUI Fast
164.3(trials 163.8 to 165.3)
MyGo
228.2(trials 223.6 to 230.1)
Rune
485.1(trials 484.9 to 486.9)
Scrollingzgx
80.4(trials 80.4 to 82.6)
GPUI Fast
164.3(trials 163.6 to 165.0)
MyGo
111.7(trials 111.5 to 111.8)
Rune
484.5(trials 476.8 to 484.9)
Bothzgx
154.3(trials 152.4 to 158.5)
GPUI Fast
165.1(trials 164.1 to 165.8)
MyGo
225.5(trials 225.1 to 226.5)
Rune
485.9(trials 484.1 to 486.3)
Frame time, 99th percentilems between frames
ModeFrameworkMedian (range)
Streamingzgx
18.3(trials 17.9 to 18.9)
GPUI Fast
25.1(trials 24.9 to 25.3)
MyGo
18.9(trials 18.4 to 25.3)
Rune
24.1(trials 24.0 to 33.8)
Scrollingzgx
17.8(trials 17.7 to 18.0)
GPUI Fast
25.2(trials 25.2 to 25.4)
MyGo
17.8(trials 17.6 to 17.8)
Rune
33.7(trials 33.3 to 33.8)
Bothzgx
17.9(trials 17.8 to 18.0)
GPUI Fast
25.1(trials 25.0 to 25.3)
MyGo
18.2(trials 17.6 to 24.9)
Rune
25.3(trials 23.8 to 33.5)
Long frames% of frames over 25 ms
ModeFrameworkMedian (range)
Streamingzgx
0.0(trials 0.0 to 0.4)
GPUI Fast
1.6(trials 0.8 to 2.0)
MyGo
0.6(trials 0.0 to 1.8)
Rune
0.4(trials 0.0 to 8.1)
Scrollingzgx
0.0
GPUI Fast
2.2(trials 1.8 to 2.7)
MyGo
0.2
Rune
8.4(trials 8.3 to 16.6)
Bothzgx
0.0
GPUI Fast
1.6(trials 1.2 to 2.1)
MyGo
0.2(trials 0.0 to 0.6)
Rune
1.9(trials 0.2 to 8.3)
MemoryMB, physical footprint
ModeFrameworkMedian (range)
Idlezgx
54(trials 54 to 55)
GPUI Fast
71
MyGo
75(trials 66 to 84)
Rune
76(trials 74 to 79)
Streamingzgx
259(trials 257 to 261)
GPUI Fast
270(trials 258 to 273)
MyGo
297(trials 295 to 297)
Rune
467(trials 464 to 467)
Scrollingzgx
254(trials 252 to 254)
GPUI Fast
267(trials 253 to 269)
MyGo
287(trials 286 to 288)
Rune
616(trials 612 to 616)
Bothzgx
259(trials 256 to 260)
GPUI Fast
264(trials 256 to 272)
MyGo
296(trials 295 to 296)
Rune
613(trials 612 to 615)
WindowServer CPU% of one core: the system compositor, while the app runs
ModeFrameworkMedian (range)
Idlezgx
0.2
GPUI Fast
1.4(trials 0.2 to 2.6)
MyGo
0.2
Rune
2.9(trials 0.2 to 5.7)
Streamingzgx
10.0(trials 9.9 to 11.2)
GPUI Fast
9.4(trials 9.3 to 9.6)
MyGo
10.6(trials 10.5 to 13.7)
Rune
9.7(trials 9.4 to 9.7)
Scrollingzgx
9.7(trials 9.6 to 9.9)
GPUI Fast
9.4(trials 9.3 to 9.7)
MyGo
10.4(trials 10.2 to 10.4)
Rune
9.6(trials 9.4 to 9.9)
Bothzgx
9.9(trials 9.8 to 13.3)
GPUI Fast
9.4(trials 9.0 to 9.5)
MyGo
10.4(trials 10.1 to 10.5)
Rune
9.4(trials 9.1 to 10.3)
App GPU timemillion GPU cycles a second, the app's own; includes per-frame wake latency
ModeFrameworkMedian (range)
Streamingzgx
18.5(trials 18.5 to 18.7)
GPUI Fast
22.1(trials 22.0 to 22.1)
MyGo
26.2(trials 24.3 to 26.3)
Rune
46.4(trials 46.3 to 46.5)
Scrollingzgx
12.6(trials 12.5 to 12.7)
GPUI Fast
22.3(trials 22.2 to 22.5)
MyGo
15.7(trials 15.5 to 15.8)
Rune
46.1(trials 45.3 to 46.4)
Bothzgx
19.7(trials 18.9 to 19.9)
GPUI Fast
22.1(trials 22.0 to 22.1)
MyGo
25.9(trials 25.5 to 26.1)
Rune
46.3(trials 46.2 to 46.4)

Text and a 100,000-row list

A streaming transcript beside a 100,000-row virtual list, updated 60 times a second. 41 trials. Raw data

CPU% of one core
ModeFrameworkMedian (range)
Streamingzgx
2.8(trials 2.8 to 2.9)
GPUI Fast
5.6(trials 4.8 to 5.8)
MyGo
8.6(trials 8.4 to 9.0)
Rune
7.3(trials 6.9 to 7.6)
Scrollingzgx
2.4(trials 2.3 to 2.5)
GPUI Fast
4.4(trials 4.1 to 4.5)
MyGo
6.6(trials 6.4 to 6.7)
Rune
6.5(trials 5.9 to 6.9)
Bothzgx
3.1(trials 3.0 to 3.1)
GPUI Fast
5.6(trials 5.6 to 5.7)
MyGo
8.6(trials 8.5 to 9.1)
Rune
7.6(trials 7.2 to 7.6)
GPU powermW, the whole GPU (the window server's compositing included), less the desktop alone
ModeFrameworkMedian (range)
Streamingzgx
57.9(trials 57.7 to 61.3)
GPUI Fast
107.2(trials 106.3 to 107.8)
MyGo
64.5(trials 64.2 to 67.3)
Rune
312.1(trials 306.8 to 316.0)
Scrollingzgx
62.5(trials 61.7 to 62.7)
GPUI Fast
104.5(trials 104.0 to 105.7)
MyGo
98.9(trials 98.6 to 99.3)
Rune
305.4(trials 302.6 to 306.9)
Bothzgx
67.0(trials 65.7 to 67.1)
GPUI Fast
107.6(trials 106.4 to 107.8)
MyGo
103.8(trials 103.0 to 105.0)
Rune
314.9(trials 311.4 to 316.1)
Frame time, 99th percentilems between frames
ModeFrameworkMedian (range)
Streamingzgx
18.1(trials 17.9 to 18.4)
GPUI Fast
17.9(trials 17.8 to 18.2)
MyGo
18.2(trials 18.1 to 25.3)
Rune
33.8(trials 33.8 to 40.4)
Scrollingzgx
18.1(trials 18.0 to 18.2)
GPUI Fast
18.0(trials 17.8 to 18.8)
MyGo
25.3(trials 18.4 to 25.5)
Rune
33.8(trials 33.7 to 34.0)
Bothzgx
18.1(trials 17.9 to 18.2)
GPUI Fast
18.0(trials 18.0 to 18.4)
MyGo
18.1(trials 18.0 to 19.0)
Rune
32.0(trials 26.1 to 41.3)
Long frames% of frames over 25 ms
ModeFrameworkMedian (range)
Streamingzgx
0.0
GPUI Fast
0.2(trials 0.0 to 0.4)
MyGo
0.6(trials 0.2 to 2.1)
Rune
17.0(trials 15.3 to 20.0)
Scrollingzgx
0.0
GPUI Fast
0.4(trials 0.0 to 0.4)
MyGo
2.7(trials 0.2 to 6.1)
Rune
14.5(trials 14.2 to 17.1)
Bothzgx
0.0
GPUI Fast
0.4(trials 0.2 to 0.6)
MyGo
0.0(trials 0.0 to 0.2)
Rune
8.4(trials 5.2 to 25.3)
MemoryMB, physical footprint
ModeFrameworkMedian (range)
Streamingzgx
236(trials 234 to 243)
GPUI Fast
247(trials 235 to 254)
MyGo
263(trials 262 to 270)
Rune
407(trials 405 to 432)
Scrollingzgx
234(trials 232 to 236)
GPUI Fast
236(trials 236 to 243)
MyGo
253(trials 251 to 254)
Rune
417(trials 416 to 419)
Bothzgx
235(trials 234 to 236)
GPUI Fast
237(trials 236 to 237)
MyGo
262(trials 261 to 263)
Rune
418(trials 418 to 419)
WindowServer CPU% of one core: the system compositor, while the app runs
ModeFrameworkMedian (range)
Streamingzgx
9.9(trials 9.6 to 10.7)
GPUI Fast
9.1(trials 9.0 to 9.6)
MyGo
10.0(trials 9.7 to 10.2)
Rune
9.5(trials 9.4 to 9.5)
Scrollingzgx
9.6(trials 9.3 to 9.7)
GPUI Fast
9.0(trials 9.0 to 9.6)
MyGo
10.4(trials 10.4 to 10.5)
Rune
9.7(trials 9.5 to 10.0)
Bothzgx
9.8(trials 9.7 to 9.8)
GPUI Fast
9.2(trials 9.1 to 9.2)
MyGo
10.3(trials 10.2 to 10.3)
Rune
10.0(trials 9.7 to 10.1)
App GPU timemillion GPU cycles a second, the app's own; includes per-frame wake latency
ModeFrameworkMedian (range)
Streamingzgx
11.7(trials 11.7 to 11.8)
GPUI Fast
18.7(trials 18.6 to 18.8)
MyGo
12.4(trials 12.3 to 12.5)
Rune
34.0(trials 33.9 to 34.4)
Scrollingzgx
12.5(trials 12.5 to 12.7)
GPUI Fast
18.5(trials 18.4 to 18.6)
MyGo
16.1(trials 16.0 to 16.1)
Rune
33.5(trials 33.4 to 33.7)
Bothzgx
13.4(trials 13.4 to 13.6)
GPUI Fast
18.8
MyGo
15.2(trials 15.2 to 16.7)
Rune
34.3(trials 34.0 to 34.4)

Animation

48 blinking dots and a shimmering line of text, animated on every refresh of a 120 Hz display. 16 trials. Raw data

CPU% of one core
ModeFrameworkMedian (range)
Animatingzgx
4.7(trials 4.6 to 4.8)
GPUI Fast
6.3(trials 5.8 to 6.7)
MyGo
8.1(trials 8.0 to 8.2)
Rune
7.3(trials 7.2 to 7.9)
GPU powermW, the whole GPU (the window server's compositing included), less the desktop alone
ModeFrameworkMedian (range)
Animatingzgx
115.9(trials 115.7 to 122.0)
GPUI Fast
140.2(trials 127.6 to 144.0)
MyGo
111.4(trials 110.6 to 117.2)
Rune
294.8(trials 293.1 to 303.0)
Frame time, 99th percentilems between frames
ModeFrameworkMedian (range)
Animatingzgx
18.2(trials 17.9 to 18.9)
GPUI Fast
12.9(trials 12.8 to 17.4)
MyGo
17.4(trials 16.8 to 17.5)
Rune
17.3(trials 17.2 to 17.4)
Long frames% of frames over 25 ms
ModeFrameworkMedian (range)
Animatingzgx
0.0
GPUI Fast
0.0
MyGo
0.0
Rune
0.0
MemoryMB, physical footprint
ModeFrameworkMedian (range)
Animatingzgx
246(trials 243 to 254)
GPUI Fast
247(trials 245 to 252)
MyGo
253(trials 253 to 260)
Rune
410(trials 410 to 423)
WindowServer CPU% of one core: the system compositor, while the app runs
ModeFrameworkMedian (range)
Animatingzgx
19.5(trials 19.3 to 19.7)
GPUI Fast
19.7(trials 19.2 to 20.0)
MyGo
21.8(trials 21.7 to 21.9)
Rune
20.0(trials 19.9 to 20.3)
App GPU timemillion GPU cycles a second, the app's own; includes per-frame wake latency
ModeFrameworkMedian (range)
Animatingzgx
22.8(trials 22.6 to 23.0)
GPUI Fast
17.7(trials 16.6 to 30.1)
MyGo
23.4(trials 23.4 to 23.5)
Rune
44.0(trials 43.8 to 44.2)

Variable-height list

100,000 chat rows of wrapped text, 1 to 8 lines each, about one in four with an image, in each framework's own list widget, which measures the rows: scrolled steadily, flung, and scrolled with a jump to a far row every half second. 50 trials. Raw data

CPU% of one core
ModeFrameworkMedian (range)
Scrollingzgx
2.6(trials 2.6 to 2.8)
zgx (Luau)
2.7(trials 2.7 to 2.9)
GPUI Fast
5.1(trials 5.1 to 5.2)
MyGo
10.0(trials 9.2 to 10.5)
Rune
7.9(trials 7.9 to 8.5)
Flingingzgx
3.2(trials 3.0 to 3.3)
zgx (Luau)
3.2(trials 3.2 to 3.4)
GPUI Fast
5.2(trials 5.2 to 5.5)
MyGo
10.5(trials 10.1 to 11.1)
Rune
8.9(trials 8.7 to 9.0)
Jumpingzgx
2.8(trials 2.7 to 2.9)
zgx (Luau)
2.9(trials 2.9 to 3.0)
GPUI Fast
5.4(trials 5.2 to 5.5)
MyGo
10.7(trials 10.3 to 10.8)
Rune
10.6(trials 10.4 to 10.7)
GPU powermW, the whole GPU (the window server's compositing included), less the desktop alone
ModeFrameworkMedian (range)
Scrollingzgx
60.5(trials 60.4 to 60.7)
zgx (Luau)
60.3(trials 59.9 to 60.5)
GPUI Fast
89.1(trials 89.0 to 89.3)
MyGo
93.9(trials 93.8 to 95.0)
Rune
244.5(trials 244.5 to 245.5)
Flingingzgx
67.2(trials 67.1 to 67.9)
zgx (Luau)
67.0(trials 66.4 to 67.3)
GPUI Fast
89.0(trials 88.9 to 89.9)
MyGo
94.3(trials 93.5 to 96.0)
Rune
240.1(trials 237.6 to 241.7)
Jumpingzgx
60.5(trials 60.4 to 60.5)
zgx (Luau)
60.8(trials 60.6 to 60.9)
GPUI Fast
89.2(trials 88.6 to 89.5)
MyGo
95.1(trials 94.2 to 96.7)
Rune
241.6(trials 241.3 to 242.0)
Frame time, 99th percentilems between frames
ModeFrameworkMedian (range)
Scrollingzgx
17.9(trials 17.9 to 18.1)
zgx (Luau)
18.0(trials 17.8 to 18.4)
GPUI Fast
17.9(trials 17.8 to 17.9)
MyGo
18.4(trials 17.9 to 19.8)
Rune
32.7(trials 32.6 to 41.2)
Flingingzgx
18.1(trials 18.0 to 18.5)
zgx (Luau)
17.9(trials 17.9 to 18.0)
GPUI Fast
17.7
MyGo
18.3(trials 17.9 to 25.3)
Rune
41.3(trials 41.2 to 41.8)
Jumpingzgx
18.1(trials 18.0 to 18.9)
zgx (Luau)
18.3(trials 18.1 to 18.4)
GPUI Fast
25.2(trials 24.9 to 25.5)
MyGo
18.7(trials 18.1 to 25.3)
Rune
33.5(trials 33.4 to 33.7)
Long frames% of frames over 25 ms
ModeFrameworkMedian (range)
Scrollingzgx
0.0
zgx (Luau)
0.0
GPUI Fast
0.2
MyGo
0.4(trials 0.2 to 0.4)
Rune
7.1(trials 6.8 to 19.6)
Flingingzgx
0.0(trials 0.0 to 0.2)
zgx (Luau)
0.0
GPUI Fast
0.4(trials 0.2 to 0.4)
MyGo
0.2(trials 0.2 to 1.2)
Rune
20.6(trials 16.8 to 22.2)
Jumpingzgx
0.0
zgx (Luau)
0.0
GPUI Fast
1.6(trials 0.4 to 4.4)
MyGo
0.4(trials 0.4 to 4.0)
Rune
7.1(trials 6.5 to 8.7)
Unfilled rows% of window captures showing a gap
ModeFrameworkMedian (range)
Scrollingzgx
0.0
zgx (Luau)
0.0
GPUI Fast
0.0
MyGo
0.0
Rune
0.0
Jumpingzgx
0.0
zgx (Luau)
0.0
GPUI Fast
0.0
MyGo
0.0
Rune
0.0
MemoryMB, physical footprint
ModeFrameworkMedian (range)
Scrollingzgx
237(trials 237 to 238)
zgx (Luau)
240(trials 238 to 241)
GPUI Fast
272(trials 270 to 272)
MyGo
254(trials 254 to 255)
Rune
436(trials 436 to 441)
Flingingzgx
238(trials 238 to 239)
zgx (Luau)
241(trials 240 to 242)
GPUI Fast
281(trials 274 to 282)
MyGo
254(trials 253 to 255)
Rune
438(trials 438 to 442)
Jumpingzgx
239(trials 238 to 239)
zgx (Luau)
242(trials 240 to 242)
GPUI Fast
272(trials 272 to 281)
MyGo
258(trials 257 to 259)
Rune
440(trials 440 to 442)
WindowServer CPU% of one core: the system compositor, while the app runs
ModeFrameworkMedian (range)
Scrollingzgx
9.6(trials 9.6 to 10.0)
zgx (Luau)
9.8(trials 9.6 to 10.6)
GPUI Fast
9.0(trials 8.9 to 9.2)
MyGo
10.8(trials 10.7 to 11.0)
Rune
9.3(trials 9.3 to 9.4)
Flingingzgx
9.6(trials 9.4 to 9.7)
zgx (Luau)
10.1(trials 9.6 to 15.4)
GPUI Fast
9.2(trials 9.0 to 9.2)
MyGo
10.7(trials 10.7 to 11.1)
Rune
9.1(trials 9.0 to 9.5)
Jumpingzgx
9.6(trials 9.5 to 9.7)
zgx (Luau)
9.5(trials 9.5 to 9.7)
GPUI Fast
9.0(trials 8.9 to 9.1)
MyGo
10.7(trials 10.6 to 10.8)
Rune
9.2(trials 8.8 to 9.3)
App GPU timemillion GPU cycles a second, the app's own; includes per-frame wake latency
ModeFrameworkMedian (range)
Scrollingzgx
13.2(trials 13.1 to 13.5)
zgx (Luau)
13.2(trials 13.0 to 13.2)
GPUI Fast
17.3(trials 17.1 to 17.3)
MyGo
15.4(trials 14.7 to 16.0)
Rune
29.5(trials 29.4 to 29.5)
Flingingzgx
14.5(trials 14.5 to 14.7)
zgx (Luau)
14.5(trials 14.1 to 14.8)
GPUI Fast
17.4
MyGo
15.2(trials 14.8 to 16.2)
Rune
28.9(trials 28.6 to 28.9)
Jumpingzgx
13.2(trials 13.2 to 13.3)
zgx (Luau)
13.3(trials 13.2 to 13.6)
GPUI Fast
17.3(trials 16.8 to 17.3)
MyGo
15.2(trials 15.1 to 16.1)
Rune
29.0(trials 29.0 to 29.2)

How this was measured

  • Machine: Apple M5 Max (Mac17,6, 18 cores, 128 GB), macOS 26.4 (25E246), AC Power.
  • Displays: 2 × Studio Display XDR (3200 x 1800 @ 120.00Hz); the window on the main display, nothing covering it.
  • Builds: zgx and GPUI Fast with their dist profile (dist (release, lto = "fat", codegen-units = 1)), rustc 1.96.0 (ac68faa20 2026-05-25); MyGo v0.6.3 (1524290, MIT) built with go1.27.3 darwin/arm64, go build -trimpath -ldflags=-s -w, cgo off; Rune at 998bef58 (dev, MIT), profile dist (Rune's perf with fat LTO and codegen-units 1), and a 14-line patch exposing its wheel path. Every framework uses the system allocator. zgx at c3c0dc9.
  • Trials: each a fresh launch, the first 5 s discarded and the next 10 s sampled every 50 ms; 3 trials of each mode, in alternating order, and 1 more of any whose CPU or GPU spread past 10% of its median; idle 2 times in the dashboard, 20–30 s after launch. Every trial had to run as long as asked, at 60 updates a second. Medians are shown, the trials' range beside them. Frame timing is 3 separate 8 s captures of each mode.

How Rune is driven

  • Ticks through AppHandle::update_if. Rune's per-frame poll, woken by wake_after, ran on frame boundaries up to 16 ms late and dropped about 5% of ticks. A timer thread now hands each tick to the UI thread through update_if, Rune's API for a timer or feed, and waits for it to run, as the other adapters' loops do. This changes the measurement: Rune now does the same 60 ticks a second of work as the others.
  • Updates apply at once (Tx::instant). Rune animates every layout and colour change on a 0.3 s spring by default. Each tick is applied instantly, as the other frameworks apply live data. Leaving the springs on would add animation frames the other frameworks don't draw.
  • sRGB blending (App::srgb_blend(true)). Rune blends translucency in linear light by default, so 10% opacity looked brighter than in the others. Its documented sRGB mode matches CSS and the other three. It is a surface format and a shader flag, with no extra pass, so it changes pixels, not cost.
  • Heavy's panel contents sit 1 pt in. A Rune border takes no layout space, while CSS, which the scene's geometry follows, places absolute children inside the border. The children are offset by the border's width so that everything lands on the same pixels. Geometry only; the cost doesn't change.
  • vlist scrolls through a small patch exposing Rune's own wheel path (rune-wheel.patch, 14 lines). Rune's public API can't set a vertical scroll offset, and only user wheel input moves a list. The patch adds Tx::wheel, which feeds the same Runtime::wheel_xy a real wheel event goes through, at once, between frames. Nothing else in Rune changes. This is what makes Rune's scroll and fling measurable; it adds no work of its own.
  • Jump reveals the row (nearest), not at the top. Rune's scroll_into_view scrolls just far enough to show a row, where the other adapters put the jumped-to row at the top. A jump still mounts and lays out the far rows, but the row lands at a different place in the viewport.
  • Rune's window isn't colour-matched by the window server. Its Metal layer is untagged (wgpu 30's default, which Rune keeps), so sRGB values reach the display unconverted and look slightly more saturated. The window server converts the other three, whose layers are tagged sRGB. Rune may skip that colour-matching work, which could lower its WindowServer cost. Kept as Rune ships it.
  • The vlist probe runs headless. Row heights are read from Rune's headless runtime, with the same font and 720 pt width, after revealing each row. A row's height doesn't depend on where it sits. Only the layout check uses this; it doesn't feed any measured figure.

What each figure is

  • CPU: the app process’s CPU time over the sample, as a percentage of one core (it can exceed 100).
  • WindowServer CPU: the CPU of macOS’s compositor, which puts every app’s frames on screen, over the same sample: what showing the app costs the system beside the app’s own CPU. It includes what WindowServer does anyway.
  • GPU power: the whole GPU’s energy over the sample, from the system’s energy model (IOReport), in milliwatts, less the desktop alone (measured each repeat). It counts everything the GPU does for the app, the window server’s compositing of its window included, so a framework is charged for how it presents its frames as well as for drawing them.
  • App GPU time (secondary): the GPU time macOS accounts to the app’s process, as cycles at the GPU’s mean clock. It includes the time from each submission to the GPU starting it, so an app that draws small frames often reads high. Kept for comparison with earlier runs.
  • Frame time: the 99th percentile of the intervals between frames shown on screen; at 60 updates a second, 16.7 ms is on time (8.3 ms for the animation, drawn at 120 Hz). Long frames are intervals over 25 ms.
  • Unfilled rows (the list): the window captured 10 times a second while scrolling and jumping; a capture counts when a stretch of the rows’ padding over 24 points shows the window’s background, where no row was drawn.
  • Memory: the process’s physical footprint (what Activity Monitor shows: resident memory plus GPU memory it owns), averaged over the sample.

Caveats

  • Compare within this run only: the same binaries measured hours apart read differently, so a cell is not comparable across runs, while the frameworks in one run share its session.
  • Idle memory is two-level: an idle window settles at one of two levels about 25 MB apart, launch to launch, as the Metal driver returns its startup memory. Read idle memory with its range.
  • MyGo is immediate mode: each frame it draws builds and draws its whole window, which is how MyGo apps work.
  • Binary size is not compared.
  • One machine, one session; a personal Mac in use, other applications kept running (the run waited until the machine was quiet). Windows and Linux are not compared here.

The full protocol, its noise and every other series are in the methodology. The numbers themselves: data.json, data.csv, and every trial under docs/results.

Edit on GitHub