Files
mapsize/PERFORMANCE.md
T

3.5 KiB
Raw Blame History

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.