Use packed cached hashes for faster table mutations - #962
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## codex/demand-driven-join-scheduling #962 +/- ##
=======================================================================
+ Coverage 87.02% 87.21% +0.19%
=======================================================================
Files 96 96
Lines 33261 34185 +924
=======================================================================
+ Hits 28945 29816 +871
- Misses 4316 4369 +53 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 9.99%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Simulation | rust_rule_insert_loop[ops1000_funcs0] |
628.6 µs | 564 µs | +11.45% |
| ⚡ | Simulation | rust_rule_insert_loop[ops1000_funcs2000] |
908.8 µs | 820.2 µs | +10.81% |
| ⚡ | Simulation | rust_rule_insert_loop[ops1000_funcs200] |
667.6 µs | 604.4 µs | +10.46% |
| ⚡ | Simulation | rust_rule_insert_loop[ops100000_funcs2000] |
49.2 ms | 44.8 ms | +9.76% |
| ⚡ | Simulation | rust_rule_insert_loop[ops100000_funcs200] |
49.6 ms | 45.6 ms | +8.77% |
| ⚡ | Simulation | rust_rule_insert_loop[ops100000_funcs0] |
49.6 ms | 45.6 ms | +8.72% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing ezr-better-rebuild (2f046f1) with codex/demand-driven-join-scheduling (d7ea2c3)
Footnotes
-
227 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
4a89124 to
e516374
Compare
e516374 to
2f046f1
Compare
Summary
This draft currently contains a 12-commit scalability stack. It improves action
execution, rebuilding, index construction, table mutation, union-find merging,
and parallel search; it also adds production-scheduler microbenchmarks and a
focused math scalability harness.
The final tree:
execution-state-local reservations;
searches to workers at a coarser granularity;
knows the removed
RowId;buffers; and
PartitionedRowBufferintroducedmidway through the stack.
The 12 commits
a89073c0— Store predicted rows contiguously. Replaces the predictedvalue map's per-entry
SmallVec/Vecownership with a rawHashTableofhash/table/arity/backing-index metadata and one contiguous
Vec<Value>.Collision checks borrow the actual key slice from that backing vector, which
reduces allocation and indirection in lookup-or-insert actions.
c548da87— Reserve fresh IDs per execution state. Replaces one sharedatomic increment per fresh ID with disjoint ID ranges held by each
ExecutionState. A global atomic reserves ranges, local allocation advanceswithout synchronization, and unused suffixes are recycled through a queue;
ordinary observable counters keep reservation size one.
912ba559— Explain counter reservation lifecycle. Documentation-onlyfollow-up describing why reservations are disjoint, how unused tails are
reused before extending the high-water mark, and how reservation size one
preserves exact observable-counter semantics.
149df0f1— Build column indexes from parallel sorted runs. Replaces theserial scan plus many small locked handoffs used at high worker counts with
coarse parallel scans. Producers create deduplicated
(Value, RowId)runssorted by destination shard; shard owners then bulk-build or merge those
contiguous runs into dense or sparse buffered subsets.
82e89543— Use coarse partitions for table rebuilds. Coarsens both fulland incremental rebuild work so a worker reuses its execution state,
scratch space, and mutation buffers across a substantial partition. It also
parallelizes the incremental dirty-ID scan, retains the prior 2K-row
parallel loop at two to three workers, and uses serial handling where the
input and worker-count thresholds favor it.
4fcb49eb— Benchmark production table parallelism. Moves the tablemutation microbenchmarks onto egglog's production work-stealing thread pool,
adds the 12-P-core point, and adds a merge-only deletion case above the
parallel threshold while remaining below the table-compaction threshold.
ab70a27e— Optimize parallel table deletion. Gives workers coarsecontiguous shard ranges, separates random hash-table erasure from a batched
stale-row write pass, and adds a known-
RowIdremoval path so rebuildingdoes not reload and compare a key it has already resolved. These mechanisms
remain in the final tree.
35cbbfd7— Benchmark large parallel table deletion. Adds a 4.2M-row,1.8M-removal merge-only case so each shard substantially exceeds L1 and
deletion scaling can be measured without triggering compaction.
6ebc2555— Partition table mutations by cached hashes. Introduces theexperimental
PartitionedRowBuffer: producers cache full hashes and stablyscatter rows into physical-shard/cache-window runs before consumers probe
the table. It also adds bounded insert coalescing, direct merge/update,
shard reservation, parallel unsorted compaction, and broader insertion
benchmarks. The partitioned buffer and seal/scatter path are later removed
by commit 12; the useful merge, compaction, and cached-probe building blocks
remain.
b531eceb— Add math scalability benchmark harness. Addsscripts/math_scalability.py, which runs the production binary at1/2/4/8/12 threads, always passes
--no-decomp, alternates measurementorder, clears ambient egglog logging settings, and records wall time, CPU
time, utilized cores, speedup, and efficiency as raw samples plus
aggregates in JSON and aggregate rows in CSV. The selected egglog input
controls the run count.
b818cd07— Improve parallel union-find and join scalability. Adds ascoped concurrent union-find view using relaxed atomic loads/CAS, while
preserving timestamp groups as semantic barriers and returning to ordinary
serial access after workers join. It also extends coarse, work-stealable
search partitioning to persistent indexes, scalar filtered indexes, and
FusedIntersect, avoiding scan-and-project row-ID copies and secondarysorts.
4a891241— Use packed cached hashes for table mutations. Replaces thePRB experiment with producer-local, per-physical-shard
HashedRowBuffers:one
Vec<Value>stores rows in arrival order with a compact hash in thetrailing lane. The 32-bit value preserves 25 low bucket-index bits and
hashbrown's exact 7-bit H2 tag, while the full hash still chooses the
physical shard. Table and known-removal entries pack hash plus
RowIdintoeight bytes; equality checks still resolve compact-hash collisions.
Performance
All measurements used
--no-decomp; math used(run 12).Cumulative math uplift
The full 12-commit range was rerun locally as an exact, interleaved
c7fc1d77-versus-4a891241A/B. Both freshly built binaries used the samerun-12 input. After one warmup per cell, a four-round Latin schedule repeated
twice balanced thread-count order, variant order, and pair position:
At 12 threads, total CPU falls from 14.80 to 7.25 CPU-seconds (51.0% less)
while effective utilization rises from 6.73 to 7.42 cores. One-to-12-thread
scaling improves from 3.23x to 6.30x, or from 26.9% to 52.5% parallel
efficiency. The improvement therefore comes from both substantially less work
and better use of the available P cores. Every timed invocation produced the
same semantic-result-prefix hash.
The individual changes were also checked with controlled A/Bs; selected
results below are not additive:
-j1and 4.1% at-j12;-j12;-j12, with theauxiliary-index rebuild itself improving from 278ms to 164ms;
-j12;-j12, and 11–13% on thelarge deletion-only benchmark;
-j12,with 22.5% less CPU and essentially neutral
-j1; and-j1and 5.60% at-j12.The final math stage curve is search/apply 8.90x, mutation merge 8.20x, and
equality rebuild 5.45x from one to 12 threads. Rebuild remains the limiting
stage at roughly 65% of clean
-j12wall time.Broad-suite safety check for the final layout
There is no cumulative
c7fc1d77-to-tip sweep for the full 12-workload suite.The broad sweep isolates the final packed-hash/no-PRB change against commit 11:
eggcc-2mmis 2.35% faster at-j12, with 2.2% less CPU.(
0.996xat-j1,0.995xat-j12; both confidence intervals include1.0).
-j1and 0.69% at-j12.Validation
cargo nextest run --release --all— 1,238 tests passedcargo test -p egglog-core-relations— 144 tests plus two doctests passedcargo clippy -p egglog-core-relations --all-targets -- -D warningscargo fmt --all -- --checkwas identical; only timing/order-dependent
print-statsdiagnostics variedacross parallel runs.