Headless mux idle benchmark
On this page
Headless mux idle benchmark#
The repeatable workload in scripts/bench_restored_mux.py measures the mux and
its PTY children without a GUI client. It reports proportional set size (PSS),
RSS, private memory, swap, process and thread counts, file descriptors, CPU
time, context switches, faults, and read and write syscalls.
Representative restored session#
The restored fixture is based on the shape of the development host's active session on 2026-08-24, scaled from 12 to 20 harness workspaces:
- 20 tabs, each with one harness-shaped PTY
- 7 tabs with a second shell PTY, for 27 PTYs total
- 8 parked tabs
- one window and one workspace
- deterministic
sleep infinitypayloads with empty scrollback
The fixture exercises persisted tab order, split trees, active panes, parked tabs, PTY creation, and the first periodic save. It does not launch an agent provider. Provider topology has its own benchmark because Codex memory would otherwise hide the mux result.
Run it with release binaries:
uv run --no-project scripts/bench_restored_mux.py \
--setup restore \
--server-bin target/release/wakterm-mux-server \
--cli-bin target/release/wakterm \
--tabs 20 --split-tabs 7 --parked-tabs 8 \
--runs 3 --settle-seconds 10 --sample-seconds 65 \
--output wakterm-restored.json
The 65-second sample intentionally crosses Wakterm's 60-second persistence
interval. The sampler reads /proc and smaps_rollup; it does not poll the mux
during the idle window.
Median of three runs on the host described below:
| Metric | Result |
|---|---|
| Restore 20 tabs and 27 PTYs | 149.0 ms |
| Mux PSS | 30.94 MiB |
| Mux plus 27 PTYs PSS | 34.44 MiB |
| Mux private memory | 30.89 MiB |
| Mux CPU time during sample | 1.05 ms |
| One-core CPU | 0.0016% |
| Read and write syscalls | 7 and 5 |
| Voluntary context switches | 4 |
| Major faults and swap | 0 and 0 |
Wakterm and upstream WezTerm#
The cross-project comparison uses the same cold spawn workload because Wakterm's v5 persisted layout is a fork-specific input. Each server gets 20 tabs with one sleeping PTY per tab. This compares headless mux and PTY steady state, not restoration behavior, terminal rendering, GPU memory, active output, or scrollback retention.
Measured on 2026-08-24:
- AMD Ryzen 9 3950X, 32 logical CPUs, 31 GiB RAM
- Fedora 44, Linux 7.1.9
- rustc 1.95.0, release builds
- Wakterm
6583a2e85 - upstream WezTerm
f93d90350 - 10-second settle, 65-second sample, median of three runs
| Metric | Wakterm | WezTerm |
|---|---|---|
| Cold setup | 558.7 ms | 532.7 ms |
| Mux PSS | 29.62 MiB | 32.67 MiB |
| Mux plus 20 PTYs PSS | 32.15 MiB | 35.20 MiB |
| Mux private memory | 29.58 MiB | 32.63 MiB |
| CPU time during sample | 0.76 ms | below measurement resolution |
| One-core CPU | 0.0012% | below measurement resolution |
| Mux threads | 95 | 86 |
| Mux file descriptors | 116 | 110 |
| Swap | 0 | 0 |
Wakterm used 3.05 MiB less PSS for both the mux and full process tree in this workload. Its cold setup took 26 ms longer. The measured Wakterm CPU includes the periodic persistence pass and is still about one thousandth of one CPU core.
Run the comparison with the same script and an upstream release build:
uv run --no-project scripts/bench_restored_mux.py \
--flavor wakterm --setup spawn \
--server-bin target/release/wakterm-mux-server \
--cli-bin target/release/wakterm \
--tabs 20 --runs 3 --settle-seconds 10 --sample-seconds 65
uv run --no-project scripts/bench_restored_mux.py \
--flavor wezterm --setup spawn \
--server-bin /path/to/wezterm-mux-server \
--cli-bin /path/to/wezterm \
--tabs 20 --runs 3 --settle-seconds 10 --sample-seconds 65
PSS is the primary memory number because it divides shared mappings among the processes that use them. Summed RSS is also retained in the JSON output, but it double-counts shared pages.