# Performance All numbers below were measured, not estimated. Re-run them on your own hardware before relying on them; filesystem caches dominate scan timings. ## Test machine (2026-10-02) | | | |---|---| | CPU | Intel Core i7-7700 @ 3.60 GHz, 4 cores / 8 threads | | RAM | 32 GiB | | OS | Linux 7.0, Go 1.27.1 | | Filesystem | ext4 on Linux software RAID (`/dev/md2`) over two 7200 rpm SATA HDDs | ## Scanner Dataset: `~/go/pkg/mod` — 388,307 files + 65,518 directories (458,510 inventory nodes), 10.5 GiB allocated. **Warm cache only**: dropping the page cache needs root, which was not available, so these measure CPU and syscall cost, not disk seeks. Cold-cache behaviour on HDDs will be dominated by seek time; expect fewer workers to be optimal there. `mapsize --no-ui --workers N ~/go/pkg/mod`, wall time, 3 runs each (`/usr/bin/time`): | workers | run 1 | run 2 | run 3 | entries/s (best) | peak RSS | |---:|---:|---:|---:|---:|---:| | 1 | 1.77 s | 1.67 s | 1.65 s | ~278,000 | 117 MB | | 2 | 1.06 s | 0.99 s | 1.00 s | ~463,000 | 120 MB | | 4 | 0.59 s | 0.59 s | 0.62 s | ~777,000 | 117 MB | | 8 (balanced default) | 0.48 s | 0.50 s | 0.51 s | ~955,000 | 121 MB | | 16 | 0.45 s | 0.44 s | 0.43 s | ~1,066,000 | 121 MB | | 32 | 0.43 s | 0.44 s | 0.42 s | ~1,092,000 | 122 MB | For comparison, `du -s` on the same tree (warm): 1.59 s, 34 MB RSS. CPU profile at 8 workers: ~60 % of samples in `statx`/`getdents` syscalls; path reconstruction for job dispatch ~7 %; aggregation is negligible. ### Memory `go test ./internal/scan -run TestMemoryPerNode` with `MAPSIZE_MEM_ROOT=~/go/pkg/mod`: 458,510 nodes, 69.1 MiB live heap, **~158 bytes per node** (node record ~112 bytes plus name storage and directory side tables). Extrapolated, 10 M entries need ~1.6 GiB. ## UI `go test ./internal/tui -bench Big` on a synthetic in-memory tree of 1,008,201 nodes (200 directories × 40 subdirectories × 100 files, plus one flat directory with 200,000 files), 200×60 terminal: | operation | time per op | |---|---:| | cold frame at root (sort children, LOD, layout incl. nested previews, paint) | 33.8 ms | | resize to a new size (layout + paint, child lists cached) | 2.0 ms | | arrow-key move + re-render | 1.5 ms | | zoomed into the 200,000-entry directory, cold | 29.5 ms | | render of a small tree (2.4 K nodes) at 200×60 | 0.66 ms | | resize relayout of the small tree | 0.45 ms | During a scan the size caches are invalidated at most every 400 ms, so a cold frame (worst case above ~34 ms) costs under 10 % of one core; other frames reuse caches. Resize events only record the new size; layout happens once per rendered frame, so a resize storm cannot queue up work. ### Geometry `go test ./internal/treemap -bench .`: | operation | time | |---|---:| | squarified layout, 300 items | 89 µs | | spatial neighbour lookup among 300 blocks | 2.1 µs | ### Filtering (1,008,201 nodes) | query | time | |---|---:| | `size > 1MB` | 31 ms | | `*.dat AND size > 500k` | 119 ms | | `path contains sub3` (reconstructs every path) | 244 ms | Filters run on a background goroutine with cancellation and a 120 ms keystroke debounce; the UI never waits for them. ## Known costs / future work * Path predicates rebuild each node's path; an incremental evaluation along the tree would make them ~10× cheaper. * Node records could shrink (owner/group/mode/link count are only needed for display and some filters) if memory on 10 M+ entry trees matters. * Cold-cache HDD benchmarks still need to be run with root access.