DIAGPT profiling#
Complete the environment-manager setup and
MPPT installation first. Run the commands below from the
repository root with the mppt environment active. The first example uses the
configured build/ tree.
Set DIAGPT_PROFILE=1 to print machine-readable records after the
off-diagonal OpenMP region. Profiling is disabled by default.
DIAGPT_PROFILE=1 DIAGPT_PROFILE_SAMPLE_STRIDE=1024 \
OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE build/bin/diagpt < input.inp
Records use the stable form:
[DIAGPT PROFILE] key=value
Exact counters include rows, determinant pairs, row/advance/direct HNTD calls,
nonzero row couplings, diagram IDs and families, MPPT2 matrix writes, and per-thread
row/pair load. The serial wall timer covers packed-index setup. Worker timers
cover worker-local backplay reset and redefinition, row fill, and complete pair
loops. The workspace_wall_s field is always zero.
Calling a clock around every pair phase would materially perturb large runs.
Therefore advance-backplay, classification, diagram dispatch, and direct-HNTD
subphase timers sample every DIAGPT_PROFILE_SAMPLE_STRIDE pair handled by each
worker. Their values are sampled worker-seconds, not elapsed wall time and not
automatically extrapolated totals. sampled_pairs and the stride are always
printed with them.
The profile validates these invariants before printing invariants_ok=1:
redef_calls == ncf - 1;rows == ncf - 1;sparse row candidates equal row HNTD calls, while intersection candidates bound advance HNTD calls;
classified_pairs == pairs;pairs == direct_hntd_calls == h2_writes;the sum of diagram-ID dispatch counts equals
pairs;all reported durations are nonnegative.
Use benchmarks/diagpt/run_benchmark.py for checksum-validated Ce3+/Pr3+
scaling runs and structured JSON/CSV output. Do not compare exact timing values
in regression tests; compare absolute energies against the versioned tolerance,
MPPT2 matrix provenance, actual OpenMP team size, and global counter invariants. Timer
records use wide scientific notation so production-scale aggregate CPU values
remain parseable.
The benchmark runner accepts --profile-mode off|base|dj. Use separate output
roots for matched modes because each invocation replaces prior results for that
case. The selected mode and both profiling environment switches are retained in
JSON and CSV provenance. Pass the prior mode’s result.json through
--reference-result to make cross-mode energy, normalized off-diagonal MPPT2 matrix elements, and
shared exact-work equality part of harness acceptance rather than a manual
comparison.
D/J detail profiling#
Exact inner D/J counters are a build-time opt-in so their hot-loop branches and
contained helper wrappers are absent from ordinary optimized binaries. The
small capability/provenance state remains available in every build. Configure a
dedicated profiling build, then set DIAGPT_PROFILE_DJ=1 at runtime. The runtime
switch also enables the base profile, so DIAGPT_PROFILE is not needed.
export CC="$CONDA_PREFIX/bin/x86_64-conda-linux-gnu-gcc"
export CXX="$CONDA_PREFIX/bin/x86_64-conda-linux-gnu-g++"
export FC="$CONDA_PREFIX/bin/x86_64-conda-linux-gnu-gfortran"
cmake -S . -B build-dj-profile \
-DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \
-DHDF5_ROOT="$CONDA_PREFIX" \
-DOpenMP_gomp_LIBRARY="$CONDA_PREFIX/lib/libgomp.so.1" \
-DMPPT_COPY_TO_HOME_BIN=OFF \
-DINSTALL_PYSCF2MPPT=OFF \
-DWITH_LIBGRPP=OFF \
-DMPPT_ENABLE_DIAGPT_DJ_PROFILE=ON
cmake --build build-dj-profile --target diagpt
DIAGPT_PROFILE_DJ=1 OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE \
build-dj-profile/bin/diagpt < input.inp
An ordinary build fails explicitly if DIAGPT_PROFILE_DJ=1 is requested. The
benchmark harness’s dj mode therefore requires the dedicated binary.
The dj_* extension reports exact D/J dispatch and routine calls, aggregate
worker time, formal ibeq/ipeq and open-orbital loop visits, rejection stages,
tested terms, nonzero contributions, hainij updates, D/J-scoped ai, cont,
and deco4 outcomes, and selected PPAA/PAPA/PACV/CVCV integral routes. The
j0001 duration is inclusive of its nested j0002; separate nested and direct
j0002 times allow an exclusive value to be derived.
Reverse D/J calls intentionally exchange occupied and virtual arrays. Therefore
*_ibeq_visits and *_ipeq_visits name formal kernel arguments rather than a
fixed physical orbital side. Zero-map rejection totals remain exact across both
directions.
For every redefined row, detail mode also prepares stable compact metadata for
nonzero equivalence entries and existing open-hole/open-particle lists. Entries
retain source position, spatial and spin-orbital identity, spin, irrep, selected
ERI class, and packed self-pair index. This metadata is measured but is not used
to change D/J traversal, sorting, screening, or accumulation order.
Equivalence-map entries represent paired spatial orbitals, so their
spin_orbital and spin fields use the documented sentinels 0 and -1;
open-hole and open-particle entries retain explicit spin-orbital identity.
Detail counters use one record per OpenMP worker and are merged after the
parallel join. Their conservation checks cover D/J routine multiplicities,
nested/direct j0002, ai route outcomes, cont spin cases, deco4 branches,
selected ERI classes, compact-list bounds, and finite nonnegative durations.
Exact inner-loop counters and clocks intentionally add overhead in the dedicated
build. Measure its profile-off overhead separately; production overhead is gated
with an adjacent ordinary optimized build compiled with the option left OFF.
Routine timers and selected-integral access census#
Build with MPPT_ENABLE_DIAGPT_ACCESS_PROFILE=ON, then set
DIAGPT_PROFILE_ACCESS=1 to identify which routine actually reads which
integrals. This mode is independent of the existing base and D/J profiles.
It covers the selected route (MPPT_SELECTED=true) and fails explicitly if
requested in an ordinary build or on the full route.
cmake -S . -B build -DMPPT_ENABLE_DIAGPT_ACCESS_PROFILE=ON
cmake --build build --parallel 1 --target diagpt
MPPT_SELECTED=true MPPT_HDF5_FILE=/path/to/selected.h5 \
DIAGPT_PROFILE_ACCESS=1 OMP_NUM_THREADS=4 OMP_DYNAMIC=FALSE \
build/bin/diagpt < input.inp > diagpt.log 2> diagpt.err
The first command updates an already configured build. For a fresh build, use the installation configuration and add the access-profile option. Ordinary optimized builds omit the access hooks, cached-pair witness fields, and routine scopes at preprocessing time. An instrumented binary with the runtime switch off retains some instrumentation overhead; use a separate ordinary build for production timing comparisons.
The final report contains two record types:
[DIAGPT ROUTINE] routine=a0006 timing=inclusive_invocation_sum calls=1 serial_calls=1 seconds= ...
[DIAGPT ACCESS] routine=cvcv_contribution storage=cvcv_pair api=scalar class=CVCV calls=18 first=1,7,1,7 value= ...
Field |
Meaning |
|---|---|
|
Innermost instrumented physical routine; helpers such as |
|
Actual pair family, J/K slice, packed J/K array, or the indexed infinity-zero placeholder |
|
|
|
Chemical |
|
Exact invocation/read count, including zero-valued integrals and repeated reads |
first and value are one successful read’s one-based spatial indices and
returned value. The witness comes from the first occupied worker slot at merge;
it can change with scheduling. It is not a complete per-call trace. XXXX
identifies a quartet containing a nonphysical index, such as infinity.
Classes use C for core below the selected window, A for the selected window,
and V for external virtuals. Each pair and then the pair pair are canonicalized
using CC, CA, AA, CV, AV, VV. Thus CVCV, CVVC, VCCV, and VCVC share
one class, while CCVV is distinct. For example, Fock reads (vc\|v'c) from
k_slice_full; that is a CVCV access without a cvcv_pair read.
Pure CVCV reads are attributed to the isolated cvcv_contribution scope inside
a0006. For factorized inputs, storage=cvcv_factors api=tile counts the direct
and exchange integral values consumed from reconstructed tiles, not individual
factor elements read from disk. The [DIAGPT CVCV DF] records separately report
factor-read bytes and I/O/GEMM durations.
Timing and concurrency#
Routine seconds sum the elapsed duration of every invocation, including
nested calls. A serial call containing an OpenMP region measures the whole
region’s wall time. Calls made by workers contribute worker elapsed time.
serial_calls distinguishes the two invocation contexts. Do not sum routine
durations into a total runtime: nested calls and parallel work overlap. Existing
phase wall timers remain the elapsed-runtime reference.
Counters and first witnesses are worker-owned and merged after the final join.
There are no clocks, atomics, or log writes in the access hooks. A serial
a0004/a0006 scope supplies attribution to its internal workers; nested
j0002 restores its caller on return. Nested OpenMP teams are rejected in this
mode. Memory is bounded by the routine/source/class registry and maximum team
size, not by the number of ERI calls.
The indexed parity replays made by DIAGPT_PROFILE_DJ=1 are excluded from the
access census so enabling both modes does not count validation reads twice.
scopes_closed=1 confirms balanced routine scopes. unscoped records expose
successful reads outside the current routine registry rather than hiding them.
Small reproducible fixtures#
ctest --test-dir build -R '^diagpt_integration_selected_eri$' --output-on-failure
The tests create a 2-core / 4-active / 2-virtual HDF5 file with 36 CAS(4,4)
determinants. Two deterministic seeds produce unequal, symmetry-consistent ERIs;
no SCF or selector calculation is needed. Inputs, namelists, logs, and CASCI/MPPT2
handoffs remain in build/access-profile-tests/.
For one inspectable run and CSV tables outside pytest:
PYTHONPATH=.:diagpt/tests/integration/access_profile \
python -m access_fixture --binary build/bin/diagpt \
--output build/access-profile-report --seed 19 --threads 4
access.csv contains every aggregate access row, routines.csv contains the
timers, and families.csv is the routine-by-storage count matrix. Reusing an
output directory replaces that fixture run’s files.
Checks compare first-read values with an independent dense eight-orbital oracle,
exact counters across 1/2/4 workers, profile-on/off CASCI/MPPT2 matrices, and coexistence
with D/J profiling when compiled. A separate case zeros only cvcv_pair and
verifies that its accesses remain visible. The fixture is for access auditing,
not a physical molecular energy reference or a performance benchmark.
To compare an adjacent ordinary build too, set MPPT_DIAGPT_PLAIN to its
absolute diagpt path before the CTest command. That optional check also verifies
that the ordinary binary rejects DIAGPT_PROFILE_ACCESS=1.
On these fixtures, general cvcv_pair reads occur in cvcv_contribution called
by a0006, while compact
CVCV and CCVV slices also occur in Fock construction. An absent row means
not observed on this input, not proof that a routine can never use that
family. One witness does not establish coverage of all spin, index-equality,
symmetry, ionization, or model-space branches.