Skip to content

perf(partition): sequential shrinking diffs + reused scratch — national build 39s → 5s#32

Merged
beetlebugorg merged 2 commits into
mainfrom
perf/partition-build
Jul 21, 2026
Merged

perf(partition): sequential shrinking diffs + reused scratch — national build 39s → 5s#32
beetlebugorg merged 2 commits into
mainfrom
perf/partition-build

Conversation

@beetlebugorg

Copy link
Copy Markdown
Owner

A national NOAA partition build (1707 cells, 6 tiers) spent ~39–48 s almost
entirely in ownedAtTierIndexed. perf put ~40% of wall-clock in the boolean
sweep and ~25% in the kernel (mmap/munmap + faulting fresh pages). Two causes,
two fixes in src/geometry/plane.zig:

1. Drop the per-cell union — diff sequentially.
owned = cov \ (∪ overlapping finer cells) built its subtrahend with unionAll,
a pairwise fold whose accumulator grows toward whole-district size — O(N²) sweep
work when hundreds of finer cells overlap one coarse cell. But
A \ (B ∪ C ∪ …) = ((A \ B) \ C) \ …, so we diff sequentially: the subject only
shrinks from one cell's coverage, every subtrahend is a single cell's coverage,
and a subject emptied early (a fully-covered gap-filler, the common case) exits
without touching the rest.

2. Reuse scratch instead of freeing to the OS.
The boolean intermediates were freed each op straight back to the page allocator
(to keep a pooling gpa from parking whole-district scratch) — that was the
syscall storm. They now live in a scratch arena reset with retained capacity per
cell: no munmap churn, and RSS stays bounded by the largest single cell's working
set, not the district.

Result

Same NOAA build: 38.7 s → 5.1 s (sys 11.4 s → 0.3 s). Composed tile output
is byte-identical; the ownedAtTier cross-check suite passes.

Also on this branch

bindings/go: OpenComposeTree (81b925e) — a one-call open of a whole baked tree
via tile57_compose_tree, replacing per-archive tile57_chart_open round-trips
that each stood up their own std.Io.Threaded pool (~35 ms/chart). Chartplotter
provider registration: 60 s → 7 s.

…ed scratch

A national NOAA partition build (1707 cells, 6 tiers) took ~39-48 s, all in
ownedAtTierIndexed. perf put ~40% of wall-clock in the boolean sweep and ~25%
in the kernel (mmap/munmap + faulting fresh pages). Two causes, two changes:

- owned = cov \ (∪ overlapping finer cells) built its subtrahend with
  unionAll — a pairwise fold whose accumulator grows toward whole-district
  size, O(N²) sweep work when hundreds of finer cells overlap one coarse
  cell. But A \ (B ∪ C ∪ …) = ((A \ B) \ C) \ …, so diff sequentially:
  the subject only SHRINKS from one cell's coverage, every subtrahend is a
  single cell's coverage, and a subject emptied early (a fully covered
  gap-filler, the common case) exits without touching the rest.

- The boolean intermediates freed each op straight back to the page
  allocator (chosen to keep a pooling gpa from parking whole-district
  scratch); that was the syscall storm. They now live in a scratch arena
  reset with retained capacity per cell — no munmap churn, and RSS is still
  bounded by the largest single cell's working set, not the district.

Same NOAA build: 38.7 s -> 5.1 s (sys 11.4 s -> 0.3 s); the composed tile
output is byte-identical and the ownedAtTier cross-check suite passes.
OpenCompose round-trips tile57_chart_open across cgo once per archive, each
standing up (and tearing down) its own std.Io.Threaded pool — ~35 ms per
chart, a minute of boot for a ~1700-cell library. tile57_compose_tree walks,
mmaps and composes the whole tree inside one engine call on its batch path;
wrap it. Measured in chartplotter: provider registration 60 s -> 7 s.
@beetlebugorg
beetlebugorg merged commit b0e1b30 into main Jul 21, 2026
5 checks passed
@beetlebugorg
beetlebugorg deleted the perf/partition-build branch July 21, 2026 00:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant