feat(graph): 🔍 separate the graph's flat-world slot cost from its traffic - #253
Open
diagonal-hamiltonian wants to merge 1 commit into
Open
feat(graph): 🔍 separate the graph's flat-world slot cost from its traffic#253diagonal-hamiltonian wants to merge 1 commit into
diagonal-hamiltonian wants to merge 1 commit into
Conversation
diagonal-hamiltonian
requested review from
fpietra,
ludmilaasb and
robertodr
as code owners
August 20, 2026 09:09
diagonal-hamiltonian
marked this pull request as draft
August 20, 2026 09:13
|
Docs preview: https://pr-253.monoprop-docs.pages.dev |
Codecov Report✅ All modified and coverable lines are covered by tests. 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
Flags with carried forward coverage won't be shown. Click here to find out more. |
diagonal-hamiltonian
force-pushed
the
perf/profile-graph-coverage
branch
from
August 20, 2026 10:40
f5d7702 to
82fb11b
Compare
diagonal-hamiltonian
marked this pull request as ready for review
August 20, 2026 10:47
robertodr
reviewed
Aug 20, 2026
| 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, |
Member
There was a problem hiding this comment.
c'mon... fprintf?? Use std::print
|
…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
force-pushed
the
perf/profile-graph-coverage
branch
from
August 20, 2026 17:03
266152b to
29ab66d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



🤖 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:ranks × partitions), whether or not that slot carriesany traffic, and
On a partitioned run the first grows with a
Pthe rank count never shows, so a breakdown that addsthem cannot say which of the two a graph is spending on. This splits them.
What changed
Five fields on the existing
GraphMemoryBreakdown, deliberately outsidetotal_bytes(),because each is a count or a slice of a field already summed there:
slot_record_bytescross_rank_byteslayer_coresLayerCores;slot_records / layer_coresrecoversPslot_recordsPper coreoccupied_slots/ slot_recordsis the occupancycross_rank_endpointsP-independent ceiling onoccupied_slotsThree helpers in
MPGraphEncoding.cppderive them.cross_rank_storage_bytesnow callscross_rank_slot_record_bytesrather than repeating its expression, so the slice cannot drift fromthe total it is a slice of.
Surfaced to Python as five
d_-prefixed keys ongraph_memory_breakdown(), matching thed_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_slotsagainst zeros at thefront, the interior and the back (the three places a scan loses count);
slot_record_bytesagainst 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,Presolves to the host's physicalcore count and every slot-record expectation becomes machine-dependent.
d_slot_record_bytes / d_slot_recordsis asserted to be exactly 32 or 40 bytes —CrossRankPartnerRangeis twosize_tand threeTermIndex, the latter 4 B or 8 B undermonoprop_WIDE_TERM_INDEX, and nothing in between.Scope
This PR was much larger and is now much smaller. It previously also carried the
monoprop_PROFILEinstrument. That instrument is held back: whether to ship an internal profiler atall 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:
grep -r 'monoprop_PROF\|profile::'over this diff returns nothing.fprintfcomment no longer applies to this PR — that code is not here. It wassix call sites, not eight (two of the grep hits were the word inside a comment), and they
became one
noexcepthelper overstd::formaton the branch that still has them.PR's result. For the record it resolved 0 of 24 timing tests against
48cadcb, with one memorycell 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 unit220/220,-L serial219/219,-L mpi, and the Python MPI suite at 1x1, 1x16, 2x8and 8x16 — 600 passed at every layout, all suites green. Extension
3abe91dcace4eef73c43526d04e95a6e.clang-format --output-replacements-xmlreports 0 replacements on every changed C++ file.