Skip to content

Precomputed symbols - #443

Merged
evaleev merged 2 commits into
evaleev:masterfrom
0xWOLAND:perf/hoist-inteval-scalars
Oct 25, 2026
Merged

evaleev merged 2 commits into
evaleev:masterfrom
0xWOLAND:perf/hoist-inteval-scalars

Conversation

@0xWOLAND

@0xWOLAND 0xWOLAND commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

libint2's generated recurrence kernels load the same coefficients from memory. Instead we can load them into a scalar once and then reuse it across the recurrence ops. This lets us reduce memory accesses substantially. It appears to be faster cc-pVQZ (1.24x), def2-QZVP (~1.24x), and ANO-RCC (~1.41x) Gaussian basis sets.

llvm estimates

CPU model upstream master hoisting branch speedup
Intel Skylake-AVX512 114,506 cycles 98,870 cycles 1.16×
AMD Zen 4 125,784 70,454 1.79×
Apple M1 125,676 70,282 1.79×
Neoverse V2 85,051 61,593 1.38×

Happy to benchmark on other machines :)

Edit: Here's the script I used to benchmarklibint using llvm-mca

@0xWOLAND 0xWOLAND changed the title feat: precomputed symbols Precomputed symbols Oct 24, 2026
generate_code() used to rediscover the hoisted inteval loads by scanning
stack_ and comparing each vertex's symbol against a recomputed "hv_" name.
assign_symbols() now records each hoisted local together with the inteval
field it is loaded from, and generate_code() declares exactly that list.
Vertices that refer to another vertex are not hoisted, since their symbol
comes from the referred vertex.

The generated library is byte-identical to that of the previous commit.
@evaleev

evaleev commented Oct 25, 2026

Copy link
Copy Markdown
Owner

Thanks for this. I validated it locally and measured wall-clock timings.

Validation. I built check for both the merge-base (69f92196) and this PR. The config was 1-body, ERI, ERI3 and ERI2 to am 4, with 1st derivatives to am 3, all scalar.

  • All tests pass on both: compiler coretest, eritest, unit tests (20M assertions), hf and hf++.
  • 2655 of the 3393 generated files change.
  • Compiling every generated .cc with -Wunused-variable -Wunused-but-set-variable gives 0 warnings.
  • Integral checksums are bit-identical to master.

Timings. Apple M-series, Apple clang -O3. The workload is all unique shell sets for one water molecule. Baseline and PR ran alternately: 3 rounds × min of 5 runs, except ANO-RCC (2 rounds × 1 run). The spread between rounds was under 0.5%.

Case master PR speedup
ERI cc-pVQZ 0.374 s 0.304 s 1.23×
ERI def2-QZVP 0.386 s 0.313 s 1.23×
ERI ANO-RCC 149.0 s 124.0 s 1.20×
ERI 1st derivative, cc-pVTZ 0.202 s 0.171 s 1.18×
ERI3 cc-pVQZ / cc-pVTZ-JKFIT 0.0099 s 0.0092 s 1.08×

The cc-pVQZ and def2-QZVP numbers match yours. ANO-RCC comes out at 1.20× here rather than 1.41×. The llvm-mca estimate for M1 (1.79×) doesn't show up in wall-clock time.

Follow-up commit (200b83e). Previously generate_code() found the hoisted loads by re-deriving each hv_ name and comparing strings against the symbols. That breaks silently if symbols are ever assigned along another path. Now assign_symbols() records each hoisted local together with its inteval field, and generate_code() declares exactly that list. Vertices that refer to another vertex are not hoisted. The generated library is byte-identical to the one from your commit.


This comment was agent-generated and human-reviewed.

@evaleev
evaleev merged commit a1c3e63 into evaleev:master Oct 25, 2026
13 checks passed
@0xWOLAND
0xWOLAND deleted the perf/hoist-inteval-scalars branch October 25, 2026 20:07
@evaleev evaleev added this to the 2.14 milestone Oct 26, 2026
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.

2 participants