Skip to content

feat(graph): 🔍 separate the graph's flat-world slot cost from its traffic - #253

Open
diagonal-hamiltonian wants to merge 1 commit into
mainfrom
perf/profile-graph-coverage
Open

feat(graph): 🔍 separate the graph's flat-world slot cost from its traffic#253
diagonal-hamiltonian wants to merge 1 commit into
mainfrom
perf/profile-graph-coverage

Conversation

@diagonal-hamiltonian

@diagonal-hamiltonian diagonal-hamiltonian commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

🤖 AI text below 🤖

Summary

graph_memory_breakdown() reported the graph's cross-rank storage as one number,
cross_rank_bytes, which mixes two costs that scale with different things:

  • one record per slot of the flat world (ranks × partitions), whether or not that slot carries
    any traffic, and
  • the endpoints actually crossing.

On a partitioned run the first grows with a P the rank count never shows, so a breakdown that adds
them cannot say which of the two a graph is spending on. This splits them.

What changed

Five fields on the existing GraphMemoryBreakdown, deliberately outside total_bytes(),
because each is a count or a slice of a field already summed there:

field what it is
slot_record_bytes the slot-proportional slice of cross_rank_bytes
layer_cores distinct LayerCores; slot_records / layer_cores recovers P
slot_records summed over cores, so P per core
occupied_slots slots carrying any traffic; / slot_records is the occupancy
cross_rank_endpoints the traffic itself, and a P-independent ceiling on occupied_slots

Three helpers in MPGraphEncoding.cpp derive them. cross_rank_storage_bytes now calls
cross_rank_slot_record_bytes rather than repeating its expression, so the slice cannot drift from
the total it is a slice of.

Surfaced to Python as five d_-prefixed keys on graph_memory_breakdown(), matching the d_
convention operator_memory_breakdown() already uses for diagnostics excluded from the sum.

Tests

Both sides of the binding, because they fail differently.

  • cpp/tests/graph_encoding_tests.cpp — five cases. occupied_slots against zeros at the
    front, the interior and the back (the three places a scan loses count); slot_record_bytes
    against a pair of storages with identical traffic and different world sizes, which is the
    whole point of the field; total_bytes() unchanged by any diagnostic; and += summing all five,
    since a partitioned propagator merges per-partition breakdowns.
  • tests/test_memory_breakdown.py — the dicts are built inside nanobind lambdas with no C++
    entry point returning the map, so which struct field each string key names is observable only
    from Python. It also pins monoprop_PARTITIONS; left alone, P resolves to the host's physical
    core count and every slot-record expectation becomes machine-dependent.

d_slot_record_bytes / d_slot_records is asserted to be exactly 32 or 40 bytes —
CrossRankPartnerRange is two size_t and three TermIndex, the latter 4 B or 8 B under
monoprop_WIDE_TERM_INDEX, and nothing in between.

Scope

This PR was much larger and is now much smaller. It previously also carried the
monoprop_PROFILE instrument. That instrument is held back: whether to ship an internal profiler at
all is a separate decision from whether the graph can report its own slot cost, and the two were
only ever in one PR because they were written in one sitting. The instrument is kept as a
cherry-pickable commit for measurement work and is not part of this diff. Consequences:

  • Nothing here is behind a build flag or an environment variable. Five always-on counters, and
    grep -r 'monoprop_PROF\|profile::' over this diff returns nothing.
  • @robertodr's fprintf comment no longer applies to this PR — that code is not here. It was
    six call sites, not eight (two of the grep hits were the word inside a comment), and they
    became one noexcept helper over std::format on the branch that still has them.
  • The earlier A/B on this branch measured a superset of this diff and should not be read as this
    PR's result. For the record it resolved 0 of 24 timing tests against 48cadcb, with one memory
    cell at 1.01x and 15 flat — but that was the instrument plus this, not this.

Reviewers who remember closed #232 pr/layer-profile: that was the instrument's ancestor, not this.

Verification

ctest -L unit 220/220, -L serial 219/219, -L mpi, and the Python MPI suite at 1x1, 1x16, 2x8
and 8x16 — 600 passed at every layout, all suites green. Extension 3abe91dcace4eef73c43526d04e95a6e.
clang-format --output-replacements-xml reports 0 replacements on every changed C++ file.

@github-actions github-actions Bot added documentation Improvements or additions to documentation python cpp labels Aug 20, 2026
@diagonal-hamiltonian
diagonal-hamiltonian marked this pull request as draft August 20, 2026 09:13
@github-actions

Copy link
Copy Markdown

Docs preview: https://pr-253.monoprop-docs.pages.dev

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.70%. Comparing base (48cadcb) to head (266152b).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #253   +/-   ##
=======================================
  Coverage   97.70%   97.70%           
=======================================
  Files          14       14           
  Lines         742      742           
  Branches       98       98           
=======================================
  Hits          725      725           
  Misses         12       12           
  Partials        5        5           
Flag Coverage Δ
cpp 97.70% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

@diagonal-hamiltonian
diagonal-hamiltonian force-pushed the perf/profile-graph-coverage branch from f5d7702 to 82fb11b Compare August 20, 2026 10:40
@diagonal-hamiltonian diagonal-hamiltonian changed the title perf(c++): 🔍 one profiling knob, absent when off, and graph coverage for the parts that had none perf(c++): 🔍 internal profiling Aug 20, 2026
@diagonal-hamiltonian
diagonal-hamiltonian marked this pull request as ready for review August 20, 2026 10:47
Comment thread cpp/monoprop/detail/Profile.h Outdated
return 0;
}
// `row` is print order over the rows that printed, not the partition index, and is not stable run to run.
std::fprintf(out,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c'mon... fprintf?? Use std::print

@sonarqubecloud

Copy link
Copy Markdown

…ffic

`graph_memory_breakdown()` reported one `cross_rank_bytes` total, which mixes two costs that
scale with different things: one record per slot of the FLAT world (ranks x partitions), and the
endpoints actually crossing. On a partitioned run the first grows with a P the rank count never
shows, so a breakdown that adds them cannot say which one a graph is spending on.

Five diagnostics now split them, deliberately OUTSIDE `total_bytes()` because each is a count or
a slice of a field already summed there: `slot_record_bytes`, `layer_cores`, `slot_records`,
`occupied_slots` and `cross_rank_endpoints`. `slot_records / layer_cores` recovers P, and
`occupied_slots / slot_records` is the occupancy.

Three helpers in `MPGraphEncoding.cpp` derive them; `cross_rank_storage_bytes` now calls the
first rather than repeating its expression, so the slice cannot drift from the total.

Covered both sides of the binding: five Boost cases on the helpers and the `+=` merge, and
`tests/test_memory_breakdown.py` on the dict keys, which are built inside nanobind lambdas with
no C++ entry point returning the map -- so which field each key names is observable only from
Python. It pins `monoprop_PARTITIONS` rather than letting P resolve to the host's core count.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@diagonal-hamiltonian
diagonal-hamiltonian force-pushed the perf/profile-graph-coverage branch from 266152b to 29ab66d Compare August 20, 2026 17:03
@diagonal-hamiltonian diagonal-hamiltonian changed the title perf(c++): 🔍 internal profiling feat(graph): 🔍 separate the graph's flat-world slot cost from its traffic Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cpp documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants