Bounded RI-J lowering and structural reuse¶
Date: 2 November 2026. Implementing issue: TENS-07 (#800). This is a measured source increment over the CPU and stream slices. Complete-method scientific acceptance and the broader planner programme remain open.
Production decision and scope¶
DensityFitting::build_J now submits stable method-owned AO, auxiliary and
factor-source identities to the same two checked IndexProgram operations.
It explicitly selects reassociated FP64 arithmetic and a bounded measured
schedule. Signed densities, factor construction, fitting rank, screening,
energy coefficients and physical-source authority are unchanged. The generic
RiJPlan default retains the original arithmetic and thread policy.
Two eligible schedules are compared on first use: the registered per-P
predecessor and one panel-product alternative. This single-right-hand-side
GEMM lowers to two GEMVs. The allocation-audited Eigen BuiltIn boundary
bypasses BLAS dispatch even in builds with EIGEN_USE_BLAS; dynamic backend
workspace is zero. No global BLAS setting is read or changed by this path.
The canonical alternative explicitly packs at most the admitted number of columns. On the inspected Eigen 5.0.1 packet-mapper ABI (internal version 3.5.0), a specialized mapper reads each separately owned per-P allocation using unit-stride packet runs instead. It neither packs factors nor invents a contiguous rank-three allocation. Exact-zero tiles return zero packets. Other Eigen versions use the canonical packed mapper when Eigen >= 3.4; older versions retain the predecessor. The version guard is intentional: a future internal mapper ABI needs another audit, not an assumed guarantee.
At most two warmups and six alternating timed executions are performed.
The work ceiling is one billion scalar contraction terms across these
executions; exceeding it keeps the deterministic predecessor. Median time
must improve by at least 5%, a measurement-noise guard rather than a
machine-specific shape threshold. Both outputs must be finite and their
maximum difference must be at most
128 * epsilon * (m*n + P) * max(1, max_abs(predecessor)).
This is a selection sanity check, not a scientific error certificate or a
promise about all subsequent densities. Independent asymmetric and
cancellation tests accompany it. Non-finite panel results on later bindings
rerun the predecessor, preserving its IEEE behavior. There is no bitwise
cross-kernel promise and no reduced precision or fast-math requirement.
Admission, reuse and threading¶
With M=m*n, each packed column needs 8*(M+1) bytes for factors and
panel gamma. Column count is the minimum of P, the packing ceiling divided
by that cost, and the remaining admitted storage divided by that cost.
The default packing ceiling is 8 MiB. Admission first includes resident
owners, density, tile metadata, full gamma, any strided-density pack,
private output, executor control and, during tuning, a second output.
The mapped alternative uses the same tile snapshot and full gamma with
zero factor packing. The full execution is preflighted before provider
visits. Failure never publishes a partial J. Resident P metadata remains
O(P); this is not a new out-of-core factor producer.
structure.hpp adds exactly one mutex-protected fixed cache entry using the
existing Budget. Its persistent control inventory is imported once into
the execution ledger; enclosing DF object size subtracts that cache object
before importing its complete inventory. Keys have fixed capacities of
five operands and twelve axes; overflow refuses rather than grows a search.
Keys include operation/schema, domain and parent revisions, selected-map
identity, ordered coordinates, extents/strides/origins, dtype/conjugation,
access, required scalar alignment, source/pattern/metric/frame/partition,
backend version, process-local hardware and placement tokens, numerical and
thread policy, cap, currently available storage and tuning/packing limits.
The cache stores only the chosen kernel, panel count, worker count and measurement times. It retains no view, provider, allocation or numerical payload. Each binding still constructs and checks the small IR, imports current buffers, acquires leases, checks value/pattern versions and admits current storage. A lower cap or allowance misses the cache. Value-only changes can reuse a schedule but cannot reuse results. Numeric packing caches, compiled-IR caches, arbitrary contraction-order search, distributed placement and cross-process serialization are explicitly deferred.
Measured selection owns one caller CPU thread, including its predecessor candidate. Requested worker ceilings and actual workers are reported and keyed; nested calls never create another team. The original explicitly selected per-P policy keeps its existing OpenMP behavior. This choice was measured on a single-socket machine; there is no affinity, remote first-touch, work stealing or multi-socket NUMA performance claim. Placement tokens must change when a caller changes placement policy. Hardware tokens are local to the process, not portable CPU fingerprints.
Measurements and rejected alternatives¶
Local source harness: benchmarks/tensor_planner.cpp, C++17, Apple Clang 21,
-O3 -DNDEBUG, Eigen 5.0.1, Apple M5 Max. The production-like compile enables
OpenMP and BLAS; benchmark launches fix the external BLAS ceiling to one.
Each full call recreates imports, provider and checked IR with stable domains
and one cache. The comparison uses the fastest qualified one-thread raw
predecessor, not the slower two-thread result. Thirty alternating full-call
samples provide medians; timings include harness numerical comparison.
m x n, P |
Predecessor one thread, us |
Warm full call, us |
Cold plan, us |
Cold full call, us |
Warm plan, us |
Warm / cold tracked peak, bytes |
|---|---|---|---|---|---|---|
24 x 24, 84 |
12.959 |
10.708 |
688.250 |
793.583 |
0.334 |
465888 / 470608 |
31 x 47, 127 |
51.667 |
41.792 |
1.209 |
376.416 |
0.375 |
1647184 / 1658952 |
97 x 97, 193 |
576.250 |
403.916 |
2.291 |
3915.416 |
0.542 |
14995744 / 15071128 |
257 x 257, 521 |
10902.333 |
7433.125 |
3.500 |
73393.250 |
2.292 |
278569184 / 279097688 |
The first cold-plan sample includes lazy OpenMP/runtime initialization. All four selected the mapped kernel: actual team one, factor packing zero bytes/zero time, P tile visits, maximum absolute discrepancy at most 1.23e-15. Tracked peaks include a declared P-by-P metric-owner inventory; they are not process RSS. A separate whole-harness run measured 297680896 bytes maximum RSS and 293372624 bytes peak process footprint. Those include allocator/runtime/code/benchmark state and cannot be subtracted from one operation’s ledger to infer exact backend overhead. This RSS run overlapped focused compilation/tests: its two smallest shapes regressed to 17.625 and 62.875 us versus 15.625 and 55.584 us for the raw predecessor. Calibration kept per-P for the first shape and selected the mapper for the second. This illustrates sensitivity to transient load; the 5% guard cannot guarantee a future speedup. These samples are excluded from the controlled timing table but retained as counterevidence. Zero backend allocation is checked separately with Eigen and global allocation disabled.
m x n, P |
Average us/call, cold cache then 1 call |
10 calls |
1000 calls |
|---|---|---|---|
24 x 24, 84 |
90.584 |
18.833 |
10.753 |
31 x 47, 127 |
352.375 |
73.108 |
42.735 |
97 x 97, 193 |
3932.500 |
756.575 |
401.004 |
257 x 257, 521 |
75349.083 |
14247.788 |
7915.742 |
Warm improvement is approximately 17-32% in this run. Ten-call sequences still lose to the raw predecessor; the largest case amortizes first-use calibration only after roughly twenty calls. A second requested-two-worker run still used one worker and measured 10.792/42.833/403.042/7873.667 us, against one-thread predecessor 13.041/51.750/577.125/11123.791 us. Existing two-thread large-shape execution was slower at 16029.083 us. There is no whole-SCF speedup claim or universal rule that fewer workers always win.
Baseline full packing of the largest case cost about 4563 us before about 3505 us of BLAS products, and required the entire additional factor payload plus unqualified opaque workspace. Tiny output tiles and lazy-expression packing regressed. Canonical bounded BuiltIn packing measured about 11143 us for the large case versus about 10955 us for its predecessor in that pilot; medium shapes sometimes improved, but not consistently enough after packing. It remains an explicitly admitted candidate/fallback on qualified older Eigen, not a presumed speedup. The zero-copy mapper is the useful measured increment. No optional TBLIS build or dependency was needed to answer this local question.
The unchanged complex stream benchmark reports pair warm/legacy ratios 1.022 and 1.050 and rectangular-panel ratios 0.881 and 0.856. Pair overhead is retained rather than hidden as a universal improvement. Genuine imaginary 2-by-5 pair tests use fresh buffers and leases with pointer-free cache keys, independent conjugated sums and release checks. This tests rebinding without adding a production stream cache or changing compensated kernels.
Evidence and remaining acceptance¶
Thirteen focused core/stream/planner cases pass. Five planner ASan/UBSan
cases and allocation-disabled OpenMP/BLAS numerical/thread cases pass.
Checks cover asymmetric/reversed layouts, signed cancellation, exact and
one-byte-below admission, every cache-key class, changed domain/value/pattern
bindings, provider and allocation failures, expired scopes and nested teams.
The production df.cpp translation unit compiles with the cached native
build flags; its existing unused-field warning is unrelated.
The local physical test stops at the existing basis-overlay integrity
refusal before a calculation. No bypass, duplicate managed runtime build,
stale native acceptance, complete vq result or matched-reference PASS is
claimed. The existing updater owns runtime delivery; Validator must use a
containing runtime for complete RHF/PBE calculations with matched settings
and reference evidence. #798/#799 science and broader #800 work remain open.
Source SHA, exact local runtime identity and raw operational evidence are
recorded on #800, outside the public product checkout.
Primary-source basis and departures¶
Matthews, High-Performance Tensor Contraction without Transposition, sections 4-7 and 9.1: packet runs and layout-aware packing inform the mapper. This implementation is not TBLIS block-scatter GEMM or its threading system.
Springer and Bientinesi, Design of a High-Performance GEMM-like Tensor-Tensor Multiplication, sections 3-5 and 7.3: charge packing and restrict candidates before calibration. This increment has two local candidates, not the GETT compiler, generated microkernels or its analytic performance model.
Gray and Kourtis, Hyper-optimized tensor network contraction, sections 2-4, especially 4.7: slicing can repeat work and largest-intermediate size is insufficient for peak live memory. Here all simultaneous owners and tuning outputs are admitted; no hypergraph optimizer is implemented.