a73x

b7e080ca

Make bench + profile workloads representative

a73x   2026-04-17 19:17

Commit message
Make bench + profile workloads representative

Replace the single-burst bench script with a bursty mixed workload
(typing, ls, scrollback, long lines, clears) separated by small sleeps
so the throttled render loop produces distinct frames per burst. Frame
capture goes from 5 to ~65 (debug) / ~180 (ReleaseSafe).

Drop the `sh -c` wrapper in `make profile` — it caused perf
--no-inherit to sample only the shell parent (6 samples), not waystty.
Running perf directly against the binary now captures ~1k samples.

Move workload to tests/bench/workload.sh so it can be tuned without a
zig recompile (embedded via addAnonymousImport). Baseline regenerated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Makefile
Old New
@@ -1,6 +1,6 @@
1 ZIG ?= zig 1 ZIG ?= zig
2 FLAMEGRAPH ?= flamegraph.pl 2 FLAMEGRAPH ?= inferno-flamegraph
3 STACKCOLLAPSE ?= stackcollapse-perf.pl 3 STACKCOLLAPSE ?= inferno-collapse-perf
4 4
5 .PHONY: build run test bench profile clean test-render golden-update bench-baseline bench-check 5 .PHONY: build run test bench profile clean test-render golden-update bench-baseline bench-check
6 6
@@ -23,8 +23,8 @@ bench: zig-out/bin/waystty
23 23
24 profile: 24 profile:
25 $(ZIG) build -Doptimize=ReleaseSafe 25 $(ZIG) build -Doptimize=ReleaseSafe
26 perf record -g -F 999 --no-inherit -o perf.data -- \ 26 WAYSTTY_BENCH=1 perf record -g -F 999 --no-inherit -o perf.data -- \
27 sh -c 'WAYSTTY_BENCH=1 ./zig-out/bin/waystty 2>bench.log' 27 ./zig-out/bin/waystty 2>bench.log
28 perf script -i perf.data \ 28 perf script -i perf.data \
29 | $(STACKCOLLAPSE) \ 29 | $(STACKCOLLAPSE) \
30 | $(FLAMEGRAPH) > flamegraph.svg 30 | $(FLAMEGRAPH) > flamegraph.svg
build.zig
Old New
@@ -86,6 +86,9 @@ pub fn build(b: *std.Build) void {
86 exe_mod.addImport("config", config_mod); 86 exe_mod.addImport("config", config_mod);
87 exe_mod.addImport("frame_loop", frame_loop_mod); 87 exe_mod.addImport("frame_loop", frame_loop_mod);
88 exe_mod.addImport("bench_stats", bench_stats_mod); 88 exe_mod.addImport("bench_stats", bench_stats_mod);
89 exe_mod.addAnonymousImport("bench_workload", .{
90 .root_source_file = b.path("tests/bench/workload.sh"),
91 });
89 92
90 const exe = b.addExecutable(.{ 93 const exe = b.addExecutable(.{
91 .name = "waystty", 94 .name = "waystty",
src/main.zig
Old New
@@ -284,7 +284,7 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
284 defer alloc.free(shell); 284 defer alloc.free(shell);
285 285
286 const bench_script: ?[:0]const u8 = if (is_bench) 286 const bench_script: ?[:0]const u8 = if (is_bench)
287 "echo warmup; sleep 0.2; seq 1 50000; find /usr/lib -name '*.so' 2>/dev/null | head -500; yes 'hello world' | head -2000; exit 0" 287 @embedFile("bench_workload")
288 else 288 else
289 null; 289 null;
290 290
tests/bench/baseline.json
Old New
@@ -1,38 +1,38 @@
1 { 1 {
2 "workload_sha": "066a95eee2d2f6195c0eb997e7e18a63f75b48010b538dd287056f948cc65005", 2 "workload_sha": "a79a3b3449f44938e56bc64555a95cc5234c73a1dc4b05c4e8cc17aa0209d1df",
3 "zig_version": "0.15.2", 3 "zig_version": "0.15.2",
4 "waystty_sha": "828c61f589b2bac3785e37531a094d6abb1f40ad", 4 "waystty_sha": "321b22803777191c86a97ad7ce7edba9b90b6c9e",
5 "frame_count": 5, 5 "frame_count": 65,
6 "sections": { 6 "sections": {
7 "snapshot": { 7 "snapshot": {
8 "min": 10, 8 "min": 6,
9 "avg": 201, 9 "avg": 42,
10 "p99": 214, 10 "p99": 216,
11 "max": 725 11 "max": 735
12 }, 12 },
13 "row_rebuild": { 13 "row_rebuild": {
14 "min": 115, 14 "min": 121,
15 "avg": 2075, 15 "avg": 1450,
16 "p99": 2166, 16 "p99": 3344,
17 "max": 5447 17 "max": 3383
18 }, 18 },
19 "atlas_upload": { 19 "atlas_upload": {
20 "min": 0, 20 "min": 0,
21 "avg": 10, 21 "avg": 4,
22 "p99": 0, 22 "p99": 47,
23 "max": 50 23 "max": 57
24 }, 24 },
25 "instance_upload": { 25 "instance_upload": {
26 "min": 4, 26 "min": 3,
27 "avg": 37, 27 "avg": 17,
28 "p99": 21, 28 "p99": 75,
29 "max": 144 29 "max": 83
30 }, 30 },
31 "gpu_submit": { 31 "gpu_submit": {
32 "min": 37, 32 "min": 22,
33 "avg": 58, 33 "avg": 48,
34 "p99": 66, 34 "p99": 99,
35 "max": 79 35 "max": 106
36 } 36 }
37 } 37 }
38 } 38 }
38 \ No newline at end of file 38 \ No newline at end of file
tests/bench/workload.sh
Old New
@@ -0,0 +1,49 @@
1 #!/bin/sh
2 # waystty bench workload — bursty mixed traffic so the throttled render
3 # loop produces distinct frames per burst (instead of one coalesced dump).
4
5 printf 'waystty bench workload\n'
6 sleep 0.1
7
8 # Phase 1: typing-like — small lines, small gaps (~60 frames)
9 i=1
10 while [ $i -le 60 ]; do
11 printf '$ echo hello %d\nhello %d\n' $i $i
12 sleep 0.02
13 i=$((i + 1))
14 done
15
16 # Phase 2: ls-style bursts (~30 frames)
17 i=1
18 while [ $i -le 30 ]; do
19 ls /usr/lib 2>/dev/null | head -80
20 sleep 0.03
21 i=$((i + 1))
22 done
23
24 # Phase 3: scrollback storms (~40 frames)
25 i=1
26 while [ $i -le 40 ]; do
27 seq 1 500
28 sleep 0.025
29 i=$((i + 1))
30 done
31
32 # Phase 4: long-line wrapping (~30 frames)
33 long=$(printf 'x%.0s' $(seq 1 160))
34 i=1
35 while [ $i -le 30 ]; do
36 printf '%s\n%s\n%s\n' "$long" "$long" "$long"
37 sleep 0.03
38 i=$((i + 1))
39 done
40
41 # Phase 5: screen-clear + redraw (~20 frames)
42 i=1
43 while [ $i -le 20 ]; do
44 printf '\033[2J\033[H=== iter %d ===\n' $i
45 sleep 0.04
46 i=$((i + 1))
47 done
48
49 exit 0