Parent tracker: #3515
Previous loop: #3529 / PR #3531
Related older generic issue: #536
Goal
Reduce the Ironbird-visible TreeDB allocation attributed to TreeDB/caching.getEntrySlice in the accepted plain-send and small-multisend TreeDB rows, without weakening flush/run ownership semantics or retaining unbounded backing arrays.
Done means one of two outcomes:
- a focused PR lands with before/after evidence reducing the reproduced
getEntrySlice allocation and no material Ironbird runtime/TPS regression; or
- the issue records a concrete classification showing the allocation is required by the current flush/run ownership model, and links the next actionable allocation blocker.
Why This Exists
After #3531, the accepted Ironbird rows still show getEntrySlice as the largest shared TreeDB-owned flat allocator in both target workloads. This is now a better next target than zstd compression, command-WAL payload pieces, or lower-volume adapter paths.
This loop should be driven by the actual Ironbird heap path. Package benchmarks and unified-bench are useful for iteration, but a local microbench-only win is not enough if accepted Ironbird heap allocation does not improve or is only re-attributed elsewhere.
Current Evidence
Candidate artifact root after #3531:
/mnt/fast4tb/ironbird-3531-memtable-allocs-20260706T094142Z
Accepted rows:
| Workload |
Heap profile |
Total alloc_space |
getEntrySlice flat alloc_space |
Runtime context |
| plain-send |
plain-send/treedb/attempt-1/pprof/simapp-treedb-all-validator-0-heap.pprof |
122.12 GiB |
8.35 GiB / 6.83% |
199,534 tx over 340.53s, 585.96 TPS |
| small-multisend |
small-multisend/treedb/attempt-1/pprof/simapp-treedb-all-validator-0-heap.pprof |
145.72 GiB |
9.84 GiB / 6.76% |
239,166 tx over 405.02s, 590.50 TPS |
Current top TreeDB-relevant flat allocators from those accepted profiles:
| Workload |
Site |
Flat alloc_space |
| plain-send |
TreeDB/caching.getEntrySlice |
8.35 GiB |
| plain-send |
TreeDB/zipper.(*ReadOnlyPrepareResult).cloneKey |
7.65 GiB |
| plain-send |
TreeDB/internal/memtable.getAppendOnlyEntries |
5.60 GiB |
| plain-send |
compress/zstd.(*fastBase).ensureHist |
3.77 GiB |
| small-multisend |
TreeDB/caching.getEntrySlice |
9.84 GiB |
| small-multisend |
TreeDB/internal/memtable.getAppendOnlyEntries |
7.25 GiB |
| small-multisend |
compress/zstd.(*fastBase).ensureHist |
4.40 GiB |
| small-multisend |
TreeDB/caching.(*Batch).SetViewValidatedWithRevision |
3.41 GiB |
Initial pprof stack classification from the coordinator/explorer pass:
- dominant
getEntrySlice path appears to be caching.buildOpRuns under canonical point-unit flush/run materialization, especially buildCanonicalUnitRuns / flushCanonicalPointUnitsStreamed.
- small checkpoint-frontier paths exist but are secondary.
Scope
Included:
TreeDB/caching.getEntrySlice and putEntrySlice pooling behavior.
TreeDB/caching.buildOpRuns and canonical point-unit flush/run materialization paths.
- Entry-slice pool sizing, admission/drop behavior, chunk classes, reuse across
buildCanonicalUnitRuns, and duplicate []batch.Entry materialization if proven by profiles.
- Counters or focused benchmarks that explain requested slice lengths, hits/misses, drops, oversize classes, and retained bytes.
Excluded:
North-Star Gates
| Gate |
Current |
Target |
Required evidence |
If the gate fails |
Plain-send getEntrySlice alloc_space |
8.35 GiB |
reduce by at least 10%, or prove required/source-shape limited |
accepted Ironbird plain-send heap profile plus focused before/after benchmark/profile |
keep issue open or close only with explicit classification and next blocker |
Small-multisend getEntrySlice alloc_space |
9.84 GiB |
reduce by at least 10%, or prove required/source-shape limited |
accepted Ironbird small-multisend heap profile plus focused before/after benchmark/profile |
keep issue open or close only with explicit classification and next blocker |
| Runtime/TPS |
plain 585.96 TPS; small 590.50 TPS from post-#3531 rows |
no material regression; default blocker threshold worse than 2% unless repeat evidence shows noise |
accepted Ironbird rows with >=300s load windows when macro validation is run |
profile/fix before merge or document explicit waiver |
| Memory retention |
bounded existing pool behavior |
no unbounded retained backing arrays and no pathological RSS/high-water growth |
tests/counters around class caps, drops, retained bytes, and reset behavior |
do not merge |
| Ownership semantics |
flush/run materialization must own mutable data as needed |
no aliasing or lifetime regression |
focused tests around mutation/lifetime contracts affected by any reuse change |
do not merge |
Root-Cause Classification Gate
Before implementation, classify getEntrySlice allocation into one or more of:
| Candidate limiter |
Evidence to collect |
Action if confirmed |
| pool miss/admission drop |
counters for requested length, class, hit/miss/drop, retained bytes |
tune bounded pool classes/admission with tests |
| oversize slice class |
requested vs granted cap and excess bytes by path |
adjust classing or avoid over-rounding |
| duplicate materialization |
line-level profile showing []batch.Entry copied/allocated more than once per run/unit |
remove duplicate copy only where ownership is safe |
| required ownership copy |
code/path proof that source entries cannot be safely borrowed |
record classification and move to next blocker |
| benchmark/harness shape |
repeated profiles disagree or counters show low local reproducibility |
do not merge a claimed optimization without stable evidence |
Required Workflow
Start phase:
Implementation phase:
Close phase:
Branch And PR Policy
- Work on a topic branch from current
origin/main.
- Do not push directly to
main.
- PR must be mergeable before merge: latest-head CI, focused tests, benchmark evidence, and review findings resolved or explicitly rejected with rationale.
- Do not request review-credit-consuming AI reviews until the PR is mature enough to avoid churn.
Parent tracker: #3515
Previous loop: #3529 / PR #3531
Related older generic issue: #536
Goal
Reduce the Ironbird-visible TreeDB allocation attributed to
TreeDB/caching.getEntrySlicein the acceptedplain-sendandsmall-multisendTreeDB rows, without weakening flush/run ownership semantics or retaining unbounded backing arrays.Done means one of two outcomes:
getEntrySliceallocation and no material Ironbird runtime/TPS regression; orWhy This Exists
After #3531, the accepted Ironbird rows still show
getEntrySliceas the largest shared TreeDB-owned flat allocator in both target workloads. This is now a better next target than zstd compression, command-WAL payload pieces, or lower-volume adapter paths.This loop should be driven by the actual Ironbird heap path. Package benchmarks and
unified-benchare useful for iteration, but a local microbench-only win is not enough if accepted Ironbird heap allocation does not improve or is only re-attributed elsewhere.Current Evidence
Candidate artifact root after #3531:
/mnt/fast4tb/ironbird-3531-memtable-allocs-20260706T094142ZAccepted rows:
getEntrySliceflat alloc_spaceplain-send/treedb/attempt-1/pprof/simapp-treedb-all-validator-0-heap.pprofsmall-multisend/treedb/attempt-1/pprof/simapp-treedb-all-validator-0-heap.pprofCurrent top TreeDB-relevant flat allocators from those accepted profiles:
TreeDB/caching.getEntrySliceTreeDB/zipper.(*ReadOnlyPrepareResult).cloneKeyTreeDB/internal/memtable.getAppendOnlyEntriescompress/zstd.(*fastBase).ensureHistTreeDB/caching.getEntrySliceTreeDB/internal/memtable.getAppendOnlyEntriescompress/zstd.(*fastBase).ensureHistTreeDB/caching.(*Batch).SetViewValidatedWithRevisionInitial pprof stack classification from the coordinator/explorer pass:
getEntrySlicepath appears to becaching.buildOpRunsunder canonical point-unit flush/run materialization, especiallybuildCanonicalUnitRuns/flushCanonicalPointUnitsStreamed.Scope
Included:
TreeDB/caching.getEntrySliceandputEntrySlicepooling behavior.TreeDB/caching.buildOpRunsand canonical point-unit flush/run materialization paths.buildCanonicalUnitRuns, and duplicate[]batch.Entrymaterialization if proven by profiles.Excluded:
SetView/SetWithRevision/ CometBFT adapter work from TreeDB alloc loop: minimize Ironbird Batch.SetWithRevision allocations #3526/TreeDB alloc loop: route CometBFT DB readonly Batch.Set to TreeDB SetView #3527/TreeDB/caching: reserve pointer batch index metadata #3528.getEntrySlicecontract is shared.snissn/compresszstd work.getEntrySliceis no longer the dominant blocker.North-Star Gates
getEntrySlicealloc_spacegetEntrySlicealloc_spaceRoot-Cause Classification Gate
Before implementation, classify
getEntrySliceallocation into one or more of:[]batch.Entrycopied/allocated more than once per run/unitRequired Workflow
Start phase:
go tool pprofterminal mode on the two accepted Ironbird heap profiles to recordtop,top -cum, and line/trace evidence forgetEntrySlice.getEntrySlicerequest length/class/hit/miss/drop/retained-byte behavior if the current code does not expose enough path proof.unified-benchprofile-dir run before implementation.Implementation phase:
Close phase:
Branch And PR Policy
origin/main.main.