detached 120730e

docs(performance): refresh measurements for tagged dependencies

commit
120730e2963773a15707ef3b6ee9e77735ae138c
author
brice · · 2026-09-30 04:38 UTC
parent
2e4532d
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +35 -29
M docs/performance.md +35 -29
@@ -2,36 +2,36 @@
22
33 ## CPU budgets
44
5-Measured: **2026-09-30, 06:14–06:16 CEST (UTC+02:00)**. Implementation commit: **`7e46072588c8dce90eaa8bc11f89a5564f182b04`**.
5+Measured: **2026-09-30, 06:32–06:34 CEST (UTC+02:00)**. Measured commit: **`9064a730c898b48f967b3f2228fb705474b4fdeb`**.
66
7-AMD Ryzen 9 7900X3D; Go `go1.27.1-X:nodwarf5 linux/amd64`. Command: `CGO_ENABLED=0 GOWORK=off go test -run '^$' -bench . -benchmem -count=5` in the indicated packages. Entries are medians of five runs. Budgets allow roughly twice the measured medians; zero-allocation paths stay at zero. CPU numbers vary with machine load.
7+AMD Ryzen 9 7900X3D; Go `go1.27.1-X:nodwarf5 linux/amd64`. Command: `CGO_ENABLED=0 GOWORK=off go test -mod=readonly -p=1 -run '^$' -bench . -benchmem -count=5 ./internal/ui ./internal/render ./internal/layout ./internal/text ./internal/css`. Package benchmarks run serially; external profiling runs are separate. Entries are medians of five runs. Budgets allow roughly twice the measured medians; zero-allocation paths stay at zero. CPU numbers vary with machine load.
88
9-The demo-frame benchmark builds a headless home-view tree, computes layout and produces a display list after warmup. Prepare uses a representative text/box command mix and excludes GPU submission. Paint uses 100 cards with two shadows and text; ListBatches uses 2,000 quads with interleaved images. ListBufferReuse includes initial buffer allocation amortized over the run, so B/op is not a steady-state allocation cost.
9+The demo-frame benchmark builds a headless home-view tree, computes layout and produces a display list after warmup. Prepare uses a representative text/box command mix and excludes GPU submission. Paint uses 100 cards with two shadows and text; ListBatches uses 2,000 quads with interleaved images. ListBufferReuse and LayoutPaintTree warm their buffers and text cache before resetting the timer; their figures measure steady state.
1010
1111 | Package / benchmark | Median ns/op | Median B/op | Median allocs/op | Budget ns/op | Budget B/op | Budget allocs/op |
1212 |---|---:|---:|---:|---:|---:|---:|
13-| internal/ui / DemoFrame | 25,865 | 39,272 | 193 | 55,000 | 80,000 | 500 |
14-| render / Prepare | 49,142 | 85,568 | 379 | 100,000 | 175,000 | 800 |
15-| render / PrepareBoxes | 67,026 | 229,377 | 1 | 140,000 | 460,000 | 2 |
16-| render / ListBatches | 112,291 | 420,571 | 2 | 230,000 | 850,000 | 4 |
17-| render / ListBufferReuse | 63,299 | 69 | 0 | 130,000 | 150 | 0 |
18-| layout / Paint | 115,660 | 479,360 | 4 | 240,000 | 960,000 | 8 |
19-| layout / LayoutPaintTree | 186,338 | 552,820 | 343 | 380,000 | 1,110,000 | 700 |
20-| layout / Layout1000 | 664,176 | 731,684 | 1,027 | 1,350,000 | 1,470,000 | 2,100 |
21-| text / AtlasWarmLookup | 31.84 | 0 | 0 | 65 | 0 | 0 |
22-| text / RasterDistinct1000 | 4,187,468 | 8,566,132 | 16,784 | 8,500,000 | 17,200,000 | 34,000 |
23-| text / ShapeParagraph (uncached) | 245,802 | 300,149 | 950 | 500,000 | 610,000 | 1,900 |
24-| text / ShapeParagraphCached | 79.34 | 0 | 0 | 160 | 0 | 0 |
25-| text / AtlasInsert | 564.9 | 968 | 3 | 1,150 | 2,000 | 6 |
26-| css / Engine/cold | 2,358,611 | 1,964,619 | 5,669 | 4,800,000 | 4,000,000 | 11,400 |
27-| css / Engine/warm | 100,682 | 1 | 0 | 205,000 | 2 | 0 |
28-| css / Engine/state-change | 348,826 | 149,107 | 363 | 700,000 | 300,000 | 750 |
29-
30-`TestDemoFrameAllocationBudget` checks the 500 allocs/op limit with `testing.AllocsPerRun`. Focused tests also check constant quad allocation, bounded paint allocation, allocation-free warm list-buffer reuse, and allocation-free idle wait results. The other table budgets are reference targets, not automated assertions.
13+| internal/ui / DemoFrame | 25,742 | 39,272 | 193 | 55,000 | 80,000 | 500 |
14+| render / Prepare | 43,668 | 85,568 | 379 | 100,000 | 175,000 | 800 |
15+| render / PrepareBoxes | 67,383 | 229,378 | 1 | 140,000 | 460,000 | 2 |
16+| render / ListBatches | 111,578 | 420,481 | 2 | 230,000 | 850,000 | 4 |
17+| render / ListBufferReuse | 63,482 | 0 | 0 | 130,000 | 0 | 0 |
18+| layout / Paint | 117,118 | 479,360 | 4 | 240,000 | 960,000 | 8 |
19+| layout / LayoutPaintTree | 183,966 | 546,648 | 313 | 380,000 | 1,100,000 | 650 |
20+| layout / Layout1000 | 667,025 | 731,673 | 1,027 | 1,350,000 | 1,470,000 | 2,100 |
21+| text / AtlasWarmLookup | 31.78 | 0 | 0 | 65 | 0 | 0 |
22+| text / RasterDistinct1000 | 4,186,372 | 8,566,134 | 16,784 | 8,500,000 | 17,200,000 | 34,000 |
23+| text / ShapeParagraph (uncached) | 231,623 | 280,987 | 895 | 500,000 | 570,000 | 1,800 |
24+| text / ShapeParagraphCached | 80.29 | 0 | 0 | 160 | 0 | 0 |
25+| text / AtlasInsert | 587.0 | 968 | 3 | 1,150 | 2,000 | 6 |
26+| css / Engine/cold | 2,379,997 | 1,964,628 | 5,669 | 4,800,000 | 4,000,000 | 11,400 |
27+| css / Engine/warm | 100,242 | 1 | 0 | 205,000 | 2 | 0 |
28+| css / Engine/state-change | 351,901 | 149,105 | 363 | 700,000 | 300,000 | 750 |
29+
30+`TestDemoFrameAllocationBudget` checks the 500 allocs/op limit with `testing.AllocsPerRun`. Focused tests also check constant quad allocation, bounded paint allocation, allocation-free warm list-buffer reuse, and allocation-free idle wait results. The real-ioctl allocation test is opt-in via `NEFERGUI_RENDER_NODE`. The other table budgets are reference targets, not automated assertions.
3131
3232 Frame construction limits allocation churn through:
3333
34-- one pre-sized quad array per prepared frame, preserving independent frame lifetimes;
34+- a detached quad array initially reserved up to 512 quads; larger visible frames grow after culling, so offscreen content cannot force an unbounded speculative allocation;
3535 - detached display-list storage sized once for commands, shadows, runs and glyphs;
3636 - a session-owned instance/batch buffer, consumed synchronously before reuse, with image references cleared after use and oversized storage discarded when smaller frames arrive;
3737 - font family normalization at font load and identity path keys computed once per element;
@@ -39,7 +39,7 @@ Frame construction limits allocation churn through:
3939
4040 `Run` builds a frame only on input or a redraw request. Idle frame construction stops. Expected release-wait timeouts return without constructing errors; real ioctl failures retain their context and wrapped errno.
4141
42-On the same implementation commit, measured **2026-09-30, 06:15–06:16 CEST**, `BenchmarkWaitPointIdle` on an unsignaled real DRM timeline took a median **21,567,553 ns/op, 0 B/op, 0 allocs/op**. This includes the requested 20 ms timeout, not active CPU time:
42+On the same implementation commit, measured **2026-09-30, 06:34 CEST**, `BenchmarkWaitPointIdle` on an unsignaled real DRM timeline took a median **21,370,548 ns/op, 0 B/op, 0 allocs/op**. This includes the requested 20 ms timeout, not active CPU time:
4343
4444 ```sh
4545 NEFERGUI_RENDER_NODE=/dev/dri/renderD128 CGO_ENABLED=0 GOWORK=off \
@@ -55,19 +55,23 @@ go tool pprof -sample_index=alloc_objects -top -cum mem.out
5555
5656 ## Memory as a dependency
5757
58-Measured: **2026-09-30, 06:12–06:14 CEST (UTC+02:00)**. Implementation commit: **`7e46072588c8dce90eaa8bc11f89a5564f182b04`**. Comparison baseline: **`1488e4a390e93603976ae3f5e9ac3fdb1bd00c1a`**, measured **2026-09-30, 06:06–06:10 CEST**.
58+Measured: **2026-09-30, 06:34–06:36 CEST (UTC+02:00)**. Measured commit: **`9064a730c898b48f967b3f2228fb705474b4fdeb`**. Comparison baseline: **`1488e4a390e93603976ae3f5e9ac3fdb1bd00c1a`**, measured **2026-09-30, 06:06–06:10 CEST**.
5959
6060 An external Go module with minimal-counter and demo views, a 960×640 window at scale 1, and a private headless NeferWL compositor was profiled on AMD/RADV. Stack: Go `go1.27.1-X:nodwarf5 linux/amd64`, Mesa/RADV 26.2.3, NeferWL `1d16b83bf90f9e8189ad21b27772382c96b9f9a8`. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages.
6161
6262 | Measurement | Minimal view | Demo view |
6363 |---|---:|---:|
64-| Live Go heap after 1,000 frames | 5.16 MiB | 5.29 MiB |
65-| Live Go heap after 3,000 frames | 5.19 MiB | 5.31 MiB |
66-| Process RSS / PSS after 1,000 frames | 62 / 39 MiB | 58 / 39 MiB |
64+| Live Go heap after 1,000 frames | 5.19 MiB | 5.32 MiB |
65+| Baseline live Go heap after 1,000 frames | 5.17 MiB | 5.27 MiB |
66+| Live Go heap after 3,000 frames | 5.23 MiB | 5.34 MiB |
67+| Baseline live Go heap after 3,000 frames | 5.20 MiB | 5.31 MiB |
68+| Process RSS / PSS after 1,000 frames | 65 / 42 MiB | 59 / 40 MiB |
69+| Baseline process RSS / PSS after 1,000 frames | 63 / 40 MiB | 60 / 41 MiB |
70+| GPU VRAM / GTT with three buffers, current and baseline | 41 / 4 MiB | 41 / 4 MiB |
6771 | Temporary allocations per rendered frame | about 36 KiB | about 136 KiB |
6872 | Baseline temporary allocations per rendered frame | about 61 KiB | about 238 KiB |
6973
70-Heap/RSS/PSS use the default Go profiling rate. Allocation figures use separate `GODEBUG=memprofilerate=1` runs: subtract cumulative profiles at frames 1 and 1,000, exclude stacks containing the measurement sampler or `runtime/pprof`, sum the remaining flat allocated bytes, then divide by 999 frames. These runs recorded about **42–43% less allocation churn** than the baseline. They do not demonstrate an equivalent reduction in RSS or frame latency. Single-run process-memory values vary with runtime and driver behavior.
74+Heap/RSS/PSS use the default Go profiling rate. Allocation figures use separate `GODEBUG=memprofilerate=1` runs: subtract cumulative profiles at frames 1 and 1,000, exclude stacks containing the measurement sampler or `runtime/pprof`, sum the remaining flat allocated bytes, then divide by 999 frames. These runs recorded about **41–43% less allocation churn** than the baseline. They do not demonstrate an equivalent reduction in RSS or frame latency. Single-run process-memory values vary with runtime and driver behavior.
7175
7276 The minimal view starts at about 0.75 MiB live Go heap, reaches 5.1 MiB after the first frame, and returns to about 0.9 MiB after closing. No sustained live-heap growth was observed over 3,000 frames. Retained heap stayed close to baseline; the session's reusable conversion buffers retain a small amount of storage. Driver mappings and Go heap capacity can remain resident after closing; RSS is not a leak measurement on its own.
7377
@@ -75,6 +79,8 @@ DRM counters reported about 41 MiB VRAM and 4 MiB GTT once all three presentatio
7579
7680 A separate approximately 20-second idle profile recorded about **91 KiB** allocated under `syncobj.WaitPoint` in the baseline and **no allocations attributed to that path** on the measured implementation. Other runtime and consumer instrumentation allocations remain; this is not a claim that the whole process allocates nothing at idle.
7781
78-Prepared quads and layout painting still allocate detached outputs. Glyph rasterization and glyph-key hashing also appear in cumulative allocation profiles. `NEFERGUI_DEBUG_DIR` enables readbacks and PNG work; leave it unset when measuring ordinary application cost.
82+The measured commit includes `purego-vulkan` v0.6.0, `wlturbo` v0.3.0 and `typesetting` v0.3.5. The subsequent `2e4532d` commit adds an empty-glyph regression test and raises the minimum compositor version checked at startup; it does not change the measured frame paths on this version-6 compositor. The comparison therefore includes both library optimizations and dependency updates, not isolated effects for each.
83+
84+Prepared quads and layout painting still allocate detached outputs. Editor and indicator command insertion can also reallocate the display list; those UI-owned costs are included in the demo measurements and are not optimized here. Glyph rasterization and glyph-key hashing also appear in cumulative allocation profiles. `NEFERGUI_DEBUG_DIR` enables readbacks and PNG work; leave it unset when measuring ordinary application cost.
7985
8086 Use `pprof`'s `alloc_space` to find cumulative allocation churn and `inuse_space` after GC to inspect retained Go memory. Use `/proc/<pid>/smaps_rollup` for RSS/PSS and DRM fdinfo for GPU counters; heap profiles do not include driver or GPU memory.
@@ -2,36 +2,36 @@
2 2
3 ## CPU budgets3 ## CPU budgets
4 4
5-Measured: **2026-09-30, 06:14–06:16 CEST (UTC+02:00)**. Implementation commit: **`7e46072588c8dce90eaa8bc11f89a5564f182b04`**.5+Measured: **2026-09-30, 06:32–06:34 CEST (UTC+02:00)**. Measured commit: **`9064a730c898b48f967b3f2228fb705474b4fdeb`**.
6 6
7-AMD Ryzen 9 7900X3D; Go `go1.27.1-X:nodwarf5 linux/amd64`. Command: `CGO_ENABLED=0 GOWORK=off go test -run '^$' -bench . -benchmem -count=5` in the indicated packages. Entries are medians of five runs. Budgets allow roughly twice the measured medians; zero-allocation paths stay at zero. CPU numbers vary with machine load.7+AMD Ryzen 9 7900X3D; Go `go1.27.1-X:nodwarf5 linux/amd64`. Command: `CGO_ENABLED=0 GOWORK=off go test -mod=readonly -p=1 -run '^$' -bench . -benchmem -count=5 ./internal/ui ./internal/render ./internal/layout ./internal/text ./internal/css`. Package benchmarks run serially; external profiling runs are separate. Entries are medians of five runs. Budgets allow roughly twice the measured medians; zero-allocation paths stay at zero. CPU numbers vary with machine load.
8 8
9-The demo-frame benchmark builds a headless home-view tree, computes layout and produces a display list after warmup. Prepare uses a representative text/box command mix and excludes GPU submission. Paint uses 100 cards with two shadows and text; ListBatches uses 2,000 quads with interleaved images. ListBufferReuse includes initial buffer allocation amortized over the run, so B/op is not a steady-state allocation cost.9+The demo-frame benchmark builds a headless home-view tree, computes layout and produces a display list after warmup. Prepare uses a representative text/box command mix and excludes GPU submission. Paint uses 100 cards with two shadows and text; ListBatches uses 2,000 quads with interleaved images. ListBufferReuse and LayoutPaintTree warm their buffers and text cache before resetting the timer; their figures measure steady state.
10 10
11 | Package / benchmark | Median ns/op | Median B/op | Median allocs/op | Budget ns/op | Budget B/op | Budget allocs/op |11 | Package / benchmark | Median ns/op | Median B/op | Median allocs/op | Budget ns/op | Budget B/op | Budget allocs/op |
12 |---|---:|---:|---:|---:|---:|---:|12 |---|---:|---:|---:|---:|---:|---:|
13-| internal/ui / DemoFrame | 25,865 | 39,272 | 193 | 55,000 | 80,000 | 500 |13+| internal/ui / DemoFrame | 25,742 | 39,272 | 193 | 55,000 | 80,000 | 500 |
14-| render / Prepare | 49,142 | 85,568 | 379 | 100,000 | 175,000 | 800 |14+| render / Prepare | 43,668 | 85,568 | 379 | 100,000 | 175,000 | 800 |
15-| render / PrepareBoxes | 67,026 | 229,377 | 1 | 140,000 | 460,000 | 2 |15+| render / PrepareBoxes | 67,383 | 229,378 | 1 | 140,000 | 460,000 | 2 |
16-| render / ListBatches | 112,291 | 420,571 | 2 | 230,000 | 850,000 | 4 |16+| render / ListBatches | 111,578 | 420,481 | 2 | 230,000 | 850,000 | 4 |
17-| render / ListBufferReuse | 63,299 | 69 | 0 | 130,000 | 150 | 0 |17+| render / ListBufferReuse | 63,482 | 0 | 0 | 130,000 | 0 | 0 |
18-| layout / Paint | 115,660 | 479,360 | 4 | 240,000 | 960,000 | 8 |18+| layout / Paint | 117,118 | 479,360 | 4 | 240,000 | 960,000 | 8 |
19-| layout / LayoutPaintTree | 186,338 | 552,820 | 343 | 380,000 | 1,110,000 | 700 |19+| layout / LayoutPaintTree | 183,966 | 546,648 | 313 | 380,000 | 1,100,000 | 650 |
20-| layout / Layout1000 | 664,176 | 731,684 | 1,027 | 1,350,000 | 1,470,000 | 2,100 |20+| layout / Layout1000 | 667,025 | 731,673 | 1,027 | 1,350,000 | 1,470,000 | 2,100 |
21-| text / AtlasWarmLookup | 31.84 | 0 | 0 | 65 | 0 | 0 |21+| text / AtlasWarmLookup | 31.78 | 0 | 0 | 65 | 0 | 0 |
22-| text / RasterDistinct1000 | 4,187,468 | 8,566,132 | 16,784 | 8,500,000 | 17,200,000 | 34,000 |22+| text / RasterDistinct1000 | 4,186,372 | 8,566,134 | 16,784 | 8,500,000 | 17,200,000 | 34,000 |
23-| text / ShapeParagraph (uncached) | 245,802 | 300,149 | 950 | 500,000 | 610,000 | 1,900 |23+| text / ShapeParagraph (uncached) | 231,623 | 280,987 | 895 | 500,000 | 570,000 | 1,800 |
24-| text / ShapeParagraphCached | 79.34 | 0 | 0 | 160 | 0 | 0 |24+| text / ShapeParagraphCached | 80.29 | 0 | 0 | 160 | 0 | 0 |
25-| text / AtlasInsert | 564.9 | 968 | 3 | 1,150 | 2,000 | 6 |25+| text / AtlasInsert | 587.0 | 968 | 3 | 1,150 | 2,000 | 6 |
26-| css / Engine/cold | 2,358,611 | 1,964,619 | 5,669 | 4,800,000 | 4,000,000 | 11,400 |26+| css / Engine/cold | 2,379,997 | 1,964,628 | 5,669 | 4,800,000 | 4,000,000 | 11,400 |
27-| css / Engine/warm | 100,682 | 1 | 0 | 205,000 | 2 | 0 |27+| css / Engine/warm | 100,242 | 1 | 0 | 205,000 | 2 | 0 |
28-| css / Engine/state-change | 348,826 | 149,107 | 363 | 700,000 | 300,000 | 750 |28+| css / Engine/state-change | 351,901 | 149,105 | 363 | 700,000 | 300,000 | 750 |
29-29+
30-`TestDemoFrameAllocationBudget` checks the 500 allocs/op limit with `testing.AllocsPerRun`. Focused tests also check constant quad allocation, bounded paint allocation, allocation-free warm list-buffer reuse, and allocation-free idle wait results. The other table budgets are reference targets, not automated assertions.30+`TestDemoFrameAllocationBudget` checks the 500 allocs/op limit with `testing.AllocsPerRun`. Focused tests also check constant quad allocation, bounded paint allocation, allocation-free warm list-buffer reuse, and allocation-free idle wait results. The real-ioctl allocation test is opt-in via `NEFERGUI_RENDER_NODE`. The other table budgets are reference targets, not automated assertions.
31 31
32 Frame construction limits allocation churn through:32 Frame construction limits allocation churn through:
33 33
34-- one pre-sized quad array per prepared frame, preserving independent frame lifetimes;34+- a detached quad array initially reserved up to 512 quads; larger visible frames grow after culling, so offscreen content cannot force an unbounded speculative allocation;
35 - detached display-list storage sized once for commands, shadows, runs and glyphs;35 - detached display-list storage sized once for commands, shadows, runs and glyphs;
36 - a session-owned instance/batch buffer, consumed synchronously before reuse, with image references cleared after use and oversized storage discarded when smaller frames arrive;36 - a session-owned instance/batch buffer, consumed synchronously before reuse, with image references cleared after use and oversized storage discarded when smaller frames arrive;
37 - font family normalization at font load and identity path keys computed once per element;37 - font family normalization at font load and identity path keys computed once per element;
@@ -39,7 +39,7 @@ Frame construction limits allocation churn through:
39 39
40 `Run` builds a frame only on input or a redraw request. Idle frame construction stops. Expected release-wait timeouts return without constructing errors; real ioctl failures retain their context and wrapped errno.40 `Run` builds a frame only on input or a redraw request. Idle frame construction stops. Expected release-wait timeouts return without constructing errors; real ioctl failures retain their context and wrapped errno.
41 41
42-On the same implementation commit, measured **2026-09-30, 06:15–06:16 CEST**, `BenchmarkWaitPointIdle` on an unsignaled real DRM timeline took a median **21,567,553 ns/op, 0 B/op, 0 allocs/op**. This includes the requested 20 ms timeout, not active CPU time:42+On the same implementation commit, measured **2026-09-30, 06:34 CEST**, `BenchmarkWaitPointIdle` on an unsignaled real DRM timeline took a median **21,370,548 ns/op, 0 B/op, 0 allocs/op**. This includes the requested 20 ms timeout, not active CPU time:
43 43
44 ```sh44 ```sh
45 NEFERGUI_RENDER_NODE=/dev/dri/renderD128 CGO_ENABLED=0 GOWORK=off \45 NEFERGUI_RENDER_NODE=/dev/dri/renderD128 CGO_ENABLED=0 GOWORK=off \
@@ -55,19 +55,23 @@ go tool pprof -sample_index=alloc_objects -top -cum mem.out
55 55
56 ## Memory as a dependency56 ## Memory as a dependency
57 57
58-Measured: **2026-09-30, 06:12–06:14 CEST (UTC+02:00)**. Implementation commit: **`7e46072588c8dce90eaa8bc11f89a5564f182b04`**. Comparison baseline: **`1488e4a390e93603976ae3f5e9ac3fdb1bd00c1a`**, measured **2026-09-30, 06:06–06:10 CEST**.58+Measured: **2026-09-30, 06:34–06:36 CEST (UTC+02:00)**. Measured commit: **`9064a730c898b48f967b3f2228fb705474b4fdeb`**. Comparison baseline: **`1488e4a390e93603976ae3f5e9ac3fdb1bd00c1a`**, measured **2026-09-30, 06:06–06:10 CEST**.
59 59
60 An external Go module with minimal-counter and demo views, a 960×640 window at scale 1, and a private headless NeferWL compositor was profiled on AMD/RADV. Stack: Go `go1.27.1-X:nodwarf5 linux/amd64`, Mesa/RADV 26.2.3, NeferWL `1d16b83bf90f9e8189ad21b27772382c96b9f9a8`. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages.60 An external Go module with minimal-counter and demo views, a 960×640 window at scale 1, and a private headless NeferWL compositor was profiled on AMD/RADV. Stack: Go `go1.27.1-X:nodwarf5 linux/amd64`, Mesa/RADV 26.2.3, NeferWL `1d16b83bf90f9e8189ad21b27772382c96b9f9a8`. Debug readbacks were disabled. Live Go heap was sampled after forced GC; RSS includes shared driver libraries, while PSS apportions shared pages.
61 61
62 | Measurement | Minimal view | Demo view |62 | Measurement | Minimal view | Demo view |
63 |---|---:|---:|63 |---|---:|---:|
64-| Live Go heap after 1,000 frames | 5.16 MiB | 5.29 MiB |64+| Live Go heap after 1,000 frames | 5.19 MiB | 5.32 MiB |
65-| Live Go heap after 3,000 frames | 5.19 MiB | 5.31 MiB |65+| Baseline live Go heap after 1,000 frames | 5.17 MiB | 5.27 MiB |
66-| Process RSS / PSS after 1,000 frames | 62 / 39 MiB | 58 / 39 MiB |66+| Live Go heap after 3,000 frames | 5.23 MiB | 5.34 MiB |
67+| Baseline live Go heap after 3,000 frames | 5.20 MiB | 5.31 MiB |
68+| Process RSS / PSS after 1,000 frames | 65 / 42 MiB | 59 / 40 MiB |
69+| Baseline process RSS / PSS after 1,000 frames | 63 / 40 MiB | 60 / 41 MiB |
70+| GPU VRAM / GTT with three buffers, current and baseline | 41 / 4 MiB | 41 / 4 MiB |
67 | Temporary allocations per rendered frame | about 36 KiB | about 136 KiB |71 | Temporary allocations per rendered frame | about 36 KiB | about 136 KiB |
68 | Baseline temporary allocations per rendered frame | about 61 KiB | about 238 KiB |72 | Baseline temporary allocations per rendered frame | about 61 KiB | about 238 KiB |
69 73
70-Heap/RSS/PSS use the default Go profiling rate. Allocation figures use separate `GODEBUG=memprofilerate=1` runs: subtract cumulative profiles at frames 1 and 1,000, exclude stacks containing the measurement sampler or `runtime/pprof`, sum the remaining flat allocated bytes, then divide by 999 frames. These runs recorded about **42–43% less allocation churn** than the baseline. They do not demonstrate an equivalent reduction in RSS or frame latency. Single-run process-memory values vary with runtime and driver behavior.74+Heap/RSS/PSS use the default Go profiling rate. Allocation figures use separate `GODEBUG=memprofilerate=1` runs: subtract cumulative profiles at frames 1 and 1,000, exclude stacks containing the measurement sampler or `runtime/pprof`, sum the remaining flat allocated bytes, then divide by 999 frames. These runs recorded about **41–43% less allocation churn** than the baseline. They do not demonstrate an equivalent reduction in RSS or frame latency. Single-run process-memory values vary with runtime and driver behavior.
71 75
72 The minimal view starts at about 0.75 MiB live Go heap, reaches 5.1 MiB after the first frame, and returns to about 0.9 MiB after closing. No sustained live-heap growth was observed over 3,000 frames. Retained heap stayed close to baseline; the session's reusable conversion buffers retain a small amount of storage. Driver mappings and Go heap capacity can remain resident after closing; RSS is not a leak measurement on its own.76 The minimal view starts at about 0.75 MiB live Go heap, reaches 5.1 MiB after the first frame, and returns to about 0.9 MiB after closing. No sustained live-heap growth was observed over 3,000 frames. Retained heap stayed close to baseline; the session's reusable conversion buffers retain a small amount of storage. Driver mappings and Go heap capacity can remain resident after closing; RSS is not a leak measurement on its own.
73 77
@@ -75,6 +79,8 @@ DRM counters reported about 41 MiB VRAM and 4 MiB GTT once all three presentatio
75 79
76 A separate approximately 20-second idle profile recorded about **91 KiB** allocated under `syncobj.WaitPoint` in the baseline and **no allocations attributed to that path** on the measured implementation. Other runtime and consumer instrumentation allocations remain; this is not a claim that the whole process allocates nothing at idle.80 A separate approximately 20-second idle profile recorded about **91 KiB** allocated under `syncobj.WaitPoint` in the baseline and **no allocations attributed to that path** on the measured implementation. Other runtime and consumer instrumentation allocations remain; this is not a claim that the whole process allocates nothing at idle.
77 81
78-Prepared quads and layout painting still allocate detached outputs. Glyph rasterization and glyph-key hashing also appear in cumulative allocation profiles. `NEFERGUI_DEBUG_DIR` enables readbacks and PNG work; leave it unset when measuring ordinary application cost.82+The measured commit includes `purego-vulkan` v0.6.0, `wlturbo` v0.3.0 and `typesetting` v0.3.5. The subsequent `2e4532d` commit adds an empty-glyph regression test and raises the minimum compositor version checked at startup; it does not change the measured frame paths on this version-6 compositor. The comparison therefore includes both library optimizations and dependency updates, not isolated effects for each.
83+
84+Prepared quads and layout painting still allocate detached outputs. Editor and indicator command insertion can also reallocate the display list; those UI-owned costs are included in the demo measurements and are not optimized here. Glyph rasterization and glyph-key hashing also appear in cumulative allocation profiles. `NEFERGUI_DEBUG_DIR` enables readbacks and PNG work; leave it unset when measuring ordinary application cost.
79 85
80 Use `pprof`'s `alloc_space` to find cumulative allocation churn and `inuse_space` after GC to inspect retained Go memory. Use `/proc/<pid>/smaps_rollup` for RSS/PSS and DRM fdinfo for GPU counters; heap profiles do not include driver or GPU memory.86 Use `pprof`'s `alloc_space` to find cumulative allocation churn and `inuse_space` after GC to inspect retained Go memory. Use `/proc/<pid>/smaps_rollup` for RSS/PSS and DRM fdinfo for GPU counters; heap profiles do not include driver or GPU memory.

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 1

Tags 12

↑↓ moveenter openesc close