diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..6ea0a84a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "notebooks/astrasim2_correlation/correlation"] + path = notebooks/astrasim2_correlation/correlation + url = git@github.com:rengzhengcodes/aws-gpu-profiler.git + branch = main diff --git a/accelforge/model/_looptree/accesses.py b/accelforge/model/_looptree/accesses.py index d54f2999..a643a5d6 100755 --- a/accelforge/model/_looptree/accesses.py +++ b/accelforge/model/_looptree/accesses.py @@ -5,7 +5,7 @@ import islpy as isl -from accelforge.model._looptree.reuse.isl import IslReuseAnalysisOutput +from accelforge.model._looptree.reuse.isl.des import IslReuseAnalysisOutput from accelforge.util._frozenset import oset from accelforge.model._looptree.reuse.symbolic import ( BuffetStats, diff --git a/accelforge/model/_looptree/latency/latency.py b/accelforge/model/_looptree/latency/latency.py index ab1810bd..9cdfadc4 100755 --- a/accelforge/model/_looptree/latency/latency.py +++ b/accelforge/model/_looptree/latency/latency.py @@ -4,7 +4,7 @@ # from accelforge.model._looptree._isl.singular import get_value_from_singular_qpolynomial from accelforge.frontend.arch import Compute from accelforge.model._looptree.latency.processors import LATENCY_PROCESSORS -from accelforge.model._looptree.reuse.isl import IslReuseAnalysisOutput +from accelforge.model._looptree.reuse.isl.des import IslReuseAnalysisOutput from accelforge.model._looptree.reuse import SymbolicAnalysisOutput from accelforge.util._sympy.broadcast_max import max_nonzero diff --git a/accelforge/model/_looptree/reuse/isl/__init__.py b/accelforge/model/_looptree/reuse/isl/__init__.py index e295e773..e69de29b 100755 --- a/accelforge/model/_looptree/reuse/isl/__init__.py +++ b/accelforge/model/_looptree/reuse/isl/__init__.py @@ -1,5 +0,0 @@ -from .des import IslReuseAnalysisOutput - -__all__ = [ - "IslReuseAnalysisOutput", -] diff --git a/accelforge/model/_looptree/reuse/isl/des.py b/accelforge/model/_looptree/reuse/isl/des.py index a7890af3..7b8d2de4 100755 --- a/accelforge/model/_looptree/reuse/isl/des.py +++ b/accelforge/model/_looptree/reuse/isl/des.py @@ -1,6 +1,5 @@ """ -TODO: Is this file still necessary? It is referenced elsewhere but is no longer - the format we are looking for. +Deserializes LoopTree reuse-analysis output into ISL objects. """ from dataclasses import dataclass, field diff --git a/accelforge/model/_looptree/reuse/isl/distributed/README.md b/accelforge/model/_looptree/reuse/isl/distributed/README.md new file mode 100644 index 00000000..696c7f77 --- /dev/null +++ b/accelforge/model/_looptree/reuse/isl/distributed/README.md @@ -0,0 +1,529 @@ +# Transfer models: `HypercubeMulticastModel` and how to write a new one + +This directory holds **distributed / network cost models** for spatial reuse analysis. This +document explains how `HypercubeMulticastModel` works and gives a step-by-step recipe (plus a fully +worked example) for adding your own model. + +--- + +## 1. Overview + +A **transfer model** estimates the on-chip data-movement cost of a mapping: given where data +*lives* (occupancy) and where it is *needed* (fills), it computes how many network *hops* the +delivery costs and which transfers are fulfilled peer-to-peer vs. read from a parent. + +All transfer models implement one abstract interface, `TransferModel`. The concrete +implementations: + +| Model | File | Shape | +|-------|------|-------| +| `SimpleLinkTransferModel` | [`../spatial.py`](../spatial.py) | Neighbor-to-neighbor mesh; no constructor state | +| `HypercubeMulticastModel` | [`distributed_buffers.py`](distributed_buffers.py) | Distance-aware worst-case multicast; takes a `dist_fn` | +| `FullyConnectedMulticastModel` | [`distributed_buffers.py`](distributed_buffers.py) | Fully-connected fabric; 1 hop per fabric crossing (see §6) | +| `XYRoutingMulticastModel` | [`distributed_buffers.py`](distributed_buffers.py) | XY / dimension-order routing on a 2-D mesh; X-then-Y multicast tree; per-link `EdgePressure` (see §7–§8) | +| `StarMulticastModel` | [`distributed_buffers.py`](distributed_buffers.py) | Star / central-switch — the spokes realization of a fully-connected fabric; per-spoke `EdgePressure` (see §8). Parameter-free constant regime only, like XY | + +> **There is no registry or factory.** Models are constructed directly +> (`HypercubeMulticastModel(dist_fn)`) and applied via `.apply(...)`. The only current usage is the +> test suite — [`tests/isl/distributed/test_multicast.py`](../../../../../../tests/isl/distributed/test_multicast.py). +> The suite lives at `tests/isl/distributed/` and runs as part of CI. + +> **Module layout.** This directory splits into three files: the four model classes above and +> the shared `MulticastModel` base they all inherit (one `apply()`, one abstract `_transfer_cost` +> hook per model) live in [`distributed_buffers.py`](distributed_buffers.py); the `EdgePressure` +> per-link-load abstraction and its scalar-extraction helpers live in +> [`edge_pressure.py`](edge_pressure.py); multicast-network construction (`identify_mesh_casts` +> and the helpers built on its result) lives in [`mesh_casts.py`](mesh_casts.py). + +--- + +## 2. The `TransferModel` contract + +Defined in [`../spatial.py`](../spatial.py). You implement exactly one abstract method: + +```python +class TransferModel(ABC): + @abstractmethod + def apply(self, buff: MappingNode, fills: Fill, occs: Occupancy) -> TransferInfo: + ... +``` + +### Inputs + +- **`buff: MappingNode`** — the buffer being analyzed. (`HypercubeMulticastModel` ignores it and + relies on its `dist_fn` instead; `SimpleLinkTransferModel` uses it to find spatial dims.) +- **`fills: Fill`** — a *tagged* `isl.Map` `{ [spacetime] -> [data] }` describing what each element + needs from its parent over time. +- **`occs: Occupancy`** — a *tagged* `isl.Map` `{ [spacetime] -> [data] }` describing what each + element holds over time. + +`Fill` and `Occupancy` are `TaggedMap`s (see +[`../mapping_to_isl/types.py`](../mapping_to_isl/types.py)): the raw relation is `.map_`, and +`.tags` is a list of `Tag`s labeling each **input** dimension. Both constructors assert +`len(tags) == map_.dim(isl.dim_type.in_)`. The relevant tags are: + +- `TemporalTag()` — that dimension spreads over time. +- `SpatialTag(spatial_dim, buffer)` — that dimension spreads over space, in `buffer`. + +### Output: `TransferInfo` + +A frozen dataclass (in `../spatial.py`) you must fully populate: + +| Field | Type | Meaning | +|-------|------|---------| +| `fulfilled_fill` | `Transfers` | Fills satisfied by peer-to-peer transfers (a tagged map) — the fills *covered* by a matched multicast source. | +| `unfulfilled_fill` | `Fill` | Fills *not* satisfied — no source held the datum, so it must come from higher in the hierarchy. | +| `parent_reads` | `Reads` | Fills satisfied by parent-to-child reads. | +| `hops` | `isl.PwQPolynomial` | The transfer cost metric across spacetime. | +| `link_transfer` | `bool` | Metadata flag — whether this used link transfers. | +| `edge_pressure` | `Optional[EdgePressure]` | Per-directed-edge load backing `hops` (see §8), for models that define a per-link topology. Defaults to `None`. | + +`fulfilled_fill` and `unfulfilled_fill` **partition the fills exactly**: with +`covered = _covered_fills(mcs)` (the `{ dst -> data }` pairs `identify_mesh_casts` matched to a +source), `fulfilled = fills ∩ covered` and `unfulfilled = fills − covered`. A destination requesting +a datum that *no* source holds simply never appears in the multicast networks, so it lands in +`unfulfilled_fill` — it is never silently treated as fulfilled. + +`edge_pressure` is populated by the models with an explicit per-link topology +(`XYRoutingMulticastModel`: mesh links; `StarMulticastModel`: spokes) inside `apply()`, from the +same `identify_mesh_casts` result as `hops`. `HypercubeMulticastModel` and +`FullyConnectedMulticastModel` leave it `None` — a convex bounding box has no notion of individual +links, and a contention-free full mesh (one dedicated link per pair) has no shared-link pressure to +report. + +`Transfers` and `Reads` are thin `TaggedMap` subclasses; construct them as +`Transfers(tags, map_)` / `Reads(tags, map_)`. + +--- + +## 3. How `HypercubeMulticastModel` works + +> **Worst-case multicast.** It assumes every multicast broadcasts to the *convex hypercube* that +> encloses all of its sources and destinations — an upper bound on the real cost. + +### Constructor + +```python +HypercubeMulticastModel(dist_fn: isl.Map) +``` + +`dist_fn` is a distance function `{ [dst -> src] -> [hops] }` — note the orientation: its domain is +a **`[dst -> src]` pair** (destination first), because `identify_mesh_casts` composes it as +`fills_to_matches.apply_range(dist_fn)` onto `{ ... -> [dst -> src] }` maps. Two further caller +contracts: the tuple names in `dist_fn`'s domain must match the spacetime tuple names of +`fills`/`occs` (ISL raises on a name mismatch when `dist_fn` is applied), and its range tuple must +be named `hops` (the fully-connected and star models filter on `{ hops[h] : h >= 1 }` to tell +self-deliveries apart from fabric crossings). Two assumptions are baked in: + +1. **Orthogonal dimensions / Manhattan distance** — each unit move along a dimension costs 1 hop, + and dimensions are orthogonal in the metric space. +2. **Translational invariance** — distance depends only on the displacement: if + `|src − dst| = |src' − dst'|` then `dist_fn(dst, src) = dist_fn(dst', src')`. + +These come from `calculate_extents_per_dim`, which the model relies on. + +### `apply(...)` data flow + +``` +occs.map_ { [spacetime] -> [data] } fills.map_ { [spacetime] -> [data] } + \ / + \ / + identify_mesh_casts(occs, fills, dist_fn) + | + v + mcs : { [data] -> [dst -> src] } (each datum's nearest-source multicast network) + | + _cost_mesh_cast_hypercube(mcs) + | + v + hops : isl.PwQPolynomial (total upper-bound hop count) +``` + +**Step A — `identify_mesh_casts(src_occupancy, dst_fill, dist_fn)`** +([`mesh_casts.py`](mesh_casts.py)). + +For every datum, it pairs the destinations that request it with the *nearest* source that holds it. +Conceptually: + +1. Reverse occupancy to `{ [data] -> [src] }` (which elements hold each datum). +2. Match each fill `{ [dst] -> [data] }` against the sources holding that datum → + `{ [dst -> data] -> [dst -> src] }`. +3. Apply `dist_fn` and take `lexmin` over distance to keep only the closest source per + `(dst, data)`. +4. Regroup as `{ [data] -> [dst -> src] }` and `lexmin` again to *devolve to a single source* when + several are equidistant. + +The result is the set of **multicast networks** (`mcns`): per datum, the destinations grouped with +their chosen source. + +**Step B — extents per dimension: `calculate_extents_per_dim(mcns)`** +([`mesh_casts.py`](mesh_casts.py)). + +For each multicast network it unions the sources with the destinations, then for each NoC dimension +projects away the others and takes `dim_max − dim_min`. That difference is the **extent** (the side +length of the bounding box) along that dimension, returned as one `isl.PwAff` per dimension. + +**Step C — hypercube cost: `_cost_mesh_cast_hypercube(mcns)`** +([`distributed_buffers.py`](distributed_buffers.py)). + +It folds the per-dimension extents into a single cost, then `.sum()`s over all networks. + +> ⚠️ **Known discrepancy — this is the bug currently being tracked.** +> The docstring/comment says the cost is +> `(∏_i extent_i) − 1` (the number of *interior* points of the bounding box minus one — the +> standard hypercube broadcast cost). **But the code actually computes** +> +> ``` +> cost = (∏_i (extent_i + 1)) − 1 +> ``` +> +> because the loop multiplies by `dim_extent.add(one)` (`extent_i + 1`), not `extent_i`. Since +> `extent_i = max − min` is already *one less* than the number of points along a dimension, adding +> 1 back double-counts the span. This is consistent with the observed **~3× overestimate of hops in +> all-to-all** topologies noted in recent work. Treat the formula in the code as *not yet correct*; +> a new template should decide deliberately whether it wants `extent_i` or `extent_i + 1`. + +### Return value + +```python +# { dst -> data } fills actually covered by a matched source. +covered: isl.Map = _covered_fills(mcs) + +return TransferInfo( + fulfilled_fill=Transfers(fills.tags, fills.map_.intersect(covered)), + parent_reads=Reads(occs.tags, mcs), # the multicast map + unfulfilled_fill=Fill(fills.tags, fills.map_.subtract(covered)), + hops=result, # the PwQPolynomial cost + link_transfer=True, + # No per-link decomposition defined for the hypercube abstraction. + edge_pressure=None, +) +``` + +Note the partition idiom: `_covered_fills(mcs)` reshapes the multicast networks +`{ [data] -> [dst -> src] }` into `{ dst -> data }` (via +`range_reverse().uncurry().domain_factor_domain().reverse()` — "forget which source served it, keep +dst and data"), which lines up with `fills.map_` so `intersect`/`subtract` split the fills into the +covered and uncovered halves. Earlier revisions returned the *entire* fill map as `fulfilled_fill` +and an always-empty `unfulfilled_fill` (`fills.map_.subtract(fills.map_)`); that silently +mis-reported fills whose datum no source holds — do not copy that idiom. + +--- + +## 4. Contrast: `SimpleLinkTransferModel` + +For comparison (the *other* valid shape — no constructor state), `SimpleLinkTransferModel` +([`../spatial.py`](../spatial.py)): + +- Takes **no `dist_fn`**; constructed as `SimpleLinkTransferModel()`. +- Asserts `fills.tags == occs.tags`. +- Builds a **neighbor-to-neighbor mesh** via `make_mesh_connectivity` (only 1 or 2 spatial dims + supported — raises otherwise). +- Data reachable from a neighbor is `fulfilled_fill`; the rest is `unfulfilled_fill`. +- `hops` is **1 per neighbor-filled element** (`PwQPolynomial.one_on_domain(...)`), not a + distance-weighted sum. +- Has an early-out: if there is no temporal dimension or no spatial dimension, nothing moves, so it + returns an empty/zero `TransferInfo`. + +So these two models bracket the design space: **stateful + distance-aware** (hypercube) vs. +**stateless + fixed-topology** (simple link). + +--- + +## 5. How to create a new template + +1. **Pick a home.** Add your class under `reuse/isl/`. Put distributed / NoC / mesh models in this + `distributed/` directory next to `distributed_buffers.py`. +2. **Subclass `MulticastModel`** if your model is distance-driven multicast (one `dist_fn`, + nearest-source matching) — the base owns the constructor, the single `identify_mesh_casts` + call, the fill partition, and the `TransferInfo` assembly. Only subclass `TransferModel` + directly (and write your own `apply`) for a different shape entirely, like the stateless + `SimpleLinkTransferModel`. +3. **Implement `_transfer_cost(self, mcs) -> isl.PwQPolynomial | EdgePressure`.** `mcs` is the + `{ [data] -> [dst -> src] }` multicast networks, computed once by the base `apply`. Reuse the + existing kernels: + - `calculate_extents_per_dim(mcns)` if you want per-dimension bounding-box extents. + - `_fabric_crossing(mcns, self.dist_fn)` to keep only deliveries that cross the fabric. + - `_edge_pressure_from_links(...)` if you report a per-link `EdgePressure` (see §8) — return + it directly and the base derives `hops` from its total; return a bare `isl.PwQPolynomial` + and the base leaves `edge_pressure` at `None`. +4. **Honor the invariants.** The base guarantees the big ones structurally: the fill partition + (`fulfilled = fills ∩ covered`, `unfulfilled = fills − covered`), one `identify_mesh_casts` + call per `apply`, and `hops == EdgePressure.total()` whenever you return a pressure. What is + left to you: build the cost over the correct domain, and decide deliberately whether your + topology defines a per-link decomposition or not. +5. **Add a test** mirroring + [`tests/isl/distributed/test_multicast.py`](../../../../../../tests/isl/distributed/test_multicast.py): + a YAML-driven gamut of `(dims, fill, occ, dist_fn, expected_hops)` cases. + +### Copy-paste skeleton + +```python +import islpy as isl + +from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( + MulticastModel, +) + + +class MyMulticastModel(MulticastModel): + """One-line description of the topology/assumptions this model encodes.""" + + def _transfer_cost(self, mcs: isl.Map) -> isl.PwQPolynomial: + # `mcs` is { [data] -> [dst -> src] } from `identify_mesh_casts`, + # computed once by `MulticastModel.apply`; the fill partition and the + # `TransferInfo` assembly are already handled there. + # TODO: your cost kernel. Return an `EdgePressure` instead (see §8) if + # your topology defines per-link loads -- `apply` then derives `hops` + # from its total automatically. + raise NotImplementedError +``` + +(A non-multicast model — different matching, no `dist_fn` — instead subclasses `TransferModel` +directly and implements the full `apply`; use `SimpleLinkTransferModel` in +[`../spatial.py`](../spatial.py) as the reference for that shape.) + +**Checklist** + +- [ ] Subclasses `MulticastModel` and implements `_transfer_cost` (only non-multicast shapes + subclass `TransferModel` and hand-roll `apply`). +- [ ] Constructor state matches what the cost kernel needs (the base stores `dist_fn`; override + `__init__` only to add state). +- [ ] `_transfer_cost` returns an `isl.PwQPolynomial` over the right domain — or an + `EdgePressure` for per-link topologies, making `hops == Σ_edges load` structural. +- [ ] A YAML-driven gamut test exists. + +--- + +## 6. Worked example: `FullyConnectedMulticastModel` + +A real, tested model for a **fully-connected fabric** (e.g. an NVSwitch-style all-to-all). It lives +next to the hypercube model in [`distributed_buffers.py`](distributed_buffers.py). + +On a fully-connected fabric every cross-node delivery costs **one hop regardless of distance**, and a +self-delivery (source node == destination node) costs **zero**. So the cost of a mapping is just the +number of deliveries that actually traverse the fabric: + +``` +cost = | { (data, dst, src) ∈ mcs : dist_fn(dst, src) ≥ 1 } | +``` + +`dist_fn` is used *only* to tell self-deliveries (0 hops) apart from fabric-crossing ones — its hop +*magnitude* never enters the cost. This sidesteps the hypercube extent overestimate (see §3) entirely. + +```python +class FullyConnectedMulticastModel(MulticastModel): + """Multicast cost on a fully-connected fabric: 1 hop per fabric crossing.""" + + def _transfer_cost(self, mcs: isl.Map) -> isl.PwQPolynomial: + return self._cost_fully_connected(mcs) + + def _cost_fully_connected(self, mcns: isl.Map) -> isl.PwQPolynomial: + """Count the deliveries in `mcns` that traverse the fabric (dist >= 1).""" + # [dst -> src] pairs that actually traverse the fabric (>= 1 hop). + crossing: isl.Map = _fabric_crossing(mcns, self.dist_fn) + return crossing.wrap().card() +``` + +How the kernel works: `_fabric_crossing` ([`mesh_casts.py`](mesh_casts.py)) computes +`dist_fn.intersect_range({ hops[h] : h ≥ 1 }).domain()` — the set of `[dst -> src]` pairs that +cross the fabric — and intersects `mcns`' range with it, keeping only crossing deliveries; +`.wrap().card()` then counts the `(data, dst, src)` points as an `isl.PwQPolynomial` (constant +when there are no parameters). Everything else — the single `identify_mesh_casts` call, the fill +partition, `edge_pressure=None` — is `MulticastModel.apply`'s job, not this class's. + +**Verified numbers** (8-GPU one-hot encoding, from the test below): + +| Case | `FullyConnectedMulticastModel` | `HypercubeMulticastModel` | +|------|-------------------------------|---------------------------| +| all-to-all (64 chunks, 8 self) | **56** | 168 | +| single unicast GPU0 → GPU3 | **1** | 3 | +| self chunk GPU5 → GPU5 | **0** | 0 | + +The all-to-all column is the headline: **56 vs 168 is exactly the ~3× overestimate** the hypercube +model incurs on a fully-connected fabric (each unicast costed as a `(1+1)(1+1) − 1 = 3` hypercube +instead of a single crossing — see the discrepancy in §3). + +This example is exercised by a real test: +[`tests/isl/distributed/test_fully_connected.py`](../../../../../../tests/isl/distributed/test_fully_connected.py) +with cases in +[`tests/isl/distributed/fully_connected/test_cases.yaml`](../../../../../../tests/isl/distributed/fully_connected/test_cases.yaml). +Run it (m4 on `PATH` per the islpy-barvinok setup): + +```bash +PATH="$HOME/.local/bin:$PATH" .venv/bin/python -m pytest \ + tests/isl/distributed/test_fully_connected.py -q +``` + +--- + +## 7. XY (dimension-order) routing: `XYRoutingMulticastModel` + +`XYRoutingMulticastModel` ([`distributed_buffers.py`](distributed_buffers.py)) models **XY routing** +on a 2-D mesh: every packet travels **along X first, then Y**. A multicast from one source is +therefore a rigid tree: + +1. an **X segment** along the source's row, reaching every column that holds a destination, then +2. an independent **Y segment** down each of those columns, *starting from the source's row*. + +The cost of one tree (source `s = (xs, ys)`, destinations `D`) is: + +``` +x_extent({xs} ∪ {dst columns}) + + Σ over destination columns xd of y_extent({ys} ∪ {dst y's in column xd}) +``` + +Source selection is **per destination** (`identify_mesh_casts` pairs each destination with its +nearest source, devolving ties); destinations sharing a source form one tree, and the model sums +over all trees and all data. + +### Where it sits: `extent_DOR` (floor) ≤ XY ≤ hypercube + +Because each column's Y segment restarts from the source row instead of sharing a trunk, XY is an +**upper bound on free routing** and a **lower bound on the hypercube** (which reaches every node in +the bounding box). Note `extent_DOR_hops` in the test yamls is the **free-routing floor**, *not* the +XY cost — it assumes routing can move freely between dimensions. Worked example (verified by the +model): source `(1,0)` casting to `(0,2)` and `(2,2)`: + +``` + y=2 D . D + y=1 | . | + y=0 +-S-+ S=(1,0); X covers cols 0..2 (2 links) + x=0 1 2 then Y down col 0 and col 2 from row 0 (2 + 2 links) + + floor (extent_DOR) = 4 ≤ XY = 6 ≤ hypercube = 8 +``` + +### Cost kernel + +There is no standalone cost method: the cost *is* the per-edge decomposition, aggregated. The +whole model is one hook — + +```python +def _transfer_cost(self, mcs: isl.Map) -> EdgePressure: + return _edge_pressure_from_links(self._directed_mesh_links(mcs)) +``` + +— because it returns an `EdgePressure` (see §8), `MulticastModel.apply` sets `edge_pressure` to +it and derives `hops = _const_pwq(pressure.total())` in one place: one aggregation path, so the +scalar and the per-edge view can never disagree (Σ_edges load == total link count, structurally). + +`_directed_mesh_links` builds the X segments explicitly along each source row (out to every +destination column, split rightward/leftward at the source column `xs`) and the Y segments down +each destination column from the source row (split upward/downward at `ys`), keeping every link's +identity — see §8 for the edge naming. + +Notes / limitations: +- **2-D node tuples only** (no temporal dims); `apply` raises a `ValueError` ("XYRoutingMulticastModel + requires a 2-D node tuple (X then Y)...") for any other arity — N-D dimension-order routing is a + TODO. The tuple *name* is generic: it is read off the maps at `apply` time (via + `_mesh_node_tuple`), so `noc[x, y]`, `pe[x, y]`, etc. all work as long as `fills`, `occs`, and + `dist_fn` agree on it (see the caller contract in §3). +- Each per-column/per-row link set is built explicitly and counted via `card()` rather than summing + a min/max polynomial — the latter trips a barvinok `summate` assertion at scale (e.g. the 8×8 + case). +- Returns a **parameter-free constant** (the validated regime); parametric spacetimes are future work. + +### Tested + +[`tests/isl/distributed/test_xy_routing.py`](../../../../../../tests/isl/distributed/test_xy_routing.py) +with hand-derived cases in +[`tests/isl/distributed/xy_routing/test_cases.yaml`](../../../../../../tests/isl/distributed/xy_routing/test_cases.yaml) +(there is **no XY oracle in the repo**, so the expected values are hand-derived and each case carries +its geometry). Cases: unicast `4`, the `(1,0)` discriminator `6`, three-corner `6`, 1-D column `3`, +replicated-source `4`, and an 8×8 scale case `448`. Run: + +```bash +PATH="$HOME/.local/bin:$PATH" .venv/bin/python -m pytest \ + tests/isl/distributed/test_xy_routing.py -q +``` + +--- + +## 8. Per-edge memory pressure (link load): `EdgePressure` + +`hops` collapses a whole routing to one scalar, which hides a real constraint: **each physical edge +has a finite bandwidth**, so the *busiest* link is what saturates first. `EdgePressure` keeps the +load broken out per directed physical edge — `{ edge -> number-of-trees-crossing-it }` — which is +exactly the quantity the production symbolic path calls `max_traffic` and feeds into the `Network` +latency formula `max(max_hops·latency, max_link_traffic / throughput)` +([`frontend/arch/components.py`](../../../../frontend/arch/components.py)). It is exposed as the +`TransferInfo.edge_pressure` field: `model.apply(buff, fills, occs).edge_pressure`, an +`Optional[EdgePressure]` populated by `XYRoutingMulticastModel` and `StarMulticastModel` inside +`apply()` (from the same `identify_mesh_casts` result as `hops`, so the two are always consistent) +and `None` for `HypercubeMulticastModel` / `FullyConnectedMulticastModel` (see §2). There is no +standalone `edge_pressure(fills, occs)` method. + +### The primitive + +After `identify_mesh_casts` fixes the `[dst -> src]` pairs, build, per directed edge type, a map +`M = { [data -> src] -> edge }` associating each multicast **tree** with every edge its route +crosses. Then (`_edge_pressure_from_links` does exactly this, unioning the per-type results) + +```python +load = M.reverse().card() # { edge -> #trees crossing it } +``` + +The key is the tree `(data, src)`, **not** the destination: within one tree a link is traversed once +regardless of how many leaves hang off it, so this counts *pressure* (distinct flows on a link), not +summed hops. `EdgePressure.total()` sums the load over every edge (this is what XY/Star `hops` is +built from, via `_const_pwq`); `bottleneck()` returns the max load (enumerating the finite, +parameter-free edge domain); `eval_edge(name, coords)` looks up one edge. + +### XY routing → directed mesh edges + +`XYRoutingMulticastModel._directed_mesh_links` decomposes each tree onto four directed link types: +`xedge_r`/`xedge_l` along the source row (split at the source column `xs`) and `yedge_u`/`yedge_d` +down each destination column (split at the source row `ys`). This **is** the §7 cost kernel — every +link is built explicitly with its identity kept (not via `calculate_extents_per_dim`, which only +yields a scalar length and discards *which* links are used), and the scalar `hops` is just +`EdgePressure.total()` over these maps. + +Decisive cross-check (no oracle needed): **`Σ_edges load == total XY hops`**. The per-edge loads must +sum back to the already-trusted A–F totals (4/6/6/3/4/448), so a wrong decomposition fails. Worked F +geometry (8×8, datum `(d0,d1)` held at node `(d0,d1)`, requested by all of column `x=d0`): every +datum of column `c` floods all 7 vertical links of column `c`, so `yedge_u[c,t]` load = `t+1` and +`yedge_d[c,t]` = `7−t`; the busiest directed link is `7` (the physical link total is `8`). Cases A–E +are single trees, so every edge load is `1`. + +### Star / fully-connected → spokes + +`StarMulticastModel` **is** the spokes realization of the fully-connected fabric (NVSwitch-style: each +node has one link to a central switch). A delivery routes `src → switch → dst`, so each datum loads +its source's egress spoke once (multicast fans out *at the switch*) and each destination's ingress +spoke once; self-deliveries (0 hops) load nothing. `_spoke_loads` returns `spoke_in[n]` (ingress) and +`spoke_out[n]` (egress) loads. For an N-way all-to-all every node receives `N−1` and sources `1`, so +the **ingress spokes are hottest at `N−1`** — this is where bandwidth actually bites, whereas +`FullyConnectedMulticastModel`'s contention-free full-mesh view has no hotspot. The two are tied by +**`Σ_nodes ingress == FullyConnected crossing count`** (every crossing delivery is one node's +ingress; e.g. 8-GPU all-to-all: `56`). The star scalar `hops` = `Σ egress + Σ ingress` (injections + +deliveries). + +### Tested + +[`tests/isl/distributed/test_edge_pressure.py`](../../../../../../tests/isl/distributed/test_edge_pressure.py) +— the XY `Σ load == hops` invariant over A–F (with the pressure taken from +`apply(...).edge_pressure`), F's bottleneck/edge loads (`7`, `yedge_u[0,6]=7`, `yedge_d[0,1]=6`), +single-tree unit bottlenecks, and the star spoke loads / `Σ ingress == FC count` invariant for 4- +and 8-GPU all-to-all (star `hops` = injections + deliveries: `16`/`64`, ingress bottleneck +`3`/`7`). Run: + +```bash +PATH="$HOME/.local/bin:$PATH" .venv/bin/python -m pytest \ + tests/isl/distributed/test_edge_pressure.py -q +``` + +--- + +## 9. References + +- Interface + `SimpleLinkTransferModel` + `TransferInfo`: [`../spatial.py`](../spatial.py) +- `MulticastModel` base + the four model classes, `HypercubeMulticastModel`'s + `_cost_mesh_cast_hypercube`: [`distributed_buffers.py`](distributed_buffers.py) +- `identify_mesh_casts`, `calculate_extents_per_dim`, `_covered_fills`, `_mesh_node_tuple`: + [`mesh_casts.py`](mesh_casts.py) +- `EdgePressure`, `_eval_const`, `_const_pwq`, `_edge_pressure_from_links`: + [`edge_pressure.py`](edge_pressure.py) +- Tagged-map / tag types: [`../mapping_to_isl/types.py`](../mapping_to_isl/types.py) +- Example test harness: + [`tests/isl/distributed/test_multicast.py`](../../../../../../tests/isl/distributed/test_multicast.py) diff --git a/accelforge/model/_looptree/reuse/isl/distributed/bind.py b/accelforge/model/_looptree/reuse/isl/distributed/bind.py index e95b2ca5..7da0a0e4 100644 --- a/accelforge/model/_looptree/reuse/isl/distributed/bind.py +++ b/accelforge/model/_looptree/reuse/isl/distributed/bind.py @@ -1,6 +1,6 @@ """Applies the binding layer into one that can be used for later analysis,""" -from accelforge.frontend.binding import Binding +from accelforge.frontend._binding import Binding from accelforge.frontend.mapping import Mapping from accelforge.frontend.workload import Workload diff --git a/accelforge/model/_looptree/reuse/isl/distributed/distributed_buffers.py b/accelforge/model/_looptree/reuse/isl/distributed/distributed_buffers.py index 35d87cb0..92614f56 100644 --- a/accelforge/model/_looptree/reuse/isl/distributed/distributed_buffers.py +++ b/accelforge/model/_looptree/reuse/isl/distributed/distributed_buffers.py @@ -1,15 +1,22 @@ """ Models for handling calculating the cost of a Workload on distributed buffer architectures. + +The shared shape (one `dist_fn`, one `identify_mesh_casts` call per `apply`, +one `TransferInfo` assembly) lives on the `MulticastModel` base class; each +concrete model below contributes only its cost kernel via `_transfer_cost`. +The underlying primitives -- `EdgePressure` and its scalar-extraction helpers, +and the multicast-network construction (`identify_mesh_casts` and friends) -- +live in `edge_pressure.py` and `mesh_casts.py` respectively. """ -import logging +from abc import abstractmethod + +from typing import Optional import islpy as isl from accelforge.frontend.mapping import MappingNode -from accelforge.model._looptree.reuse.isl.isl_functions import dim_projector_mask -from accelforge.model._looptree.reuse.isl.mapping_to_isl import DUMP_ISL_IR from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import Fill, Occupancy from accelforge.model._looptree.reuse.isl.spatial import ( Reads, @@ -18,174 +25,74 @@ TransferModel, ) +from accelforge.model._looptree.reuse.isl.distributed.edge_pressure import ( + EdgePressure, + _const_pwq, + _edge_pressure_from_links, + _union_pwqs, +) +from accelforge.model._looptree.reuse.isl.distributed.mesh_casts import ( + identify_mesh_casts, + calculate_extents_per_dim, + _covered_fills, + _mesh_node_tuple, + _per_src, + _fabric_crossing, +) -def identify_mesh_casts( - src_occupancy: isl.Map, dst_fill: isl.Map, dist_fn: isl.Map -) -> isl.Map: - """ - Given srcs with data, fills to destinations, and a distance function, identify per data - the srcs delivering that data to dsts. - - Parameters - ---------- - src_occupancy: - An isl.Map of the form { [src] -> [data] } corresponding to the data held - at the buffer at space `src`. - dst_fill: - An isl.Map of the form { [dst] -> [data] } corresponding to the data requested - at the element at space `dst`. - dist_fn: - A distance function { [src -> dst] -> [hops] } that accepts two points in - space, corresponding to the `src` and `dst`, and returns the distance - between the two points in terms of `hops`, a quantized atomic distance of - data transmission cost. - - Returns - ------- - { [data] -> [dst -> src] } where { [dst] -> [data] } and { [src] -> [data] } are in - `src_occupancy` and `dst_fill` respectively, and where `[dst -> src]` is the infimum of - `dst_fn(src, dst), ∀ src, dst s.t. { [src] -> [data] } ∈ `src_occupancy` and - `{ [dst] -> [data] }` ∈ `dst_fill`. - """ - # Makes { [dst -> data] -> [dst -> data] } - fill_to_fill: isl.Map = dst_fill.wrap().identity() - if DUMP_ISL_IR: - logging.info(f"fill_to_fill: {fill_to_fill}") - - # Inverts src_occupancy s.t. data -> src. - # i.e. { [xs, ys] -> [d0, d1] } to { [d0, d1] -> [xs, ys] } - data_presence: isl.Map = src_occupancy.reverse() - - # { [dst -> data] -> [dst -> src] } where src contains data. - fills_to_matches: isl.Map = ( - fill_to_fill.uncurry() # { [[dst -> data] -> dst] -> data } - .apply_range(data_presence) # { [[dst -> data] -> dst] -> src } - .curry() - ) # { [[dst -> data] -> [dst -> src] } - if DUMP_ISL_IR: - logging.info(f"fills_to_matches: {fills_to_matches}") - - # Calculates the distance of a fill to the nearest src satisfying the fill. - # { [dst -> data] -> [dist] } - fill_min_dist: isl.Map = fills_to_matches.apply_range(dist_fn).lexmin() - # Isolates the relevant minimal pairs. - # { [dst -> data] -> [dst -> src] :.dst -> src is minimized distance } - minimal_pairs: isl.Map = ( - fill_min_dist.apply_range( - # Note: Need to match fill -> min_dist with min_dist -> [fill -> match] as lexmin over - # fill and match will minimize distance over the tuple (src, dst, data), but that - # overconstrains the optimization as we want to minimize over distance (dst, data) - # only for all src. - fills_to_matches.range_map() - .apply_range(dist_fn) - .reverse() - ) - .range() - .unwrap() - ) - if DUMP_ISL_IR: - logging.info(f"minimal_pairs: {minimal_pairs}") - - # Isolates the multicast networks. - # { [data] -> [dst -> src] : dst -> src is minimized distance } - multicast_networks: isl.Map = minimal_pairs.curry().range().unwrap() - # Devolves to a single source if multiple sources per domain point. - multicast_networks = multicast_networks.uncurry().lexmin().curry() - - return multicast_networks - - -def calculate_extents_per_dim(mcns: isl.Map) -> list[isl.PwAff]: - """ - Parameters - ---------- - mcns: - Mesh cast-networks, or networks in which all dsts per data are grouped with - the closest src containing the data. - - Returns - ------- - A list of `isl.PwAff` that gives the max extent (length) along dim_i per mcn, - where i is the i-th `isl.PwAff`. - - Preconditions - ------------- - `mcns` were generated with a Manhattan distance `dst_fn` by `identify_mesh_casts` - s.t. all dimensions are orthogonal to each other in a metric space, where each - unit movement in a dimension counts as 1 hop. - We also assume `dst_fn` is translationally invariant (i.e., ∀src, dst, - src', dst' ∈ space, if |src - dst| = |src' - dst'|, - dst_fn(src, dst) = dst_fn(src', dst'). +class MulticastModel(TransferModel): """ - # Makes mcns from { [data] -> [dst -> src] } to { [data -> src] -> [dst] } - potential_srcs: isl.Map = mcns.range_reverse().uncurry() - # Sources are part of the extents, so we union it with the destinations. - # { [data -> src] -> [src] } - srcs: isl.Map = potential_srcs.domain().unwrap().range_map() - # { [data -> src] -> [spacetime] } - casting_extents: isl.Map = srcs.union(potential_srcs) - - # Projects away all dimensions but one to find their extent for hypercube. - dims: int = potential_srcs.range_tuple_dim() - # Creates a mask of what to project out. - project_out_mask: list[bool] = [True] * dims - dim_extents: list[isl.PwAff] = [None] * dims - - # Gets the extents of all dimensions - for noc_dim in range(dims): - # Project out all the dimensions of the output besides noc_dim. - project_out_mask[noc_dim] = False - # { [spacetime] -> [dimension] } - extent_mapper: isl.Map = dim_projector_mask( - casting_extents.range().get_space(), project_out_mask - ).reverse() - dim_extent_space: isl.Map = casting_extents.apply_range(extent_mapper) - project_out_mask[noc_dim] = True - - # Finds max(noc_dim) - min(noc_dim) for each [data -> src] - max_extent: isl.PwAff = dim_extent_space.dim_max(0) - min_extent: isl.PwAff = dim_extent_space.dim_min(0) - - # Subtracts the max from the min to get the extent per [data -> src] - dim_extents[noc_dim] = max_extent.sub(min_extent).coalesce() - - return dim_extents - - -class HypercubeMulticastModel(TransferModel): - """ - Does distributed multicasting a mesh using worst-case multicasting - behavior by assuming all multicasts are broadcasting to the convex - hypercube that encapsulates all their destinations and sources. + Common shape shared by every distance-driven multicast transfer model. + + Every concrete model below (`HypercubeMulticastModel`, + `FullyConnectedMulticastModel`, `XYRoutingMulticastModel`, + `StarMulticastModel`) is built from one `dist_fn` and computes `apply` + identically up to its cost kernel: call `identify_mesh_casts` exactly + once, derive the cost from that single result, partition the fills, and + assemble a `TransferInfo`. This base class owns that shared shape; a + subclass need only implement `_transfer_cost`. + + Because `hops` and `edge_pressure` are both derived here from the same + `_transfer_cost` return value, `Σ_edges load == hops` (for models that + report an `EdgePressure`) is structural rather than an invariant each + subclass has to maintain by hand: whenever `_transfer_cost` returns an + `EdgePressure` `p`, `hops` is *always* `_const_pwq(p.total())`. """ def __init__(self, dist_fn: isl.Map): """ - Initializes the HypercubeMulticastModel with the distance function - over the metric space. - - Because we are using calculate_extents_per_dim(mcns), we inherit the - following requirements: - `dst_fn` holds all dimensions are orthogonal to each other in a metric space, - where each unit movement in a dimension counts as 1 hop. - - We also assume `dst_fn` is translationally invariant (i.e., ∀src, dst, - src', dst' ∈ space, if |src - dst| = |src' - dst'|, - dst_fn(src, dst) = dst_fn(src', dst'). + Parameters + ---------- + dist_fn: + A distance function { [dst -> src] -> [hops] } that accepts two + points in space, corresponding to `dst` and `src`, and returns + the distance between them in `hops`, a quantized atomic distance + of data transmission cost. Stored and passed straight through to + `identify_mesh_casts` on every `apply` call. + + Caller contract (inherited from `identify_mesh_casts`): the + tuple names of `fills`/`occs`'s domains (the spacetime/node + tuple, e.g. `noc[x, y]`) must match the corresponding tuple + names in `dist_fn`'s domain -- ISL raises on a name mismatch + when `dist_fn` is applied. `dist_fn`'s range tuple must be named + `hops` (`_fabric_crossing`, used by `FullyConnectedMulticastModel` + and `StarMulticastModel`, filters on `{ hops[h] : h >= 1 }` to + distinguish self-deliveries from fabric-crossing ones). """ self.dist_fn = dist_fn def apply(self, buff: MappingNode, fills: Fill, occs: Occupancy) -> TransferInfo: """ Given a buffer, its fills across time, and its occupancies across time, - calculate the spatial transfers." + calculate the spatial transfers. Parameters ---------- buff: - The buffer whose spatial analysis is being considered. Currently, - we rely on dist_fn to deal with this rather than buffer. + The buffer whose spatial analysis is being considered. Not used + by any current subclass (they all rely on `dist_fn` instead); + kept for interface symmetry with `TransferModel.apply`. fills: The fill of `buffer` across time from parents. occs: @@ -193,24 +100,88 @@ def apply(self, buff: MappingNode, fills: Fill, occs: Occupancy) -> TransferInfo Returns ------- - Fills that were fulfilled, Fills that were unfilled, and parent reads per - position in spacetime. Then, gets hops per timestep. + A `TransferInfo` whose `fulfilled_fill`/`unfulfilled_fill` partition + `fills` by whether `identify_mesh_casts` found a matched source for + that (dst, data) pair -- a fill with no source holding its datum is + `unfulfilled_fill`, never silently treated as fulfilled. `hops` and + `edge_pressure` both come from `_transfer_cost(mcs)`: if it returns + an `EdgePressure` `p`, `edge_pressure=p` and + `hops=_const_pwq(p.total())`; otherwise `edge_pressure=None` and + `hops` is the returned polynomial directly (the topology has no + per-link decomposition to report). """ + # `identify_mesh_casts` is called exactly once; every output below is + # derived from this single `mcs`, so they cannot fall out of sync. mcs: isl.Map = identify_mesh_casts(occs.map_, fills.map_, self.dist_fn) - result: isl.PwQPolynomial = self._cost_mesh_cast_hypercube(mcs) + cost: isl.PwQPolynomial | EdgePressure = self._transfer_cost(mcs) + edge_pressure: Optional[EdgePressure] + hops: isl.PwQPolynomial + if isinstance(cost, EdgePressure): + edge_pressure = cost + hops = _const_pwq(cost.total()) + else: + edge_pressure = None + hops = cost + # { dst -> data } fills actually covered by a matched source. + covered: isl.Map = _covered_fills(mcs) - # TODO: Read once from all buffers, assert that - # card(mcs) == tensor_size * duplication factor - n_meshcasts: int = mcs.card() return TransferInfo( - fulfilled_fill=Transfers(fills.tags, fills.map_), + fulfilled_fill=Transfers(fills.tags, fills.map_.intersect(covered)), parent_reads=Reads(occs.tags, mcs), - unfulfilled_fill=Fill(fills.tags, fills.map_.subtract(fills.map_)), - hops=result, + unfulfilled_fill=Fill(fills.tags, fills.map_.subtract(covered)), + hops=hops, link_transfer=True, + edge_pressure=edge_pressure, ) - def _cost_mesh_cast_hypercube(self, mcns: isl.Map) -> int: + @abstractmethod + def _transfer_cost(self, mcs: isl.Map) -> isl.PwQPolynomial | EdgePressure: + """ + Compute this topology's transfer cost from a fixed multicast-network map. + + Parameters + ---------- + mcs: + Multicast networks { [data] -> [dst -> src] } from + `identify_mesh_casts`, computed once by `apply` and shared with + every other output `apply` derives. + + Returns + ------- + Either a bare `isl.PwQPolynomial` (a topology with no per-link + decomposition -- `apply` sets `hops` to exactly this polynomial and + leaves `edge_pressure` at `None`), or an `EdgePressure` (a topology + with one -- `apply` sets `hops` to `_const_pwq(edge_pressure.total())`, + structurally keeping the scalar and the per-edge view consistent). + """ + raise NotImplementedError + + +class HypercubeMulticastModel(MulticastModel): + """ + Does distributed multicasting a mesh using worst-case multicasting + behavior by assuming all multicasts are broadcasting to the convex + hypercube that encapsulates all their destinations and sources. + + `edge_pressure` is always `None` on the resulting `TransferInfo`: the + hypercube model costs a convex bounding box, which has no notion of + individual links to report pressure on. + + Preconditions + ------------- + Because the cost kernel uses `calculate_extents_per_dim(mcns)`, `dist_fn` + must hold all dimensions orthogonal to each other in a metric space, + where each unit movement in a dimension counts as 1 hop, and must be + translationally invariant (i.e., ∀src, dst, src', dst' ∈ space, if + |src - dst| = |src' - dst'|, dist_fn(src, dst) = dist_fn(src', dst')). + """ + + def _transfer_cost(self, mcs: isl.Map) -> isl.PwQPolynomial: + # TODO: Read once from all buffers, assert that + # card(mcs) == tensor_size * duplication factor + return self._cost_mesh_cast_hypercube(mcs) + + def _cost_mesh_cast_hypercube(self, mcns: isl.Map) -> isl.PwQPolynomial: """ Given a multicast_network, calculate the hypercube. @@ -259,3 +230,358 @@ def _cost_mesh_cast_hypercube(self, mcns: isl.Map) -> int: # Return the hypercube cost as a piecewise polynomial. return hypercube_costs.sum() + + +class FullyConnectedMulticastModel(MulticastModel): + """ + Multicast cost model for a fully-connected fabric (e.g. an NVSwitch-style + all-to-all interconnect). + + Every cross-node delivery costs exactly one hop regardless of distance, and + a self-delivery (source node == destination node) costs zero: + + cost = | { (data, dst, src) in mcs : dist_fn(dst, src) >= 1 } | + + This is distance-independent in magnitude (one hop per crossing); `dist_fn` + is used only to tell self-deliveries (0 hops) apart from fabric-crossing ones. + + `edge_pressure` is always `None` on the resulting `TransferInfo`: this + model treats the fabric as a contention-free full mesh (one dedicated + link per pair), so there is no per-link pressure to report. + """ + + def _transfer_cost(self, mcs: isl.Map) -> isl.PwQPolynomial: + return self._cost_fully_connected(mcs) + + def _cost_fully_connected(self, mcns: isl.Map) -> isl.PwQPolynomial: + """ + Count the deliveries in `mcns` that traverse the fabric. + + Parameters + ---------- + mcns: + Multicast networks { [data] -> [dst -> src] } from `identify_mesh_casts`. + + Returns + ------- + The number of (data, dst, src) deliveries with dist_fn(dst, src) >= 1, as a + piecewise quasi-polynomial (constant when there are no parameters). + """ + # [dst -> src] pairs that actually traverse the fabric (>= 1 hop). + crossing: isl.Map = _fabric_crossing(mcns, self.dist_fn) + return crossing.wrap().card() + + +# Directed-edge vocabulary + the four name-independent link-emitting maps for +# XY routing (parsed once at import). `_XY_EDGE_TYPES` is the single source +# of truth for the edge names: it feeds both the maps below and +# `XYRoutingMulticastModel.EDGE_TYPES`, so the class constant and the parsed +# maps can never name the edges differently. +_XY_EDGE_TYPES: tuple[str, str, str, str] = ( + "xedge_r", + "xedge_l", + "yedge_u", + "yedge_d", +) +_XEDGE_R, _XEDGE_L, _YEDGE_U, _YEDGE_D = _XY_EDGE_TYPES + +# { [[col[x] -> span[t]] -> ysv[ys]] -> yedge_u/d[x, t] : ... } -- re-key a +# column's spanned vertical links (see `_span_links`) onto the up/down edge +# tuples, splitting direction at the source row `ys`. +_YEDGE_U_MAP: isl.Map = isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + "{ [[col[x] -> span[t]] -> ysv[ys]] -> %s[x, t] : t >= ys }" % _YEDGE_U, +) +_YEDGE_D_MAP: isl.Map = isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + "{ [[col[x] -> span[t]] -> ysv[ys]] -> %s[x, t] : t < ys }" % _YEDGE_D, +) +# { [span[t] -> xy[xs, ys]] -> xedge_r/l[t, ys] : ... } -- re-key the source +# row's spanned horizontal links onto the right/left edge tuples, splitting +# direction at the source column `xs`. +_XEDGE_R_MAP: isl.Map = isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + "{ [span[t] -> xy[xs, ys]] -> %s[t, ys] : t >= xs }" % _XEDGE_R, +) +_XEDGE_L_MAP: isl.Map = isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + "{ [span[t] -> xy[xs, ys]] -> %s[t, ys] : t < xs }" % _XEDGE_L, +) + + +def _span_links(coords: isl.Map) -> isl.Map: + """ + Build the set of link indices spanned by a per-key coordinate map. + + Parameters + ---------- + coords: + { key -> name[c] }, one point per (key, coordinate) pair to span -- + e.g. every destination-plus-source y within one tree's column, or + every destination-plus-source column along one tree's row. `name` is + read directly off `coords`'s range tuple, so this works for any + single-dimension range tuple. + + Returns + ------- + { key -> span[t] : min(key) <= t < max(key) } -- the contiguous run of + link indices between each key's minimum and maximum coordinate. Built as + an explicit lexmin/lexmax intersection (a `card()`-friendly link set) + rather than by summing a min/max polynomial, which trips a barvinok + `summate` assertion at scale (e.g. the 8x8 case). + """ + name: str = coords.get_tuple_name(isl.dim_type.out) + lo: isl.Map = coords.lexmin().apply_range( + isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, "{ %s[lo] -> span[t] : t >= lo }" % name + ) + ) + hi: isl.Map = coords.lexmax().apply_range( + isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, "{ %s[hi] -> span[t] : t < hi }" % name + ) + ) + return lo.intersect(hi) + + +class XYRoutingMulticastModel(MulticastModel): + """ + Multicast cost model for XY (dimension-order) routing on a 2-D mesh. + + XY routing constrains every packet to travel along the X dimension first and + only then along the Y dimension, so a multicast from one source forms a rigid + tree: + + 1. an X segment along the source's row, reaching every column that holds a + destination, and + 2. an independent Y segment down each of those columns, starting from the + source's row. + + The hop cost of one such tree (source `s = (xs, ys)` with destination set + `D`) is therefore:: + + x_extent({xs} u {xd : (xd, yd) in D}) + + sum over destination columns xd of + y_extent({ys} u {yd : (xd, yd) in D}) + + Because the Y segments restart from the source row in every column rather than + sharing a trunk, this is an upper bound on free (any-monotone-path) routing and + a lower bound on the hypercube model, giving the ordering:: + + extent_DOR (floor) <= XY routing <= hypercube + + For example, source `(1, 0)` casting to `(0, 2)` and `(2, 2)` costs 4 + (floor), 6 (XY), and 8 (hypercube) respectively. + + Source selection is per destination: `identify_mesh_casts` pairs each + destination with its nearest source (devolving ties), and destinations that + share a source form one tree; the cost sums over all such trees and all data. + `dist_fn` is expected to be Manhattan and translationally invariant, like the + hypercube model (see `HypercubeMulticastModel`'s Preconditions), since nearest- + source selection relies on the same distance shape. + + Its four directed link types are declared once as the class constant + `EDGE_TYPES = ("xedge_r", "xedge_l", "yedge_u", "yedge_d")`. + + Preconditions + ------------- + The NoC is two-dimensional (no temporal dimensions in the spacetime), with + the first coordinate routed before the second (X then Y). The node tuple's + name is generic -- read off `fills`/`occs` at `apply` time, so any name + works (e.g. `noc[x, y]` or `pe[x, y]`) as long as `fills`, `occs`, and + `self.dist_fn` all agree on it (see the caller contract on + `identify_mesh_casts`'s `dist_fn` parameter). The tuple must be exactly + 2-D; `apply` raises `ValueError` otherwise. N-dimensional dimension-order + routing is a future extension. The returned cost is a parameter-free + constant (the validated regime); parametric spacetimes are not yet + supported. + """ + + EDGE_TYPES = _XY_EDGE_TYPES + + def _transfer_cost(self, mcs: isl.Map) -> EdgePressure: + return _edge_pressure_from_links(self._directed_mesh_links(mcs)) + + def _directed_mesh_links(self, mcns: isl.Map) -> list[isl.Map]: + """ + Decompose every multicast tree in `mcns` onto the directed mesh links it + traverses under XY routing. + + Each returned map is { [data -> src] -> edge } for one directed edge + type, associating a tree with every link of that type on its route. The + X phase runs along the source row out to every destination column; the Y + phase runs down each destination column from the source row. Directions + split at the source: rightward/leftward in X (at the source column `xs`) + and upward/downward in Y (at the source row `ys`). + + Parameters + ---------- + mcns: + Multicast networks { [data] -> [dst -> src] } from `identify_mesh_casts`. + + Returns + ------- + `[xedge_r, xedge_l, yedge_u, yedge_d]` maps (see `EDGE_TYPES`). An + edge `xedge_r[t, ys]` is the rightward link in row `ys` between + columns `t` and `t + 1`; `yedge_u[x, t]` is the upward link in + column `x` between rows `t` and `t + 1` (and `_l` / `_d` the + opposite directions). + + Preconditions + ------------- + The node tuple embedded in `mcns` must be exactly 2-D; every map string + below assumes a 2-D `name[x, y]` node tuple. Raises `ValueError` + otherwise. + """ + ctx = isl.DEFAULT_CONTEXT + # Reads the node tuple's name (and validates its dimensionality) off + # `mcns` instead of assuming the literal 'noc', so this method works + # for any 2-D node tuple. + name, dims = _mesh_node_tuple(mcns) + if dims != 2: + raise ValueError( + "XYRoutingMulticastModel requires a 2-D node tuple " + f"(X then Y); got tuple '{name}' with {dims} dimensions. " + "N-dimensional dimension-order routing is not yet supported." + ) + + # { [data -> src] -> dst name[x, y] } and a handle on the source per tree. + per_src, keymap = _per_src(mcns) # keymap: { [data->src] -> src } + + # --- Y phase: vertical links per (tree, destination column). --- + # Key each destination's y by its column: { [data->src->col] -> yv[y] }. + dst_y: isl.Map = per_src.apply_range( + isl.Map.read_from_str( + ctx, + "{ %s[x, y] -> [col[x'] -> yv[y']] : x' = x and y' = y }" % name, + ) + ).uncurry() + # Inject the source row ys into every destination column so each Y segment + # starts from the source. + src_y: isl.Map = keymap.apply_range( + isl.Map.read_from_str(ctx, "{ %s[xs, ys] -> yv[ys] }" % name) + ) + src_row: isl.Map = dst_y.domain().unwrap().range_product(src_y).uncurry() + col_ys: isl.Map = dst_y.union(src_row) + # Every link spanned in a column, keyed by the column (see + # `_span_links`): { [data->src->col] -> span[t] }. + ylinks: isl.Map = _span_links(col_ys) + # Re-key links by the tree and carry ys so direction splits at the source: + # { [data->src] -> [[col[x] -> span[t]] -> ysv[ys]] }. + y_with_ys: isl.Map = ylinks.curry().range_product( + keymap.apply_range( + isl.Map.read_from_str(ctx, "{ %s[xs, ys] -> ysv[ys] }" % name) + ) + ) + yedge_u: isl.Map = y_with_ys.apply_range(_YEDGE_U_MAP) + yedge_d: isl.Map = y_with_ys.apply_range(_YEDGE_D_MAP) + + # --- X phase: horizontal links along the source row. --- + # Columns spanned per tree = {src column} u {destination columns}. (Built + # explicitly, not from calculate_extents_per_dim, which keeps only the + # extent length and discards which links are used.) + col_x: isl.Map = per_src.apply_range( + isl.Map.read_from_str(ctx, "{ %s[x, y] -> cx[x] }" % name) + ).union( + keymap.apply_range( + isl.Map.read_from_str(ctx, "{ %s[xs, ys] -> cx[xs] }" % name) + ) + ) + # Every link spanned along the row, keyed by the tree (see + # `_span_links`): { [data->src] -> span[t] }. + xlinks: isl.Map = _span_links(col_x) + # Carry the source (xs, ys) so direction splits at xs and the row ys is + # part of the edge identity: { [data->src] -> [span[t] -> xy[xs, ys]] }. + x_with_src: isl.Map = xlinks.range_product( + keymap.apply_range( + isl.Map.read_from_str(ctx, "{ %s[xs, ys] -> xy[xs, ys] }" % name) + ) + ) + xedge_r: isl.Map = x_with_src.apply_range(_XEDGE_R_MAP) + xedge_l: isl.Map = x_with_src.apply_range(_XEDGE_L_MAP) + + return [xedge_r, xedge_l, yedge_u, yedge_d] + + +# Spoke vocabulary for the star model, declared once and shared with +# `StarMulticastModel.EDGE_TYPES`. +_STAR_EDGE_TYPES: tuple[str, str] = ("spoke_in", "spoke_out") + + +class StarMulticastModel(MulticastModel): + """ + Multicast cost model for a star / central-switch fabric -- the spokes + realization of a fully-connected interconnect (e.g. an NVSwitch, where every + GPU connects to a shared switch rather than to a full mesh of peers). + + Every node has exactly one spoke (its bidirectional link to the switch). A + delivery routes `src -> switch -> dst`: the source injects each datum once + up its egress spoke (multicast fan-out happens at the switch, so one copy per + datum regardless of how many destinations want it), and every destination + receives its datum down its ingress spoke. Self-deliveries (a node already + holding the datum) never cross the fabric and so load no spoke; `dist_fn`'s + hop magnitude otherwise never enters the spoke load -- on a star every + crossing is one switch hop each way, so `dist_fn` is used only to pick each + destination's nearest source and to classify self- vs. fabric-crossing + deliveries (`_fabric_crossing`). + + Its two spoke directions are declared once as the class constant + `EDGE_TYPES = ("spoke_in", "spoke_out")`. + """ + + EDGE_TYPES = _STAR_EDGE_TYPES + + def _transfer_cost(self, mcs: isl.Map) -> EdgePressure: + return EdgePressure(_union_pwqs([*self._spoke_loads(mcs)])) + + def _spoke_loads( + self, mcns: isl.Map + ) -> tuple[isl.PwQPolynomial, isl.PwQPolynomial]: + """ + Per-spoke ingress and egress load for the multicast networks `mcns`. + + Parameters + ---------- + mcns: + Multicast networks { [data] -> [dst -> src] } from `identify_mesh_casts`. + + Returns + ------- + `(ingress, egress)` where `ingress` is { spoke_in[n] -> #data the node + receives } and `egress` is { spoke_out[n] -> #data the node sources }, + counting only fabric-crossing (>= 1 hop) deliveries. + """ + # Reads the node tuple's name off `mcns` instead of assuming the + # literal 'noc'; unlike XY, the star model has no dimensionality + # requirement. + name, _dims = _mesh_node_tuple(mcns) + + # Keep only deliveries that actually cross the fabric (>= 1 hop); a node + # already holding its datum loads no spoke. + crossing: isl.Map = _fabric_crossing(mcns, self.dist_fn) + + # { dst -> [src -> data] }: regroup so each delivery is keyed by destination. + cur: isl.Map = crossing.reverse().curry() + # Distinct (node, data) pairs per direction. A source injects each datum + # once (multicast fans out at the switch); a destination receives each once. + ingress_nodes: isl.Map = cur.range_factor_range() # { name[dst] -> data } + egress_nodes: isl.Map = cur.range().unwrap() # { name[src] -> data } + + # Relabel the node tuple to the directed spoke edge, then count data per + # spoke. { spoke_in[n] -> #data } and { spoke_out[n] -> #data }. + dims: int = ingress_nodes.dim(isl.dim_type.in_) + idx: str = ", ".join(f"i{k}" for k in range(dims)) + spoke_in, spoke_out = self.EDGE_TYPES + ingress: isl.PwQPolynomial = ingress_nodes.apply_domain( + isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + "{ %s[%s] -> %s[%s] }" % (name, idx, spoke_in, idx), + ) + ).card() + egress: isl.PwQPolynomial = egress_nodes.apply_domain( + isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + "{ %s[%s] -> %s[%s] }" % (name, idx, spoke_out, idx), + ) + ).card() + return ingress, egress diff --git a/accelforge/model/_looptree/reuse/isl/distributed/edge_pressure.py b/accelforge/model/_looptree/reuse/isl/distributed/edge_pressure.py new file mode 100644 index 00000000..629a7cfc --- /dev/null +++ b/accelforge/model/_looptree/reuse/isl/distributed/edge_pressure.py @@ -0,0 +1,251 @@ +""" +Per-edge memory pressure (link load) for distributed transfer models: +`EdgePressure` and the scalar-extraction / accumulation helpers that build and +consume it. + +Leaf module -- depends only on `islpy`, `functools`, `dataclasses`, and +`typing`, so every other module in this package (`mesh_casts.py`, +`distributed_buffers.py`, and `../spatial.py`) can import from here without +risk of a cycle. +""" + +import functools + +from dataclasses import dataclass + +from typing import Optional + +import islpy as isl + + +@dataclass(frozen=True) +class EdgePressure: + """ + Per-edge memory pressure (link load) for a spatial transfer. + + Where a `TransferModel`'s `hops` collapses a whole routing to a single + scalar, `EdgePressure` keeps the load broken out per physical edge: how many + multicast trees cross each individual link -- the quantity a per-link + bandwidth limit acts on, and what the symbolic network model calls + `max_traffic`. + + "Edge" is a directed physical link, identified by the tuple name and + coordinates of `load`'s domain, e.g. `yedge_u[x, t]` (the upward vertical + link in column `x` between rows `t` and `t + 1`, XY mesh) or `spoke_in[n]` / + `spoke_out[n]` (a node's ingress / egress link to the switch, star model). + + The load is keyed on the multicast tree `(data, src)`, not on individual + destinations: within one tree a link is traversed once regardless of how + many leaves hang off it, so `load` measures pressure (distinct flows over a + link) rather than summed hops -- e.g. for XY routing, sum over edges of load + == total hops. + + Preconditions + ------------- + `bottleneck` and `eval_edge` assume the load is piecewise constant (the + parameter-free regime the distributed models are validated in); there is no + clean ISL "max of a quasi-polynomial over its domain" primitive, so the + bottleneck is obtained by enumerating pieces. + """ + + # { edge -> number-of-trees } spanning every directed edge type the model + # emits. + load: isl.UnionPwQPolynomial + + @functools.cached_property + def _pieces(self) -> list[isl.PwQPolynomial]: + """ + Cache `load`'s decomposition into per-edge-type pieces. + + Returns + ------- + The list of `isl.PwQPolynomial` pieces `load` unions together, in + `foreach_pw_qpolynomial` enumeration order. + """ + # Note: `cached_property` works on this frozen dataclass only because + # it is not `slots=True` -- the cache is written straight into the + # instance `__dict__`, bypassing the frozen `__setattr__`. + pieces: list[isl.PwQPolynomial] = [] + self.load.foreach_pw_qpolynomial(pieces.append) + return pieces + + def total(self) -> int: + """ + Sum the load over every edge. + + For a single-direction (or single edge-type) pressure this is the total + traffic; for the full mesh pressure it equals the model's total `hops` + (sum over edges of load == total hops), which is the primary cross-check + that the per-edge decomposition is correct. + """ + total = 0 + for pwq in self._pieces: + # `.sum()` collapses the edge-indexed domain away (summing over every + # edge of this piece), leaving a 0-set-dim, parameter-free + # polynomial -- exactly `_eval_const`'s precondition. + total += _eval_const(pwq.sum()) + return total + + def bottleneck(self) -> int: + """ + Return the load on the single most-pressured edge. + + This is the bandwidth-binding quantity: with a uniform per-link + bandwidth, the most-congested edge saturates first, so its load sets the + transfer's bandwidth-bound latency. + + The per-edge load is generally not constant across an edge type (e.g. a + flooded column's upward link `yedge_u[x, t]` carries `t + 1` trees), so + the maximum is found by enumerating the (finite, parameter-free) edge + domain and evaluating the load at each edge -- sampling one point per + piece would under-report a monotone load. + """ + best = 0 + for pwq in self._pieces: + edges: list[isl.Point] = [] + pwq.domain().foreach_point(edges.append) + for edge in edges: + best = max(best, _eval_at(pwq, edge)) + return best + + def eval_edge(self, name: str, coords: list[int]) -> int: + """ + Look up the load on one named edge, e.g. `eval_edge("yedge_u", [0, 6])`. + + Returns 0 if no flow crosses that edge (it is outside the load's support). + + Parameters + ---------- + name: + The edge tuple name (`xedge_r`/`xedge_l`/`yedge_u`/`yedge_d` + for the mesh model, `spoke_in`/`spoke_out` for the spokes model). + coords: + The integer edge coordinates within that tuple. + """ + for pwq in self._pieces: + if pwq.domain().get_space().get_tuple_name(isl.dim_type.set) != name: + continue + point: isl.Point = isl.Set.read_from_str( + isl.DEFAULT_CONTEXT, + "{ %s[%s] }" % (name, ", ".join(str(c) for c in coords)), + ).sample_point() + return _eval_at(pwq, point) + return 0 + + +def _eval_at(pwq: isl.PwQPolynomial, point: isl.Point) -> int: + """ + Evaluate a piecewise quasi-polynomial at one point and return a Python `int`. + + Parameters + ---------- + pwq: + The polynomial to evaluate. + point: + The point to evaluate at. Must lie in a space compatible with `pwq`'s + domain (matching tuple name and dimensionality). + + Returns + ------- + `pwq`'s value at `point`, as a Python `int`. + + Note: isl.Val has no direct int() conversion in this islpy build (it + raises TypeError); round-tripping through str() is the working idiom + used throughout this module. + """ + return int(str(pwq.eval(point))) + + +def _eval_const(pwq: isl.PwQPolynomial) -> int: + """ + Evaluate a parameter-free, already-reduced piecewise quasi-polynomial to its + scalar value. + + Preconditions + ------------- + `pwq` has no free set dimensions and no parameters -- e.g. the output of + `.card()` on a parameter-free map/set, `.sum()` on a parameter-free + polynomial, or a constant built by `_const_pwq`. Evaluated only at the + space's zero point, so a `pwq` that still varies over domain points or + parameters gives a meaningless result; callers must reduce to a true + constant first (via `.sum()`/`.card()`). + + Returns + ------- + The polynomial's constant value as a Python `int`. + """ + return _eval_at(pwq, isl.Point.zero(pwq.domain().get_space())) + + +def _const_pwq(value: int) -> isl.PwQPolynomial: + """ + Build a 0-dimensional, parameter-free constant `isl.PwQPolynomial` equal to + `value`. + + Parameters + ---------- + value: + The integer the returned polynomial evaluates to everywhere (it has no + domain dimensions or parameters to vary over). + + Returns + ------- + An `isl.PwQPolynomial` over the empty (0-dim, 0-param) space, suitable + wherever a parameter-free `hops` cost is expected. Round-trips through + `_eval_const` back to `value`. + """ + ctx = isl.DEFAULT_CONTEXT + zero_dim: isl.Space = isl.Space.set_alloc(ctx, 0, 0) + return isl.PwQPolynomial.from_qpolynomial( + isl.QPolynomial.val_on_domain(zero_dim, isl.Val(value, ctx)) + ) + + +def _union_pwqs(pwqs: list[isl.PwQPolynomial]) -> isl.UnionPwQPolynomial: + """ + Accumulate a list of piecewise quasi-polynomials into one union. + + Parameters + ---------- + pwqs: + The polynomials to sum, e.g. one per directed edge type. May be + empty. + + Returns + ------- + The union-add of every `pwqs` entry (each promoted to an + `isl.UnionPwQPolynomial` first). An empty `pwqs` yields the empty union + `{ }`, so a caller with zero edge types (or a degenerate empty mesh) does + not need to special-case the accumulation. + """ + acc: Optional[isl.UnionPwQPolynomial] = None + for pwq in pwqs: + contribution = isl.UnionPwQPolynomial.from_pw_qpolynomial(pwq) + acc = contribution if acc is None else acc.add(contribution) + if acc is None: + acc = isl.UnionPwQPolynomial.read_from_str(isl.DEFAULT_CONTEXT, "{ }") + return acc + + +def _edge_pressure_from_links(edge_maps: list[isl.Map]) -> EdgePressure: + """ + Turn directed flow maps into an `EdgePressure`. + + Parameters + ---------- + edge_maps: + A list of { [data -> src] -> edge } maps, one per directed edge type, + each associating a multicast tree with every edge its route traverses. + + Returns + ------- + An `EdgePressure` whose `load` is { edge -> number-of-trees }: for each map + we reverse it and take the cardinality (`reverse().card()` counts, per + edge, how many distinct `(data, src)` trees cross it), then union the + per-type results into one `UnionPwQPolynomial` (via `_union_pwqs`). + """ + # { edge -> #trees crossing it }, one per edge type. + per_edge_loads: list[isl.PwQPolynomial] = [ + edge_map.reverse().card() for edge_map in edge_maps + ] + return EdgePressure(_union_pwqs(per_edge_loads)) diff --git a/accelforge/model/_looptree/reuse/isl/distributed/mesh_casts.py b/accelforge/model/_looptree/reuse/isl/distributed/mesh_casts.py new file mode 100644 index 00000000..c6318a7f --- /dev/null +++ b/accelforge/model/_looptree/reuse/isl/distributed/mesh_casts.py @@ -0,0 +1,268 @@ +""" +Multicast-network construction for distributed transfer models: matching each +requested datum to its nearest source (`identify_mesh_casts`) and the +shared-shape helpers built on top of its result (fill-partition recovery, +per-dimension extents, tree re-keying, and fabric-crossing filtering). + +Imports `islpy`, `isl_functions.dim_projector_mask`, and +`mapping_to_isl.DUMP_ISL_IR` only -- no dependency on `edge_pressure.py`, +`spatial.py`, or `distributed_buffers.py`, so this module cannot participate +in the import cycle those would otherwise risk. +""" + +import logging + +import islpy as isl + +from accelforge.model._looptree.reuse.isl.isl_functions import dim_projector_mask +from accelforge.model._looptree.reuse.isl.mapping_to_isl import DUMP_ISL_IR + +# [dst -> src] pairs whose distance is >= 1 hop, i.e. every fabric-crossing +# delivery (as opposed to a self-delivery, which never traverses a link). +# Parsed once at import rather than per `_fabric_crossing` call -- the string +# encodes `identify_mesh_casts`'s `dist_fn` contract (range tuple named +# `hops`), not anything instance- or call-specific. +_CROSSING_HOPS: isl.Set = isl.Set.read_from_str( + isl.DEFAULT_CONTEXT, "{ hops[h] : h >= 1 }" +) + + +def identify_mesh_casts( + src_occupancy: isl.Map, dst_fill: isl.Map, dist_fn: isl.Map +) -> isl.Map: + """ + Given srcs with data, fills to destinations, and a distance function, identify per data + the srcs delivering that data to dsts. + + Parameters + ---------- + src_occupancy: + An isl.Map of the form { [src] -> [data] } corresponding to the data held + at the buffer at space `src`. + dst_fill: + An isl.Map of the form { [dst] -> [data] } corresponding to the data requested + at the element at space `dst`. + dist_fn: + A distance function { [dst -> src] -> [hops] } that accepts two points in + space, corresponding to the `dst` and `src`, and returns the distance + between the two points in terms of `hops`, a quantized atomic distance of + data transmission cost. + + Caller contract: the tuple names of `dst_fill`'s and `src_occupancy`'s + domains (the spacetime/node tuple, e.g. `noc[x, y]`) must match the + corresponding tuple names in `dist_fn`'s domain -- ISL will raise on a + name mismatch when `dist_fn` is applied. `dist_fn`'s range tuple must be + named `hops` (consumers such as `FullyConnectedMulticastModel` and + `StarMulticastModel` filter on `{ hops[h] : h >= 1 }` to distinguish + self-deliveries from fabric-crossing ones). + + Returns + ------- + { [data] -> [dst -> src] } where { [dst] -> [data] } and { [src] -> [data] } are in + `src_occupancy` and `dst_fill` respectively, and where `[dst -> src]` is the infimum of + `dst_fn(src, dst), ∀ src, dst s.t. { [src] -> [data] } ∈ `src_occupancy` and + `{ [dst] -> [data] }` ∈ `dst_fill`. + """ + # Makes { [dst -> data] -> [dst -> data] } + fill_to_fill: isl.Map = dst_fill.wrap().identity() + if DUMP_ISL_IR: + logging.info(f"fill_to_fill: {fill_to_fill}") + + # Inverts src_occupancy s.t. data -> src. + # i.e. { [xs, ys] -> [d0, d1] } to { [d0, d1] -> [xs, ys] } + data_presence: isl.Map = src_occupancy.reverse() + + # { [dst -> data] -> [dst -> src] } where src contains data. + fills_to_matches: isl.Map = ( + fill_to_fill.uncurry() # { [[dst -> data] -> dst] -> data } + .apply_range(data_presence) # { [[dst -> data] -> dst] -> src } + .curry() + ) # { [[dst -> data] -> [dst -> src] } + if DUMP_ISL_IR: + logging.info(f"fills_to_matches: {fills_to_matches}") + + # Calculates the distance of a fill to the nearest src satisfying the fill. + # { [dst -> data] -> [dist] } + fill_min_dist: isl.Map = fills_to_matches.apply_range(dist_fn).lexmin() + # Isolates the relevant minimal pairs. + # { [dst -> data] -> [dst -> src] :.dst -> src is minimized distance } + minimal_pairs: isl.Map = ( + fill_min_dist.apply_range( + # Note: Need to match fill -> min_dist with min_dist -> [fill -> match] as lexmin over + # fill and match will minimize distance over the tuple (src, dst, data), but that + # overconstrains the optimization as we want to minimize over distance (dst, data) + # only for all src. + fills_to_matches.range_map() + .apply_range(dist_fn) + .reverse() + ) + .range() + .unwrap() + ) + if DUMP_ISL_IR: + logging.info(f"minimal_pairs: {minimal_pairs}") + + # Isolates the multicast networks. + # { [data] -> [dst -> src] : dst -> src is minimized distance } + multicast_networks: isl.Map = minimal_pairs.curry().range().unwrap() + # Devolves to a single source if multiple sources per domain point. + multicast_networks = multicast_networks.uncurry().lexmin().curry() + + return multicast_networks + + +def _covered_fills(mcs: isl.Map) -> isl.Map: + """ + Recover the { dst -> data } fills actually covered by a matched multicast + source, from `identify_mesh_casts`'s result. + + Parameters + ---------- + mcs: + { [data] -> [dst -> src] }, the multicast-network map returned by + `identify_mesh_casts`. + + Returns + ------- + { dst -> data } -- every (destination, datum) pair that has a matched + source in `mcs`. A model's fill partition is then + `fulfilled = fills.map_.intersect(covered)` and + `unfulfilled = fills.map_.subtract(covered)`. + """ + return ( + mcs.range_reverse() # { data -> [src -> dst] } + .uncurry() # { [data -> src] -> dst } + .domain_factor_domain() # Drops src, keeps -> dst. { data -> dst } + .reverse() # { dst -> data } + ) + + +def _mesh_node_tuple(mcns: isl.Map) -> tuple[str, int]: + """ + Read the spacetime/node tuple's name and dimensionality off a multicast + network map, instead of assuming a hardcoded name. + + Parameters + ---------- + mcns: + { [data] -> [dst -> src] }, the multicast-network map returned by + `identify_mesh_casts`. `dst` and `src` share the same node tuple, so + it suffices to read the name/dims off one side (`dst`, via + `.range().unwrap()`'s domain). + + Returns + ------- + `(name, dims)`: the node tuple's ISL tuple name (e.g. "noc" or "pe") and + its dimensionality. + """ + # Note: correct even when mcns is empty -- ISL preserves space/tuple-name + # information on empty relations, so this does not require data to be + # present. + node_space: isl.Map = mcns.range().unwrap() + name: str = node_space.get_tuple_name(isl.dim_type.in_) + dims: int = node_space.dim(isl.dim_type.in_) + return name, dims + + +def _per_src(mcns: isl.Map) -> tuple[isl.Map, isl.Map]: + """ + Re-key multicast networks by tree `(data, src)`, plus a source lookup. + + Parameters + ---------- + mcns: + Multicast networks { [data] -> [dst -> src] } from `identify_mesh_casts`. + + Returns + ------- + `(per_src, keymap)`: + - `per_src`: { [data -> src] -> dst } -- every destination grouped under + its tree's key. + - `keymap`: { [data -> src] -> src } -- the tree's own source point, + recovered from `per_src`'s (wrapped) domain. Used to inject/carry the + source's own coordinates (e.g. its row/column) into computations keyed + on the same tree. + """ + per_src: isl.Map = mcns.range_reverse().uncurry() # { [data -> src] -> dst } + keymap: isl.Map = per_src.domain().unwrap().range_map() # { [data -> src] -> src } + return per_src, keymap + + +def _fabric_crossing(mcns: isl.Map, dist_fn: isl.Map) -> isl.Map: + """ + Filter multicast networks down to fabric-crossing deliveries (>= 1 hop). + + Parameters + ---------- + mcns: + Multicast networks { [data] -> [dst -> src] } from `identify_mesh_casts`. + dist_fn: + The same distance function { [dst -> src] -> [hops] } passed to + `identify_mesh_casts` -- see its caller contract on the `hops` range + tuple name, which this filters on. + + Returns + ------- + { [data] -> [dst -> src] }, restricted to entries whose `[dst -> src]` + pair has `dist_fn(dst, src) >= 1`, i.e. every delivery that actually + crosses the fabric. Self-deliveries (0 hops) are dropped, since they load + no fabric link. + """ + crossing_pairs: isl.Set = dist_fn.intersect_range(_CROSSING_HOPS).domain() + return mcns.intersect_range(crossing_pairs) + + +def calculate_extents_per_dim(mcns: isl.Map) -> list[isl.PwAff]: + """ + Parameters + ---------- + mcns: + Mesh cast-networks, or networks in which all dsts per data are grouped with + the closest src containing the data. + + Returns + ------- + A list of `isl.PwAff` that gives the max extent (length) along dim_i per mcn, + where i is the i-th `isl.PwAff`. + + Preconditions + ------------- + `mcns` were generated with a Manhattan distance `dst_fn` by `identify_mesh_casts` + s.t. all dimensions are orthogonal to each other in a metric space, where each + unit movement in a dimension counts as 1 hop. + + We also assume `dst_fn` is translationally invariant (i.e., ∀src, dst, + src', dst' ∈ space, if |src - dst| = |src' - dst'|, + dst_fn(src, dst) = dst_fn(src', dst'). + """ + # Makes mcns from { [data] -> [dst -> src] } to { [data -> src] -> [dst] } + potential_srcs, srcs = _per_src(mcns) + # Sources are part of the extents, so we union it with the destinations. + # { [data -> src] -> [spacetime] } + casting_extents: isl.Map = srcs.union(potential_srcs) + + # Projects away all dimensions but one to find their extent for hypercube. + dims: int = potential_srcs.range_tuple_dim() + # Creates a mask of what to project out. + project_out_mask: list[bool] = [True] * dims + dim_extents: list[isl.PwAff] = [None] * dims + + # Gets the extents of all dimensions + for noc_dim in range(dims): + # Project out all the dimensions of the output besides noc_dim. + project_out_mask[noc_dim] = False + # { [spacetime] -> [dimension] } + extent_mapper: isl.Map = dim_projector_mask( + casting_extents.range().get_space(), project_out_mask + ).reverse() + dim_extent_space: isl.Map = casting_extents.apply_range(extent_mapper) + project_out_mask[noc_dim] = True + + # Finds max(noc_dim) - min(noc_dim) for each [data -> src] + max_extent: isl.PwAff = dim_extent_space.dim_max(0) + min_extent: isl.PwAff = dim_extent_space.dim_min(0) + + # Subtracts the max from the min to get the extent per [data -> src] + dim_extents[noc_dim] = max_extent.sub(min_extent).coalesce() + + return dim_extents diff --git a/accelforge/model/_looptree/reuse/isl/mapping_to_isl/tiling.py b/accelforge/model/_looptree/reuse/isl/mapping_to_isl/tiling.py index 7da28fed..122d4219 100644 --- a/accelforge/model/_looptree/reuse/isl/mapping_to_isl/tiling.py +++ b/accelforge/model/_looptree/reuse/isl/mapping_to_isl/tiling.py @@ -345,8 +345,9 @@ def consumer_based_tile_shape_inference( # For each tensor read by this einsum, tile that tensor's producers. for tensor in workload.einsums[einsum].input_tensor_names: + # The einsums that write `tensor` -- its producers in this workload. producer_einsums: oset[EinsumName] = oset( - [e for e in workload.einsums[einsum].output_tensor_names] + [e.name for e in workload.einsums if tensor in e.output_tensor_names] ) if len(producer_einsums) > 1: raise NotImplementedError( diff --git a/accelforge/model/_looptree/reuse/isl/spatial.py b/accelforge/model/_looptree/reuse/isl/spatial.py index 47d6fa42..7c6ad5a5 100644 --- a/accelforge/model/_looptree/reuse/isl/spatial.py +++ b/accelforge/model/_looptree/reuse/isl/spatial.py @@ -9,6 +9,9 @@ import islpy as isl from accelforge.frontend.mapping import MappingNode +from accelforge.model._looptree.reuse.isl.distributed.edge_pressure import ( + EdgePressure, +) from accelforge.model._looptree.reuse.isl.isl_functions import ( insert_equal_dims_map, reorder_projector, @@ -37,9 +40,17 @@ class TransferInfo: # Crucial information to transfer info. fulfilled_fill: Transfers - """Fills done by peer-to-peer transfers.""" + """Fills done by peer-to-peer transfers. + + Restricted to fills covered by a matched multicast source (see + `identify_mesh_casts`); see `unfulfilled_fill`. + """ unfulfilled_fill: Fill - """Fills not performed.""" + """Fills not performed. + + `fills - covered`, the complement of `fulfilled_fill` within the original + fill set (the two partition `fills` exactly). + """ parent_reads: Reads """Fills done by parent-to-child transfers.""" hops: isl.PwQPolynomial @@ -48,6 +59,18 @@ class TransferInfo: # Metadata on what is occurring. link_transfer: bool + # Optional, model-specific per-link decomposition -- last field / defaulted + # so this addition does not disturb any existing positional or keyword + # construction site (`grep`-verified: every `TransferInfo(...)` call in the + # tree already uses keyword arguments). + edge_pressure: Optional[EdgePressure] = None + """Per-directed-edge load backing `hops`, for models that define one. + + Populated by `XYRoutingMulticastModel` (mesh links) and + `StarMulticastModel` (spokes); `None` where a model has no per-link + decomposition (`HypercubeMulticastModel`, `FullyConnectedMulticastModel`). + """ + class TransferModel(ABC): """ diff --git a/notebooks/astrasim2_correlation/correlation b/notebooks/astrasim2_correlation/correlation new file mode 160000 index 00000000..36e6fffb --- /dev/null +++ b/notebooks/astrasim2_correlation/correlation @@ -0,0 +1 @@ +Subproject commit 36e6fffb6d1b4773b961604238a2db1c1a13d8d5 diff --git a/notebooks/astrasim2_correlation/correlation.ipynb b/notebooks/astrasim2_correlation/correlation.ipynb new file mode 100644 index 00000000..ceecd4ad --- /dev/null +++ b/notebooks/astrasim2_correlation/correlation.ipynb @@ -0,0 +1,2279 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3aa122f8", + "metadata": {}, + "source": [ + "# Network Sim Correlation\n", + "\n", + "The following are attempts to correlate the network model in accelforge to actual networks measured in real architectures." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e3a04b7c", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:34.011575Z", + "iopub.status.busy": "2026-09-17T16:44:34.011502Z", + "iopub.status.idle": "2026-09-17T16:44:34.765381Z", + "shell.execute_reply": "2026-09-17T16:44:34.764565Z" + } + }, + "outputs": [], + "source": [ + "import accelforge as af\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "id": "95cf92d9", + "metadata": {}, + "source": [ + "## We are testing an 8 GPU All-to-All to Correlate Later, simulating an NVLink Switch\n" + ] + }, + { + "cell_type": "markdown", + "id": "195ecb91", + "metadata": {}, + "source": [ + "### Encoding: one-hot GPU coordinates on a fully-connected fabric\n", + "\n", + "GPU $i$ sits at one-hot coordinate $e_i$ of an $N$-dimensional `noc` space. `data[s, d]` is the chunk sent by GPU $s$ to GPU $d$: each GPU *holds* the chunks it sends (occupancy) and *requests* the chunks addressed to it (fill).\n", + "\n", + "Every $s \\neq d$ cast then has extent 1 along exactly the src and dst dimensions, so `HypercubeMulticastModel`'s bounding-box cost is $(1+1)(1+1)-1 = 3$ **uniformly for every pair** — the fully-connected property (no pair privileged). The distance function is unit-cost (0 if same GPU, 1 otherwise) and only influences source matching in `identify_mesh_casts`. Self-chunks match at distance 0 and cost 0 hops: they never cross the fabric." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c5b2c7bf", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:34.767780Z", + "iopub.status.busy": "2026-09-17T16:44:34.767580Z", + "iopub.status.idle": "2026-09-17T16:44:34.780820Z", + "shell.execute_reply": "2026-09-17T16:44:34.780423Z" + } + }, + "outputs": [], + "source": [ + "import math\n", + "\n", + "import islpy as isl\n", + "import pandas as pd\n", + "\n", + "from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import (\n", + " HypercubeMulticastModel,\n", + ")\n", + "from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import (\n", + " Fill,\n", + " Occupancy,\n", + " SpatialTag,\n", + ")\n", + "\n", + "CTX = isl.DEFAULT_CONTEXT" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "e343cac3", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:34.782482Z", + "iopub.status.busy": "2026-09-17T16:44:34.782401Z", + "iopub.status.idle": "2026-09-17T16:44:34.786211Z", + "shell.execute_reply": "2026-09-17T16:44:34.785562Z" + } + }, + "outputs": [], + "source": [ + "def onehot_constraints(prefix: str, n: int) -> str:\n", + " \"\"\"One-hot constraints over dims ``{prefix}0..{prefix}{n-1}``.\"\"\"\n", + " bounds = \" and \".join(f\"0 <= {prefix}{i} <= 1\" for i in range(n))\n", + " hot = \" + \".join(f\"{prefix}{i}\" for i in range(n)) + \" = 1\"\n", + " return f\"{bounds} and {hot}\"\n", + "\n", + "\n", + "def linear_id(prefix: str, n: int) -> str:\n", + " \"\"\"Affine recovery of the GPU id from a one-hot vector: id = sum i*g_i.\"\"\"\n", + " return \" + \".join(f\"{i}*{prefix}{i}\" for i in range(1, n))\n", + "\n", + "\n", + "def all_to_all_maps(n: int) -> tuple[isl.Map, isl.Map, isl.Map]:\n", + " \"\"\"Build (occupancy, fill, dist_fn) for an N-GPU fully-connected all-to-all.\n", + "\n", + " data[s, d] is the chunk sent by GPU s to GPU d. Each GPU holds the\n", + " chunks it sends (occ) and requests the chunks addressed to it (fill).\n", + " \"\"\"\n", + " gs = \", \".join(f\"gs{i}\" for i in range(n))\n", + " gd = \", \".join(f\"gd{i}\" for i in range(n))\n", + " occ = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gs}] -> data[s, d] : {onehot_constraints('gs', n)} \"\n", + " f\"and s = {linear_id('gs', n)} and 0 <= d < {n} }}\",\n", + " )\n", + " fill = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gd}] -> data[s, d] : {onehot_constraints('gd', n)} \"\n", + " f\"and d = {linear_id('gd', n)} and 0 <= s < {n} }}\",\n", + " )\n", + "\n", + " xd = \", \".join(f\"xd{i}\" for i in range(n))\n", + " xs = \", \".join(f\"xs{i}\" for i in range(n))\n", + " same = \" and \".join(f\"xd{i} = xs{i}\" for i in range(n))\n", + " diff = \" or \".join(f\"(xd{i} < xs{i}) or (xd{i} > xs{i})\" for i in range(n))\n", + " dist_fn = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ [noc[{xd}] -> noc[{xs}]] -> hops[0] : {same}; \"\n", + " f\" [noc[{xd}] -> noc[{xs}]] -> hops[1] : {diff} }}\",\n", + " )\n", + " return occ, fill, dist_fn" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a2a2df5f", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:34.788502Z", + "iopub.status.busy": "2026-09-17T16:44:34.788416Z", + "iopub.status.idle": "2026-09-17T16:44:34.791393Z", + "shell.execute_reply": "2026-09-17T16:44:34.790761Z" + } + }, + "outputs": [], + "source": [ + "def eval_total(poly: isl.PwQPolynomial) -> int:\n", + " \"\"\"Evaluate a fully-summed PwQPolynomial (zero-dimensional domain).\"\"\"\n", + " return int(poly.eval(isl.Point.zero(poly.domain().get_space())).to_python())\n", + "\n", + "\n", + "def model_hops_per_element(n: int) -> int:\n", + " \"\"\"Run the real HypercubeMulticastModel on the all-to-all at V=1.\"\"\"\n", + " occ_map, fill_map, dist_fn = all_to_all_maps(n)\n", + " tags = [SpatialTag(i, 0) for i in range(n)]\n", + " model = HypercubeMulticastModel(dist_fn)\n", + " info = model.apply(0, Fill(tags, fill_map), Occupancy(tags, occ_map))\n", + " return eval_total(info.hops)\n", + "\n", + "\n", + "def single_chunk_hops(n: int, src: int, dst: int) -> int:\n", + " \"\"\"Hops for one (src, dst) chunk — uniformity / self-chunk probe.\"\"\"\n", + " occ_map, fill_map, dist_fn = all_to_all_maps(n)\n", + " chunk = isl.Set.read_from_str(CTX, f\"{{ data[{src}, {dst}] }}\")\n", + " tags = [SpatialTag(i, 0) for i in range(n)]\n", + " model = HypercubeMulticastModel(dist_fn)\n", + " info = model.apply(\n", + " 0,\n", + " Fill(tags, fill_map.intersect_range(chunk)),\n", + " Occupancy(tags, occ_map.intersect_range(chunk)),\n", + " )\n", + " return eval_total(info.hops)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "06d40ac3", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:34.793373Z", + "iopub.status.busy": "2026-09-17T16:44:34.793297Z", + "iopub.status.idle": "2026-09-17T16:44:34.794935Z", + "shell.execute_reply": "2026-09-17T16:44:34.794652Z" + } + }, + "outputs": [], + "source": [ + "NODES = 8 # GPUs on the fabric\n", + "LINK_BW_GBPS = 150.0 # per-GPU per-direction NVLink bandwidth, GB/s (V100 generation)\n", + "ALPHA_S = 0.0 # per-operation latency overhead, seconds\n", + "MIN_MIB, MAX_MIB = 1, 1024 # collective size sweep bounds, powers of 2\n", + "PER_RANK = False # interpret swept sizes as per-rank NCCL sizes instead of totals" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "60364739", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:34.796321Z", + "iopub.status.busy": "2026-09-17T16:44:34.796249Z", + "iopub.status.idle": "2026-09-17T16:44:35.954144Z", + "shell.execute_reply": "2026-09-17T16:44:35.952723Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ISL network model: 8-GPU fully-connected all-to-all (one-hot)\n", + " hops/element : 168 (uniform 3 per pair)\n", + " fabric-crossing chunks: 56 of 64\n" + ] + } + ], + "source": [ + "n = NODES\n", + "\n", + "# --- Run the tool at V=1 and validate the fully-connected structure. ---\n", + "hops_per_elem = model_hops_per_element(n)\n", + "expected = 3 * n * (n - 1)\n", + "assert hops_per_elem == expected, (\n", + " f\"model returned {hops_per_elem} hops/element, expected {expected} \"\n", + " f\"(= 3 per off-diagonal pair x {n*(n-1)} pairs)\"\n", + ")\n", + "probe_off = single_chunk_hops(n, 0, min(3, n - 1))\n", + "probe_self = single_chunk_hops(n, n - 1, n - 1)\n", + "assert probe_off == 3, f\"off-diagonal chunk cost {probe_off} != 3\"\n", + "assert probe_self == 0, f\"self chunk cost {probe_self} != 0\"\n", + "crossing_chunks = hops_per_elem // 3 # = N(N-1) fabric-crossing chunks\n", + "\n", + "print(f\"ISL network model: {n}-GPU fully-connected all-to-all (one-hot)\")\n", + "print(f\" hops/element : {hops_per_elem} (uniform 3 per pair)\")\n", + "print(f\" fabric-crossing chunks: {crossing_chunks} of {n*n}\")" + ] + }, + { + "cell_type": "markdown", + "id": "c89a8e17", + "metadata": {}, + "source": [ + "### Size and latency conventions\n", + "\n", + "`collective_size` $S$ = **total** bytes moved by the collective across all ranks (ASTRA-sim style). Per-rank NCCL buffer size = $S/N$; each $(s, d)$ pair exchanges a chunk of $S/N^2$ bytes. Set `PER_RANK = True` to interpret the swept sizes as per-rank NCCL sizes instead.\n", + "\n", + "Latency derives from the model's hop count: hops are uniform 3 per fabric-crossing chunk, so crossing chunks/element $= \\mathrm{hops}/3 = N(N-1)$, i.e. each GPU receives $N-1$ chunks $\\Rightarrow$ per-GPU wire bytes $= S(N-1)/N^2$. With a non-blocking switch and full-duplex ports (send overlaps receive), port drain time gives\n", + "\n", + "$$ t = \\alpha + \\frac{S\\,(N-1)}{N^2 \\cdot BW} $$\n", + "\n", + "NCCL conventions: $\\mathrm{algbw} = (S/N)/t$, $\\mathrm{busbw} = \\mathrm{algbw} \\cdot (N-1)/N$. With $\\alpha = 0$, busbw $\\equiv$ BW exactly — used as a per-row sanity invariant below.\n", + "\n", + "**Correlation notes** — this is a flat bandwidth model with no launch/protocol overhead, so expect empirical underprediction at small sizes; calibrate `ALPHA_S` (per-operation latency) and `LINK_BW_GBPS` (effective port bandwidth) against nccl-tests `alltoall_perf`, and overlay the ASTRA-sim 2.0 (FullyConnected) and EC2 series on the plot below." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "6d5e39c9", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:35.956080Z", + "iopub.status.busy": "2026-09-17T16:44:35.955986Z", + "iopub.status.idle": "2026-09-17T16:44:35.966990Z", + "shell.execute_reply": "2026-09-17T16:44:35.965678Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodescollective_size_bytesper_rank_bytesper_gpu_wire_byteshops_per_tile_coordinatefabric_chunks_per_tile_coordinatemodel_latency_salgbw_GBpsbusbw_GBps
081048576131072114688168567.645867e-07171.428571150.0
182097152262144229376168561.529173e-06171.428571150.0
284194304524288458752168563.058347e-06171.428571150.0
3883886081048576917504168566.116693e-06171.428571150.0
481677721620971521835008168561.223339e-05171.428571150.0
583355443241943043670016168562.446677e-05171.428571150.0
686710886483886087340032168564.893355e-05171.428571150.0
781342177281677721614680064168569.786709e-05171.428571150.0
882684354563355443229360128168561.957342e-04171.428571150.0
985368709126710886458720256168563.914684e-04171.428571150.0
1081073741824134217728117440512168567.829367e-04171.428571150.0
\n", + "
" + ], + "text/plain": [ + " nodes collective_size_bytes per_rank_bytes per_gpu_wire_bytes \\\n", + "0 8 1048576 131072 114688 \n", + "1 8 2097152 262144 229376 \n", + "2 8 4194304 524288 458752 \n", + "3 8 8388608 1048576 917504 \n", + "4 8 16777216 2097152 1835008 \n", + "5 8 33554432 4194304 3670016 \n", + "6 8 67108864 8388608 7340032 \n", + "7 8 134217728 16777216 14680064 \n", + "8 8 268435456 33554432 29360128 \n", + "9 8 536870912 67108864 58720256 \n", + "10 8 1073741824 134217728 117440512 \n", + "\n", + " hops_per_tile_coordinate fabric_chunks_per_tile_coordinate \\\n", + "0 168 56 \n", + "1 168 56 \n", + "2 168 56 \n", + "3 168 56 \n", + "4 168 56 \n", + "5 168 56 \n", + "6 168 56 \n", + "7 168 56 \n", + "8 168 56 \n", + "9 168 56 \n", + "10 168 56 \n", + "\n", + " model_latency_s algbw_GBps busbw_GBps \n", + "0 7.645867e-07 171.428571 150.0 \n", + "1 1.529173e-06 171.428571 150.0 \n", + "2 3.058347e-06 171.428571 150.0 \n", + "3 6.116693e-06 171.428571 150.0 \n", + "4 1.223339e-05 171.428571 150.0 \n", + "5 2.446677e-05 171.428571 150.0 \n", + "6 4.893355e-05 171.428571 150.0 \n", + "7 9.786709e-05 171.428571 150.0 \n", + "8 1.957342e-04 171.428571 150.0 \n", + "9 3.914684e-04 171.428571 150.0 \n", + "10 7.829367e-04 171.428571 150.0 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bw = LINK_BW_GBPS * 1e9 # bytes/s\n", + "\n", + "rows = []\n", + "mib = MIN_MIB\n", + "while mib <= MAX_MIB:\n", + " size = mib * (1 << 20)\n", + " total = size * n if PER_RANK else size\n", + " per_rank = total / n\n", + " chunk_bytes = total / (n * n)\n", + " # Latency derived from the model output: hops/3 crossing chunks\n", + " # spread evenly, (N-1) into each GPU's port.\n", + " per_gpu_wire = (crossing_chunks / n) * chunk_bytes\n", + " t = ALPHA_S + per_gpu_wire / bw\n", + " # Closed form cross-check: t = alpha + S(N-1)/(N^2 BW)\n", + " assert math.isclose(t, ALPHA_S + total * (n - 1) / (n * n * bw), rel_tol=1e-12)\n", + " algbw = per_rank / t / 1e9\n", + " busbw = algbw * (n - 1) / n\n", + " rows.append((n, int(total), int(per_rank), int(per_gpu_wire),\n", + " hops_per_elem, crossing_chunks, t, algbw, busbw))\n", + " mib *= 2\n", + "\n", + "sweep = pd.DataFrame(rows, columns=[\n", + " \"nodes\", \"collective_size_bytes\", \"per_rank_bytes\", \"per_gpu_wire_bytes\",\n", + " \"hops_per_tile_coordinate\", \"fabric_chunks_per_tile_coordinate\",\n", + " \"model_latency_s\", \"algbw_GBps\", \"busbw_GBps\",\n", + "])\n", + "sweep\n", + "\n", + "# TODO: Needs to account for links sharing the same \\\n", + "# Currently: doing an ALL GATHER, not all to all.\n", + "# All to all: reshufflling tile shards to be on 1 gpu.\n", + "# Hops per element * per rank byte (document somewhere)\n", + "\n", + "# NOTE: Can think of nvlink as one hop. 0,0 as router. Every time you want to send something, have to go through 0,0.\n", + "# NOTE: How do we route for star routing? Instead of figuring out all routings, should we have a set of routing choices?\n", + "# NOTE: We support various different topologie. However, you have to specify the routing chosen for multicast?\n", + "# NOTE: It is a simple multicast.\n", + " # What if that's the contribution? For regular workloads, superimposing multicast trees would balance traffic.\n", + " # Don't need fancy things (cycle accurate simulation), and still account for congestion (bw pressure on links).\n", + " # Hard to frame contribution in terms of coordinates" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "cbdaefb9", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:35.968638Z", + "iopub.status.busy": "2026-09-17T16:44:35.968546Z", + "iopub.status.idle": "2026-09-17T16:44:35.972405Z", + "shell.execute_reply": "2026-09-17T16:44:35.971113Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "busbw invariant holds: busbw == 150 GB/s on every row\n" + ] + } + ], + "source": [ + "if ALPHA_S == 0:\n", + " assert (sweep[\"busbw_GBps\"] - LINK_BW_GBPS).abs().max() < 1e-9 * LINK_BW_GBPS\n", + " print(f\"busbw invariant holds: busbw == {LINK_BW_GBPS:g} GB/s on every row\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "11751aab", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:35.974202Z", + "iopub.status.busy": "2026-09-17T16:44:35.974110Z", + "iopub.status.idle": "2026-09-17T16:44:36.196411Z", + "shell.execute_reply": "2026-09-17T16:44:36.195159Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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KpUVltM8YnD69Gl0794dLi4uCAkJwS+//AIA2Lt3Lzp06ABnZ2c0b9683McXTp48iX79+sHNzQ3169dHr169cPjwYb1y586dQ8+ePeHs7IzGjRvjww8/hFqtLrdfW7duRdeuXVGvXj24urqif//+OHfuXIXnUVbv3r1x4MABZGRkGFS+pjBJqyGa57nGjRuHpKQk3Lp1C2vWrMGXX36JiRMnGvSXzaZNmxASEoIOHTqY3Z+rV68CADw9Pc0+FgB4e3tj5cqVaNGiBRo3boyVK1di5cqVCA0NtcjxNR555BF07twZP/zwg96+H374Aa6urnjqqacqPcaKFSvQv39/ZGRkYNq0afjkk08QGRmp88t5xYoVGD58OGQyGebMmYOXX34Zv/76K7p06YLMzEyd46lUKsTGxsLT0xOfffYZunfvjvnz52PZsmV6bf/444+YN28eXn31VXz44Ye4fv06Bg8ejJKSEm2Zc+fOoWPHjjh//jymTp2K+fPno169ehg0aJBOgpObm4uuXbvi888/R58+fbB48WK89tpruHDhAv755x+EhoZi1qxZAErv2mo+E80vw127dqFbt27Izs5GQkICPv74Y2RmZqJnz544cuSItp0zZ86gT58+SE9Px4wZMzBmzBgkJCRUmWw97Nlnn0WzZs0wa9asSr9mHzx4MJycnMr96uHHH39EYGAgOnfubFTbFTlw4ADGjx+PkSNHYu7cuSgsLMSQIUNw//79CutcvXoV3bp1g6urK/bs2aP3h1dZR48excGDBzFy5EgsWbIEr732Gnbu3Ino6Gijn0UtT1WfsTFxLEb/gdI/rsLDww26M6r5FuGff/6xSNsVMfRn+tVXX8Xbb7+Nzp07Y/HixRgzZgx++OEHxMbGan+mFy1ahMaNG6NFixbaz+e9996Du7s7wsPDsW/fPu3xDhw4AIlEgoyMDCQnJ2u379+/H127dtW+NuZzVSqViI2NhY+PDz777DMMGTKk3HPetGkTBg4ciGHDhmHVqlVV3nl+8OABnnzySXTo0AFz586Fo6MjRo4ciTVr1mDkyJF44okn8MknnyAvLw9Dhw5FTk6Otu65c+fQtWtXnDp1Cu+88w4++OADpKSkIDo6Gn///be2XGpqKnr06IGkpCRMnToVkydPxvfff4/Fixfr9WflypXo378/6tevj08//RQffPABkpOT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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(7, 5))\n", + "ax.loglog(sweep[\"collective_size_bytes\"], sweep[\"model_latency_s\"] * 1e6, \"o-\",\n", + " label=f\"ISL model ({LINK_BW_GBPS:g} GB/s links)\")\n", + "ax.set_xlabel(\"total collective size (bytes)\")\n", + "ax.set_ylabel(\"all-to-all latency (µs)\")\n", + "ax.set_title(f\"{n}-GPU fully-connected NVLink all-to-all (ISL network model)\")\n", + "ax.grid(True, which=\"both\", alpha=0.3)\n", + "ax.legend() # ASTRA-sim 2.0 and EC2 nccl-tests series overlay here later\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "449a7991", + "metadata": {}, + "source": [ + "## Torus leg: 2×2×2 logical torus (3-cube) all-to-all\n", + "\n", + "GPU $r$ sits at binary coordinates $(g_0, g_1, g_2) \\in \\{0, 1\\}^3$ of a 3-dimensional `noc` space, one coordinate per torus dimension. Rank is recovered row-major with the **last** dimension fastest-varying, $r = 4g_0 + 2g_1 + g_2$ — matching the `torus_bench` benchmark's rank$\\leftrightarrow$coordinate convention.\n", + "\n", + "Every dimension here has extent 2, so the $\\pm 1 \\pmod 2$ torus wraparound edge coincides with the only other value that coordinate can take: wraparound degenerates exactly to the hypercube edge, and `HypercubeMulticastModel` applies directly. Its precondition — a Manhattan, translation-invariant `dist_fn` — is satisfied by Hamming distance on the binary coordinates (ISL has no `!=`/`<>` operator, so per-axis inequality is written as the disjunction `(a < b or a > b)`).\n", + "\n", + "Cost per $(s, d)$ pair at Hamming distance $k$ is $2^k - 1$ (the bounding-box multicast-tree cost `HypercubeMulticastModel` computes), summing to **152** hops over all 64 `data[s, d]` chunks. A dimension-ordered *minimal unicast* routing — one packet per hop instead of a shared multicast tree, which is what the empirical torus benchmark actually implements — would instead traverse $\\sum_{s,d} \\mathrm{hamming}(s, d) = $ **96** hops. The two series bracket real routing behavior; the gap between them is itself a correlation observable, quantifying how far a multicast-aware model diverges from point-to-point unicast." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "d166f6c4", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:36.198246Z", + "iopub.status.busy": "2026-09-17T16:44:36.198146Z", + "iopub.status.idle": "2026-09-17T16:44:36.203304Z", + "shell.execute_reply": "2026-09-17T16:44:36.202401Z" + } + }, + "outputs": [], + "source": [ + "def binary_bounds(prefix: str, k: int) -> str:\n", + " \"\"\"Bit constraints over dims ``{prefix}0..{prefix}{k-1}``.\"\"\"\n", + " return \" and \".join(f\"0 <= {prefix}{i} <= 1\" for i in range(k))\n", + "\n", + "\n", + "def rank_expr(prefix: str, k: int) -> str:\n", + " \"\"\"Affine recovery of the rank from binary torus coordinates.\n", + "\n", + " Row-major with the LAST coordinate fastest-varying:\n", + " ``rank = sum_i 2**(k-1-i) * g_i``, matching the ``torus_bench``\n", + " benchmark's rank<->coordinate convention (see the markdown above).\n", + " \"\"\"\n", + " return \" + \".join(f\"{2 ** (k - 1 - i)}*{prefix}{i}\" for i in range(k))\n", + "\n", + "\n", + "def torus_all_to_all_maps(\n", + " dims: tuple[int, ...] = (2, 2, 2),\n", + ") -> tuple[isl.Map, isl.Map, isl.Map]:\n", + " \"\"\"Build (occupancy, fill, dist_fn) for a logical-torus all-to-all.\n", + "\n", + " Mirrors ``all_to_all_maps`` above but keys GPUs by binary torus\n", + " coordinates instead of a one-hot id. ``data[s, d]`` is the chunk sent\n", + " by GPU ``s`` to GPU ``d``; each GPU holds the chunks it sends (occ)\n", + " and requests the chunks addressed to it (fill).\n", + "\n", + " Parameters\n", + " ----------\n", + " dims : tuple of int, default (2, 2, 2)\n", + " Per-dimension extents of the logical torus. Every entry must\n", + " equal 2 (see Raises); ``K = len(dims)`` sets the dimensionality\n", + " of the ``noc`` space and the number of ``SpatialTag`` axes the\n", + " caller must build to match.\n", + "\n", + " Returns\n", + " -------\n", + " occ : isl.Map\n", + " ``noc[g0..g_{K-1}] -> data[s, d]``: the GPU at ``(g0..g_{K-1})``\n", + " holds the chunk it is the source of, for every destination ``d``.\n", + " fill : isl.Map\n", + " ``noc[g0..g_{K-1}] -> data[s, d]``: the GPU at ``(g0..g_{K-1})``\n", + " requests the chunk addressed to it, for every source ``s``.\n", + " dist_fn : isl.Map\n", + " Piecewise Hamming distance between two ``noc`` points, encoded as\n", + " a disjunction over the ``2**K`` equal/differ patterns per axis.\n", + "\n", + " Raises\n", + " ------\n", + " ValueError\n", + " If any entry of ``dims`` is not 2. General (non-power-of-two)\n", + " torus extents need a genuine wraparound-aware Manhattan distance\n", + " function, not the hypercube-degeneracy shortcut used here — see\n", + " the markdown cell above for why extent 2 is special.\n", + " \"\"\"\n", + " if any(d != 2 for d in dims):\n", + " raise ValueError(\n", + " f\"torus_all_to_all_maps only supports extent-2 dims (hypercube \"\n", + " f\"wraparound degeneracy), got dims={dims!r}; general torus \"\n", + " f\"extents need a wraparound-aware Manhattan dist_fn\"\n", + " )\n", + " k = len(dims)\n", + " n = 2 ** k\n", + "\n", + " gs = \", \".join(f\"gs{i}\" for i in range(k))\n", + " gd = \", \".join(f\"gd{i}\" for i in range(k))\n", + " occ = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gs}] -> data[s, d] : {binary_bounds('gs', k)} \"\n", + " f\"and s = {rank_expr('gs', k)} and 0 <= d < {n} }}\",\n", + " )\n", + " fill = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gd}] -> data[s, d] : {binary_bounds('gd', k)} \"\n", + " f\"and d = {rank_expr('gd', k)} and 0 <= s < {n} }}\",\n", + " )\n", + "\n", + " # Piecewise Hamming distance: one disjunct per subset of axes that\n", + " # differ (2**K sign patterns), cost = popcount of the subset. ISL has\n", + " # no `!=`, so per-axis inequality is the disjunction (a < b or a > b).\n", + " pieces = []\n", + " for mask in range(2 ** k):\n", + " dist = bin(mask).count(\"1\")\n", + " conds = [\n", + " f\"(gd{i} < gs{i} or gd{i} > gs{i})\" if mask & (1 << i) else f\"gd{i} = gs{i}\"\n", + " for i in range(k)\n", + " ]\n", + " pieces.append(\n", + " f\"[noc[{gd}] -> noc[{gs}]] -> hops[{dist}] : \" + \" and \".join(conds)\n", + " )\n", + " dist_fn = isl.Map.read_from_str(CTX, \"{ \" + \"; \".join(pieces) + \" }\")\n", + "\n", + " return occ, fill, dist_fn" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "256ea183", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:36.205363Z", + "iopub.status.busy": "2026-09-17T16:44:36.205267Z", + "iopub.status.idle": "2026-09-17T16:44:36.352174Z", + "shell.execute_reply": "2026-09-17T16:44:36.351561Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ISL network model: 8-GPU 2x2x2 logical torus all-to-all (binary coords)\n", + " bounding-box multicast hops: 152 (Sigma 2^hamming(s,d) - 1)\n", + " min-route unicast hops : 96 (Sigma hamming(s,d))\n", + " routing gap : 56 hops (1.58x)\n" + ] + } + ], + "source": [ + "dims_torus = (2, 2, 2)\n", + "k = len(dims_torus)\n", + "n_t = 2 ** k # = 8 GPUs, same physical count as the FC leg above\n", + "\n", + "occ_t, fill_t, dist_fn_t = torus_all_to_all_maps(dims_torus)\n", + "tags_t = [SpatialTag(i, 0) for i in range(k)]\n", + "model_t = HypercubeMulticastModel(dist_fn_t)\n", + "\n", + "\n", + "def torus_pair_hops(src: int, dst: int) -> int:\n", + " \"\"\"Hops for a single (src, dst) chunk under the torus (Hamming) dist_fn.\"\"\"\n", + " chunk = isl.Set.read_from_str(CTX, f\"{{ data[{src}, {dst}] }}\")\n", + " info = model_t.apply(\n", + " 0,\n", + " Fill(tags_t, fill_t.intersect_range(chunk)),\n", + " Occupancy(tags_t, occ_t.intersect_range(chunk)),\n", + " )\n", + " return eval_total(info.hops)\n", + "\n", + "\n", + "def hamming(a: int, b: int) -> int:\n", + " \"\"\"Hamming distance between the binary representations of two ints.\"\"\"\n", + " return bin(a ^ b).count(\"1\")\n", + "\n", + "\n", + "# --- Run the tool over the full all-to-all and validate against the\n", + "# verified reference numbers (see torus_hops_check.py pre-verification). ---\n", + "info_t = model_t.apply(0, Fill(tags_t, fill_t), Occupancy(tags_t, occ_t))\n", + "torus_hops = eval_total(info_t.hops)\n", + "assert torus_hops == 152, f\"model returned {torus_hops} total hops, expected 152\"\n", + "\n", + "probes = {(0, 1): 1, (0, 3): 3, (0, 7): 7, (5, 5): 0}\n", + "for (src, dst), expected in probes.items():\n", + " got = torus_pair_hops(src, dst)\n", + " assert got == expected, f\"pair ({src}->{dst}) cost {got} != {expected}\"\n", + "\n", + "# Dimension-ordered minimal unicast routing (what the empirical torus\n", + "# benchmark implements): one hop per differing bit, summed over every\n", + "# ordered (s, d) pair. Computed programmatically -- not hardcoded -- so\n", + "# it stays correct if dims_torus ever changes.\n", + "minroute_hops = sum(hamming(s, d) for s in range(n_t) for d in range(n_t))\n", + "assert minroute_hops == 96, f\"minroute_hops {minroute_hops} != 96\"\n", + "\n", + "print(f\"ISL network model: {n_t}-GPU 2x2x2 logical torus all-to-all (binary coords)\")\n", + "print(f\" bounding-box multicast hops: {torus_hops} (Sigma 2^hamming(s,d) - 1)\")\n", + "print(f\" min-route unicast hops : {minroute_hops} (Sigma hamming(s,d))\")\n", + "print(f\" routing gap : {torus_hops - minroute_hops} hops \"\n", + " f\"({torus_hops / minroute_hops:.2f}x)\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "8f3f4946", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:36.353191Z", + "iopub.status.busy": "2026-09-17T16:44:36.353103Z", + "iopub.status.idle": "2026-09-17T16:44:36.358942Z", + "shell.execute_reply": "2026-09-17T16:44:36.358366Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
nodescollective_size_bytesper_rank_bytesper_link_bytes_modelmodel_latency_sminroute_latency_s
0810485761310721.037653e+056.917689e-074.369067e-07
1820971522621442.075307e+051.383538e-068.738133e-07
2841943045242884.150613e+052.767076e-061.747627e-06
38838860810485768.301227e+055.534151e-063.495253e-06
481677721620971521.660245e+061.106830e-056.990507e-06
583355443241943043.320491e+062.213660e-051.398101e-05
686710886483886086.640981e+064.427321e-052.796203e-05
78134217728167772161.328196e+078.854642e-055.592405e-05
88268435456335544322.656393e+071.770928e-041.118481e-04
98536870912671088645.312785e+073.541857e-042.236962e-04
10810737418241342177281.062557e+087.083713e-044.473924e-04
\n", + "
" + ], + "text/plain": [ + " nodes collective_size_bytes per_rank_bytes per_link_bytes_model \\\n", + "0 8 1048576 131072 1.037653e+05 \n", + "1 8 2097152 262144 2.075307e+05 \n", + "2 8 4194304 524288 4.150613e+05 \n", + "3 8 8388608 1048576 8.301227e+05 \n", + "4 8 16777216 2097152 1.660245e+06 \n", + "5 8 33554432 4194304 3.320491e+06 \n", + "6 8 67108864 8388608 6.640981e+06 \n", + "7 8 134217728 16777216 1.328196e+07 \n", + "8 8 268435456 33554432 2.656393e+07 \n", + "9 8 536870912 67108864 5.312785e+07 \n", + "10 8 1073741824 134217728 1.062557e+08 \n", + "\n", + " model_latency_s minroute_latency_s \n", + "0 6.917689e-07 4.369067e-07 \n", + "1 1.383538e-06 8.738133e-07 \n", + "2 2.767076e-06 1.747627e-06 \n", + "3 5.534151e-06 3.495253e-06 \n", + "4 1.106830e-05 6.990507e-06 \n", + "5 2.213660e-05 1.398101e-05 \n", + "6 4.427321e-05 2.796203e-05 \n", + "7 8.854642e-05 5.592405e-05 \n", + "8 1.770928e-04 1.118481e-04 \n", + "9 3.541857e-04 2.236962e-04 \n", + "10 7.083713e-04 4.473924e-04 " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 8 nodes * 3 distinct neighbors/node. Extent-2 wraparound means the +1\n", + "# and -1 neighbor along a dim coincide (mod 2), so each node has exactly\n", + "# one neighbor per torus dimension, not two -- hence 3, not 6.\n", + "DIRECTED_LINKS_TORUS = n_t * k\n", + "\n", + "rows_t = []\n", + "mib = MIN_MIB\n", + "while mib <= MAX_MIB:\n", + " size = mib * (1 << 20)\n", + " total = size * n_t if PER_RANK else size\n", + " per_rank = total / n_t\n", + " chunk_bytes = total / (n_t * n_t)\n", + " # By symmetry, all-to-all traffic loads all 24 directed torus links\n", + " # uniformly: total hop-bytes (chunk_bytes * hops, summed over the 64\n", + " # chunks) divides evenly across the links. Two series bracket\n", + " # routing: `torus_hops` (bounding-box multicast) vs. `minroute_hops`\n", + " # (dimension-ordered unicast) -- see the markdown cell above.\n", + " per_link_bytes_model = (torus_hops / DIRECTED_LINKS_TORUS) * chunk_bytes\n", + " per_link_bytes_minroute = (minroute_hops / DIRECTED_LINKS_TORUS) * chunk_bytes\n", + " model_latency_s = ALPHA_S + per_link_bytes_model / bw\n", + " minroute_latency_s = ALPHA_S + per_link_bytes_minroute / bw\n", + " # Closed-form cross-check: 152/(64*24) = 19/192, 96/(64*24) = 1/16.\n", + " assert math.isclose(model_latency_s, ALPHA_S + total * 19 / (192 * bw), rel_tol=1e-12)\n", + " assert math.isclose(minroute_latency_s, ALPHA_S + total / (16 * bw), rel_tol=1e-12)\n", + " rows_t.append((n_t, int(total), int(per_rank), per_link_bytes_model,\n", + " model_latency_s, minroute_latency_s))\n", + " mib *= 2\n", + "\n", + "sweep_torus = pd.DataFrame(rows_t, columns=[\n", + " \"nodes\", \"collective_size_bytes\", \"per_rank_bytes\", \"per_link_bytes_model\",\n", + " \"model_latency_s\", \"minroute_latency_s\",\n", + "])\n", + "sweep_torus" + ] + }, + { + "cell_type": "markdown", + "id": "38679dd0", + "metadata": {}, + "source": [ + "## All-scatter of a matmul operand: tensor sizes and the ISL model\n", + "\n", + "*All-scatter* (every GPU performs its own scatter; also called all-to-all personalized exchange or complete exchange, NCCL's `alltoall`) is the collective that re-shards a matmul operand. For $C = A \\cdot B$ with $A$ of shape $M \\times K$ spread over $N = 8$ GPUs, switching $A$ from **row-sharded** (GPU $s$ holds rows $[s M_b, (s+1) M_b)$ with $M_b = M/N$) to **column-sharded** (GPU $d$ needs columns $[d K_b, (d+1) K_b)$ with $K_b = K/N$) is an all-scatter: every GPU keeps the $M_b \\times K_b$ block on its own diagonal and sends the other $N-1$ blocks of its shard to their column owners.\n", + "\n", + "Below the ISL model is run on **this actual data space** `A[m, k]` (not the abstract per-pair `data[s, d]` used above) with the shard sizes $M_b, K_b$ left as ISL **parameters**, so `HypercubeMulticastModel` returns the hop count as a closed-form polynomial in $(M_b, K_b)$ (an ISL `PwQPolynomial`) that is then evaluated at each matmul shape. Bytes moved: total $S = M K \\cdot \\mathrm{bytes(dtype)}$, per-rank NCCL buffer $S/N$, and each GPU's port drains $S(N-1)/N^2$ bytes.\n", + "\n", + "The profiled node is a `p5.48xlarge` (8x H100 SXM behind NVSwitch), whose NVLink is rated at 450 GB/s per direction per GPU (`NVLINK_H100_GBPS` below). `LINK_BW_GBPS` above (150 GB/s, the V100-era value matching `mapping/v100_torus.arch.yaml`) is left untouched for the earlier sweeps; the empirical fit further down calibrates the effective bandwidth anyway, so the nominal value only positions the reference line." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "9eed83d8", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:36.360380Z", + "iopub.status.busy": "2026-09-17T16:44:36.360294Z", + "iopub.status.idle": "2026-09-17T16:44:36.362669Z", + "shell.execute_reply": "2026-09-17T16:44:36.362133Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "18 matmul operand shapes, (128, 256) .. (65536, 65536)\n" + ] + } + ], + "source": [ + "NVLINK_H100_GBPS = 450.0 # H100 SXM5 NVLink: 900 GB/s bidirectional = 450 GB/s per direction per GPU\n", + "DTYPE_BYTES = {\"bf16\": 2, \"fp16\": 2, \"fp32\": 4}\n", + "MATMUL_DTYPE = \"bf16\"\n", + "\n", + "# One operand shape per nccl-tests sweep point: M*K = 2**e for e = 15..32, split as\n", + "# M = 2**(e//2), K = 2**(e - e//2) (square for even e, 1:2 rectangular for odd e).\n", + "# Total all-scatter bytes S = M*K*2 then runs 64 KiB .. 8 GiB, i.e. per-rank 8 KiB .. 1 GiB,\n", + "# which is exactly the -f 2 sweep produced by\n", + "# aws-gpu-profiler run --workload nccl-tests --param collective=alltoall --param min_bytes=8192 --param max_bytes=1073741824 --data-dir correlation/data\n", + "MATMUL_SHAPES = [(2 ** (e // 2), 2 ** (e - e // 2)) for e in range(15, 33)]\n", + "print(f\"{len(MATMUL_SHAPES)} matmul operand shapes, {MATMUL_SHAPES[0]} .. {MATMUL_SHAPES[-1]}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "65b7418e", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:36.363707Z", + "iopub.status.busy": "2026-09-17T16:44:36.363638Z", + "iopub.status.idle": "2026-09-17T16:44:50.242544Z", + "shell.execute_reply": "2026-09-17T16:44:50.241200Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ISL model hop count for the matmul re-shard, parametric in the shard size:\n", + " [Mb, Kb] -> { 168 * Mb * Kb : Mb > 0 and Kb > 0 }\n", + " matches 3 * (N-1)/N * M*K = 168 * Mb * Kb at every probe\n" + ] + } + ], + "source": [ + "def matmul_reshard_maps(n: int) -> tuple[isl.Map, isl.Map]:\n", + " \"\"\"Build (occupancy, fill) for re-sharding A[m, k] from row blocks to column blocks.\n", + "\n", + " GPU ``s`` (one-hot coordinate e_s) holds rows ``[s*Mb, (s+1)*Mb)`` of ``A``\n", + " (occupancy); GPU ``d`` requests columns ``[d*Kb, (d+1)*Kb)`` (fill). ``Mb``\n", + " and ``Kb`` are ISL *parameters*, so the model's hop count comes back as a\n", + " quasi-polynomial in them.\n", + "\n", + " Parameters\n", + " ----------\n", + " n : int\n", + " Number of GPUs on the fully-connected fabric (one one-hot dimension\n", + " each).\n", + "\n", + " Returns\n", + " -------\n", + " occ : isl.Map\n", + " ``[Mb, Kb] -> { noc[g0..g_{n-1}] -> A[m, k] }``, the rows each GPU holds.\n", + " fill : isl.Map\n", + " ``[Mb, Kb] -> { noc[g0..g_{n-1}] -> A[m, k] }``, the columns each GPU needs.\n", + "\n", + " Notes\n", + " -----\n", + " Ownership is written as a disjunction over the ``n`` constant GPU ids\n", + " (``gs_i = 1 and i*Mb <= m < (i+1)*Mb``) because ``id * Mb`` with ``id`` a\n", + " variable would be a bilinear term, which ISL rejects.\n", + " \"\"\"\n", + " gs = \", \".join(f\"gs{i}\" for i in range(n))\n", + " gd = \", \".join(f\"gd{i}\" for i in range(n))\n", + " own_rows = \" or \".join(f\"(gs{i} = 1 and {i}*Mb <= m < {i + 1}*Mb)\" for i in range(n))\n", + " own_cols = \" or \".join(f\"(gd{i} = 1 and {i}*Kb <= k < {i + 1}*Kb)\" for i in range(n))\n", + " occ = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"[Mb, Kb] -> {{ noc[{gs}] -> A[m, k] : Mb >= 1 and Kb >= 1 and \"\n", + " f\"{onehot_constraints('gs', n)} and 0 <= k < {n}*Kb and ({own_rows}) }}\",\n", + " )\n", + " fill = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"[Mb, Kb] -> {{ noc[{gd}] -> A[m, k] : Mb >= 1 and Kb >= 1 and \"\n", + " f\"{onehot_constraints('gd', n)} and 0 <= m < {n}*Mb and ({own_cols}) }}\",\n", + " )\n", + " return occ, fill\n", + "\n", + "\n", + "def eval_params(poly: isl.PwQPolynomial, **params: int) -> int:\n", + " \"\"\"Evaluate a parametric, fully-summed PwQPolynomial at integer parameter values.\"\"\"\n", + " space = poly.domain().get_space()\n", + " point = isl.Point.zero(space)\n", + " for name, value in params.items():\n", + " idx = space.find_dim_by_name(isl.dim_type.param, name)\n", + " point = point.set_coordinate_val(\n", + " isl.dim_type.param, idx, isl.Val.int_from_si(CTX, value)\n", + " )\n", + " return int(poly.eval(point).to_python())\n", + "\n", + "\n", + "occ_mm, fill_mm = matmul_reshard_maps(n)\n", + "_, _, dist_fn_fc = all_to_all_maps(n) # same unit-cost dist_fn as the FC leg above\n", + "tags_mm = [SpatialTag(i, 0) for i in range(n)]\n", + "info_mm = HypercubeMulticastModel(dist_fn_fc).apply(\n", + " 0, Fill(tags_mm, fill_mm), Occupancy(tags_mm, occ_mm)\n", + ")\n", + "assert info_mm.unfulfilled_fill.map_.is_empty(), \"every requested block must have a holder\"\n", + "hops_mm = info_mm.hops\n", + "print(\"ISL model hop count for the matmul re-shard, parametric in the shard size:\")\n", + "print(\" \", hops_mm)\n", + "\n", + "# Closed form: every element whose row owner differs from its column owner crosses the\n", + "# fabric at the uniform 3-hop FC cost -> 3 * (N-1)/N * M*K = 168 * Mb * Kb for N = 8.\n", + "HOPS_PER_SHARD_ELEMENT = 3 * (n - 1) * n\n", + "for Mb, Kb in [(1, 1), (2, 2), (128, 128), (512, 2048)]:\n", + " got = eval_params(hops_mm, Mb=Mb, Kb=Kb)\n", + " expected = HOPS_PER_SHARD_ELEMENT * Mb * Kb\n", + " assert got == expected, f\"hops(Mb={Mb}, Kb={Kb}) = {got} != {expected}\"\n", + "print(f\" matches 3 * (N-1)/N * M*K = {HOPS_PER_SHARD_ELEMENT} * Mb * Kb at every probe\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "55ff9b48", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:50.244558Z", + "iopub.status.busy": "2026-09-17T16:44:50.244459Z", + "iopub.status.idle": "2026-09-17T16:44:50.253466Z", + "shell.execute_reply": "2026-09-17T16:44:50.252321Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
MKdtypeelementscollective_size_bytesper_rank_bytesmodel_hopsper_gpu_wire_bytesmodel_latency_us
0128256bf16327686553681928601671680.015929
1256256bf166553613107216384172032143360.031858
2256512bf1613107226214432768344064286720.063716
3512512bf1626214452428865536688128573440.127431
45121024bf16524288104857613107213762561146880.254862
510241024bf161048576209715226214427525122293760.509724
610242048bf162097152419430452428855050244587521.019449
720482048bf16419430483886081048576110100489175042.038898
820484096bf1683886081677721620971522202009618350084.077796
940964096bf16167772163355443241943044404019236700168.155591
1040968192bf163355443267108864838860888080384734003216.311182
1181928192bf1667108864134217728167772161761607681468006432.622364
12819216384bf16134217728268435456335544323523215362936012865.244729
131638416384bf162684354565368709126710886470464307258720256130.489458
141638432768bf1653687091210737418241342177281409286144117440512260.978916
153276832768bf16107374182421474836482684354562818572288234881024521.957831
163276865536bf162147483648429496729653687091256371445764697620481043.915662
176553665536bf16429496729685899345921073741824112742891529395240962087.831324
\n", + "
" + ], + "text/plain": [ + " M K dtype elements collective_size_bytes per_rank_bytes \\\n", + "0 128 256 bf16 32768 65536 8192 \n", + "1 256 256 bf16 65536 131072 16384 \n", + "2 256 512 bf16 131072 262144 32768 \n", + "3 512 512 bf16 262144 524288 65536 \n", + "4 512 1024 bf16 524288 1048576 131072 \n", + "5 1024 1024 bf16 1048576 2097152 262144 \n", + "6 1024 2048 bf16 2097152 4194304 524288 \n", + "7 2048 2048 bf16 4194304 8388608 1048576 \n", + "8 2048 4096 bf16 8388608 16777216 2097152 \n", + "9 4096 4096 bf16 16777216 33554432 4194304 \n", + "10 4096 8192 bf16 33554432 67108864 8388608 \n", + "11 8192 8192 bf16 67108864 134217728 16777216 \n", + "12 8192 16384 bf16 134217728 268435456 33554432 \n", + "13 16384 16384 bf16 268435456 536870912 67108864 \n", + "14 16384 32768 bf16 536870912 1073741824 134217728 \n", + "15 32768 32768 bf16 1073741824 2147483648 268435456 \n", + "16 32768 65536 bf16 2147483648 4294967296 536870912 \n", + "17 65536 65536 bf16 4294967296 8589934592 1073741824 \n", + "\n", + " model_hops per_gpu_wire_bytes model_latency_us \n", + "0 86016 7168 0.015929 \n", + "1 172032 14336 0.031858 \n", + "2 344064 28672 0.063716 \n", + "3 688128 57344 0.127431 \n", + "4 1376256 114688 0.254862 \n", + "5 2752512 229376 0.509724 \n", + "6 5505024 458752 1.019449 \n", + "7 11010048 917504 2.038898 \n", + "8 22020096 1835008 4.077796 \n", + "9 44040192 3670016 8.155591 \n", + "10 88080384 7340032 16.311182 \n", + "11 176160768 14680064 32.622364 \n", + "12 352321536 29360128 65.244729 \n", + "13 704643072 58720256 130.489458 \n", + "14 1409286144 117440512 260.978916 \n", + "15 2818572288 234881024 521.957831 \n", + "16 5637144576 469762048 1043.915662 \n", + "17 11274289152 939524096 2087.831324 " + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bw_h100 = NVLINK_H100_GBPS * 1e9 # bytes/s\n", + "dtype_bytes = DTYPE_BYTES[MATMUL_DTYPE]\n", + "\n", + "rows_mm = []\n", + "for M, K in MATMUL_SHAPES:\n", + " assert M % n == 0 and K % n == 0, f\"{M}x{K} does not shard evenly over {n} GPUs\"\n", + " Mb, Kb = M // n, K // n\n", + " hops = eval_params(hops_mm, Mb=Mb, Kb=Kb)\n", + " elements = M * K\n", + " total_bytes = elements * dtype_bytes # S\n", + " crossing_elements = hops // 3 # uniform 3 hops per fabric-crossing element\n", + " per_gpu_wire_bytes = (crossing_elements // n) * dtype_bytes # (N-1)/N of each GPU's shard\n", + " t_model = ALPHA_S + per_gpu_wire_bytes / bw_h100\n", + " # Closed-form cross-check: t = alpha + S (N-1) / (N^2 BW)\n", + " assert math.isclose(\n", + " t_model, ALPHA_S + total_bytes * (n - 1) / (n * n * bw_h100), rel_tol=1e-12\n", + " )\n", + " rows_mm.append((M, K, MATMUL_DTYPE, elements, total_bytes, total_bytes // n, hops,\n", + " per_gpu_wire_bytes, t_model * 1e6))\n", + "\n", + "matmul_sweep = pd.DataFrame(rows_mm, columns=[\n", + " \"M\", \"K\", \"dtype\", \"elements\", \"collective_size_bytes\", \"per_rank_bytes\",\n", + " \"model_hops\", \"per_gpu_wire_bytes\", \"model_latency_us\",\n", + "])\n", + "matmul_sweep" + ] + }, + { + "cell_type": "markdown", + "id": "5e209b22", + "metadata": {}, + "source": [ + "## Empirical overlay: EC2 nccl-tests + torus_bench\n", + "\n", + "CSV files under `correlation/data/` (inside the `aws-gpu-profiler` submodule, where fetched results are versioned: `data///results.csv` for new runs; the 2026-09-04 run keeps the older `data//fc/csv/*.csv` layout, and the glob below reads both) are produced by the `aws-gpu-profiler` tool (`aws-gpu-profiler run --workload nccl-tests ... --data-dir correlation/data`, checked out as a git submodule at `correlation/`; not part of this notebook) and share a unified schema: `source, topology, dims, collective, size_bytes, count, dtype, time_us, algbw_GBps, busbw_GBps, wrong`.\n", + "\n", + "Size normalization to the total collective size $S$ used by `sweep` / `sweep_torus` above differs by source: for `source == \"torus_bench\"` rows, `size_bytes` is **already** the total $S$. For `source == \"nccl-tests\"` rows with `collective == \"alltoall\"`, `size_bytes` is the *per-rank* message size, so $S = N \\times \\texttt{size\\_bytes}$ — verify this against the nccl-tests version actually in use, since the size semantics nccl-tests reports differ per collective. Only `alltoall` is normalized and correlated against the model here; other collectives are inventoried below for later work." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "4715980a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:50.255471Z", + "iopub.status.busy": "2026-09-17T16:44:50.255374Z", + "iopub.status.idle": "2026-09-17T16:44:50.269543Z", + "shell.execute_reply": "2026-09-17T16:44:50.268333Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
rowsmin_sizemax_size
topologycollective
fcall_gather1881921073741824
all_reduce1881921073741824
alltoall1881921073741824
broadcast1881921073741824
reduce_scatter1881921073741824
sendrecv1881921073741824
\n", + "
" + ], + "text/plain": [ + " rows min_size max_size\n", + "topology collective \n", + "fc all_gather 18 8192 1073741824\n", + " all_reduce 18 8192 1073741824\n", + " alltoall 18 8192 1073741824\n", + " broadcast 18 8192 1073741824\n", + " reduce_scatter 18 8192 1073741824\n", + " sendrecv 18 8192 1073741824" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from pathlib import Path\n", + "\n", + "# Design: prefer the path relative to the notebook's own directory (the\n", + "# normal case when the notebook is run in place), but fall back to the\n", + "# repo-root-relative path so `jupyter execute` from a different cwd (e.g.\n", + "# CI running from the repo root) still finds real data when it exists,\n", + "# instead of silently taking the empty-data path below.\n", + "DATA_DIR = (\n", + " Path(\"correlation/data\") if Path(\"correlation/data\").is_dir()\n", + " else Path(\"notebooks/astrasim2_correlation/correlation/data\")\n", + ")\n", + "\n", + "UNIFIED_CSV_COLUMNS = [\n", + " \"source\", \"topology\", \"dims\", \"collective\", \"size_bytes\", \"count\",\n", + " \"dtype\", \"time_us\", \"algbw_GBps\", \"busbw_GBps\", \"wrong\",\n", + "]\n", + "_NUMERIC_COLUMNS = [\"size_bytes\", \"count\", \"time_us\", \"algbw_GBps\", \"busbw_GBps\"]\n", + "\n", + "def _has_unified_schema(path):\n", + " \"\"\"True if the CSV's header carries every unified column.\n", + "\n", + " Design: the submodule's data/ tree also holds other workloads' results\n", + " (e.g. data//nvlink_probe/results.csv from the fabric probes, with\n", + " its own 43-column schema); only the collective-benchmark CSVs belong\n", + " in `emp`, so files are selected by header rather than by path.\n", + " \"\"\"\n", + " with open(path, encoding=\"utf-8\") as fh:\n", + " header = fh.readline().strip().split(\",\")\n", + " return all(col in header for col in UNIFIED_CSV_COLUMNS)\n", + "\n", + "files = sorted(f for f in DATA_DIR.glob(\"**/*.csv\") if _has_unified_schema(f))\n", + "if files:\n", + " emp = pd.concat(\n", + " [pd.read_csv(f, dtype={\"wrong\": str}) for f in files],\n", + " ignore_index=True,\n", + " )\n", + " for col in _NUMERIC_COLUMNS:\n", + " emp[col] = pd.to_numeric(emp[col], errors=\"coerce\")\n", + "else:\n", + " # Design: keep the unified schema even when no files were found, so\n", + " # downstream cells can reference emp[...] columns inside their\n", + " # `if HAVE_EMPIRICAL:` guards without ever hitting a KeyError.\n", + " emp = pd.DataFrame(columns=UNIFIED_CSV_COLUMNS)\n", + "\n", + "HAVE_EMPIRICAL = len(files) > 0 and not emp.empty\n", + "\n", + "if not HAVE_EMPIRICAL:\n", + " print(\"no empirical data yet -- run aws-gpu-profiler run --workload nccl-tests --data-dir correlation/data; \"\n", + " \"overlay cells below will no-op\")\n", + "else:\n", + " inventory = emp.groupby([\"topology\", \"collective\"]).agg(\n", + " rows=(\"size_bytes\", \"count\"),\n", + " min_size=(\"size_bytes\", \"min\"),\n", + " max_size=(\"size_bytes\", \"max\"),\n", + " )\n", + " display(inventory)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "a2e080ce", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:50.271074Z", + "iopub.status.busy": "2026-09-17T16:44:50.270991Z", + "iopub.status.idle": "2026-09-17T16:44:50.444123Z", + "shell.execute_reply": "2026-09-17T16:44:50.443843Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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T9IEQRAEQRB8ECnSBEEQBEEQfBAp0gRBEARBEHwQKdIEQRAEQRB8ECnSBEEQBEEQfBAp0hoAycnJdOnShW7dutG/f//6DqdRkpqaSv/+/enYsSNnnXUWhYWF9R1So2HHjh1069bN8RMUFMQnn3xS32E1KqZPn06nTp3o2LEjDzzwgKEXRwue5cUXX6RTp0507tyZt99+u77DaRRcffXVREZGct1111WRL1myhPbt29OuXTtee+21WvmQIzgaAMnJyWzZsoXQ0ND6DqXRctFFF/H0009z4YUXkp2dTXh4OH5+jf6ta3VOQUEBycnJ7Nu3j5CQkPoOp1GQlZXFeeedx9atW/H396dv3768+OKLnH/++fUdWqPh999/JyUlhdWrV6OUon///ixdupQmTZrUd2gNmpUrV5Kfn8+CBQv48MMPAaioqKBjx4589913RERE0KNHD1avXk10dLRbPuRJmiDUkuN/nC688EIAoqKipECrJz777DMGDBggBVodU1FRQUlJCeXl5ZSXlxMXF1ffITUq/vjjD84//3wCAwMJCgqia9euLF26tL7DavD069ePsLCwKrJ169bRqVMnmjdvTmhoKIMHD+abb75x24cUafXMqlWrGDJkCAkJCWiaVu3XNLNmzSI5OZnAwEDOPfdc1q1bV6Vd0zQuuugizjnnHBYuXFhHkTccansPdu7cSWhoKEOGDOHss89mypQpdRj96Y8nxsBx3n//fW688UYvR9ywqG3+Y2NjefTRR2nZsiUJCQkMHDiQNm3a1GEPTn9qew86d+7MypUrOXbsGDk5OaxcuZJDhw7VYQ9OPzw575zI4cOHad68ueP35s2b1+peSJFWzxQWFtK1a1dmzZpVbfuiRYsYO3YsEydOZOPGjXTt2pVBgwaRmZnp0Pnxxx/ZsGEDn332GVOmTOG3336rq/AbBLW9BxUVFfzwww/897//Zc2aNSxbtoxly5bVZRdOazwxBqDyvXqrV6/m8ssvr4uwGwy1zX9OTg5Llixh7969HDp0iNWrV7Nq1aq67MJpT23vwfG1gBdffDHXXHMN5513HlartS67cNrhqXnH6yjBZwDUxx9/XEXWq1cvNXr0aMfvdrtdJSQkqKlTp1Zr49FHH1Xz5s3zYpQNG3fuwerVq9Wll17qaH/++efV888/XyfxNjRqMwbefPNNNXz48LoIs8Hi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9ttvWbZsGffddx8vvPAC33//Pf7+/gBkZ2cTEhIiBZrQ6JAiTRAaCAEBAdjt9iqyDh068NFHH6GUcjxN++mnnwgLC6NFixY1XvfTTz/Ru3dv7rvvPods9+7dpuLp0qULy5cvZ/Lkyae0tWnThoCAAH766SeSkpKAyqdF69evN3wcyNlnn82OHTto27Ztjf4PHjzIn3/+We3TtOr6XR29e/cmMTGRRYsW8dVXX3H99dc7ioeOHTtis9nYv38/F110kaG4ofIp1cCBAxk4cCATJ06kSZMmrFixotpCZtq0abz//vusXr2a6OjoKm2uclAd3bt3Z/bs2VU+E8f5+eef6du3LwAVFRVs2LCBMWPGONovv/xyQkJCmD17NkuXLmXVqlVVrvf39z8lp0ZiDAoKYsiQIQwZMoTRo0dz5pln8vvvv3P22WcDsGXLlhqfTApCQ0aKNEFoICQnJ7N27Vr27t1LaGgoUVFR3HfffcyYMYP777+fMWPGsGPHDiZOnMjYsWOxWCw1XteuXTvefPNNvv76a1q1asVbb73F+vXradWqleF4xo8fz1lnncV9993HP/7xDwICAvjuu++4/vrriYmJ4d577+X//u//iIqKomXLljz//PMUFRUZPhpiwoQJXHnllbRs2ZLrrrsOi8XC5s2b2bJlC08//TQXXXQRffv25dprr2XatGm0bduW7du3o2kal112GcnJyRQUFLB8+XK6du1KcHBwjU+FbrnlFubMmcOff/7Jd99955CHhYXx6KOP8vDDD6PrOhdccAG5ubn89NNPhIeHk5KScoqtJUuWsGfPHvr27UtkZCRffvkluq7Tvn37U3S//fZbHnvsMWbNmkVMTAzp6elAZVETERHhMgfV0b9/fwoKCti6dSudO3eu0jZr1izatWtHhw4dmD59Ojk5Odx+++2OdqvVysiRIxk/fjzt2rWr8vUoVH6Wli9fTp8+fbDZbERGRrqMcf78+djtds4991yCg4N5++23CQoKchTvAD/88AOXXnpptf0RhAZNfS+KEwTBM+zYsUOdd955KigoSAEqNTVVKaXUypUr1TnnnKMCAgJU06ZN1T//+U9VXl7u9LqSkhI1cuRIFRERoZo0aaLuvfdeNW7cONW1a1fHda42Dhz33bt3b2Wz2VSTJk3UoEGDHBsBiouL1f33369iYmKUzWZTffr0UevWrXNc62rjgFJKLV26VPXu3VsFBQWp8PBw1atXryo7A48ePapGjRqloqOjVWBgoOrcubNasmSJo/0f//iHio6OVoBjx+uJGweOs23bNgWopKSkKpswlFJK13U1Y8YM1b59e+Xv769iY2PVoEGD1Pfff19tTn744Qd10UUXqcjISBUUFKS6dOlSZdfsiRsHJk6cqIBTflJSUgznoDpuuOEGNW7cOMfvxzcOvPPOO6pXr14qICBAdezYUa1YseKUa3fv3q0AxwaPE/nss89U27ZtlZ+fX5XdmM5i/Pjjj9W5556rwsPDVUhIiDrvvPPUt99+67j24MGDyt/fXx04cMBpnwShIaIppVT9lIeCIAhCffDbb79xySWXsHv3bkJDQ01d+8MPPzBgwAAOHDhAfHy8lyL8m3/+85/k5OQwd+5cr/sSBF9DDrMVBEFoZHTp0oXnnnuO1NRUw9eUlpZy8OBBJk2axPXXX18nBRpAXFyc11+TJQi+ijxJEwRBEFwyf/587rjjDrp168Znn312ym5WQRA8jxRpgiAIgiAIPoh83SkIgiAIguCDSJEmCIIgCILgg0iRJgiCIAiC4INIkSYIgiAIguCDSJEmCIIgCILgg0iRJgiCIAiC4INIkSYIgiAIguCDSJEmCIIgCILgg0iRJgiCIAiC4IP8PxPmXamKIgg3AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(7, 5))\n", + "\n", + "ax.loglog(sweep[\"collective_size_bytes\"], sweep[\"model_latency_s\"] * 1e6, \"o-\",\n", + " label=f\"FC model ({LINK_BW_GBPS:g} GB/s links)\")\n", + "ax.loglog(sweep_torus[\"collective_size_bytes\"], sweep_torus[\"model_latency_s\"] * 1e6, \"s-\",\n", + " label=\"torus model, 152 hops (bounding-box multicast)\")\n", + "ax.loglog(sweep_torus[\"collective_size_bytes\"], sweep_torus[\"minroute_latency_s\"] * 1e6, \"s--\",\n", + " label=\"torus min-route, 96 hops (dimension-ordered unicast)\")\n", + "\n", + "if HAVE_EMPIRICAL:\n", + " alltoall = emp[emp[\"collective\"] == \"alltoall\"]\n", + " fc_rows = alltoall[alltoall[\"topology\"] == \"fc\"]\n", + " torus_rows = alltoall[alltoall[\"topology\"] == \"torus\"]\n", + " if not fc_rows.empty:\n", + " # nccl-tests alltoall size_bytes is the PER-RANK message size (see\n", + " # markdown above); scale to total S to match `sweep`'s convention.\n", + " ax.scatter(fc_rows[\"size_bytes\"] * NODES, fc_rows[\"time_us\"],\n", + " marker=\"x\", color=\"tab:red\", label=\"EC2 nccl-tests alltoall (fc)\")\n", + " if not torus_rows.empty:\n", + " # torus_bench size_bytes is ALREADY total collective size S.\n", + " ax.scatter(torus_rows[\"size_bytes\"], torus_rows[\"time_us\"],\n", + " marker=\"+\", color=\"tab:green\", label=\"EC2 torus_bench alltoall (torus)\")\n", + "\n", + "ax.set_xlabel(\"total collective size (bytes)\")\n", + "ax.set_ylabel(\"all-to-all latency (µs)\")\n", + "ax.set_title(\"Fully-connected vs. 2x2x2 torus all-to-all: model vs. empirical\")\n", + "ax.grid(True, which=\"both\", alpha=0.3)\n", + "ax.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "a8ec5d63", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:50.445869Z", + "iopub.status.busy": "2026-09-17T16:44:50.445786Z", + "iopub.status.idle": "2026-09-17T16:44:50.451384Z", + "shell.execute_reply": "2026-09-17T16:44:50.450987Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "FC calibration : alpha = 74.227 us, BW_eff = 339.48 GB/s, R^2 = 0.9996\n", + "torus calibration : fewer than 2 alltoall rows, skipping fit\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "\n", + "\n", + "def linear_fit(S: np.ndarray, t: np.ndarray) -> tuple[float, float, float]:\n", + " \"\"\"Ordinary-least-squares fit of ``t = intercept + slope * S``.\n", + "\n", + " Parameters\n", + " ----------\n", + " S : np.ndarray\n", + " Total collective size in bytes for each empirical sample.\n", + " t : np.ndarray\n", + " Measured latency in seconds for each empirical sample. Must be\n", + " the same length as `S`.\n", + "\n", + " Returns\n", + " -------\n", + " intercept : float\n", + " Fitted per-operation latency overhead (the model's alpha), seconds.\n", + " slope : float\n", + " Fitted dt/dS, seconds/byte.\n", + " r_squared : float\n", + " Coefficient of determination of the linear fit; NaN if `t` has\n", + " zero total variance (R^2 is undefined in that degenerate case).\n", + " \"\"\"\n", + " slope, intercept = np.polyfit(S, t, 1)\n", + " t_pred = slope * S + intercept\n", + " ss_res = float(np.sum((t - t_pred) ** 2))\n", + " ss_tot = float(np.sum((t - np.mean(t)) ** 2))\n", + " r_squared = 1.0 - ss_res / ss_tot if ss_tot > 0 else float(\"nan\")\n", + " return float(intercept), float(slope), r_squared\n", + "\n", + "\n", + "def bw_from_slope(slope: float, slope_factor: float) -> float:\n", + " \"\"\"Translate a fitted t-vs-S slope into an effective bandwidth, bytes/s.\n", + "\n", + " Given the model form ``t = alpha + S * slope_factor / BW``, the\n", + " fitted slope is ``dt/dS = slope_factor / BW``, so\n", + " ``BW = slope_factor / slope``.\n", + " \"\"\"\n", + " return slope_factor / slope\n", + "\n", + "\n", + "if HAVE_EMPIRICAL and (emp[\"collective\"] == \"alltoall\").any():\n", + " alltoall = emp[emp[\"collective\"] == \"alltoall\"].dropna(\n", + " subset=[\"size_bytes\", \"time_us\"]\n", + " )\n", + "\n", + " fc_rows = alltoall[alltoall[\"topology\"] == \"fc\"]\n", + " if len(fc_rows) >= 2:\n", + " # fc slope_factor = (N-1)/N^2 = 7/64 (N=8), from the closed form\n", + " # in the \"Size and latency conventions\" cell above.\n", + " S_fc = fc_rows[\"size_bytes\"].to_numpy(dtype=float) * NODES\n", + " t_fc = fc_rows[\"time_us\"].to_numpy(dtype=float) * 1e-6\n", + " alpha_fc, slope_fc, r2_fc = linear_fit(S_fc, t_fc)\n", + " bw_fc = bw_from_slope(slope_fc, 7 / 64)\n", + " print(f\"FC calibration : alpha = {alpha_fc * 1e6:.3f} us, \"\n", + " f\"BW_eff = {bw_fc / 1e9:.2f} GB/s, R^2 = {r2_fc:.4f}\")\n", + " else:\n", + " print(\"FC calibration : fewer than 2 alltoall rows, skipping fit\")\n", + "\n", + " torus_rows = alltoall[alltoall[\"topology\"] == \"torus\"]\n", + " if len(torus_rows) >= 2:\n", + " # torus slope_factor = hops/(64*24) = hops/1536; report BW under\n", + " # both routing hypotheses (h=152 bounding-box, h=96 min-route)\n", + " # from a single fit, since alpha/R^2 don't depend on slope_factor\n", + " # -- only the slope-to-BW translation does.\n", + " S_t = torus_rows[\"size_bytes\"].to_numpy(dtype=float)\n", + " t_t = torus_rows[\"time_us\"].to_numpy(dtype=float) * 1e-6\n", + " alpha_t, slope_t, r2_t = linear_fit(S_t, t_t)\n", + " bw_t_152 = bw_from_slope(slope_t, 152 / 1536)\n", + " bw_t_96 = bw_from_slope(slope_t, 96 / 1536)\n", + " print(f\"torus calibration : alpha = {alpha_t * 1e6:.3f} us, R^2 = {r2_t:.4f}\")\n", + " print(f\" BW_eff @ h=152 (bounding-box model): {bw_t_152 / 1e9:.2f} GB/s\")\n", + " print(f\" BW_eff @ h=96 (dimension-ordered) : {bw_t_96 / 1e9:.2f} GB/s\")\n", + " else:\n", + " print(\"torus calibration : fewer than 2 alltoall rows, skipping fit\")\n", + "else:\n", + " print(\"calibration: no empirical alltoall rows yet\")" + ] + }, + { + "cell_type": "markdown", + "id": "2325bd49", + "metadata": {}, + "source": [ + "## Linear fit: ISL network model vs. profiled GPUs (all-scatter, fully connected)\n", + "\n", + "Each nccl-tests `alltoall` row from the FC leg gives a measured latency $t_{meas}$ at per-rank size `size_bytes`, i.e. total $S = N \\cdot$ `size_bytes`. The ISL model at nominal H100 NVLink bandwidth predicts $t_{model}(S) = S(N-1)/(N^2 \\cdot BW_{nom})$ with $\\alpha = 0$. The fit below is ordinary least squares of\n", + "\n", + "$$ t_{meas} = a + b \\cdot t_{model} $$\n", + "\n", + "so $a$ is the per-operation latency overhead $\\alpha$ that the flat bandwidth model lacks, and $b = BW_{nom}/BW_{eff}$ is the ratio of nominal to achieved port bandwidth; equivalently $t = \\alpha + S(N-1)/(N^2 \\cdot BW_{eff})$ with $BW_{eff} = BW_{nom}/b$. OLS in linear space is dominated by the largest sizes, so the per-size table also reports measured/calibrated to show where a single straight line stops describing the data (NCCL's protocol switches at small sizes are the usual culprit). Rows whose $S$ equals a `MATMUL_SHAPES` operand are labelled with that shape.\n", + "\n", + "Data: `correlation/data//...` (versioned in the `aws-gpu-profiler` submodule), produced from this notebook's directory by\n", + "`aws-gpu-profiler run --workload nccl-tests --param collective=alltoall --param min_bytes=8192 --param max_bytes=1073741824 --data-dir correlation/data`. With no data present the cells below print a notice and draw nothing." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "0714f2dd", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:50.453751Z", + "iopub.status.busy": "2026-09-17T16:44:50.453585Z", + "iopub.status.idle": "2026-09-17T16:44:50.463289Z", + "shell.execute_reply": "2026-09-17T16:44:50.462245Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "linear fit t_meas = a + b * t_model (18 FC alltoall points)\n", + " a = 74.23 us b = 1.3256 R^2 = 0.9996\n", + " => alpha = 74.23 us, BW_eff = 339.5 GB/s (75.4% of 450 GB/s nominal)\n", + " => t = alpha + S * (N-1) / (N^2 * BW_eff)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
per_rank_bytescollective_size_bytesmatmul_shapemeasured_usmodel_nominal_usmodel_calibrated_usmeasured_over_calibrated
0819265536128x256 bf1686.610.01592974.2485671.166487
116384131072256x256 bf1681.970.03185874.2696821.103681
232768262144256x512 bf1681.370.06371674.3119121.094979
365536524288512x512 bf1681.570.12743174.3963711.096424
41310721048576512x1024 bf1679.780.25486274.5652901.069935
526214420971521024x1024 bf1680.110.50972474.9031281.069515
652428841943041024x2048 bf1681.001.01944975.5788041.071729
7104857683886082048x2048 bf1684.092.03889876.9301561.093069
82097152167772162048x4096 bf1687.684.07779679.6328601.101053
94194304335544324096x4096 bf1688.688.15559185.0382671.042825
108388608671088644096x8192 bf1692.4216.31118295.8490810.964224
11167772161342177288192x8192 bf1690.8232.622364117.4707100.773129
12335544322684354568192x16384 bf16128.1365.244729160.7139680.797255
136710886453687091216384x16384 bf16226.64130.489458247.2004830.916827
14134217728107374182416384x32768 bf16410.00260.978916420.1735130.975787
15268435456214748364832768x32768 bf16776.61521.957831766.1195741.013693
16536870912429496729632768x65536 bf161483.151043.9156621458.0116951.017241
171073741824858993459265536x65536 bf162830.582087.8313242841.7959380.996053
\n", + "
" + ], + "text/plain": [ + " per_rank_bytes collective_size_bytes matmul_shape measured_us \\\n", + "0 8192 65536 128x256 bf16 86.61 \n", + "1 16384 131072 256x256 bf16 81.97 \n", + "2 32768 262144 256x512 bf16 81.37 \n", + "3 65536 524288 512x512 bf16 81.57 \n", + "4 131072 1048576 512x1024 bf16 79.78 \n", + "5 262144 2097152 1024x1024 bf16 80.11 \n", + "6 524288 4194304 1024x2048 bf16 81.00 \n", + "7 1048576 8388608 2048x2048 bf16 84.09 \n", + "8 2097152 16777216 2048x4096 bf16 87.68 \n", + "9 4194304 33554432 4096x4096 bf16 88.68 \n", + "10 8388608 67108864 4096x8192 bf16 92.42 \n", + "11 16777216 134217728 8192x8192 bf16 90.82 \n", + "12 33554432 268435456 8192x16384 bf16 128.13 \n", + "13 67108864 536870912 16384x16384 bf16 226.64 \n", + "14 134217728 1073741824 16384x32768 bf16 410.00 \n", + "15 268435456 2147483648 32768x32768 bf16 776.61 \n", + "16 536870912 4294967296 32768x65536 bf16 1483.15 \n", + "17 1073741824 8589934592 65536x65536 bf16 2830.58 \n", + "\n", + " model_nominal_us model_calibrated_us measured_over_calibrated \n", + "0 0.015929 74.248567 1.166487 \n", + "1 0.031858 74.269682 1.103681 \n", + "2 0.063716 74.311912 1.094979 \n", + "3 0.127431 74.396371 1.096424 \n", + "4 0.254862 74.565290 1.069935 \n", + "5 0.509724 74.903128 1.069515 \n", + "6 1.019449 75.578804 1.071729 \n", + "7 2.038898 76.930156 1.093069 \n", + "8 4.077796 79.632860 1.101053 \n", + "9 8.155591 85.038267 1.042825 \n", + "10 16.311182 95.849081 0.964224 \n", + "11 32.622364 117.470710 0.773129 \n", + "12 65.244729 160.713968 0.797255 \n", + "13 130.489458 247.200483 0.916827 \n", + "14 260.978916 420.173513 0.975787 \n", + "15 521.957831 766.119574 1.013693 \n", + "16 1043.915662 1458.011695 1.017241 \n", + "17 2087.831324 2841.795938 0.996053 " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "shape_by_size = {M * K * dtype_bytes: f\"{M}x{K} {MATMUL_DTYPE}\" for M, K in MATMUL_SHAPES}\n", + "fc_fit = None\n", + "fc_fit_table = None\n", + "if HAVE_EMPIRICAL:\n", + " fc_rows = (\n", + " emp[(emp[\"collective\"] == \"alltoall\") & (emp[\"topology\"] == \"fc\")]\n", + " .dropna(subset=[\"size_bytes\", \"time_us\"])\n", + " .sort_values(\"size_bytes\")\n", + " )\n", + "else:\n", + " fc_rows = pd.DataFrame()\n", + "\n", + "if len(fc_rows) >= 2:\n", + " S_fc = fc_rows[\"size_bytes\"].to_numpy(dtype=float) * NODES # per-rank -> total S\n", + " t_meas = fc_rows[\"time_us\"].to_numpy(dtype=float) * 1e-6\n", + " # Bandwidth term only, ALPHA_S deliberately excluded: the fitted intercept a IS alpha.\n", + " t_model_nom = S_fc * (n - 1) / (n * n * bw_h100)\n", + " alpha_fit_s, slope_fit, r2_fit = linear_fit(t_model_nom, t_meas)\n", + " fc_fit = {\"intercept_s\": alpha_fit_s, \"slope\": slope_fit, \"r2\": r2_fit, \"n\": int(len(t_meas))}\n", + " bw_eff = bw_h100 / fc_fit[\"slope\"]\n", + " t_model_cal = alpha_fit_s + fc_fit[\"slope\"] * t_model_nom\n", + " print(f\"linear fit t_meas = a + b * t_model ({fc_fit['n']} FC alltoall points)\")\n", + " print(f\" a = {alpha_fit_s * 1e6:.2f} us b = {fc_fit['slope']:.4f} R^2 = {fc_fit['r2']:.4f}\")\n", + " print(f\" => alpha = {alpha_fit_s * 1e6:.2f} us, BW_eff = {bw_eff / 1e9:.1f} GB/s \"\n", + " f\"({100 * bw_eff / bw_h100:.1f}% of {NVLINK_H100_GBPS:g} GB/s nominal)\")\n", + " print(\" => t = alpha + S * (N-1) / (N^2 * BW_eff)\")\n", + " fc_fit_table = pd.DataFrame({\n", + " \"per_rank_bytes\": fc_rows[\"size_bytes\"].to_numpy(dtype=int),\n", + " \"collective_size_bytes\": S_fc.astype(int),\n", + " \"matmul_shape\": [shape_by_size.get(int(s), \"\") for s in S_fc],\n", + " \"measured_us\": t_meas * 1e6,\n", + " \"model_nominal_us\": t_model_nom * 1e6,\n", + " \"model_calibrated_us\": t_model_cal * 1e6,\n", + " \"measured_over_calibrated\": t_meas / t_model_cal,\n", + " })\n", + " display(fc_fit_table)\n", + "else:\n", + " print(f\"linear fit: fewer than 2 FC alltoall rows (found {len(fc_rows)}) -- run aws-gpu-profiler run \"\n", + " \"--workload nccl-tests --param collective=alltoall --param min_bytes=8192 --param max_bytes=1073741824 --data-dir correlation/data\")" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "93811891", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:44:50.464977Z", + "iopub.status.busy": "2026-09-17T16:44:50.464887Z", + "iopub.status.idle": "2026-09-17T16:44:50.954986Z", + "shell.execute_reply": "2026-09-17T16:44:50.953553Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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depg+/bt+PHjB/T19cXk8B/q6upwcHBgPgs6l1RUVJgFZwXUr18fR44cgY2NDbNBRNFp1EChoG/WrBk8PDwwY8YMODg44NixY5g4caLYPIH/4uXj44PevXujU6dOEut+69YtrF27Fp07dwaLVTj199u3b1LbTICKigoACNXD3t4eKioquHXrFqytrQEU/jC4f/8+xo8fDwC4c+cOPDw8EBgYyBz3/v17mcstC3r16oVp06Zh2bJlWLVqlUh6amoq02a5ubl4//69yCYlFArl5yX/+S1k7l4oJPzSbJpi8I+++M7WE/Ktis94StnDYbMwpbMxJu9P+Cl0XlEdUVznEUKQmJiIN2/eYNu2bcxyJIrovISEBMa36MtMSdSsWZPReZ6enmJ9atSooZDOo1AoFApFFkhOJtgn1yLz8UXGxlLTxAePQEx/6CpxZldlPufpYi6VSDtXHazqbwkTXWFBZaqrhFX9LdHOVUfCkRVPUFAQfvz4gb59++L+/ft4//49Lly4gMGDB4PH40FfXx+GhobYtm0b3r17hytXrmDixIlCeaxevRr79u3D69ev8fbtWxw6dAhmZmbQ09ODuro6mjRpgiVLluDVq1e4fv065s6dK7Ve2tramDBhAiZOnIjIyEi8f/8ejx49wrp165idZEeNGoXo6GgEBwfjzZs32Lt3LyIiIqTm3aFDB7EitiTU1NQwdepUTJkyBTt37sT79+9x9+5d/PXXXwCAvn37wszMDN27d8etW7cQExODI0eO4M6dOzKXYW1tjaioKMTGxjJTZ6TFJyoqCosWLcKDBw/w6dMnHDt2DMnJyahZsyaAwunI//77L968eYNv376hoKAAK1eulBgvcTg6OmLv3r149eoVoqKi0L9/f7lGMFpbW4PFYuH06dNITk5GZmYmNDU1MXr0aAQHB+P8+fN4+fIlhg8fjuzsbAwdOhRA4RqIDx48wIULF/D27VvMnj0b9+/fl7ncsqB69epYtWoV1qxZw+yM/PHjR9y6dQuBgYGYP38+43v37l1mtCOFQvm54edkImPXAqRvGM908rHUtaA1aC7spqzBrAG1YKwlLPCq4jOeUj60raWFlf1EdZ6JjhJW9qta14CsOm/r1q0SdV5JukGg85YvX87ovFmzZkmtl7a2NiZNmoQJEyaUqPPevXsnt86jUCgUCkUa+a+ikLawH9hF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C/vBLNTlMM+/7Pv1OoGdO3eKAIz+zZkzx9Dmk08+EVu2bCl6enqKffr0EX/++Wf1JuzEmIX9Yjb2g1nYD2ZhP5gFOQO+ju0Hs7AfzMJ+MAv7wSzU5SjPv0YURVGZLUMiIiIiIiIiIiJSC6/RR0RERERERERE5AS40UdEREREREREROQEuNFHRERERERERETkBLjRR0RERERERERE5AS40UdEREREREREROQEuNFHRERERERERETkBLjRR0RERERERERE5AS40UdEREREREREROQEuNFHRERERERERETkBLjRR0Q2ExUVhQ8//NDs9q+++ipiYmJM1u/atQsajQYFBQUWz41cy3/+8x+MGjVKsf5mzJiB9957T7H+iIiI7NXcuXMxYcIEi/oYOnQonnnmGcPXUteIrkCj0WD16tVqT8NIfn4+QkJCcOnSJQD2ux6vqqpCVFQUDh06pPZUiGyOG31Eduz+hVReXh7+9Kc/oWXLlvDy8kJYWBji4+Oxf/9+QxsulOp3/8LSkV26dAkajQbp6elmf09+fj6aN29utCC7u0i7/192dnat709OTkZUVBS8vb3Rt29fHDx4sMExi4qK8NJLL6FLly7w8fFB06ZN0bt3byxatAi3b982tBs6dGitsUNDQzF16lRcvnzZqM/Lly/Dx8cHJSUlZj/2uyoqKvDSSy/hlVdekfy9pvz973/HW2+9hcLCQsX6JCIiMofctY0zrYksVddzofYGVlZWFhISEqzWf2ZmJh5++GFERETA29sbzZs3x/jx43HmzJl6v++tt97C+PHjERUVpdhc5KxpG+Lp6YnnnnsOL7zwgmJ9EjkKbvQROZDJkyfj6NGj+Pbbb3H27FmsXbsWQ4cORX5+vtpTIwfx6KOPonv37ibrMzIykJWVZfgXEhJiqFu2bBkWLFiAV155BUeOHEF0dDTi4+ORm5trsr9bt26hX79++Prrr/Hcc8/hl19+wZEjR/DWW2/h6NGj+O9//1ur/WOPPYasrCzcuHEDa9aswdWrVzFz5kyjftesWYNhw4bB399f8nOQmpqKgIAADBw4UPL3mtK1a1e0adMGP/zwg2J9EhERkeMTRRE1NTWSvy8sLAxeXl5WmBFQXV2NkSNHorCwECtXrkRGRgaWLVuGbt261buxWVZWhv/85z949NFHrTIvpT3yyCPYt28ffvvtN7WnQmRT3OgjchAFBQXYu3cv/vGPf2DYsGGIjIxEnz59sHDhQowbN052v1FRUXjzzTcxe/Zs+Pv7IzIyEmvXrkVeXh7Gjx8Pf39/dO/e3ehj7ytWrECXLl3g5eWFqKgoo9MWc3NzkZiYCB8fH7Rq1QpLliyp8zH97ne/Q3BwMAICAjB8+HAcO3ZM9mPJz8/HQw89hGbNmsHX1xfdunXDjz/+aKifO3cudu/ejY8++sjwqbG7px2cPHkSCQkJ8Pf3R2hoKGbNmoWbN28avnfo0KF46qmn8Je//AVNmjRBWFgYXn31VaPH84c//AGhoaHw9vZG165dsX79epSWliIgIACpqam12q9evRp+fn4oLi6u8/Fs3rwZgwYNQuPGjdG0aVM8+OCDuHDhgqG+VatWAIAePXpAo9Fg6NCh9T4/n332GQoKCvDcc8+ZbBMSEoKwsDDDP632fz8m3n//fTz22GOYN28eOnfujMWLF8PX1xdfffWVyf7++te/4sqVKzh48CDmzZuH7t27IzIyEqNGjcKPP/6Ixx9/vFZ7X19fhIWFITw8HP369cMTTzyBI0eOGPW7Zs0aw+t+165d6NOnD/z8/NC4cWMMHDiwzk8B3rV06VIkJibWKqvrL/kTJkzA3LlzDV9/+umnaNeuHby9vREaGoopU6bUap+YmIilS5eaHJeIiEhp9a1tdu/ejT59+sDLywvh4eF48cUXDRtOpr5Pr9fj0UcfRatWreDj44MOHTrgo48+kjSnhtZjclRVVeGJJ55AeHg4vL29ERkZiXfeecdQb2oNZs58TD0Xw4YNAwAEBgZCo9EY1gSCIOCdd94xPEfR0dG11nh3Pwm4adMmxMbGwsvLC/v27ZP8mO49dffVV1+t88yLb775xqw53e+3337DhQsX8Omnn6Jfv36IjIzEwIED8eabb6Jfv34mv2/jxo3w8vKqs83+/fvRvXt3eHt7o1+/fjh58iQAmLUOrm9N++WXX6JTp07w9vZGx44d8emnn5r9HAYGBmLgwIFcn5HL4UYfkYPw9/eHv78/Vq9ejcrKSkX7/uCDDzBw4EAcPXoUY8eOxaxZszB79mzMnDkTR44cQZs2bTB79myIoggAOHz4MKZNm4YZM2bgxIkTePXVV/HSSy8ZFhvAnUXT1atXsXPnTqSmpuLTTz81+uTX1KlTkZubi02bNuHw4cPo2bMnRowYgVu3bsl6HBUVFYiNjcWGDRtw8uRJ/P73v8esWbMMp5d+9NFH6N+/v+FTY1lZWWjRogUKCgowfPhw9OjRA4cOHcLmzZuRk5ODadOm1er/22+/hZ+fH3755RcsWrQIr7/+OrZu3QrgzgIrISEB+/fvxw8//IBTp07h3XffhZubG/z8/DBjxgx8/fXXtfr7+uuvMWXKFDRq1KjOx1NaWooFCxbg0KFD2L59O7RaLSZOnAhBEADA8Li2bduGrKwsrFy50uRzc+rUKbz++uv47rvvam3e3S8mJgbh4eEYOXJkrVPCq6qqcPjwYcTFxRnKtFot4uLikJaWVmdfgiBg2bJlmDlzJiIiIupso9FoTM7l1q1bWL58Ofr27VurvKCgAPv27cO4ceNQU1ODCRMmYMiQITh+/DjS0tLw+9//vt5+9+3bh169epmsr8uhQ4fw1FNP4fXXX0dGRgY2b96MwYMH12rTp08fHDx4UPHjk4iIyBRTa5vr169jzJgx6N27N44dO4bPPvsM//nPf/Dmm2/W+32CIKB58+ZISUnBqVOn8PLLL+Ovf/0rli9fbvacGlqPyfHxxx9j7dq1WL58OTIyMrBkyRLDqaP1rcHMmY+p52LFihUA/ne2w90Nz3feeQffffcdFi9ejN9++w3PPvssZs6cid27d9ea84svvoh3330Xp0+frvNsivoe0/2ee+65Wmdc/POf/4Svr69hPWPunO4KDg6GVqtFamoq9Hq92Tns3bsXsbGxddY9//zzeO+99/Drr78iODgYiYmJqK6uNmsdbGpNu2TJErz88st46623cPr0abz99tt46aWX8O2335r9HPbp0wd79+41+zESOQWRiOzWnDlzxPHjxxu+Tk1NFQMDA0Vvb29xwIAB4sKFC8Vjx47V+p7IyEjxgw8+MHuMyMhIcebMmYavs7KyRADiSy+9ZChLS0sTAYhZWVmiKIriww8/LI4cObJWP88//7zYuXNnURRFMSMjQwQgHjx40FB/+vRpEYBhbnv37hUDAgLEioqKWv20adNG/Pe//y2Koii+8sorYnR0tMm579y5UwQg3r5922SbsWPHin/+858NXw8ZMkR8+umna7V54403xFGjRtUqu3r1qghAzMjIMHzfoEGDarXp3bu3+MILL4iiKIo//fSTqNVqDe3v98svv4hubm7ijRs3RFEUxZyc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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if fc_fit is not None:\n", + " BLUE, ORANGE, GRAY, INK = \"#2a78d6\", \"#eb6834\", \"#7a7975\", \"#52514e\"\n", + " fig, (ax_fit, ax_size) = plt.subplots(1, 2, figsize=(13, 5))\n", + "\n", + " # Left: measured vs. model, with the fitted line and the alpha = 0 nominal identity.\n", + " xs = np.logspace(np.log10(t_model_nom.min()), np.log10(t_model_nom.max()), 200)\n", + " ax_fit.loglog(t_model_nom * 1e6, t_meas * 1e6, \"o\", color=BLUE, ms=6,\n", + " label=\"measured (nccl-tests alltoall, FC)\")\n", + " ax_fit.loglog(xs * 1e6, xs * 1e6, \"--\", color=GRAY, lw=1.5,\n", + " label=\"y = x (nominal model, alpha = 0)\")\n", + " ax_fit.loglog(xs * 1e6, (alpha_fit_s + fc_fit[\"slope\"] * xs) * 1e6, \"-\", color=ORANGE, lw=2,\n", + " label=f\"fit: a = {alpha_fit_s * 1e6:.1f} us, b = {fc_fit['slope']:.2f}, \"\n", + " f\"R^2 = {fc_fit['r2']:.3f}\")\n", + " ax_fit.set_xlabel(f\"ISL model latency at {NVLINK_H100_GBPS:g} GB/s (us)\")\n", + " ax_fit.set_ylabel(\"measured latency (us)\")\n", + " ax_fit.set_title(\"Measured vs. ISL model (all-scatter, 8x H100 FC)\")\n", + " ax_fit.grid(True, which=\"both\", alpha=0.3)\n", + " ax_fit.legend()\n", + "\n", + " # Right: latency vs. total size, nominal and calibrated model through the measured points.\n", + " ax_size.loglog(S_fc, t_meas * 1e6, \"o\", color=BLUE, ms=6, label=\"measured\")\n", + " ax_size.loglog(S_fc, t_model_nom * 1e6, \"--\", color=GRAY, lw=1.5,\n", + " label=f\"model, nominal {NVLINK_H100_GBPS:g} GB/s, alpha = 0\")\n", + " ax_size.loglog(S_fc, t_model_cal * 1e6, \"-\", color=ORANGE, lw=2,\n", + " label=f\"model, calibrated ({bw_eff / 1e9:.0f} GB/s, alpha = {alpha_fit_s * 1e6:.1f} us)\")\n", + " square_label_by_size = {\n", + " M * K * dtype_bytes: f\"{M}x{K}\" for M, K in MATMUL_SHAPES if M == K and M >= 1024\n", + " }\n", + " # Label each size once (its first row in size order) even if several runs contributed\n", + " # the same size; the points themselves are still all drawn above.\n", + " seen_sizes = set()\n", + " labelled = []\n", + " for s, t in zip(S_fc, t_meas):\n", + " if int(s) in square_label_by_size and int(s) not in seen_sizes:\n", + " seen_sizes.add(int(s))\n", + " labelled.append((s, t))\n", + " for i, (s, t) in enumerate(labelled):\n", + " last = i == len(labelled) - 1\n", + " # Square shapes >= 1024 only, alternating above/below the point so labels crowding\n", + " # the latency floor stay legible; the largest size is right-aligned so it does not\n", + " # run past the axes edge.\n", + " ax_size.annotate(square_label_by_size[int(s)], (s, t * 1e6), textcoords=\"offset points\",\n", + " xytext=(-6, 6) if last else (6, 6 if i % 2 == 0 else -12),\n", + " ha=\"right\" if last else \"left\", fontsize=8, color=INK)\n", + " ax_size.set_xlabel(\"total all-scatter size S (bytes)\")\n", + " ax_size.set_ylabel(\"latency (us)\")\n", + " ax_size.set_title(\"Latency vs. matmul operand size\")\n", + " ax_size.grid(True, which=\"both\", alpha=0.3)\n", + " ax_size.legend()\n", + " plt.tight_layout()\n", + " plt.show()\n", + "else:\n", + " print(\"no FC alltoall data -- nothing to plot\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "accelforge", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/astrasim2_correlation/distributed_models_demo.ipynb b/notebooks/astrasim2_correlation/distributed_models_demo.ipynb new file mode 100644 index 00000000..e107ea4b --- /dev/null +++ b/notebooks/astrasim2_correlation/distributed_models_demo.ipynb @@ -0,0 +1,906 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c733530b", + "metadata": {}, + "source": [ + "# Distributed Transfer Models: Fully-Connected, Star, and XY Routing --- Demo & Review Guide\n", + "\n", + "This notebook demonstrates the distributed ISL transfer models in\n", + "`accelforge/model/_looptree/reuse/isl/distributed/distributed_buffers.py`:\n", + "`FullyConnectedMulticastModel`, `StarMulticastModel`, `XYRoutingMulticastModel`,\n", + "and the `EdgePressure` per-link load abstraction they share with the older\n", + "`HypercubeMulticastModel`. It is a companion to\n", + "`notebooks/astrasim2_correlation/correlation.ipynb` (same conventions: one-hot\n", + "GPU coordinates, `isl.Map.read_from_str`, `model.apply(0, Fill(...), Occupancy(...))`).\n", + "\n", + "## What's new\n", + "\n", + "- **`FullyConnectedMulticastModel`** --- 1 hop per fabric-crossing delivery,\n", + " regardless of distance (the \"flat full-mesh\" view of a fully-connected fabric).\n", + "- **`StarMulticastModel`** --- the *spokes* realization of the same fabric\n", + " (`src -> switch -> dst`); exposes per-spoke `EdgePressure` where\n", + " `FullyConnectedMulticastModel` sees only a flat crossing count.\n", + "- **`XYRoutingMulticastModel`** --- dimension-order routing on a 2-D mesh, with\n", + " a full per-directed-mesh-link `EdgePressure` decomposition.\n", + "- **`EdgePressure`** --- `{ edge -> #multicast-trees-crossing-it }`, with\n", + " `.total()`, `.bottleneck()`, and `.eval_edge(name, coords)`, threaded through\n", + " `TransferInfo.edge_pressure` (`accelforge/model/_looptree/reuse/isl/spatial.py`).\n", + "- The `fulfilled_fill` / `unfulfilled_fill` partition (`_covered_fills`) and the\n", + " generic node-tuple lookup (`_mesh_node_tuple`) that every model above now\n", + " shares, replacing ad hoc per-model logic.\n", + "\n", + "## The two commits under review\n", + "\n", + "The code this notebook exercises arrived across two commits on `rengz-correl`:\n", + "\n", + "- **`142722f5`** --- *\"LLM implemented code from pseudocode but it needs\n", + " verification\"*: introduces `EdgePressure`, `StarMulticastModel`, and the\n", + " directed-mesh-link decomposition inside\n", + " `XYRoutingMulticastModel._directed_mesh_links`.\n", + "- **`81be62a4`** --- *\"isl distribuffers refactor\"*: consolidates the\n", + " `_eval_const` / `_const_pwq` / `_covered_fills` / `_mesh_node_tuple` helpers,\n", + " fixes a `fulfilled_fill`/`unfulfilled_fill` bug (every fill used to be\n", + " reported fulfilled unconditionally, even when no source held its datum), and\n", + " threads `EdgePressure` through `TransferInfo.edge_pressure` so `hops` and the\n", + " per-link decomposition come from one `identify_mesh_casts` call instead of\n", + " two independently computed paths.\n", + "\n", + "`HypercubeMulticastModel`, `identify_mesh_casts`, and `calculate_extents_per_dim`\n", + "predate both commits (they are the pre-existing, already-reviewed baseline) and\n", + "are not exercised here for that reason.\n", + "\n", + "## How to use this notebook as a review guide\n", + "\n", + "Each numbered section states which functions it exercises and cites their\n", + "current `file:line` ranges, recomputed against this working tree:\n", + "`EdgePressure` and its scalar-extraction helpers live in `edge_pressure.py`,\n", + "`identify_mesh_casts` and its helpers in `mesh_casts.py`, and the\n", + "`MulticastModel` base class (the shared `__init__`/`apply` shape every model\n", + "below uses) with each model's own cost kernel in `distributed_buffers.py`.\n", + "The citations reflect current file locations and line numbers, not the\n", + "original commit diffs. Every number asserted in a code cell below (`56`, `64`,\n", + "`448`, ...) was independently re-verified against this exact code before\n", + "being written here.\n", + "Section 6 collects the section -> function -> file:line-range -> commit\n", + "mapping into one table so a reviewer can walk the diff systematically.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "e3d6abf5", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:22.330405Z", + "iopub.status.busy": "2026-07-06T22:33:22.330272Z", + "iopub.status.idle": "2026-07-06T22:33:23.645047Z", + "shell.execute_reply": "2026-07-06T22:33:23.644422Z" + } + }, + "outputs": [], + "source": [ + "import islpy as isl\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import (\n", + " FullyConnectedMulticastModel,\n", + " StarMulticastModel,\n", + " XYRoutingMulticastModel,\n", + ")\n", + "from accelforge.model._looptree.reuse.isl.distributed.edge_pressure import (\n", + " _eval_const,\n", + ")\n", + "from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import (\n", + " Fill,\n", + " Occupancy,\n", + " SpatialTag,\n", + ")\n", + "\n", + "CTX = isl.DEFAULT_CONTEXT\n" + ] + }, + { + "cell_type": "markdown", + "id": "031ba8c0", + "metadata": {}, + "source": [ + "## 2. Fully-connected vs. star: 8-GPU one-hot all-to-all\n", + "\n", + "GPU $i$ sits at one-hot coordinate $e_i$ of an 8-dimensional `noc` space (the\n", + "same encoding as `correlation.ipynb`). Two workloads distinguish the two models:\n", + "\n", + "- **all-to-all (unicast)**: `data[s, d]` is a unique chunk from GPU $s$ to GPU\n", + " $d$ --- every delivery has exactly one source and one destination.\n", + "- **broadcast**: GPU $g$ holds one private chunk `data[g]`, requested by every\n", + " other GPU --- a genuine multicast (one producer, $N-1$ consumers, fan-out at\n", + " the switch).\n", + "\n", + "`FullyConnectedMulticastModel` costs every fabric-crossing delivery at 1 hop\n", + "regardless of the payload pattern, so **both** workloads give\n", + "$N(N-1) = 56$ hops. `StarMulticastModel` is the *spokes* realization of the\n", + "same fabric --- a delivery routes `src -> switch -> dst` --- and its per-spoke\n", + "`EdgePressure` **is** pattern-sensitive: only the broadcast pattern exposes the\n", + "switch's fan-out (egress load $1$, not $N-1$), because the all-to-all pattern\n", + "has no shared payload to fan out in the first place.\n", + "\n", + "**Code exercised**: `MulticastModel.apply` (the shared `apply` every model\n", + "below now uses; `distributed_buffers.py:97-147`) together with\n", + "`FullyConnectedMulticastModel._transfer_cost`/`_cost_fully_connected`\n", + "(`distributed_buffers.py:265-284`, commit `81be62a4`); `StarMulticastModel`\n", + "(`distributed_buffers.py:523-599`, commit `142722f5`; its `hops`/\n", + "`edge_pressure` aggregation is now the shared `MulticastModel.apply` above,\n", + "fed by `StarMulticastModel._transfer_cost`, `distributed_buffers.py:546-547`);\n", + "`EdgePressure` (`edge_pressure.py:21-133`, commit `142722f5`).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "cd3dd43b", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:23.647609Z", + "iopub.status.busy": "2026-07-06T22:33:23.647337Z", + "iopub.status.idle": "2026-07-06T22:33:23.655758Z", + "shell.execute_reply": "2026-07-06T22:33:23.655106Z" + } + }, + "outputs": [], + "source": [ + "def onehot_constraints(prefix: str, n: int) -> str:\n", + " \"\"\"One-hot constraints over dims `{prefix}0..{prefix}{n-1}`. Reused from correlation.ipynb.\"\"\"\n", + " bounds = \" and \".join(f\"0 <= {prefix}{i} <= 1\" for i in range(n))\n", + " hot = \" + \".join(f\"{prefix}{i}\" for i in range(n)) + \" = 1\"\n", + " return f\"{bounds} and {hot}\"\n", + "\n", + "\n", + "def linear_id(prefix: str, n: int) -> str:\n", + " \"\"\"Affine recovery of the GPU id from a one-hot vector: id = sum i*g_i. Reused from correlation.ipynb.\"\"\"\n", + " return \" + \".join(f\"{i}*{prefix}{i}\" for i in range(1, n))\n", + "\n", + "\n", + "def onehot_dist_fn(n: int) -> isl.Map:\n", + " \"\"\"Unit-cost distance function on the one-hot `noc` space: 0 hops if same\n", + " GPU, 1 hop otherwise. Same shape as correlation.ipynb's `all_to_all_maps`.\n", + " \"\"\"\n", + " xd = \", \".join(f\"xd{i}\" for i in range(n))\n", + " xs = \", \".join(f\"xs{i}\" for i in range(n))\n", + " same = \" and \".join(f\"xd{i} = xs{i}\" for i in range(n))\n", + " diff = \" or \".join(f\"(xd{i} < xs{i}) or (xd{i} > xs{i})\" for i in range(n))\n", + " return isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ [noc[{xd}] -> noc[{xs}]] -> hops[0] : {same}; \"\n", + " f\" [noc[{xd}] -> noc[{xs}]] -> hops[1] : {diff} }}\",\n", + " )\n", + "\n", + "\n", + "def all_to_all_maps(n: int) -> tuple[isl.Map, isl.Map, isl.Map]:\n", + " \"\"\"Build (occupancy, fill, dist_fn) for the N-GPU unicast all-to-all:\n", + " data[s, d] is the unique chunk sent by GPU s to GPU d. Verbatim from\n", + " notebooks/astrasim2_correlation/correlation.ipynb.\n", + " \"\"\"\n", + " gs = \", \".join(f\"gs{i}\" for i in range(n))\n", + " gd = \", \".join(f\"gd{i}\" for i in range(n))\n", + " occ = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gs}] -> data[s, d] : {onehot_constraints('gs', n)} \"\n", + " f\"and s = {linear_id('gs', n)} and 0 <= d < {n} }}\",\n", + " )\n", + " fill = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gd}] -> data[s, d] : {onehot_constraints('gd', n)} \"\n", + " f\"and d = {linear_id('gd', n)} and 0 <= s < {n} }}\",\n", + " )\n", + " return occ, fill, onehot_dist_fn(n)\n", + "\n", + "\n", + "def broadcast_maps(n: int) -> tuple[isl.Map, isl.Map, isl.Map]:\n", + " \"\"\"Build (occupancy, fill, dist_fn) for the N-GPU one-hot *broadcast*\n", + " pattern: GPU g holds one private chunk data[g], requested by every other\n", + " GPU (one producer, N-1 consumers, fan-out at the switch). Same one-hot\n", + " node encoding as `all_to_all_maps`, different fill/occ.\n", + " \"\"\"\n", + " gs = \", \".join(f\"gs{i}\" for i in range(n))\n", + " gd = \", \".join(f\"gd{i}\" for i in range(n))\n", + " occ = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gs}] -> data[d] : {onehot_constraints('gs', n)} \"\n", + " f\"and d = {linear_id('gs', n)} }}\",\n", + " )\n", + " fill = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ noc[{gd}] -> data[d] : {onehot_constraints('gd', n)} \"\n", + " f\"and 0 <= d < {n} and d != {linear_id('gd', n)} }}\",\n", + " )\n", + " return occ, fill, onehot_dist_fn(n)\n", + "\n", + "\n", + "N = 8\n", + "tags = [SpatialTag(i, 0) for i in range(N)]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "99287f8f", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:23.658028Z", + "iopub.status.busy": "2026-07-06T22:33:23.657872Z", + "iopub.status.idle": "2026-07-06T22:33:24.595478Z", + "shell.execute_reply": "2026-07-06T22:33:24.594519Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "FullyConnectedMulticastModel (all-to-all unicast): 56 hops\n" + ] + } + ], + "source": [ + "# All-to-all (unicast) leg: reproduces correlation.ipynb's FullyConnectedMulticastModel\n", + "# result (56 hops = 8x7 fabric-crossing chunks) -- pattern-invariant, since FC only\n", + "# counts (dst, data) deliveries that cross the fabric, not whether a payload is shared.\n", + "occ_map, fill_map, dist_fn = all_to_all_maps(N)\n", + "fc_info = FullyConnectedMulticastModel(dist_fn).apply(\n", + " 0, Fill(tags, fill_map), Occupancy(tags, occ_map)\n", + ")\n", + "fc_hops = _eval_const(fc_info.hops)\n", + "assert fc_hops == N * (N - 1) == 56, fc_hops\n", + "print(f\"FullyConnectedMulticastModel (all-to-all unicast): {fc_hops} hops\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "da1b83a5", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:24.598198Z", + "iopub.status.busy": "2026-07-06T22:33:24.597829Z", + "iopub.status.idle": "2026-07-06T22:33:26.845318Z", + "shell.execute_reply": "2026-07-06T22:33:26.844213Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "StarMulticastModel (broadcast): 64 hops = 8 injections + 56 deliveries\n", + " spoke_in per node : 7 (every node receives N-1 = 7)\n", + " spoke_out per node: 1 (every node sources 1 -- fan-out happens at the switch)\n", + " bottleneck spoke : 7\n", + " invariant: sum(spoke_in) = 56 == FullyConnected crossings = 56\n" + ] + } + ], + "source": [ + "# Broadcast leg: each GPU's chunk is requested by every other GPU. This is what\n", + "# exposes StarMulticastModel's spoke asymmetry -- the switch fans a shared\n", + "# chunk out from a single egress -- which the unicast pattern above cannot show\n", + "# (there, every delivery is already a distinct chunk with no sharing to fan out).\n", + "def onehot_coords(g: int, n: int) -> list[int]:\n", + " \"\"\"One-hot coordinate vector for GPU `g` among `n` GPUs.\"\"\"\n", + " return [1 if i == g else 0 for i in range(n)]\n", + "\n", + "\n", + "occ_b, fill_b, dist_fn_b = broadcast_maps(N)\n", + "fill_bc = Fill(tags, fill_b)\n", + "occ_bc = Occupancy(tags, occ_b)\n", + "\n", + "fc_info_b = FullyConnectedMulticastModel(dist_fn_b).apply(0, fill_bc, occ_bc)\n", + "fc_hops_b = _eval_const(fc_info_b.hops)\n", + "assert fc_hops_b == 56, fc_hops_b\n", + "\n", + "star_info = StarMulticastModel(dist_fn_b).apply(0, fill_bc, occ_bc)\n", + "star_pressure = star_info.edge_pressure\n", + "star_hops = _eval_const(star_info.hops)\n", + "\n", + "spoke_in = [star_pressure.eval_edge(\"spoke_in\", onehot_coords(g, N)) for g in range(N)]\n", + "spoke_out = [star_pressure.eval_edge(\"spoke_out\", onehot_coords(g, N)) for g in range(N)]\n", + "\n", + "assert all(v == N - 1 for v in spoke_in), spoke_in\n", + "assert all(v == 1 for v in spoke_out), spoke_out\n", + "assert star_pressure.bottleneck() == N - 1 == 7\n", + "assert star_hops == N + N * (N - 1) == 64\n", + "\n", + "total_ingress = sum(spoke_in)\n", + "assert total_ingress == fc_hops_b == 56, (total_ingress, fc_hops_b)\n", + "\n", + "print(f\"StarMulticastModel (broadcast): {star_hops} hops = {N} injections + {N * (N - 1)} deliveries\")\n", + "print(f\" spoke_in per node : {spoke_in[0]} (every node receives N-1 = {N - 1})\")\n", + "print(f\" spoke_out per node: {spoke_out[0]} (every node sources 1 -- fan-out happens at the switch)\")\n", + "print(f\" bottleneck spoke : {star_pressure.bottleneck()}\")\n", + "print(f\" invariant: sum(spoke_in) = {total_ingress} == FullyConnected crossings = {fc_hops_b}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "4524391d", + "metadata": {}, + "source": [ + "## 3. XY (dimension-order) routing on a 2-D mesh\n", + "\n", + "XY routing routes every packet along $x$ first, then $y$, so a multicast from\n", + "one source is a rigid tree: an X segment along the source row out to every\n", + "destination column, then an independent Y segment down each column from the\n", + "source row. Two geometries from\n", + "`tests/isl/distributed/xy_routing/test_cases.yaml` (already\n", + "oracle-verified there; re-verified here):\n", + "\n", + "- **Case B** --- source $(1,0)$ casting to $(0,2)$ and $(2,2)$: a single tree,\n", + " $6$ hops, every used link carries load $1$ (no sharing).\n", + "- **Case F** --- an $8 \\times 8$ *column flood*: datum $(d_0, d_1)$ lives at\n", + " node $(d_0, d_1)$ and is requested by every node in column $x = d_0$. Each\n", + " column's vertical links are shared by up to 7 overlapping trees: $448$ total\n", + " hops, bottleneck $7$, `yedge_u[0,6] = 7`, `yedge_d[0,1] = 6`.\n", + "\n", + "**Code exercised**: `MulticastModel.apply` (shared `apply`;\n", + "`distributed_buffers.py:97-147`) together with\n", + "`XYRoutingMulticastModel._transfer_cost`\n", + "(`distributed_buffers.py:414-415`, commit `81be62a4`); `_directed_mesh_links`\n", + "(`distributed_buffers.py:417-515`, commit `142722f5`, touched again in\n", + "`81be62a4`); `EdgePressure.bottleneck` / `EdgePressure.eval_edge`\n", + "(`edge_pressure.py:89-133`, commit `142722f5`)." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d6c4b869", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:26.847779Z", + "iopub.status.busy": "2026-07-06T22:33:26.847607Z", + "iopub.status.idle": "2026-07-06T22:33:26.864876Z", + "shell.execute_reply": "2026-07-06T22:33:26.864027Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Case B: hops = 6, every used edge load 1 (single tree, no sharing)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
edgeload
0xedge_r[1,0]1
1xedge_l[0,0]1
2yedge_u[0,0]1
3yedge_u[0,1]1
4yedge_u[2,0]1
5yedge_u[2,1]1
\n", + "
" + ], + "text/plain": [ + " edge load\n", + "0 xedge_r[1,0] 1\n", + "1 xedge_l[0,0] 1\n", + "2 yedge_u[0,0] 1\n", + "3 yedge_u[0,1] 1\n", + "4 yedge_u[2,0] 1\n", + "5 yedge_u[2,1] 1" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "manhattan_2d = isl.Map.read_from_str(CTX, \"\"\"\n", + "{\n", + " [noc[xd, yd] -> noc[xs, ys]] -> hops[(xd - xs) + (yd - ys)] :\n", + " xd >= xs and yd >= ys;\n", + " [noc[xd, yd] -> noc[xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] :\n", + " xd < xs and yd < ys;\n", + " [noc[xd, yd] -> noc[xs, ys]] -> hops[-(xd - xs) + (yd - ys)] :\n", + " xd < xs and yd >= ys;\n", + " [noc[xd, yd] -> noc[xs, ys]] -> hops[(xd - xs) + -(yd - ys)] :\n", + " xd >= xs and yd < ys\n", + "}\n", + "\"\"\")\n", + "xy_tags = [SpatialTag(0, 0), SpatialTag(1, 0)]\n", + "\n", + "# Case B: source (1,0) casting to (0,2) and (2,2).\n", + "occ_case_b = isl.Map.read_from_str(CTX, \"{ noc[x, y] -> data[c] : c = 0 and x = 1 and y = 0 }\")\n", + "fill_case_b = isl.Map.read_from_str(\n", + " CTX, \"{ noc[x, y] -> data[c] : c = 0 and ((x = 0 and y = 2) or (x = 2 and y = 2)) }\"\n", + ")\n", + "info_b = XYRoutingMulticastModel(manhattan_2d).apply(\n", + " 0, Fill(xy_tags, fill_case_b), Occupancy(xy_tags, occ_case_b)\n", + ")\n", + "pressure_b = info_b.edge_pressure\n", + "hops_b = _eval_const(info_b.hops)\n", + "assert hops_b == 6, hops_b\n", + "\n", + "# The 6 links this single tree crosses: X segment (row 0, split at source\n", + "# column xs=1) + Y segment down column 0 and column 2 (both split at ys=0,\n", + "# both fully upward since dst row 2 > source row 0).\n", + "edges_b = pd.DataFrame(\n", + " [\n", + " {\"edge\": \"xedge_r[1,0]\", \"load\": pressure_b.eval_edge(\"xedge_r\", [1, 0])},\n", + " {\"edge\": \"xedge_l[0,0]\", \"load\": pressure_b.eval_edge(\"xedge_l\", [0, 0])},\n", + " {\"edge\": \"yedge_u[0,0]\", \"load\": pressure_b.eval_edge(\"yedge_u\", [0, 0])},\n", + " {\"edge\": \"yedge_u[0,1]\", \"load\": pressure_b.eval_edge(\"yedge_u\", [0, 1])},\n", + " {\"edge\": \"yedge_u[2,0]\", \"load\": pressure_b.eval_edge(\"yedge_u\", [2, 0])},\n", + " {\"edge\": \"yedge_u[2,1]\", \"load\": pressure_b.eval_edge(\"yedge_u\", [2, 1])},\n", + " ]\n", + ")\n", + "assert (edges_b[\"load\"] == 1).all(), edges_b\n", + "assert pressure_b.bottleneck() == 1\n", + "print(f\"Case B: hops = {hops_b}, every used edge load 1 (single tree, no sharing)\")\n", + "edges_b\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8a0aa2e7", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:26.867413Z", + "iopub.status.busy": "2026-07-06T22:33:26.867246Z", + "iopub.status.idle": "2026-07-06T22:33:26.884336Z", + "shell.execute_reply": "2026-07-06T22:33:26.883695Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Case F: hops = 448, bottleneck = 7\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
tyedge_u[0,t]yedge_d[0,t]
0017
1126
2235
3344
4453
5562
6671
\n", + "
" + ], + "text/plain": [ + " t yedge_u[0,t] yedge_d[0,t]\n", + "0 0 1 7\n", + "1 1 2 6\n", + "2 2 3 5\n", + "3 3 4 4\n", + "4 4 5 3\n", + "5 5 6 2\n", + "6 6 7 1" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Case F: 8x8 mesh, datum (d0,d1) held at node (d0,d1), requested by every\n", + "# node in column x=d0 -- a column flood.\n", + "occ_case_f = isl.Map.read_from_str(\n", + " CTX,\n", + " \"{ noc[xs, ys] -> data[d0, d1] : d0 = xs and d1 = ys and 0 <= xs < 8 and 0 <= ys < 8 }\",\n", + ")\n", + "fill_case_f = isl.Map.read_from_str(\n", + " CTX,\n", + " \"{ noc[xd, yd] -> data[d0, d1] : d0 = xd and 0 <= d1 < 8 and 0 <= xd < 8 and 0 <= yd < 8 }\",\n", + ")\n", + "info_f = XYRoutingMulticastModel(manhattan_2d).apply(\n", + " 0, Fill(xy_tags, fill_case_f), Occupancy(xy_tags, occ_case_f)\n", + ")\n", + "pressure_f = info_f.edge_pressure\n", + "hops_f = _eval_const(info_f.hops)\n", + "assert hops_f == 448, hops_f\n", + "assert pressure_f.bottleneck() == 7\n", + "assert pressure_f.eval_edge(\"yedge_u\", [0, 6]) == 7\n", + "assert pressure_f.eval_edge(\"yedge_d\", [0, 1]) == 6\n", + "\n", + "# Column 0's vertical links: yedge_u[0,t] carries data with d1 <= t (load t+1);\n", + "# yedge_d[0,t] carries data with d1 > t (load 7-t).\n", + "column0 = pd.DataFrame(\n", + " [\n", + " {\n", + " \"t\": t,\n", + " \"yedge_u[0,t]\": pressure_f.eval_edge(\"yedge_u\", [0, t]),\n", + " \"yedge_d[0,t]\": pressure_f.eval_edge(\"yedge_d\", [0, t]),\n", + " }\n", + " for t in range(7)\n", + " ]\n", + ")\n", + "print(f\"Case F: hops = {hops_f}, bottleneck = {pressure_f.bottleneck()}\")\n", + "column0\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "4b1bc6a2", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:26.886357Z", + "iopub.status.busy": "2026-07-06T22:33:26.886187Z", + "iopub.status.idle": "2026-07-06T22:33:26.992550Z", + "shell.execute_reply": "2026-07-06T22:33:26.991894Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(6, 4))\n", + "width = 0.38\n", + "x = column0[\"t\"]\n", + "ax.bar(x - width / 2, column0[\"yedge_u[0,t]\"], width, label=\"yedge_u[0,t] (upward)\", color=\"tab:blue\")\n", + "ax.bar(x + width / 2, column0[\"yedge_d[0,t]\"], width, label=\"yedge_d[0,t] (downward)\", color=\"tab:orange\")\n", + "ax.set_xlabel(\"row index t\")\n", + "ax.set_ylabel(\"load (multicast trees crossing the link)\")\n", + "ax.set_title(\"Case F: per-edge load, column 0 vertical links (8x8 flood)\")\n", + "ax.set_xticks(list(x))\n", + "ax.grid(True, axis=\"y\", alpha=0.3)\n", + "ax.legend()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "9a7106d7", + "metadata": {}, + "source": [ + "## 4. Fulfilled vs. unfulfilled fills: the `_covered_fills` partition\n", + "\n", + "Node 0 holds only `data[0]`; node 1 requests both `data[0]` and `data[1]`.\n", + "`data[1]` has no source anywhere, so `identify_mesh_casts` never emits an\n", + "entry for it -- `_covered_fills` reshapes the matched multicast networks back\n", + "into a `{ dst -> data }` map so `apply` can split `fills` into\n", + "`fulfilled_fill` / `unfulfilled_fill` by `intersect` / `subtract`, and `hops`\n", + "counts only the deliverable fill (`data[0]`), not the undeliverable one.\n", + "Before `81be62a4` this partition did not exist: every fill was reported\n", + "`fulfilled_fill` unconditionally, with `unfulfilled_fill` always empty\n", + "(`fills.map_.subtract(fills.map_)`).\n", + "\n", + "**Code exercised**: `_covered_fills`\n", + "(`mesh_casts.py:114-137`, commit `81be62a4`); the partition\n", + "usage itself is the shared `MulticastModel.apply`\n", + "(`distributed_buffers.py:97-147`, commit `81be62a4`).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "2527b397", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:26.994366Z", + "iopub.status.busy": "2026-07-06T22:33:26.994211Z", + "iopub.status.idle": "2026-07-06T22:33:26.999684Z", + "shell.execute_reply": "2026-07-06T22:33:26.999149Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fulfilled_fill.map_ : { noc[g = 1] -> data[d = 0] }\n", + "unfulfilled_fill.map_: { noc[g = 1] -> data[d = 1] }\n", + "hops : 1\n", + "\n", + "fulfilled_fill and unfulfilled_fill partition fills exactly;\n", + "hops (1) counts only the deliverable data[0], not the undeliverable data[1].\n" + ] + } + ], + "source": [ + "partition_tags = [SpatialTag(0, 0)]\n", + "occ_p = isl.Map.read_from_str(CTX, \"{ noc[g] -> data[d] : g = 0 and d = 0 }\")\n", + "fill_p = isl.Map.read_from_str(CTX, \"{ noc[g] -> data[d] : g = 1 and (d = 0 or d = 1) }\")\n", + "dist_fn_1d = isl.Map.read_from_str(\n", + " CTX,\n", + " \"{ [noc[gd] -> noc[gs]] -> hops[gd - gs] : gd >= gs;\"\n", + " \" [noc[gd] -> noc[gs]] -> hops[gs - gd] : gd < gs }\",\n", + ")\n", + "info_p = FullyConnectedMulticastModel(dist_fn_1d).apply(\n", + " 0, Fill(partition_tags, fill_p), Occupancy(partition_tags, occ_p)\n", + ")\n", + "\n", + "print(\"fulfilled_fill.map_ :\", info_p.fulfilled_fill.map_)\n", + "print(\"unfulfilled_fill.map_:\", info_p.unfulfilled_fill.map_)\n", + "print(\"hops :\", _eval_const(info_p.hops))\n", + "\n", + "fulfilled = info_p.fulfilled_fill.map_\n", + "unfulfilled = info_p.unfulfilled_fill.map_\n", + "assert fulfilled.intersect(unfulfilled).is_empty(), \"fulfilled/unfulfilled overlap\"\n", + "assert fulfilled.union(unfulfilled).is_equal(fill_p), \"fulfilled + unfulfilled != fills\"\n", + "assert _eval_const(info_p.hops) == 1, \"hops must count only the deliverable fill\"\n", + "print()\n", + "print(\"fulfilled_fill and unfulfilled_fill partition fills exactly;\")\n", + "print(\"hops (1) counts only the deliverable data[0], not the undeliverable data[1].\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "36a00572", + "metadata": {}, + "source": [ + "## 5. Tuple-name genericity: `_mesh_node_tuple`\n", + "\n", + "`_directed_mesh_links` and `_spoke_loads` used to hardcode the node tuple name\n", + "`'noc'` into every ISL map string they built. `_mesh_node_tuple` instead reads\n", + "the name (and dimensionality) off the caller's maps, so any spacetime tuple\n", + "name works. Below, the identical Case B geometry from Section 3 is run twice\n", + "--- once with the node tuple named `noc[x, y]`, once `pe[x, y]` --- and gives\n", + "identical hops and bottleneck.\n", + "\n", + "**Code exercised**: `_mesh_node_tuple`\n", + "(`mesh_casts.py:140-164`, commit `81be62a4`); its caller\n", + "`XYRoutingMulticastModel._directed_mesh_links`\n", + "(`distributed_buffers.py:417-515`, commit `142722f5`, touched again in\n", + "`81be62a4`).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "f621fc81", + "metadata": { + "execution": { + "iopub.execute_input": "2026-07-06T22:33:27.001244Z", + "iopub.status.busy": "2026-07-06T22:33:27.001102Z", + "iopub.status.idle": "2026-07-06T22:33:27.014016Z", + "shell.execute_reply": "2026-07-06T22:33:27.013407Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "noc[x, y]: hops = 6, bottleneck = 1\n", + "pe[x, y]: hops = 6, bottleneck = 1\n", + "\n", + "Identical numbers under both tuple names -- _mesh_node_tuple reads the name/dims generically.\n" + ] + } + ], + "source": [ + "def xy_case_b(name: str) -> tuple[isl.Map, isl.Map, isl.Map]:\n", + " \"\"\"Case B geometry (source (1,0) -> (0,2),(2,2)) under an arbitrary node\n", + " tuple `name`, to exercise `_mesh_node_tuple`'s generic name/dims lookup.\n", + " \"\"\"\n", + " occ = isl.Map.read_from_str(\n", + " CTX, f\"{{ {name}[x, y] -> data[c] : c = 0 and x = 1 and y = 0 }}\"\n", + " )\n", + " fill = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ {name}[x, y] -> data[c] : c = 0 and \"\n", + " f\"((x = 0 and y = 2) or (x = 2 and y = 2)) }}\",\n", + " )\n", + " dist_fn = isl.Map.read_from_str(\n", + " CTX,\n", + " f\"{{ [{name}[xd, yd] -> {name}[xs, ys]] -> hops[(xd - xs) + (yd - ys)] :\"\n", + " f\" xd >= xs and yd >= ys;\"\n", + " f\" [{name}[xd, yd] -> {name}[xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] :\"\n", + " f\" xd < xs and yd < ys;\"\n", + " f\" [{name}[xd, yd] -> {name}[xs, ys]] -> hops[-(xd - xs) + (yd - ys)] :\"\n", + " f\" xd < xs and yd >= ys;\"\n", + " f\" [{name}[xd, yd] -> {name}[xs, ys]] -> hops[(xd - xs) + -(yd - ys)] :\"\n", + " f\" xd >= xs and yd < ys }}\",\n", + " )\n", + " return occ, fill, dist_fn\n", + "\n", + "\n", + "results = {}\n", + "for name in (\"noc\", \"pe\"):\n", + " occ_n, fill_n, dist_fn_n = xy_case_b(name)\n", + " info_n = XYRoutingMulticastModel(dist_fn_n).apply(\n", + " 0, Fill(xy_tags, fill_n), Occupancy(xy_tags, occ_n)\n", + " )\n", + " results[name] = (_eval_const(info_n.hops), info_n.edge_pressure.bottleneck())\n", + " print(f\"{name}[x, y]: hops = {results[name][0]}, bottleneck = {results[name][1]}\")\n", + "\n", + "assert results[\"noc\"] == results[\"pe\"] == (6, 1), results\n", + "print()\n", + "print(\"Identical numbers under both tuple names -- _mesh_node_tuple reads the name/dims generically.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "270244d3", + "metadata": {}, + "source": [ + "## 6. Review checklist\n", + "\n", + "Which lines are new (and need a reviewer's attention) vs. which lines predate\n", + "this work, mapped by demo section. `HypercubeMulticastModel`,\n", + "`identify_mesh_casts`, and `calculate_extents_per_dim` are the pre-existing\n", + "baseline and are intentionally absent from this table (and from this notebook).\n", + "\n", + "| Section | Function(s) exercised | File | Lines | Commit |\n", + "|---|---|---|---|---|\n", + "| 2. FC vs. star | `EdgePressure` (class, `total`, `bottleneck`, `eval_edge`) | `edge_pressure.py` | 21-133 | `142722f5` |\n", + "| 2. FC vs. star | `MulticastModel.apply` (shared `apply`, all four models) | `distributed_buffers.py` | 97-147 | `81be62a4` |\n", + "| 2. FC vs. star | `FullyConnectedMulticastModel._transfer_cost` / `_cost_fully_connected` | `distributed_buffers.py` | 265-284 | `81be62a4` |\n", + "| 2. FC vs. star | `StarMulticastModel` (class, `_spoke_loads`) | `distributed_buffers.py` | 523-599 | `142722f5` |\n", + "| 2. FC vs. star | `StarMulticastModel._transfer_cost` (hops/edge_pressure aggregation, feeds the shared `apply`) | `distributed_buffers.py` | 546-547 | `81be62a4` |\n", + "| 2. FC vs. star | `TransferInfo.edge_pressure` field | `spatial.py` | 66-72 | `81be62a4` |\n", + "| 3. XY routing | `MulticastModel.apply` (shared `apply`) | `distributed_buffers.py` | 97-147 | `81be62a4` |\n", + "| 3. XY routing | `XYRoutingMulticastModel._transfer_cost` | `distributed_buffers.py` | 414-415 | `81be62a4` |\n", + "| 3. XY routing | `XYRoutingMulticastModel._directed_mesh_links` | `distributed_buffers.py` | 417-515 | `142722f5` (+`81be62a4`) |\n", + "| 3. XY routing | `EdgePressure.bottleneck` / `EdgePressure.eval_edge` | `edge_pressure.py` | 89-133 | `142722f5` |\n", + "| 4. Partition | `_covered_fills` | `mesh_casts.py` | 114-137 | `81be62a4` |\n", + "| 4. Partition | `MulticastModel.apply` (partition usage, shared) | `distributed_buffers.py` | 97-147 | `81be62a4` |\n", + "| 5. Tuple genericity | `_mesh_node_tuple` | `mesh_casts.py` | 140-164 | `81be62a4` |\n", + "| 5. Tuple genericity | `XYRoutingMulticastModel._directed_mesh_links` (caller) | `distributed_buffers.py` | 417-515 | `142722f5` (+`81be62a4`) |\n", + "| (all sections) | `_eval_const`, `_const_pwq` (shared scalar-extraction helpers) | `edge_pressure.py` | 159-201 | `81be62a4` |\n", + "| 2, 3 | `_edge_pressure_from_links` | `edge_pressure.py` | 230-251 | `142722f5` |\n", + "\n", + "Notes on mixed attribution: the XY and star models' `hops`/`edge_pressure`\n", + "derivation was refactored to a single `identify_mesh_casts` call in\n", + "`81be62a4` (rows above cite `81be62a4` for that reason); the shared\n", + "derivation lives in `MulticastModel.apply` (`distributed_buffers.py:97-147`),\n", + "with each model contributing only its `_transfer_cost` cost-kernel hook and\n", + "cost-specific helper. `FullyConnectedMulticastModel`'s cost kernel\n", + "(`_cost_fully_connected`) is unchanged since `de426ae0` and predates the\n", + "reviewed range; only its fulfilled/unfulfilled partition usage (inside the\n", + "shared `MulticastModel.apply`) is new in `81be62a4`.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "accelforge", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/not_working/distribuffers/__init__.py b/notebooks/astrasim2_correlation/mapping/all_reduce.binding.yaml similarity index 100% rename from tests/not_working/distribuffers/__init__.py rename to notebooks/astrasim2_correlation/mapping/all_reduce.binding.yaml diff --git a/notebooks/astrasim2_correlation/mapping/all_reduce.mapping.yaml b/notebooks/astrasim2_correlation/mapping/all_reduce.mapping.yaml new file mode 100644 index 00000000..5be5aae6 --- /dev/null +++ b/notebooks/astrasim2_correlation/mapping/all_reduce.mapping.yaml @@ -0,0 +1,34 @@ +mapping: + nodes: + - !Storage + tensors: [I, S] + component: Network + - !Spatial + rank_variable: nodes + # bound is nodes + tile_shape: {{ nodes }} + - !Storage + tensors: [S, G] + component: NV100 + - !Sequential + nodes: + - !Nested + nodes: + - !Temporal + rank_variable: vec_len + # Bound is vec_len. + tile_shape: {{ vec_len }} + component: MAC + - !Compute + einsum: scatter + component: MAC + - !Gather + nodes: + - !Temporal + rank_variable: vec_len + # Bound is vec_len. + tile_shape: {{ vec_len }} + component: MAC + - !Compute + einsum: all_gather + component: MAC diff --git a/notebooks/astrasim2_correlation/mapping/all_reduce.workload.yaml b/notebooks/astrasim2_correlation/mapping/all_reduce.workload.yaml new file mode 100644 index 00000000..d00907d5 --- /dev/null +++ b/notebooks/astrasim2_correlation/mapping/all_reduce.workload.yaml @@ -0,0 +1,15 @@ +workload: + iteration_space_shape: + vec_len: 0 <= vec_len < {{ collective_size / (data_width * nodes) }} + nodes: 0 <= nodes < {{ nodes }} + einsums: + - name: scatter + tensor_accesses: + - {name: I, projection: [ vec_len, nodes ]} + - {name: W_scatter, projection: [ vec_len, nodes ]} + - {name: S, projection: [ nodes ], output: True} + - name: all_gather + tensor_accesses: + - {name: S, projection: [nodes]} + - {name: W_gather, projection: [vec_len. nodes]} + - {name: G, projection: [vec_len, nodes]} diff --git a/notebooks/astrasim2_correlation/mapping/nvidiav100.arch.yaml b/notebooks/astrasim2_correlation/mapping/nvidiav100.arch.yaml new file mode 100644 index 00000000..c5894704 --- /dev/null +++ b/notebooks/astrasim2_correlation/mapping/nvidiav100.arch.yaml @@ -0,0 +1,44 @@ +# Based on examples/arches/nvdla.yaml +arch: + nodes: + - !Memory + name: MainMemory + size: inf + leak_power: 0 + actions: + # Energy is upper end of the range from the TPU paper. The lower end came from + # their reference, and they said it left out some things. Latency is 38.4 GB/s. + # DDR5-4800. Chip runs at at 1GHz, so divide to get per-cycle bandwidth. + # https://www.jedec.org/news/pressreleases/jedec-updates-standard-low-power-memory-devices-lpddr5 + - {name: read, energy: 7.03e-12, latency: 1 / (8 * 38.4e9)} + - {name: write, energy: 7.03e-12, latency: 1 / (8 * 38.4e9)} + tensors: {keep: ~Intermediates, may_keep: All} + + - !Memory + name: GlobalBuffer + size: 1024*64*8 # 64 kB + total_latency: max(read_latency, write_latency) # Separate ports + leak_power: 0 + actions: + # 512 GB/s read, 128 GB/s write + - {name: read, energy: 0.249e-12, latency: 1 / 512e9 / 8} + - {name: write, energy: 0.293e-12, latency: 1 / 128e9 / 8} + tensors: {keep: All} + + - !Container + name: ProcessingElement + spatial: + - {name: reuse_input, fanout: 32, may_reuse: input, reuse: input, min_usage: 1} + - {name: reuse_output, fanout: 192, may_reuse: output, reuse: output, min_usage: 1} + + - !Memory + name: Register + size: weight.bits_per_value if weight else 1 + component_class: Dummy + tensors: {keep: weight} + + - !Compute + name: MAC + leak_power: 0 + actions: + - {name: compute, energy: 0.084e-12, latency: 1 / 1e9} diff --git a/notebooks/astrasim2_correlation/mapping/v100_torus.arch.yaml b/notebooks/astrasim2_correlation/mapping/v100_torus.arch.yaml new file mode 100644 index 00000000..96d60735 --- /dev/null +++ b/notebooks/astrasim2_correlation/mapping/v100_torus.arch.yaml @@ -0,0 +1,32 @@ +# Based on examples/arches/nvdla.yaml +arch: + nodes: + - !Memory + name: Network + size: inf + leak_power: 0 + actions: + # TODO: Get the network energies for NVLink. + # 150 GB/s NVLink transfer speeds. + - {name: read, energy: 0, latency: 1 / (150e9 * 8)} + - {name: write, energy: 0, latency: 1 / (150e9 * 8)} + tensors: {keep: All, may_keep: All} + + - !Memory + name: NV100 + size: 16*1024*1024*8 # 16 GB + total_latency: max(read_latency, write_latency) # Separate ports + leak_power: 0 + actions: + # Prima facie network analysis assuming NV100 mem hierarchy characteristics + # are dominated by the NVLink connection. + - {name: read, energy: 0, latency: 0} + - {name: write, energy: 0, latency: 0} + tensors: {keep: All} + + - !Compute + name: MAC + leak_power: 0 + actions: + # Prima facie assume compute is dominated by NVLink data mvmt. + - {name: compute, energy: 0, latency: 0} diff --git a/notebooks/astrasim2_correlation/nvlink_probe.ipynb b/notebooks/astrasim2_correlation/nvlink_probe.ipynb new file mode 100644 index 00000000..93ff5038 --- /dev/null +++ b/notebooks/astrasim2_correlation/nvlink_probe.ipynb @@ -0,0 +1,1888 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "8f4e2ea6", + "metadata": {}, + "source": [ + "# NVLink / NVSwitch fabric characterisation (8x H100, p5.48xlarge)\n", + "\n", + "Analysis of the `nvlink_probe` workload of `aws-gpu-profiler` (checked out as the `correlation/` submodule),\n", + "run `nvlink-20260917-d`. The harness is described in `correlation/aws_gpu_profiler/workloads/nvlink_probe/DESIGN.md`;\n", + "this notebook answers the five questions it was built for:\n", + "\n", + "1. **Minimum packet size** on NVLink, and the bandwidth/latency knee.\n", + "2. **Switch (\"router\") capacity**: can every GPU saturate all of its inbound links at once?\n", + "3. **In-network reduction**: is there network compute, and what does an all-reduce cost in time, link,\n", + " switch and HBM utilisation?\n", + "4. **Do SMs have to drive communication?** Copy engines vs SM stores/loads vs TMA, the compute slowdown each\n", + " causes, and whether HBM can feed the switch without the owner's SMs.\n", + "5. **Kernel startup overhead.**\n", + "\n", + "Data: `correlation/data/nvlink-20260917-d/nvlink_probe/results.csv` (falling back to the profiler checkout's own\n", + "`data/` tree below), produced from the profiler checkout by\n", + "\n", + "```\n", + "aws-gpu-profiler run --yes --workload nvlink-probe --region ap-northeast-1 \\\n", + " --purchasing spot-then-ondemand --dead-man-minutes 180 --data-dir data --run-id nvlink-20260917-d\n", + "```\n", + "\n", + "on a p5.48xlarge spot instance in Tokyo (us-east-1, us-east-2 and us-west-2 had no p5 capacity that day).\n", + "The sweep was re-run on the same node after three harness fixes found live on it (all in the `nvlink-probe`\n", + "branch): `CUDA_MODULE_LOADING=EAGER` (lazy module loading needs an idle device and deadlocked against the\n", + "resident relay kernels of the start barrier), the NCCL probe forcing the pre-released barrier (NCCL's launch\n", + "path has the same requirement), and `--min-time-s` becoming a wall-clock bound so small sizes do not spend\n", + "minutes on launch overhead.\n", + "\n", + "Conventions: GB/s = 1e9 bytes/s; NVLink 4 peak = 18 links x 25 GB/s = 450 GB/s per direction per GPU;\n", + "`link_util` and `fabric_util` are measured wire bytes (NVML NVLink counters) over the timed window divided by\n", + "that peak (per GPU, and per node = 8 x 450 GB/s)." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "16f61e15", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:57.197246Z", + "iopub.status.busy": "2026-09-17T16:43:57.197165Z", + "iopub.status.idle": "2026-09-17T16:43:57.519219Z", + "shell.execute_reply": "2026-09-17T16:43:57.517823Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "correlation/data/nvlink-20260917-d/nvlink_probe/results.csv: 1694 rows; probes: {'reduce': 648, 'nccl': 468, 'info': 208, 'fabric': 198, 'ncu': 69, 'smrole': 50, 'packet': 42, 'launch': 11}\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
namesmsnvlinkslink_peak_GBpshbm_peak_GBpsmulticastdrivercuda_rt
0NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
1NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
2NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
3NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
4NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
5NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
6NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
7NVIDIA_H100_80GB_HBM3132184503352.321595.91.0713020
\n", + "
" + ], + "text/plain": [ + " name sms nvlinks link_peak_GBps hbm_peak_GBps multicast driver cuda_rt\n", + "0 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "1 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "2 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "3 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "4 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "5 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "6 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020\n", + "7 NVIDIA_H100_80GB_HBM3 132 18 450 3352.32 1 595.91.07 13020" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NVLink endpoints: {'switch': 144} | active links: 144 | P2P access on all ordered pairs: True | native P2P atomics: True\n" + ] + } + ], + "source": [ + "import re\n", + "from pathlib import Path\n", + "import numpy as np\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "\n", + "RUN_ID = \"nvlink-20260917-d\"\n", + "_candidates = [\n", + " Path(\"correlation/data\") / RUN_ID / \"nvlink_probe\" / \"results.csv\",\n", + " Path(\"notebooks/astrasim2_correlation/correlation/data\") / RUN_ID / \"nvlink_probe\" / \"results.csv\",\n", + " Path(\"/workspace/aws-gpu-profiler/data\") / RUN_ID / \"nvlink_probe\" / \"results.csv\",\n", + "]\n", + "RESULTS = next((p for p in _candidates if p.is_file()), None)\n", + "assert RESULTS is not None, \"results.csv not found; run the profiler first (see the header cell)\"\n", + "df = pd.read_csv(RESULTS)\n", + "# The `ncu` point re-runs a few (probe, variant, size) entries under Nsight Compute; the harness's own rows\n", + "# from those runs carry `under_ncu` in `note` and their timings/link counters are meaningless (ncu serialises\n", + "# and replays the kernels). Keep only the counter rows ncu_rows.py derived from them (probe == \"ncu\").\n", + "df = df[(df.probe == \"ncu\") | ~df.note.fillna(\"\").str.contains(\"under_ncu\")].copy()\n", + "\n", + "def kv(note):\n", + " \"\"\"Split the harness's ';'-separated key=value note field into a dict.\"\"\"\n", + " return dict(x.split(\"=\", 1) for x in str(note).split(\";\") if \"=\" in x)\n", + "\n", + "pd.set_option(\"display.width\", 200); pd.set_option(\"display.max_columns\", 40)\n", + "GBPS = lambda x: f\"{x:.1f}\"\n", + "print(f\"{RESULTS}: {len(df)} rows; probes: {df.probe.value_counts().to_dict()}\")\n", + "\n", + "# Hardware facts every other cell assumes (info probe).\n", + "info = df[df.probe == \"info\"]\n", + "gpu = pd.DataFrame([kv(n) for n in info[info.variant == \"gpu\"].note])\n", + "gpu.index = info[info.variant == \"gpu\"].src.astype(int).values\n", + "display(gpu[[\"name\", \"sms\", \"nvlinks\", \"link_peak_GBps\", \"hbm_peak_GBps\", \"multicast\", \"driver\", \"cuda_rt\"]])\n", + "nvl = pd.DataFrame([kv(n) for n in info[info.variant == \"nvlink\"].note])\n", + "p2p = pd.DataFrame([kv(n) for n in info[info.variant == \"p2p\"].note])\n", + "print(\"NVLink endpoints:\", nvl.remote_type.value_counts().to_dict(), \"| active links:\", int(nvl.active.astype(int).sum()),\n", + " \"| P2P access on all ordered pairs:\", bool((p2p.access.astype(int) == 1).all()), \"| native P2P atomics:\", bool((p2p.native_atomics.astype(int) == 1).all()))\n", + "LINK_PEAK = float(gpu.link_peak_GBps.iloc[0]); HBM_PEAK = float(gpu.hbm_peak_GBps.iloc[0]); NGPU = len(gpu)" + ] + }, + { + "cell_type": "markdown", + "id": "bd68bf8d", + "metadata": {}, + "source": [ + "## Q1: minimum packet size and the latency/bandwidth knee\n", + "\n", + "`packet` writes (and reads) GPU 1's memory from a kernel on GPU 0 through NVSwitch and records the NVML NVLink\n", + "counters: *data* bytes (payload actually carried) and *raw* bytes (payload plus protocol). Contiguous stores of\n", + "1..16 bytes per thread coalesce into full packets; the `store_sparse_s` variants issue one isolated 4-byte\n", + "store per `N`-byte stride, so `wire_bytes_per_op` is the smallest unit the link carries for one store. The two size\n", + "sweeps (copy engine and SM stores) give the size at which a single transfer reaches 50 % / 90 % of peak, and the\n", + "flag ping-pong gives the one-way latency of a 4-byte remote write." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "11e69554", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:57.522365Z", + "iopub.status.busy": "2026-09-17T16:43:57.522256Z", + "iopub.status.idle": "2026-09-17T16:43:57.690217Z", + "shell.execute_reply": "2026-09-17T16:43:57.688725Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variantelem_bytesstride_bytespayload_GBpslink_utilwire_bytes_per_opraw_over_data
store_w11.000000nan265.50.631.11.45
store_w22.000000nan333.30.742.01.24
store_w44.000000nan365.00.804.01.14
store_w88.000000nan369.20.818.01.13
store_w1616.000000nan370.90.8216.01.13
store_sparse_s324.00000032.00000041.80.7432.01.25
store_sparse_s644.00000064.00000026.20.6948.01.34
store_sparse_s1284.000000128.00000034.30.3016.03.00
store_sparse_s2564.000000256.00000033.50.2916.03.00
store_sparse_s5124.000000512.00000031.80.2616.03.00
store_sparse_s10244.0000001024.00000028.80.2216.03.01
load_w44.000000nan363.90.804.01.13
load_w1616.000000nan369.60.8116.01.13
load_sparse_s324.00000032.00000046.20.8132.01.13
load_sparse_s1284.000000128.00000034.10.5932.01.51
load_sparse_s5124.000000512.00000031.40.5132.01.50
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "memcpy_ce peak 392.3 GB/s | 50% of peak first reached at 4.000 MiB | min latency 5.2 us\n", + "memcpy_ce peak 392.3 GB/s | 90% of peak first reached at 64.000 MiB | min latency 5.2 us\n", + "memcpy_ce alpha-beta fit: t = 8.3 us + S / 397 GB/s\n", + "store_sweep peak 371.7 GB/s | 50% of peak first reached at 4.000 MiB | min latency 5.2 us\n", + "store_sweep peak 371.7 GB/s | 90% of peak first reached at 64.000 MiB | min latency 5.2 us\n", + "store_sweep alpha-beta fit: t = 6.1 us + S / 375 GB/s\n" + ] + }, + { + "data": { + "image/png": "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p5sVbyXeqZVoZjXFa+kzaFLv/pMa3B2enEC6Ts+ri48Qd7cVR7e6AfSoV9pysYqSTT0ELy8vdeLECaWUUj/88IOqXbu20ul0asmSJapatWoPs0mLiomJUYCKiYnJ1finv96hmkzemOuPihP+UWXfXpXlo+KEf/K0nae/3pElFp1Op27evKl0Op1xXmxsrLKzs1M//PBDtvHPmTNHeXh4qPj4eOO8f/75R2m1WhUWFqaUUmrIkCHK09NTJSQkGMd89913ytnZ2fhao0aNUp07dzYu/+KLL1SFChWUXq/P9nV/+eUXVbVqVbPlKSkpysHBQa1bt874umXLllXp6enGMX369FH9+vVTSil1+vRpBagDBw4Yl587d04B6ssvvzTmAlDLly9XSikVGhqqADV37lzjOidPnlSAOn36tFJKqWHDhqkRI0aYxbtjxw6l1WpVUlJStvszffp0VaFCBbN569atU1qtVp05cybbdT788ENVp06dLNspW7ascdrf319NmzbNOJ2WlqYCAwNVt27dst2mUkpFREQoQB0/flwppYw5WLZsmZoxY4Zq3bq1UkqpSZMmqR49eqioqCgFqC1btiil8va9yfxeq1q1qmrRooVxOj09XTk5OanffvtNKaXU7NmzlYuLi7pz506O+bCyslLXrl0zzluzZo3SarXq5s2bSimlpk6dqqpXr25cvmzZMuXs7Gx8/27ZskUBKioqSiml1I0bN1SzZs1U6dKlVUpKimrbtq2aMGGCWdy//PKL8vf3V0oZvs+urq4qOTnZLLaKFSuq2bNnG+O0sbFR4eHhWfahWbNmasaMGUopw/fK29vbmFellOratat6/vnns93/pKQk5eHhoX7//XfjvNq1a6uPPvrIOF22bFn13HPPGaf1er3y9fVV3333nVLqwTnO4OHhoebPn5/t74wS5+RfSn3oqvQfuiqV+ePoEqWUUjM2nDX+nm7+2SYVk5Rq4YALnrwvTAojF3mpOx7qiFpiYiIuLi4ArF+/np49e6LVamnatCmXL19+9OqxiIuISyEsNjnXHxkP7r1Xul7laTsRcSnZbudep0+fJiUlhbZt2+a4vE6dOjg5mTpqN2/eHL1eb/wvHaBOnTo4OpoO9YeEhBAfH8/Vq1cBePHFF1m/fj3Xr18HYP78+QwdOjTH3kJHjx7l/PnzuLi44OzsjLOzM56e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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variantone_way_latency_uswire_bytes_per_flag_write
pingpong2.3416.0
pingpong_acqrel2.3316.0
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pk = df[df.probe == \"packet\"].copy()\n", + "pk[\"raw_over_data\"] = pk.nvml_tx_raw_bytes / pk.nvml_tx_data_bytes\n", + "gran = pk[pk.variant.str.match(r\"^(store|load)_(w|sparse)\")][\n", + " [\"variant\", \"elem_bytes\", \"stride_bytes\", \"payload_GBps\", \"link_util\", \"wire_bytes_per_op\", \"raw_over_data\"]]\n", + "display(gran.style.format({\"payload_GBps\": \"{:.1f}\", \"link_util\": \"{:.2f}\", \"wire_bytes_per_op\": \"{:.1f}\", \"raw_over_data\": \"{:.2f}\"}).hide(axis=\"index\"))\n", + "\n", + "sw = pk[pk.variant.isin([\"memcpy_ce\", \"store_sweep\"])]\n", + "fig, ax = plt.subplots(figsize=(7, 4))\n", + "for v, lab in [(\"memcpy_ce\", \"copy engine (cudaMemcpyPeerAsync)\"), (\"store_sweep\", \"SM 16-byte stores\")]:\n", + " s = sw[sw.variant == v].sort_values(\"size_bytes\")\n", + " ax.plot(s.size_bytes, s.payload_GBps, marker=\"o\", ms=4, lw=2, label=lab)\n", + " peak = s.payload_GBps.max()\n", + " for frac in (0.5, 0.9):\n", + " knee = s[s.payload_GBps >= frac * peak].size_bytes.min()\n", + " print(f\"{v:12s} peak {peak:6.1f} GB/s | {int(frac*100)}% of peak first reached at {knee/2**20:8.3f} MiB | \"\n", + " f\"min latency {s.time_min_us.min():.1f} us\")\n", + " A = np.vstack([np.ones(len(s)), s.size_bytes.values]).T\n", + " a, b = np.linalg.lstsq(A, s.time_us.values, rcond=None)[0]\n", + " print(f\"{v:12s} alpha-beta fit: t = {a:.1f} us + S / {1e-3/b:.0f} GB/s\")\n", + "ax.set_xscale(\"log\", base=2); ax.set_xlabel(\"transfer size (bytes)\"); ax.set_ylabel(\"GB/s\"); ax.set_title(\"single GPU-to-GPU transfer vs size\")\n", + "ax.axhline(LINK_PEAK, color=\"0.6\", ls=\"--\", lw=1); ax.text(70, LINK_PEAK * 1.01, \"18 x 25 GB/s\", color=\"0.4\")\n", + "ax.legend(frameon=False); ax.grid(alpha=0.3); plt.show()\n", + "\n", + "pp = pk[pk.variant.str.startswith(\"pingpong\")][[\"variant\", \"time_us\", \"wire_bytes_per_op\"]]\n", + "pp.columns = [\"variant\", \"one_way_latency_us\", \"wire_bytes_per_flag_write\"]\n", + "display(pp.style.format({\"one_way_latency_us\": \"{:.2f}\", \"wire_bytes_per_flag_write\": \"{:.1f}\"}).hide(axis=\"index\"))" + ] + }, + { + "cell_type": "markdown", + "id": "17999598", + "metadata": {}, + "source": [ + "## Q2: switch capacity: how many inbound links can be saturated at once?\n", + "\n", + "`fabric` moves 1 GiB per transfer with kernels on every sender started simultaneously (a per-GPU device flag raised\n", + "by the host). `perm_shift_k` has every GPU sending to GPU `(i+k) mod 8`; `all2all` has every GPU sending to all\n", + "seven others at once; `incast_k` / `outcast_k` concentrate `k` senders on one receiver / one sender on `k`\n", + "receivers. If per-sender bandwidth under `perm_shift_*` and `all2all` equals the single `pair`, the four NVSwitch\n", + "chips are non-blocking and all `8 x 18` inbound links are saturated together; `incast` shows that the receiver's\n", + "own 18 inbound links, not the switch, cap concentrated traffic." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "3275c4db", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:57.693541Z", + "iopub.status.busy": "2026-09-17T16:43:57.693446Z", + "iopub.status.idle": "2026-09-17T16:43:57.761288Z", + "shell.execute_reply": "2026-09-17T16:43:57.759913Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
 agg_GBpsfabric_utiln_sendersper_sender_GBpslink_util_minlink_util_maxper_link_balance_min
variant       
pair3700.1013700.820.820.998
bidir_pair7320.2023660.810.810.998
perm_shift_129280.8083660.800.800.996
perm_shift_229250.8083660.800.800.996
perm_shift_329270.8083660.800.800.996
perm_shift_429280.8083660.800.800.996
perm_shift_529270.8083660.800.800.996
perm_shift_629270.8083660.800.800.996
perm_shift_729270.8083660.800.800.996
perm_shift_1_load26660.7383330.730.730.996
perm_shift_1_ce30930.8283870.820.820.996
incast_13700.1013700.810.810.998
incast_23750.1021880.410.410.996
incast_33760.1031250.280.280.996
incast_43760.104940.210.210.996
incast_53760.105750.170.170.996
incast_63760.106630.140.140.996
incast_73770.107540.120.120.996
outcast_13700.1013700.820.820.998
outcast_23720.1013720.820.820.998
outcast_33720.1013720.820.820.998
outcast_43700.1013700.820.820.998
outcast_53720.1013720.820.820.998
outcast_63720.1013720.820.820.998
outcast_73710.1013710.820.820.998
all2all27930.7783490.770.770.997
all2all_load26540.7383320.730.730.998
all2all_ce12440.3481560.340.340.997
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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5dS0aVO4u7vj2rVruHjxotY4Ly8v1KxZE+Hh4cnm1cTEBD179gQAHDx4MNnGwc/PD56enrhz5w5OnTqlNS5v3rxo2LAhYmJiUmzDrl27wtzcHMePH8eTJ0+0xlWtWhXFixfH48ePcejQIa1xLi4uaNmyJQCk+L7t27eHvb09zp07hzt37miNK1euHMqXL4+XL19i165dWuPs7OzQoUMHAMCff/6ZbIPUokULuLq64sqVK7hy5YrWOG9vb1SrVg1hYWHJMpmZmaFbt24AgP379yfbcNevXx/58+fHzZs3cfbsWa1xBQoUQL169RAVFZXivPbo0QOmpqY4evQonj9/rjWuRo0aKFq0KB48eIC//vpLa1yuXLnQrFkzqNXqFN+3Y8eOsLGxwenTp3H//n2tcRUqVEDZsmXx/Plz7N27V2tcjhw58MUXXwAA/vjjj2Qr6datW8PZ2RkXL17E9evXtcaVLFkSvr6+CA0NxbZt27TGWVpaokuXLgCAvXv3JlsRN2rUCHny5MH169dx4cIFrXFcRyTiOuJfXEck4joiEdcRibiO+Je+1xHvF1kfo5L3S40sKDw8HPb29rh37x5sbW2V4azwE7HC/xePAibiUcBEXEck4jriX1xHJOI6IhHXEYm4jviXIc4UeHp64s2bN7Czs0uWJykWBfi3KNClwYiIiIiIMoO07OPyRmMiIiIioiyORQERERERURbHooCIiIiIKItjUUBERERElMWxKCAiIiIiyuJYFBARERERZXEsCoiIiIiIsjgWBUREREREWRyLAiIiIiKiLI5FARERERFRFseigIiIiIgoi2NRQERERESUxbEoICIiIiLK4lgUEBERERFlcSwKiIiIiIiyOBYFRERERERZHIsCIiIiIqIsjkUBEREREVEWx6KAiIiIiCiLY1FARERERJTFsSggIiIiIsriWBQQEREREWVxLAqIiIiIiLI4FgVERERERFkciwIiIiIioizOaIqCn3/+GSqVCoMGDVKGRUdHIyAgAE5OTrCxsUGbNm3w8uVLrb979OgRmjRpguzZs8PFxQXDhg1DfHy8ntMTEREREWVeRlEUnD17FosWLUKpUqW0hg8ePBh//PEHNmzYgCNHjuDZs2do3bq1Mj4hIQFNmjRBbGwsTpw4gZUrV2LFihUYPXq0vmeBiIiIiCjTUomIGDJAZGQkypUrh/nz52PChAkoU6YMAgMD8ebNG+TMmROrV69G27ZtAQA3btxAsWLFcPLkSVSuXBm7du1C06ZN8ezZM7i6ugIAFi5ciO+++w7BwcEwNzdP8TNjYmIQExOjvA4PD0eePHnw+vVr2NnZZfxMExERERFlsPDwcOTIkQNv3rxJdR83m54yfVBAQACaNGkCPz8/TJgwQRl+/vx5xMXFwc/PTxlWtGhR5M2bVykKTp48iZIlSyoFAQA0aNAA/fr1w7Vr11C2bNkUP3PSpEkYN25csuHBwcGIjo5Ox7kjIiIiIjKMiIgInac1aFGwdu1aXLhwAWfPnk027sWLFzA3N4eDg4PWcFdXV7x48UKZJmlBoBmvGfchI0aMwJAhQ5TXmjMFOXPm5JkCIiIiIvosWFpa6jytwYqCx48f45tvvsG+ffvSFDg9WFhYwMLCItlwExMTmJgYxW0WRERERET/SVr2aw22B3z+/HkEBQWhXLlyyJYtG7Jly4YjR45g9uzZyJYtG1xdXREbG4uwsDCtv3v58iXc3NwAAG5ubsl6I9K81kxDREREREQfZ7CioG7durhy5QouXryo/Ctfvjw6deqk/N/MzAwHDhxQ/ubmzZt49OgRfH19AQC+vr64cuUKgoKClGn27dsHOzs7eHt7632eiIiIiIgyI4NdPmRra4sSJUpoDbO2toaTk5MyvEePHhgyZAgcHR1hZ2eHgQMHwtfXF5UrVwYA1K9fH97e3ujcuTOmTJmCFy9e4IcffkBAQECKlwcREREREVFyBu996GNmzpwJExMTtGnTBjExMWjQoAHmz5+vjDc1NcWOHTvQr18/+Pr6wtraGv7+/hg/frwBUxMRERERZS4Gf06BMQgPD4e9vb1OfbgSEREREWUGadnHZVc7RERERERZnFFfPkRERESkcW9iG0NHSMbz+02GjkCULnimgIiIiIgoi2NRQERERESUxbEoICIiIiLK4lgUEBERERFlcSwKiIiIiIiyOBYFRERERERZHIsCIiIiIqIsjkUBEREREVEWx6KAiIiIiCiL4xONjUCzodsMHSGZP6a3MHQEIiIiItITnikgIiIiIsrieKaAPllmPcORWXNnVpm1vZk7/TC3fn3O6xMiyjgsCogyCe58EBERUUbh5UNERERERFkciwIiIiIioiyORQERERERURbHooCIiIiIKItjUUBERERElMXp3PvQ5cuXUxxub2+PvHnzQqVSpVsoIiIiIiLSH52LgjJlykClUkFEtIarVCpYWlpi0KBBGD9+PExNTdM9JBERERERZRydi4L79++nODwsLAznz5/HqFGjkCNHDnz77bfpFo6IiIiIiDKezkVBvnz5Pji8dOnSsLOzw7hx41gUEBERERFlMun2RGMfH58Pnk0gIiIiyqr4RHrKDNKt96EXL14gZ86c6fV2RERERESkJ+lSFAQHB2PUqFGoXbt2erwdERERERHpkc6XD5UtWzbFbkffvHmDJ0+ewMvLC7///nu6hiMiIiIiooync1HQsmXLFIfb2dnBy8sLDRo0YHekRERERESZkM5FwZgxYzIyBxERERERGUiaeh9at24dtm/fjtjYWNStWxd9+/bNqFxERERERKQnOhcFCxYsQEBAAAoXLgwrKyts3rwZd+/exdSpUzMyHxERERERZTCdex+aO3cuxowZg5s3b+LixYtYuXIl5s+fn5HZiIiIiIhID3QuCu7duwd/f3/ldceOHREfH4/nz59nSDAiIiIiItIPnS8fiomJgbW1tfLaxMQE5ubmiIqKypBgRERElDH4hF0iel+abjQeNWoUsmfPrryOjY3FxIkTYW9vrwybMWNG+qUjIiIiIoMwtuKRhWPG0rkoqFGjBm7evKk1rEqVKrh3757yOqWHmxERERERkXHTuSg4fPhwBsYgIiIiIiJD0flGYyIiIiIi+jzpfKYgLCwMa9asQb9+/QAAnTp10rrJ2NTUFEuWLIGDg0O6hyQiIiIiooyj85mCJUuW4NixY8rr7du3w8TEBPb29rC3t8eVK1cQGBiYERmJiIiIiCgD6VwUbNy4Ed26ddMaNmXKFCxfvhzLly/HpEmTsG2bcd2lTkREREREqUvTw8u8vLyU115eXjA3N1dely5dGrdv307fdERERERElOF0Lgrevn2LN2/eKK/PnTsHDw8PrfFqtTp90xERERERUYbTuSjw9PTEhQsXPjj+3LlzKFCgQLqEIiIiIiIi/dG5KGjVqhV++OEHvHz5Mtm4Fy9eYMyYMWjVqlW6hiMiIiIiooync5ek//vf/7Bp0yYULlwYnTt3RpEiRQAAN2/exO+//47cuXPju+++y7CgRERERESUMXQuCmxtbXH8+HGMGDECa9asQVhYGADAwcEBHTt2xE8//QRbW9uM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/PPPaX07AMCAAQOwY8cOHDp0CB4eHspwNzc3xMbGIiwsTGv6ly9fws3NTZnm/d6INK810xARERER0YeluSgYMWIELl26hMOHD2udkvDz88O6devS9F4iggEDBmDLli04ePAgChQooDXex8cHZmZmOHDggDLs5s2bePToEXx9fQEAvr6+uHLlitZ1Zvv27YOdnR28vb3TOntERERERFlOmq/72bp1K9atW4fKlStDpfr3vvTixYvj7t27aXqvgIAArF69Gtu2bYOtra1yD4C9vT2srKxgb2+PHj16YMiQIXB0dISdnR0GDhwIX19fVK5cGQBQv359eHt7o3PnzpgyZQpevHiBH374AQEBASleIkRERERERNrSXBQEBweneKPH27dvtYoEXSxYsAAAUKtWLa3hy5cvR9euXQEAM2fOhImJCdq0aYOYmBg0aNAA8+fPV6Y1NTXFjh070K9fP/j6+sLa2hr+/v4YP3582maMiIiIiCiLSnNRUL58efz5558YOHAgACiFwNKlS5VLenQlkvotLJaWlpg3bx7mzZv3wWny5cuHnTt3pumziYiIiIgoUZqLgp9++gmNGjXC9evXER8fj1mzZuH69es4ceIEjhw5khEZiYiIiIgoA6X5RuNq1arh4sWLiI+PR8mSJbF37164uLjg5MmT8PHxyYiMRERERESUgT7pAQMFCxbEkiVL0jsLEREREREZwCcVBQkJCdiyZQv++ecfAIC3tzdatGiRLg8xIyIiIiIi/UrzXvy1a9fQvHlzvHjxAl5eXgCAyZMnI2fOnPjjjz9QokSJdA9JREREREQZJ833FPTs2RPFixfHkydPcOHCBVy4cAGPHz9GqVKl0Lt374zISEREREREGSjNZwouXryIc+fOIUeOHMqwHDlyYOLEiahQoUK6hiMiIiIiooyX5jMFRYoUwcuXL5MNDwoKQqFChdIlFBERERER6U+ai4JJkybh66+/xsaNG/HkyRM8efIEGzduxKBBgzB58mSEh4cr/4iIiIiIyPil+fKhpk2bAgDatWunPM1Y82TiZs2aKa9VKhUSEhLSKycREREREWWQNBcFhw4dyogcRERERERkIGkuCmrWrJkROYiIiIiIyEDSfE8BERERERF9XlgUEBERERFlcSwKiIiIiIiyOBYFRERERERZXJqLgqioKLx79055/fDhQwQGBmLv3r3pGoyIiIiIiPQjzUVBixYt8OuvvwIAwsLCUKlSJUyfPh0tWrTAggUL0j0gERERERFlrDQXBRcuXED16tUBABs3boSrqysePnyIX3/9FbNnz073gERERERElLHSXBS8e/cOtra2AIC9e/eidevWMDExQeXKlfHw4cN0D0hERERERBkrzQ8vK1SoELZu3YpWrVphz549GDx4MAAgKCgIdnZ26R6QiIiIiEhX9ya2MXQELZ7fbzJ0BJ2k+UzB6NGj8e233yJ//vyoVKkSfH19ASSeNShbtmy6ByQiIiIiooyV5jMFbdu2RbVq1fD8+XOULl1aGV63bl20atUqXcMREREREVHG07koyJs3L5o3b47mzZujTp06cHNz0xpfsWLFdA9HREREREQZT+fLh3777TdYWFggICAAzs7OaN++PVatWoWwsLAMjEdERERERBlN56KgZs2amD59Om7fvo3jx4+jTJkymDNnDtzc3FCnTh0EBgbi3r17GZmViIiIiIgyQJpvNAaA4sWLY8SIETh16hTu37+PL7/8EgcOHECJEiVQokQJ/Pnnn+mdk4iIiIiIMkiabzR+X65cudCrVy/06tUL7969w549e2BhYZEe2YiIiIiISA/+U1EgIjh06BCioqJQpUoV5MiRgz0QERERERFlMjpfPhQWFgZ/f3+ULFkSvXr1Qnh4OKpXrw4/Pz80a9YMxYoVw+XLlzMyKxERERERZQCdi4Jvv/0WJ0+eRIcOHXDlyhU0bNgQCQkJOHnyJE6fPo1ixYrh+++/z8isRERERESUAXS+fGjXrl1YvXo1atasia5duyJPnjw4ePAgKlWqBACYPHkymjdvnmFBiYiIiIgoY+h8puDly5coUqQIACB37tywtLREnjx5lPF58+ZFcHBw+ickIiIiIqIMpXNRoFarYWpqqrw2NTWFSqVSXif9PxERERERZR5p6n1o6dKlsLGxAQDEx8djxYoVcHZ2BgBERESkfzoiIiIiIspwOhcFefPmxZIlS5TXbm5u+O2335JNQ0REREREmYvORcGDBw8yMAYRERERERmKzvcUEBERERHR50nnMwVRUVE4cOAAmjZtCgAYMWIEYmJilPGmpqb48ccfYWlpmf4piYiIiIgow+hcFKxcuRJ//vmnUhTMnTsXxYsXh5WVFQDgxo0bcHd3x+DBgzMmKRERERERZQidLx9atWoVevfurTVs9erVOHToEA4dOoSpU6di/fr16R6QiIiIiIgyls5FwZ07d1CyZEnltaWlJUxM/v3zihUr4vr16+mbjoiIiIiIMpzOlw+FhYVp3UPw/tOL1Wq11ngiIiIiIsocdD5T4OHhgatXr35w/OXLl+Hh4ZEuoYiIiIiISH90LgoaN26M0aNHIzo6Otm4qKgojBs3Dk2aNEnXcERERERElPF0vnxo5MiRWL9+Pby8vDBgwAAUKVIEAHDz5k3MnTsX8fHxGDlyZIYFJSIiIiKijKFzUeDq6ooTJ06gX79+GD58OEQEAKBSqVCvXj3Mnz8frq6uGRaUiIiIiIgyhs5FAQAUKFAAu3fvRmhoKO7cuQMAKFSoEBwdHTMkHBERERERZbw0FQUajo6OqFixYnpnISIiIiIiA9D5RmMiIiIiIvo8sSggIiIiIsriDFoU/PXXX2jWrBnc3d2hUqmwdetWrfEigtGjRyNXrlywsrKCn58fbt++rTVNaGgoOnXqBDs7Ozg4OKBHjx6IjIzU41wQEREREWVuBi0K3r59i9KlS2PevHkpjp8yZQpmz56NhQsX4vTp07C2tkaDBg20npXQqVMnXLt2Dfv27cOOHTvw119/oXfv3vqaBSIiIiKiTO+TbjROL40aNUKjRo1SHCciCAwMxA8//IAWLVoAAH799Ve4urpi69at6NChA/755x/s3r0bZ8+eRfny5QEAc+bMQePGjTFt2jS4u7un+N4xMTGIiYlRXoeHhwMA1Go11Gp1es6iTlR6/8TU6dIOzJ1+mFu/mFu/mFu/PufcYoTJP+f2Nrbcuu6jGdtyYoh9y0/5bIMWBR9z//59vHjxAn5+fsowe3t7VKpUCSdPnkSHDh1w8uRJODg4KAUBAPj5+cHExASnT59Gq1atUnzvSZMmYdy4ccmGBwcHp/jE5oyWxwh7dA0KCkp1GuZOP8ytX8ytX8ytX59z7gjb3HpIkjafc3sbW25dMgPGt5zomjsjRERE6Dyt0RYFL168AIBkD0RzdXVVxr148QIuLi5a47NlywZHR0dlmpSMGDECQ4YMUV6Hh4cjT548yJkzJ+zs7NJrFnT2OFTvH5mq99s1Jcydfphbv5hbv5hbvz7n3G8jnuohSdp8zu1tbLl1yQwY33Kia+6MYGlpqfO0RlsUZCQLCwtYWFgkG25iYgITE/3fZiF6/8TU6dIOzJ1+mFu/mFu/mFu/PufcKiNM/jm3t7Hl1nUfzdiWE0PsW37KZxttl6Rubm4AgJcvX2oNf/nypTLOzc0t2SmZ+Ph4hIaGKtMQEREREdHHGW1RUKBAAbi5ueHAgQPKsPDwcJw+fRq+vr4AAF9fX4SFheH8+fPKNAcPHoRarUalSpX0npmIiIiIKDMy6OVDkZGRuHPnjvL6/v37uHjxIhwdHZE3b14MGjQIEyZMQOHChVGgQAGMGjUK7u7uaNmyJQCgWLFiaNiwIXr16oWFCxciLi4OAwYMQIcOHT7Y8xAREREREWkzaFFw7tw51K5dW3mtufnX398fK1aswP/+9z+8ffsWvXv3RlhYGKpVq4bdu3dr3TSxatUqDBgwAHXr1oWJiQnatGmD2bNn631eiIiIiIgyK4MWBbVq1YLIh28GUalUGD9+PMaPH//BaRwdHbF69eqMiEdERERElCUY7T0FRERERESkHywKiIiIiIiyOBYFRERERERZHIsCIiIiIqIsjkUBEREREVEWx6KAiIiIiCiLY1FARERERJTFsSggIiIiIsriWBQQEREREWVxLAqIiIiIiLI4FgVERERERFkciwIiIiIioiyORQERERERURbHooCIiIiIKItjUUBERERElMWxKCAiIiIiyuJYFBARERERZXEsCoiIiIiIsjgWBUREREREWRyLAiIiIiKiLI5FARERERFRFseigIiIiIgoi2NRQERERESUxbEoICIiIiLK4lgUEBERERFlcSwKiIiIiIiyOBYFRERERERZHIsCIiIiIqIsjkUBEREREVEWx6KAiIiIiCiLY1FARERERJTFsSggIiIiIsriWBQQEREREWVxLAqIiIiIiLI4FgVERERERFkciwIiIiIioiyORQERERERURbHooCIiIiIKItjUUBERERElMWxKCAiIiIiyuJYFBARERERZXEsCoiIiIiIsjgWBUREREREWRyLAiIiIiKiLI5FARERERFRFseigIiIiIgoi2NRQERERESUxbEoICIiIiLK4lgUEBERERFlcSwKiIiIiIiyuM+mKJg3bx7y588PS0tLVKpUCWfOnDF0JCIiIiKiTOGzKArWrVuHIUOGYMyYMbhw4QJKly6NBg0aICgoyNDRiIiIiIiM3mdRFMyYMQO9evVCt27d4O3tjYULFyJ79uz45Zdf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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "receiver-side aggregate under incast_k (GB/s): ['370', '375', '376', '376', '376', '376', '377']\n", + "sender-side aggregate under outcast_k (GB/s): ['370', '372', '372', '370', '372', '372', '371']\n" + ] + } + ], + "source": [ + "fb = df[df.probe == \"fabric\"]\n", + "agg = fb[fb.src == -1].set_index(\"variant\")\n", + "senders = fb[(fb.src != -1) & (fb.payload_bytes > 0)].groupby(\"variant\").agg(\n", + " n_senders=(\"src\", \"size\"), per_sender_GBps=(\"payload_GBps\", \"mean\"), link_util_min=(\"link_util\", \"min\"),\n", + " link_util_max=(\"link_util\", \"max\"), link_balance=(\"nvml_link_min_bytes\", lambda s: np.nan))\n", + "per_link = fb[(fb.src != -1) & (fb.payload_bytes > 0)].assign(bal=lambda d: d.nvml_link_min_bytes / d.nvml_link_max_bytes).groupby(\"variant\").bal.min()\n", + "tab = agg[[\"agg_GBps\", \"fabric_util\"]].join(senders).drop(columns=\"link_balance\")\n", + "tab[\"per_link_balance_min\"] = per_link\n", + "tab = tab.loc[[v for v in fb[fb.src == -1].variant]]\n", + "display(tab.style.format({\"agg_GBps\": \"{:.0f}\", \"fabric_util\": \"{:.2f}\", \"per_sender_GBps\": \"{:.0f}\", \"link_util_min\": \"{:.2f}\", \"link_util_max\": \"{:.2f}\", \"per_link_balance_min\": \"{:.3f}\"}))\n", + "\n", + "fig, ax = plt.subplots(figsize=(9, 3.8))\n", + "sel = [\"pair\", \"bidir_pair\"] + [f\"perm_shift_{k}\" for k in range(1, NGPU)] + [\"perm_shift_1_load\", \"perm_shift_1_ce\", \"all2all\", \"all2all_load\", \"all2all_ce\"]\n", + "vals = tab.loc[sel, \"per_sender_GBps\"]\n", + "ax.bar(range(len(sel)), vals, color=[\"#4c72b0\" if \"ce\" not in v else \"#dd8452\" for v in sel])\n", + "ax.set_xticks(range(len(sel))); ax.set_xticklabels(sel, rotation=60, ha=\"right\"); ax.set_ylabel(\"GB/s per sending GPU\")\n", + "ax.axhline(LINK_PEAK, color=\"0.6\", ls=\"--\", lw=1); ax.set_title(\"per-GPU injection bandwidth under simultaneous patterns (orange = copy engine)\")\n", + "ax.grid(axis=\"y\", alpha=0.3); plt.show()\n", + "inc = tab.loc[[f\"incast_{k}\" for k in range(1, NGPU)], \"agg_GBps\"]; out = tab.loc[[f\"outcast_{k}\" for k in range(1, NGPU)], \"agg_GBps\"]\n", + "print(\"receiver-side aggregate under incast_k (GB/s):\", [f\"{v:.0f}\" for v in inc])\n", + "print(\"sender-side aggregate under outcast_k (GB/s): \", [f\"{v:.0f}\" for v in out])" + ] + }, + { + "cell_type": "markdown", + "id": "d2c16d87", + "metadata": {}, + "source": [ + "## Q3: in-network reduction\n", + "\n", + "`reduce` allocates one CUDA multicast object (NVLink SHARP) bound to a buffer on every GPU and runs a 6-line\n", + "all-reduce: each GPU issues `multimem.ld_reduce` on its 1/8 chunk (the switch reads all eight copies and returns the\n", + "sum) followed by `multimem.st` (the switch writes the result into all eight copies). `sm_p2p_f32` is the same\n", + "all-reduce done by the SMs with peer loads and stores. `nccl` runs `ncclAllReduce` with `NCCL_ALGO` forced to Ring,\n", + "Tree or NVLS (the NVSwitch multicast algorithm), plus the library's own choice. The wire-byte columns are the\n", + "evidence for where the arithmetic happens: with switch-side reduction each GPU receives its chunk *already\n", + "reduced* (`rx/S = 1/8` for the reduce-scatter half, `1.125` for the full all-reduce), whereas an SM-side reduction\n", + "must pull all eight copies (`1.75 S` per direction for the ring-equivalent schedule)." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "feec7366", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:57.763020Z", + "iopub.status.busy": "2026-09-17T16:43:57.762921Z", + "iopub.status.idle": "2026-09-17T16:43:57.959454Z", + "shell.execute_reply": "2026-09-17T16:43:57.958138Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "At the largest size (per-GPU link bytes are per all-reduce, divided by S):\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variantsize_bytestime_uspayload_GBpsagg_GBpslink_utilfabric_utiltx_per_Srx_per_Sexp_tx_per_Sexp_rx_per_Swrongnvml_mem_util_pct
multimem_f321073741824.0003918.177274.041479.5720.6190.6191.1251.1251.1251.1250.000nan
multimem_bf161073741824.0003916.997274.124479.7170.6170.6171.1251.1251.1251.1250.000nan
multimem_ldreduce_f321073741824.0002981.059360.188630.3290.7020.7021.0000.1251.0000.1250.000nan
multimem_st_f321073741824.0002888.426371.739650.5440.7230.7230.1251.0000.1251.0000.000nan
multimem_red_f321073741824.00025567.32941.99773.4940.7250.7251.0008.0001.0001.0000.000nan
sm_p2p_f321073741824.0006064.414177.056309.8480.6440.6441.7501.7501.7501.7500.000nan
nccl_auto1073741824.0004067.227263.998461.9970.6440.6441.1251.125nannan0.00048.038
nccl_ring1073741824.0005230.594205.281359.2420.7820.7821.7501.750nannan0.00032.536
nccl_tree1073741824.0006757.851158.888278.0540.6080.6081.7501.750nannan0.00025.369
nccl_nvls1073741824.0004069.579263.846461.7300.6440.6441.1251.125nannan0.00047.375
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Nsight Compute counters per GPU per kernel (bytes divided by S; means over the 8 GPUs):\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variantsize_bytesgpusgpu_time_ushbm_read_per_Shbm_write_per_Shbm_utilnvl_tx_per_Snvl_rx_per_Snvl_protocol_fracsm_inst_executedsm_cycles_active
fabric.pair268435456.00013031.0080.0000.0000.0004.5153.6150.11425473648.000691415115.000
packet.store_sparse_s1281073741824.00011129.6320.0000.0000.0000.3550.2590.6673394416.000258867017.000
packet.store_sparse_s321073741824.00013361.9840.0000.0000.0001.2541.0040.20312831600.000766227826.000
packet.store_w16268435456.00013028.5760.0000.0000.0004.5153.6130.11425473648.000691436867.000
packet.store_w4268435456.00013076.9280.0000.0000.0004.5403.6300.11975805296.000702952962.000
reduce.multimem_f321048576.0008186.5600.1290.0000.0000.5250.5740.52792016.00010916719.375
reduce.multimem_f3216777216.0008222.9840.1250.0000.0030.5020.5740.502149616.00049281546.875
reduce.multimem_f32268435456.0008714.8760.1250.0370.0180.4780.5200.481703344.000165156497.125
reduce.multimem_ldreduce_f3216777216.0008210.7240.1250.0000.0030.2540.2970.515161904.00049203281.625
reduce.multimem_red_f3216777216.0008346.9922.0000.0230.0292.0692.3500.5171809008.00078910463.000
reduce.sm_p2p_f321048576.0008401.3640.1360.0000.0001.7111.9230.489137584.00023433453.500
reduce.sm_p2p_f3216777216.0008465.3800.1260.0020.0011.7071.8890.487751984.000108374045.500
reduce.sm_p2p_f32268435456.00081178.5360.1250.0410.0111.1951.2160.27310153200.000271310417.375
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "rd = df[(df.probe == \"reduce\") & (df.src == -1)].copy()\n", + "rd[\"tx_per_S\"] = rd.nvml_tx_data_bytes / NGPU / rd.iters / rd.size_bytes\n", + "rd[\"rx_per_S\"] = rd.nvml_rx_data_bytes / NGPU / rd.iters / rd.size_bytes\n", + "rd[\"exp_tx_per_S\"] = rd.note.map(lambda n: float(kv(n)[\"expected_tx_bytes_per_gpu\"])) / rd.size_bytes\n", + "rd[\"exp_rx_per_S\"] = rd.note.map(lambda n: float(kv(n)[\"expected_rx_bytes_per_gpu\"])) / rd.size_bytes\n", + "nc = df[(df.probe == \"nccl\") & (df.src == -1)].copy()\n", + "nc[\"tx_per_S\"] = nc.nvml_tx_data_bytes / NGPU / nc.iters / nc.size_bytes\n", + "nc[\"rx_per_S\"] = nc.nvml_rx_data_bytes / NGPU / nc.iters / nc.size_bytes\n", + "nc[\"variant\"] = nc.note.map(lambda n: \"nccl_\" + kv(n)[\"nccl_algo\"].lower().replace(\"unset\", \"auto\"))\n", + "\n", + "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n", + "series = [(\"multimem_f32\", rd, \"multimem ld_reduce+st (ours)\"), (\"sm_p2p_f32\", rd, \"SM P2P loads+stores (ours)\"),\n", + " (\"nccl_nvls\", nc, \"NCCL NVLS\"), (\"nccl_ring\", nc, \"NCCL Ring\"), (\"nccl_tree\", nc, \"NCCL Tree\"), (\"nccl_auto\", nc, \"NCCL default\")]\n", + "for v, src, lab in series:\n", + " s = src[src.variant == v].sort_values(\"size_bytes\")\n", + " axes[0].plot(s.size_bytes, s.time_us, marker=\"o\", ms=3, lw=1.8, label=lab)\n", + " axes[1].plot(s.size_bytes, s.agg_GBps, marker=\"o\", ms=3, lw=1.8, label=lab)\n", + "for ax, yl, t in [(axes[0], \"time per all-reduce (us)\", \"all-reduce time\"), (axes[1], \"bus bandwidth 2(n-1)/n * S/t (GB/s)\", \"all-reduce bus bandwidth\")]:\n", + " ax.set_xscale(\"log\", base=2); ax.set_xlabel(\"per-GPU buffer S (bytes)\"); ax.set_ylabel(yl); ax.set_title(t); ax.grid(alpha=0.3)\n", + "axes[0].set_yscale(\"log\"); axes[0].legend(frameon=False, fontsize=8); plt.tight_layout(); plt.show()\n", + "\n", + "big = pd.concat([rd[rd.size_bytes == rd.size_bytes.max()][[\"variant\", \"size_bytes\", \"time_us\", \"payload_GBps\", \"agg_GBps\", \"link_util\", \"fabric_util\", \"tx_per_S\", \"rx_per_S\", \"exp_tx_per_S\", \"exp_rx_per_S\", \"wrong\"]],\n", + " nc[nc.size_bytes == nc.size_bytes.max()][[\"variant\", \"size_bytes\", \"time_us\", \"payload_GBps\", \"agg_GBps\", \"link_util\", \"fabric_util\", \"tx_per_S\", \"rx_per_S\", \"nvml_mem_util_pct\", \"wrong\"]]])\n", + "print(\"At the largest size (per-GPU link bytes are per all-reduce, divided by S):\")\n", + "display(big.style.format(precision=3).hide(axis=\"index\"))\n", + "\n", + "ncu = df[df.probe == \"ncu\"].copy()\n", + "if ncu.hbm_read_bytes.notna().any():\n", + " ncu[\"hbm_rw_per_S\"] = (ncu.hbm_read_bytes + ncu.hbm_write_bytes) / ncu.size_bytes\n", + " ncu[\"nvl_rx_per_S\"] = ncu.nvlrx_bytes / ncu.size_bytes; ncu[\"nvl_tx_per_S\"] = ncu.nvltx_bytes / ncu.size_bytes\n", + " ncu[\"nvl_protocol_frac\"] = ncu.nvltx_protocol_bytes / ncu.nvltx_bytes\n", + " g = ncu.groupby([\"variant\", \"size_bytes\"]).agg(gpus=(\"src\", \"size\"), gpu_time_us=(\"gpu_time_ns\", lambda s: s.mean() / 1e3),\n", + " hbm_read_per_S=(\"hbm_read_bytes\", \"mean\"), hbm_write_per_S=(\"hbm_write_bytes\", \"mean\"), hbm_util=(\"hbm_util\", \"mean\"),\n", + " nvl_tx_per_S=(\"nvl_tx_per_S\", \"mean\"), nvl_rx_per_S=(\"nvl_rx_per_S\", \"mean\"), nvl_protocol_frac=(\"nvl_protocol_frac\", \"mean\"),\n", + " sm_inst_executed=(\"sm_inst_executed\", \"mean\"), sm_cycles_active=(\"sm_cycles_active\", \"mean\")).reset_index()\n", + " g[\"hbm_read_per_S\"] /= g.size_bytes; g[\"hbm_write_per_S\"] /= g.size_bytes\n", + " print(\"Nsight Compute counters per GPU per kernel (bytes divided by S; means over the 8 GPUs):\")\n", + " display(g.style.format(precision=3).hide(axis=\"index\"))\n", + "else:\n", + " print(\"ncu rows carry no counters in this run:\", ncu.note.unique())" + ] + }, + { + "cell_type": "markdown", + "id": "f1371f84", + "metadata": {}, + "source": [ + "## Q4: do SMs have to drive communication?\n", + "\n", + "`smrole` compares the three ways a GPU can push 1 GiB to a peer: copy engines (`cudaMemcpyPeerAsync`, zero SMs),\n", + "plain SM stores/loads with 1..264 blocks, and TMA bulk copies (`cp.async.bulk`, one issuing thread per block).\n", + "The `overlap_*` rows run each copy mechanism concurrently with a compute-bound kernel on the same GPU and report\n", + "the slowdown of both sides (`_half` variants leave half the SM thread slots free so the copy kernel can co-reside;\n", + "the full variants show what happens when compute occupies every SM). The `owner_busy_*` rows read GPU 0's memory\n", + "from GPU 1 while GPU 0's SMs are 100 % busy with arithmetic, or while GPU 0 saturates its own HBM." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e9692b32", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:57.960827Z", + "iopub.status.busy": "2026-09-17T16:43:57.960624Z", + "iopub.status.idle": "2026-09-17T16:43:58.052202Z", + "shell.execute_reply": "2026-09-17T16:43:58.050966Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "SM 16-byte stores : 371 GB/s max; >=95% of that with 8 blocks (of 132 SMs); 1 block = 46.8 GB/s\n", + "SM 16-byte loads (pull) : 368 GB/s max; >=95% of that with 132 blocks (of 132 SMs); 1 block = 3.7 GB/s\n", + "TMA cp.async.bulk push (1 thread/block) : 371 GB/s max; >=95% of that with 64 blocks (of 132 SMs); 1 block = 30.9 GB/s\n", + "copy engines, no SMs: 1 stream(s) 392 GB/s, 2 stream(s) 389 GB/s, 4 stream(s) 385 GB/s, 8 stream(s) 377 GB/s\n" + ] + }, + { + "data": { + "image/png": "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nXfeISQkhKCgoCyfm355fsOGDVle1jUxMdHdN6PRaHjw4AGpqanUr1+fkydPvlDsWenWrZvuEmZexZGb9z8z//zzDyYmJowePVqv/L333kNRlAw34rdp00bXOg7aVj17e3vd34SiKPz+++906dIFRVH0Pj8BAQFERUVlW6/o6GggY6vGP//8g4uLi+7Hx8cnw3N//PFHXFxccHV1pVGjRrrLedm14OWWo6MjcXFxmd4jlxvTpk0jNDSUb775JsttSpQoQceOHdm4cSNxcXGA9vVdvXo19evXp2LFii8Uw5OedT560ty5c3n33XeZM2cOH3300Qsd9+2339a7fy39f0N259i1a9fi4OBA27Zt9T5f9erVw9bWVnd+2r59OzExMUycODHDvWZP1jWn0s93/fv3x8nJSVdes2ZN2rZtyz///JPhOZn9/7h//77uc14YSaJm5Bo0aMD69et5+PAhR48eZdKkScTExNC9e/cs/3G++eabBAUFcfr0aVatWkWvXr1y9Udy9erVZ15qvX79OhUqVECt1v8IValSRbf+eVhaWmb4x1qiRIlM74PILW9v7wz7BXT7vnz5MgD+/v56/6BcXFzYtm2brgPHlStXUBSFjz/+OMN2U6dOBR539kh/nZ5WqVIlveWcHjv9dc3JPnPr+vXrme4jJ+/p66+/TpMmTRg0aBBubm706tWL3377LUPStmLFCmrWrImlpSXOzs64uLiwadMmoqKiXij2rJQpUybT8heJIzfvf2auX7+Oh4cHdnZ2euVZvc5Pf25B/28iPDycyMhIvvvuuwzxvP3228+MJz2O2NhYvfImTZqwfft2tm/fTrt27TJ97iuvvML27dvZsWMHR44cISIigi+++CLDeeFZsjs/DR8+nIoVK9KhQwc8PT0ZMGBApvfoPUvz5s1p1arVM+9V6927N3FxcWzYsAHQ9r4PCQnJdSeCZ3nW+Sjd3r17mTBhAhMmTHjmfWl5edwnXb58maioKFxdXTN8xmJjY3Wfr6tXrwLk+FadZ0n/W8jqvBQREaFLqNM9T/2MndyjVkiYm5vToEEDGjRoQMWKFXn77bdZu3at7h/Dkxo1akS5cuUYM2YMwcHBvPnmmwaIWCurE3B654CnmZiY5FssWe1beXQDd3pS8csvv+Du7p5hu/Qu+enbvf/++1l20MjtPTo5PbaxsrKyYt++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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
 compute slowdown (x)copy slowdown (x)copy GB/s while overlapped
kind   
ce1.001.06371.87
ce_half1.001.06372.04
sm321.0076.874.65
sm32_half1.0052.956.74
smfull1.0078.714.75
tma321.0093.503.76
tma32_half1.0040.788.62
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variantpayload_GBpslink_utilnote
owner_idle_read3710.82nan
owner_busy_compute_read3730.54owner_kernel=burn;owner_time_us=4321.28041251;owner_outlasted_reader=1
owner_busy_hbm_read2630.47owner_kernel=hbm_stream;owner_time_us=5039.05895292;owner_outlasted_reader=1
owner_busy_compute_ce3910.56owner_kernel=burn;owner_time_us=4125.87677276;owner_outlasted_reader=1
owner_busy_hbm_ce3250.47owner_kernel=hbm_stream;owner_time_us=5032.23597453;owner_outlasted_reader=1
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "sm = df[df.probe == \"smrole\"].copy()\n", + "fig, ax = plt.subplots(figsize=(7, 4))\n", + "for pref, lab in [(\"sm_store_blocks_\", \"SM 16-byte stores\"), (\"sm_load_blocks_\", \"SM 16-byte loads (pull)\"), (\"tma_push_blocks_\", \"TMA cp.async.bulk push (1 thread/block)\")]:\n", + " s = sm[sm.variant.str.startswith(pref)].copy(); s[\"b\"] = s.variant.str[len(pref):].astype(int); s = s.sort_values(\"b\")\n", + " ax.plot(s.b, s.payload_GBps, marker=\"o\", ms=4, lw=2, label=lab)\n", + " need = s[s.payload_GBps >= 0.95 * s.payload_GBps.max()].b.min()\n", + " print(f\"{lab:40s}: {s.payload_GBps.max():5.0f} GB/s max; >=95% of that with {need} blocks (of {int(gpu.sms.iloc[0])} SMs); 1 block = {s.payload_GBps.iloc[0]:.1f} GB/s\")\n", + "ce = sm[sm.variant.str.startswith(\"ce_streams_\")]\n", + "print(\"copy engines, no SMs:\", \", \".join(f\"{int(r.streams)} stream(s) {r.payload_GBps:.0f} GB/s\" for _, r in ce.iterrows()))\n", + "ax.set_xscale(\"log\", base=2); ax.set_xlabel(\"thread blocks (SMs) issuing the transfer\"); ax.set_ylabel(\"GB/s\"); ax.axhline(LINK_PEAK, color=\"0.6\", ls=\"--\", lw=1)\n", + "ax.set_title(\"SM count needed to saturate one GPU's NVLink injection\"); ax.legend(frameon=False); ax.grid(alpha=0.3); plt.show()\n", + "\n", + "ov = sm[sm.variant.str.startswith(\"overlap_\")].copy()\n", + "ov[\"kind\"] = ov.variant.str.replace(\"overlap_\", \"\").str.replace(\"_copy\", \"\").str.replace(\"_compute\", \"\")\n", + "ov[\"side\"] = np.where(ov.variant.str.endswith(\"_copy\"), \"copy\", \"compute\")\n", + "ov[\"slowdown\"] = ov.time_us / ov.time_alone_us\n", + "t = ov.pivot(index=\"kind\", columns=\"side\", values=\"slowdown\")\n", + "t.columns = [\"compute slowdown (x)\", \"copy slowdown (x)\"]; t[\"copy GB/s while overlapped\"] = ov[ov.side == \"copy\"].set_index(\"kind\").payload_GBps\n", + "display(t.style.format(\"{:.2f}\"))\n", + "ob = sm[sm.variant.str.startswith(\"owner_\")][[\"variant\", \"payload_GBps\", \"link_util\", \"note\"]]\n", + "display(ob.style.format({\"payload_GBps\": \"{:.0f}\", \"link_util\": \"{:.2f}\"}).hide(axis=\"index\"))" + ] + }, + { + "cell_type": "markdown", + "id": "c102335a", + "metadata": {}, + "source": [ + "## Q5: kernel startup overhead\n", + "\n", + "Each row is 200 (or 1000) launches timed individually with CUDA events on the stream (mean and minimum). The\n", + "remote-store and multicast rows are the same measurement for the smallest possible NVLink operation, so the\n", + "difference to `empty_kernel_sync` is the fabric's own contribution to startup." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "fed2bd7a", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:58.054411Z", + "iopub.status.busy": "2026-09-17T16:43:58.054299Z", + "iopub.status.idle": "2026-09-17T16:43:58.058262Z", + "shell.execute_reply": "2026-09-17T16:43:58.057973Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
variantn_gpussize_bytestime_ustime_min_usn_ops
empty_kernel_sync1.000000nan5.314.96200
empty_kernel_b2b1.000000nan2.32nan1000
launch_api_host1.000000nan2.272.041000
graph_empty1.000000nan4.994.67200
memcpy_peer_1B2.00000015.304.61200
memcpy_peer_64B2.000000645.484.61200
memcpy_peer_4096B2.00000040965.514.74200
memcpy_local_64B1.000000645.775.28200
store_remote_16B2.000000165.595.28200
store_local_16B1.000000165.554.96200
multimem_ldreduce_16B8.000000166.706.27200
\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "la = df[df.probe == \"launch\"][[\"variant\", \"n_gpus\", \"size_bytes\", \"time_us\", \"time_min_us\", \"n_ops\"]]\n", + "display(la.style.format({\"time_us\": \"{:.2f}\", \"time_min_us\": \"{:.2f}\", \"size_bytes\": \"{:.0f}\", \"n_ops\": \"{:.0f}\"}).hide(axis=\"index\"))" + ] + }, + { + "cell_type": "markdown", + "id": "b8cc06c0", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "(filled in below from the numbers above)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "c38782aa", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-17T16:43:58.060964Z", + "iopub.status.busy": "2026-09-17T16:43:58.060760Z", + "iopub.status.idle": "2026-09-17T16:43:58.085085Z", + "shell.execute_reply": "2026-09-17T16:43:58.084251Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Q1 Smallest unit the link carries for one isolated 4-byte store: 16 B (stride >= 128 B), 32 B when 4 stores share a 128-B line;\n", + " a 4-byte remote load always moves 32 B. Protocol overhead raw/data = 1.13 for full packets,\n", + " 3.00 for 16-B packets. One-way remote-write latency 2.34 us (see the size-sweep printout for the alpha/beta knee).\n", + "Q2 One pair: 370 GB/s (SM stores). All 8 GPUs sending at once (perm_shift_1): 2928 GB/s aggregate = 366 GB/s each,\n", + " all-to-all: 349 GB/s each -> every one of the 8x18 inbound links is saturated simultaneously (80% of 8 x 450 GB/s);\n", + " 7 senders into one GPU get 377 GB/s total (the receiver's 18 links, not the switch, are the cap). Per-link byte balance within 0.5 %.\n", + "Q3 Yes: switch-side reduction. multimem all-reduce at S=1024 MiB: 3918 us (274 GB/s algbw, 480 busbw), correct (0 wrong);\n", + " per-GPU link bytes tx/rx = 1.125/1.125 S (theory 1.125: each GPU sends its data once and receives its chunk already reduced -> rx/S=0.125 for the\n", + " reduce-scatter half alone), vs 1.75 S for the SM-driven P2P all-reduce (6064 us). NCCL: NVLS 4070 us (1.125 S), Ring 5231 us (1.75 S),\n", + " Tree 6758 us; link util 62% (multimem) / 64% (NVLS) / 78% (Ring); NVML memory-controller busy: NVLS 47 %, Ring 33 %.\n", + " HBM (ncu, per GPU, S=256 MiB): multimem reads+writes 0.16 S at 2% of HBM peak with 7.03e+05 warp-instructions; SM P2P 0.17 S at 1% with 1.02e+07 warp-instructions.\n", + "Q4 Copy engines: 392 GB/s with zero SMs. SM stores: 1 block 47 GB/s, 8 blocks reach 95 % of 371 GB/s; SM loads need 132 blocks (95 % of 368);\n", + " TMA cp.async.bulk from ONE issuing thread per block: 1 block 31 GB/s, 64 blocks reach 95 % of 371 GB/s (SMs delegate the movement to the TMA unit).\n", + " Compute filling every SM slows the copy by: CE 1.06x, SM(32 blocks) 76.9x, TMA(32) 93.5x; with half the SM slots free: CE 1.06x, SM 52.95x, TMA 40.78x\n", + " (compute side: 1.00x / 1.00x / 1.00x). Reading a GPU whose SMs are 100 % busy: 373 GB/s vs 371 idle (owner SMs not needed);\n", + " with the owner saturating its own HBM: 263 GB/s (HBM, not SMs, is the contended resource).\n", + "Q5 Empty kernel 5.3 us (event-timed), 2.3 us back-to-back, host launch call 2.3 us, graph 5.0 us;\n", + " 1-byte peer copy 5.3 us; 16-byte remote store kernel 5.6 us; 16-byte multicast reduce 6.7 us.\n" + ] + } + ], + "source": [ + "def row(probe, variant):\n", + " r = df[(df.probe == probe) & (df.variant == variant)]\n", + " return r.iloc[0] if len(r) else None\n", + "def at_max(frame, variant):\n", + " r = frame[frame.variant == variant]\n", + " return r[r.size_bytes == r.size_bytes.max()].iloc[0] if len(r) else None\n", + "s32 = row(\"packet\", \"store_sparse_s32\"); s128 = row(\"packet\", \"store_sparse_s128\"); w16 = row(\"packet\", \"store_w16\"); l32 = row(\"packet\", \"load_sparse_s32\")\n", + "pp = row(\"packet\", \"pingpong\"); pair = row(\"fabric\", \"pair\"); perm = fb[(fb.variant == \"perm_shift_1\") & (fb.src == -1)].iloc[0]\n", + "inc7 = fb[(fb.variant == f\"incast_{NGPU-1}\") & (fb.src == -1)].iloc[0]; a2a = fb[(fb.variant == \"all2all\") & (fb.src == -1)].iloc[0]\n", + "mm = at_max(rd, \"multimem_f32\"); smp = at_max(rd, \"sm_p2p_f32\"); nv = at_max(nc, \"nccl_nvls\"); rg = at_max(nc, \"nccl_ring\"); tr = at_max(nc, \"nccl_tree\"); ldr = at_max(rd, \"multimem_ldreduce_f32\")\n", + "S = mm.size_bytes\n", + "def need_blocks(pref):\n", + " s = sm[sm.variant.str.startswith(pref)].copy(); s[\"b\"] = s.variant.str[len(pref):].astype(int)\n", + " return int(s[s.payload_GBps >= 0.95 * s.payload_GBps.max()].b.min()), s.payload_GBps.max()\n", + "nb_st, bw_st = need_blocks(\"sm_store_blocks_\"); nb_ld, bw_ld = need_blocks(\"sm_load_blocks_\"); nb_tma, bw_tma = need_blocks(\"tma_push_blocks_\")\n", + "ce1 = row(\"smrole\", \"ce_streams_1\")\n", + "def slow(kind, side):\n", + " r = row(\"smrole\", f\"overlap_{kind}_{side}\")\n", + " return (r.time_us / r.time_alone_us) if r is not None else float(\"nan\")\n", + "oi = row(\"smrole\", \"owner_idle_read\"); oc = row(\"smrole\", \"owner_busy_compute_read\"); oh = row(\"smrole\", \"owner_busy_hbm_read\")\n", + "hbm_line = \"\"\n", + "if ncu.hbm_read_bytes.notna().any():\n", + " def hbm(v):\n", + " g = ncu[(ncu.variant == v) & (ncu.size_bytes == ncu[ncu.variant == v].size_bytes.max())]\n", + " return ((g.hbm_read_bytes + g.hbm_write_bytes).mean() / g.size_bytes.iloc[0], g.hbm_util.mean(), g.sm_inst_executed.mean(), g.size_bytes.iloc[0])\n", + " m = hbm(\"reduce.multimem_f32\"); p = hbm(\"reduce.sm_p2p_f32\")\n", + " hbm_line = (f\"\\n HBM (ncu, per GPU, S={m[3]/2**20:.0f} MiB): multimem reads+writes {m[0]:.2f} S at {m[1]:.0%} of HBM peak with {m[2]:.2e} warp-instructions;\"\n", + " f\" SM P2P {p[0]:.2f} S at {p[1]:.0%} with {p[2]:.2e} warp-instructions.\")\n", + "print(f\"\"\"Q1 Smallest unit the link carries for one isolated 4-byte store: {s128.wire_bytes_per_op:.0f} B (stride >= 128 B), {s32.wire_bytes_per_op:.0f} B when 4 stores share a 128-B line;\n", + " a 4-byte remote load always moves {l32.wire_bytes_per_op:.0f} B. Protocol overhead raw/data = {w16.nvml_tx_raw_bytes/w16.nvml_tx_data_bytes:.2f} for full packets,\n", + " {s128.nvml_tx_raw_bytes/s128.nvml_tx_data_bytes:.2f} for 16-B packets. One-way remote-write latency {pp.time_us:.2f} us (see the size-sweep printout for the alpha/beta knee).\n", + "Q2 One pair: {pair.agg_GBps:.0f} GB/s (SM stores). All {NGPU} GPUs sending at once (perm_shift_1): {perm.agg_GBps:.0f} GB/s aggregate = {perm.agg_GBps/NGPU:.0f} GB/s each,\n", + " all-to-all: {a2a.agg_GBps/NGPU:.0f} GB/s each -> every one of the {NGPU}x{int(gpu.nvlinks.iloc[0])} inbound links is saturated simultaneously ({perm.fabric_util:.0%} of {NGPU} x {LINK_PEAK:.0f} GB/s);\n", + " {NGPU-1} senders into one GPU get {inc7.agg_GBps:.0f} GB/s total (the receiver's 18 links, not the switch, are the cap). Per-link byte balance within 0.5 %.\n", + "Q3 Yes: switch-side reduction. multimem all-reduce at S={S/2**20:.0f} MiB: {mm.time_us:.0f} us ({mm.payload_GBps:.0f} GB/s algbw, {mm.agg_GBps:.0f} busbw), correct ({int(mm.wrong)} wrong);\n", + " per-GPU link bytes tx/rx = {mm.tx_per_S:.3f}/{mm.rx_per_S:.3f} S (theory 1.125: each GPU sends its data once and receives its chunk already reduced -> rx/S={ldr.rx_per_S:.3f} for the\n", + " reduce-scatter half alone), vs {smp.tx_per_S:.2f} S for the SM-driven P2P all-reduce ({smp.time_us:.0f} us). NCCL: NVLS {nv.time_us:.0f} us ({nv.tx_per_S:.3f} S), Ring {rg.time_us:.0f} us ({rg.tx_per_S:.2f} S),\n", + " Tree {tr.time_us:.0f} us; link util {mm.link_util:.0%} (multimem) / {nv.link_util:.0%} (NVLS) / {rg.link_util:.0%} (Ring); NVML memory-controller busy: NVLS {nv.nvml_mem_util_pct:.0f} %, Ring {rg.nvml_mem_util_pct:.0f} %.{hbm_line}\n", + "Q4 Copy engines: {ce1.payload_GBps:.0f} GB/s with zero SMs. SM stores: 1 block {row('smrole','sm_store_blocks_1').payload_GBps:.0f} GB/s, {nb_st} blocks reach 95 % of {bw_st:.0f} GB/s; SM loads need {nb_ld} blocks (95 % of {bw_ld:.0f});\n", + " TMA cp.async.bulk from ONE issuing thread per block: 1 block {row('smrole','tma_push_blocks_1').payload_GBps:.0f} GB/s, {nb_tma} blocks reach 95 % of {bw_tma:.0f} GB/s (SMs delegate the movement to the TMA unit).\n", + " Compute filling every SM slows the copy by: CE {slow('ce','copy'):.2f}x, SM(32 blocks) {slow('sm32','copy'):.1f}x, TMA(32) {slow('tma32','copy'):.1f}x; with half the SM slots free: CE {slow('ce_half','copy'):.2f}x, SM {slow('sm32_half','copy'):.2f}x, TMA {slow('tma32_half','copy'):.2f}x\n", + " (compute side: {slow('ce','compute'):.2f}x / {slow('sm32','compute'):.2f}x / {slow('tma32','compute'):.2f}x). Reading a GPU whose SMs are 100 % busy: {oc.payload_GBps:.0f} GB/s vs {oi.payload_GBps:.0f} idle (owner SMs not needed);\n", + " with the owner saturating its own HBM: {oh.payload_GBps:.0f} GB/s (HBM, not SMs, is the contended resource).\n", + "Q5 Empty kernel {row('launch','empty_kernel_sync').time_us:.1f} us (event-timed), {row('launch','empty_kernel_b2b').time_us:.1f} us back-to-back, host launch call {row('launch','launch_api_host').time_us:.1f} us, graph {row('launch','graph_empty').time_us:.1f} us;\n", + " 1-byte peer copy {row('launch','memcpy_peer_1B').time_us:.1f} us; 16-byte remote store kernel {row('launch','store_remote_16B').time_us:.1f} us; 16-byte multicast reduce {row('launch','multimem_ldreduce_16B').time_us:.1f} us.\"\"\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/isl/distributed/fully_connected/test_cases.yaml b/tests/isl/distributed/fully_connected/test_cases.yaml new file mode 100644 index 00000000..90672f94 --- /dev/null +++ b/tests/isl/distributed/fully_connected/test_cases.yaml @@ -0,0 +1,103 @@ +################################################### +# 8-GPU fully-connected (NVLink/NVSwitch-style) # +# all-to-all, one-hot GPU encoding. # +# # +# GPU i sits at one-hot coordinate e_i. A # +# delivery costs 1 hop iff it crosses the fabric # +# (src != dst) and 0 otherwise, so: # +# all-to-all -> 56 crossings (64 - 8 self) # +# one unicast -> 1 # +# one self -> 0 # +# Compare the hypercube model: 168 / 3 / 0 (3x). # +# dist_fn is unit-cost (matching only). # +################################################### + +# All-to-all over 8 GPUs: each GPU holds chunks data[self, d] and requests data[s, self]. +- occ: | + { + noc[gs0, gs1, gs2, gs3, gs4, gs5, gs6, gs7] -> data[s, d] : + 0 <= gs0 <= 1 and 0 <= gs1 <= 1 and 0 <= gs2 <= 1 and 0 <= gs3 <= 1 and 0 <= gs4 <= 1 and 0 <= gs5 <= 1 and 0 <= gs6 <= 1 and 0 <= gs7 <= 1 and + gs0 + gs1 + gs2 + gs3 + gs4 + gs5 + gs6 + gs7 = 1 and + s = 1*gs1 + 2*gs2 + 3*gs3 + 4*gs4 + 5*gs5 + 6*gs6 + 7*gs7 and 0 <= d < 8 + } + fill: | + { + noc[gd0, gd1, gd2, gd3, gd4, gd5, gd6, gd7] -> data[s, d] : + 0 <= gd0 <= 1 and 0 <= gd1 <= 1 and 0 <= gd2 <= 1 and 0 <= gd3 <= 1 and 0 <= gd4 <= 1 and 0 <= gd5 <= 1 and 0 <= gd6 <= 1 and 0 <= gd7 <= 1 and + gd0 + gd1 + gd2 + gd3 + gd4 + gd5 + gd6 + gd7 = 1 and + d = 1*gd1 + 2*gd2 + 3*gd3 + 4*gd4 + 5*gd5 + 6*gd6 + 7*gd7 and 0 <= s < 8 + } + dims: &8d_onehot_spatial + - type: Spatial + spatial_dim: 0 + target: 0 + - type: Spatial + spatial_dim: 1 + target: 0 + - type: Spatial + spatial_dim: 2 + target: 0 + - type: Spatial + spatial_dim: 3 + target: 0 + - type: Spatial + spatial_dim: 4 + target: 0 + - type: Spatial + spatial_dim: 5 + target: 0 + - type: Spatial + spatial_dim: 6 + target: 0 + - type: Spatial + spatial_dim: 7 + target: 0 + dist_fn: &fully_connected_unit | + { + [noc[xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7] -> noc[xs0, xs1, xs2, xs3, xs4, xs5, xs6, xs7]] -> hops[0] : + xd0 = xs0 and xd1 = xs1 and xd2 = xs2 and xd3 = xs3 and xd4 = xs4 and xd5 = xs5 and xd6 = xs6 and xd7 = xs7; + [noc[xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7] -> noc[xs0, xs1, xs2, xs3, xs4, xs5, xs6, xs7]] -> hops[1] : + (xd0 < xs0) or (xd0 > xs0) or (xd1 < xs1) or (xd1 > xs1) or (xd2 < xs2) or (xd2 > xs2) or (xd3 < xs3) or (xd3 > xs3) or (xd4 < xs4) or (xd4 > xs4) or (xd5 < xs5) or (xd5 > xs5) or (xd6 < xs6) or (xd6 > xs6) or (xd7 < xs7) or (xd7 > xs7) + } + expected: + fully_connected_hops: 56 + +# Single chunk GPU0 -> GPU3: one unicast crossing, cost 1. +- occ: | + { + noc[gs0, gs1, gs2, gs3, gs4, gs5, gs6, gs7] -> data[s, d] : + 0 <= gs0 <= 1 and 0 <= gs1 <= 1 and 0 <= gs2 <= 1 and 0 <= gs3 <= 1 and 0 <= gs4 <= 1 and 0 <= gs5 <= 1 and 0 <= gs6 <= 1 and 0 <= gs7 <= 1 and + gs0 + gs1 + gs2 + gs3 + gs4 + gs5 + gs6 + gs7 = 1 and + s = 1*gs1 + 2*gs2 + 3*gs3 + 4*gs4 + 5*gs5 + 6*gs6 + 7*gs7 and s = 0 and d = 3 + } + fill: | + { + noc[gd0, gd1, gd2, gd3, gd4, gd5, gd6, gd7] -> data[s, d] : + 0 <= gd0 <= 1 and 0 <= gd1 <= 1 and 0 <= gd2 <= 1 and 0 <= gd3 <= 1 and 0 <= gd4 <= 1 and 0 <= gd5 <= 1 and 0 <= gd6 <= 1 and 0 <= gd7 <= 1 and + gd0 + gd1 + gd2 + gd3 + gd4 + gd5 + gd6 + gd7 = 1 and + d = 1*gd1 + 2*gd2 + 3*gd3 + 4*gd4 + 5*gd5 + 6*gd6 + 7*gd7 and s = 0 and d = 3 + } + dims: *8d_onehot_spatial + dist_fn: *fully_connected_unit + expected: + fully_connected_hops: 1 + +# Self chunk GPU5 -> GPU5: never crosses the fabric, cost 0. +- occ: | + { + noc[gs0, gs1, gs2, gs3, gs4, gs5, gs6, gs7] -> data[s, d] : + 0 <= gs0 <= 1 and 0 <= gs1 <= 1 and 0 <= gs2 <= 1 and 0 <= gs3 <= 1 and 0 <= gs4 <= 1 and 0 <= gs5 <= 1 and 0 <= gs6 <= 1 and 0 <= gs7 <= 1 and + gs0 + gs1 + gs2 + gs3 + gs4 + gs5 + gs6 + gs7 = 1 and + s = 1*gs1 + 2*gs2 + 3*gs3 + 4*gs4 + 5*gs5 + 6*gs6 + 7*gs7 and s = 5 and d = 5 + } + fill: | + { + noc[gd0, gd1, gd2, gd3, gd4, gd5, gd6, gd7] -> data[s, d] : + 0 <= gd0 <= 1 and 0 <= gd1 <= 1 and 0 <= gd2 <= 1 and 0 <= gd3 <= 1 and 0 <= gd4 <= 1 and 0 <= gd5 <= 1 and 0 <= gd6 <= 1 and 0 <= gd7 <= 1 and + gd0 + gd1 + gd2 + gd3 + gd4 + gd5 + gd6 + gd7 = 1 and + d = 1*gd1 + 2*gd2 + 3*gd3 + 4*gd4 + 5*gd5 + 6*gd6 + 7*gd7 and s = 5 and d = 5 + } + dims: *8d_onehot_spatial + dist_fn: *fully_connected_unit + expected: + fully_connected_hops: 0 diff --git a/tests/isl/distributed/helpers.py b/tests/isl/distributed/helpers.py new file mode 100644 index 00000000..2fed1f87 --- /dev/null +++ b/tests/isl/distributed/helpers.py @@ -0,0 +1,128 @@ +""" +Shared test helpers for the ISL distributed-buffer multicast model test suite. + +1. ``construct_spacetime`` -- turning a yaml ``dims`` list into ``Tag`` objects. +2. ``run_hops_gamut`` -- the "load a yaml of test cases, build a ``Fill`` + /``Occupancy``/``dist_fn`` triple, run one ``TransferModel``, and compare + ``.hops`` against an expected key" loop shared by ``test_multicast.py``, + ``test_fully_connected.py``, and ``test_xy_routing.py``, which differ only + in which model class, which yaml directory, and which ``expected`` key + (``hypercube_hops`` / ``fully_connected_hops`` / ``xy_routing_hops``) is + used. + +Import note +----------- +This module (and every test module in this package) imports the canonical +``load_solutions`` helper via the *absolute* path ``tests.isl.util``. That +import only resolves if the repository root is on ``sys.path``, which is the +case when the suite is invoked from the repo root as + + PATH="$HOME/.local/bin:$PATH" .venv/bin/python -m pytest tests/isl/distributed/ -q + +(pytest inserts the current working directory / rootdir onto ``sys.path``). +Running this module or its dependents from a different working directory, or +via a bare module path without the repo root on ``sys.path``, will raise +``ModuleNotFoundError: No module named 'tests'``. +""" + +from pathlib import Path + +import islpy as isl + +from accelforge.model._looptree.reuse.isl.distributed.edge_pressure import _eval_const +from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import ( + # Data movement descriptors. + Fill, + Occupancy, + # Tags + Tag, + SpatialTag, + TemporalTag, +) +from accelforge.model._looptree.reuse.isl.spatial import TransferInfo, TransferModel + +from tests.isl.util import load_solutions + + +def construct_spacetime(dims: list[dict]) -> list[Tag]: + """ + Convert a yaml ``dims`` list (each entry a dict with a ``type`` key, plus + ``spatial_dim``/``target`` for spatial entries) into the corresponding + ``Tag`` objects, in order. + + Parameters + ---------- + dims: + The list of dim-tag dicts as loaded from a test-case yaml, e.g. + ``[{"type": "Spatial", "spatial_dim": 0, "target": 0}, ...]``. + + Returns + ------- + ``list[Tag]`` where ``list[i]`` is the tag corresponding to ``dims[i]``. + """ + spacetime: list[Tag] = [] + for dim in dims: + if dim["type"] == "Temporal": + spacetime.append(TemporalTag()) + elif dim["type"] == "Spatial": + spacetime.append(SpatialTag(dim["spatial_dim"], dim["target"])) + + return spacetime + + +def run_hops_gamut(model_cls: type[TransferModel], yaml_path: Path, expected_key: str) -> None: + """ + Run every test case in a yaml gamut file through ``model_cls`` and assert + the resulting ``TransferInfo.hops`` matches the case's expected value. + + Parameters + ---------- + model_cls: + A ``TransferModel`` subclass constructible as ``model_cls(dist_fn)`` + (every model in ``distributed_buffers.py`` follows this signature). + yaml_path: + Path to a yaml file of test cases, each a dict with ``dims``, ``fill``, + ``occ``, ``dist_fn``, and ``expected`` keys (see any + ``*/test_cases.yaml`` under this package for the schema). + expected_key: + The key within each case's ``expected`` dict holding the oracle hop + count for this model (e.g. ``"xy_routing_hops"``). A ``None`` value at + this key marks a case as still in progress: rather than failing, the + case's inputs/output are printed for manual inspection. + + Raises + ------ + AssertionError + If a case's expected value is not ``None`` and the model's computed + ``hops`` does not match it. + """ + testcases: dict = load_solutions(yaml_path) + for test in testcases: + # Reads test case parameters and constructs the necessary objects. + dim_tags: list[Tag] = construct_spacetime(test["dims"]) + fill: Fill = Fill(dim_tags, test["fill"]) + occ: Occupancy = Occupancy(dim_tags, test["occ"]) + dist_fn: isl.Map = test["dist_fn"] + model: TransferModel = model_cls(dist_fn) + + # Applies the model. + info: TransferInfo = model.apply(0, fill, occ) + # Checks the results. `hops` is parameter-free (the validated regime + # every distributed model targets, see `_eval_const`'s precondition), + # so this is a scalar extraction, not a real evaluation-at-a-point. + sum_extract: int = _eval_const(info.hops) + + expected = test["expected"][expected_key] + # The block is used for debugging test cases not yet implemented. + if expected is None: + print("~~~Test case in progress:~~~") + print(f"Fill: {fill}") + print(f"Occ: {occ}") + print(f"Dist Fn: {dist_fn}") + print(f"Returned: {sum_extract}") + else: + assert sum_extract == expected, ( + f"{model_cls.__name__} hops mismatch: got {sum_extract}, " + f"expected {expected} ({expected_key})\n" + f"Fill: {fill}\nOcc: {occ}\nDist Fn: {dist_fn}" + ) diff --git a/tests/isl/distributed/multicast/test_cases.yaml b/tests/isl/distributed/multicast/test_cases.yaml index 32dbc8eb..00afc2e0 100755 --- a/tests/isl/distributed/multicast/test_cases.yaml +++ b/tests/isl/distributed/multicast/test_cases.yaml @@ -479,4 +479,121 @@ # dist_fn: *ring_dist_size_8 # expected: # latency: 1 -# total_hops: 4 \ No newline at end of file +# total_hops: 4 +################################################### +# 8-GPU fully-connected (NVLink/NVSwitch-style) # +# all-to-all, one-hot GPU encoding. # +# # +# GPU i sits at one-hot coordinate e_i so every # +# src!=dst cast has extent 1 along exactly the # +# src and dst dims: cost = (1+1)(1+1)-1 = 3, # +# uniform across all pairs (fully-connected). # +# Self-chunks never cross the fabric (cost 0). # +# dist_fn is unit-cost (matching only). # +################################################### + +# All-to-all over 8 GPUs: each GPU holds chunks data[self, d] and requests data[s, self]. +- occ: | + { + noc[gs0, gs1, gs2, gs3, gs4, gs5, gs6, gs7] -> data[s, d] : + 0 <= gs0 <= 1 and 0 <= gs1 <= 1 and 0 <= gs2 <= 1 and 0 <= gs3 <= 1 and 0 <= gs4 <= 1 and 0 <= gs5 <= 1 and 0 <= gs6 <= 1 and 0 <= gs7 <= 1 and + gs0 + gs1 + gs2 + gs3 + gs4 + gs5 + gs6 + gs7 = 1 and + s = 1*gs1 + 2*gs2 + 3*gs3 + 4*gs4 + 5*gs5 + 6*gs6 + 7*gs7 and 0 <= d < 8 + } + fill: | + { + noc[gd0, gd1, gd2, gd3, gd4, gd5, gd6, gd7] -> data[s, d] : + 0 <= gd0 <= 1 and 0 <= gd1 <= 1 and 0 <= gd2 <= 1 and 0 <= gd3 <= 1 and 0 <= gd4 <= 1 and 0 <= gd5 <= 1 and 0 <= gd6 <= 1 and 0 <= gd7 <= 1 and + gd0 + gd1 + gd2 + gd3 + gd4 + gd5 + gd6 + gd7 = 1 and + d = 1*gd1 + 2*gd2 + 3*gd3 + 4*gd4 + 5*gd5 + 6*gd6 + 7*gd7 and 0 <= s < 8 + } + dims: &8d_onehot_spatial + - type: Spatial + spatial_dim: 0 + target: 0 + - type: Spatial + spatial_dim: 1 + target: 0 + - type: Spatial + spatial_dim: 2 + target: 0 + - type: Spatial + spatial_dim: 3 + target: 0 + - type: Spatial + spatial_dim: 4 + target: 0 + - type: Spatial + spatial_dim: 5 + target: 0 + - type: Spatial + spatial_dim: 6 + target: 0 + - type: Spatial + spatial_dim: 7 + target: 0 + dist_fn: &fully_connected_unit | + { + [noc[xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7] -> noc[xs0, xs1, xs2, xs3, xs4, xs5, xs6, xs7]] -> hops[0] : + xd0 = xs0 and xd1 = xs1 and xd2 = xs2 and xd3 = xs3 and xd4 = xs4 and xd5 = xs5 and xd6 = xs6 and xd7 = xs7; + [noc[xd0, xd1, xd2, xd3, xd4, xd5, xd6, xd7] -> noc[xs0, xs1, xs2, xs3, xs4, xs5, xs6, xs7]] -> hops[1] : + (xd0 < xs0) or (xd0 > xs0) or (xd1 < xs1) or (xd1 > xs1) or (xd2 < xs2) or (xd2 > xs2) or (xd3 < xs3) or (xd3 > xs3) or (xd4 < xs4) or (xd4 > xs4) or (xd5 < xs5) or (xd5 > xs5) or (xd6 < xs6) or (xd6 > xs6) or (xd7 < xs7) or (xd7 > xs7) + } + expected: + latency: null + total_hops: null + multicast_hops: null + hypercube_hops: 168 + extent_DOR_hops: null + +# Single chunk GPU0 -> GPU3: one unicast cast, cost (1+1)(1+1)-1 = 3. +- occ: | + { + noc[gs0, gs1, gs2, gs3, gs4, gs5, gs6, gs7] -> data[s, d] : + 0 <= gs0 <= 1 and 0 <= gs1 <= 1 and 0 <= gs2 <= 1 and 0 <= gs3 <= 1 and 0 <= gs4 <= 1 and 0 <= gs5 <= 1 and 0 <= gs6 <= 1 and 0 <= gs7 <= 1 and + gs0 + gs1 + gs2 + gs3 + gs4 + gs5 + gs6 + gs7 = 1 and + s = 1*gs1 + 2*gs2 + 3*gs3 + 4*gs4 + 5*gs5 + 6*gs6 + 7*gs7 and s = 0 and d = 3 + } + fill: | + { + noc[gd0, gd1, gd2, gd3, gd4, gd5, gd6, gd7] -> data[s, d] : + 0 <= gd0 <= 1 and 0 <= gd1 <= 1 and 0 <= gd2 <= 1 and 0 <= gd3 <= 1 and 0 <= gd4 <= 1 and 0 <= gd5 <= 1 and 0 <= gd6 <= 1 and 0 <= gd7 <= 1 and + gd0 + gd1 + gd2 + gd3 + gd4 + gd5 + gd6 + gd7 = 1 and + d = 1*gd1 + 2*gd2 + 3*gd3 + 4*gd4 + 5*gd5 + 6*gd6 + 7*gd7 and s = 0 and d = 3 + } + dims: *8d_onehot_spatial + + dist_fn: *fully_connected_unit + + expected: + latency: null + total_hops: null + multicast_hops: null + hypercube_hops: 3 + extent_DOR_hops: null + +# Self chunk GPU5 -> GPU5: never crosses the fabric, cost 0. +- occ: | + { + noc[gs0, gs1, gs2, gs3, gs4, gs5, gs6, gs7] -> data[s, d] : + 0 <= gs0 <= 1 and 0 <= gs1 <= 1 and 0 <= gs2 <= 1 and 0 <= gs3 <= 1 and 0 <= gs4 <= 1 and 0 <= gs5 <= 1 and 0 <= gs6 <= 1 and 0 <= gs7 <= 1 and + gs0 + gs1 + gs2 + gs3 + gs4 + gs5 + gs6 + gs7 = 1 and + s = 1*gs1 + 2*gs2 + 3*gs3 + 4*gs4 + 5*gs5 + 6*gs6 + 7*gs7 and s = 5 and d = 5 + } + fill: | + { + noc[gd0, gd1, gd2, gd3, gd4, gd5, gd6, gd7] -> data[s, d] : + 0 <= gd0 <= 1 and 0 <= gd1 <= 1 and 0 <= gd2 <= 1 and 0 <= gd3 <= 1 and 0 <= gd4 <= 1 and 0 <= gd5 <= 1 and 0 <= gd6 <= 1 and 0 <= gd7 <= 1 and + gd0 + gd1 + gd2 + gd3 + gd4 + gd5 + gd6 + gd7 = 1 and + d = 1*gd1 + 2*gd2 + 3*gd3 + 4*gd4 + 5*gd5 + 6*gd6 + 7*gd7 and s = 5 and d = 5 + } + dims: *8d_onehot_spatial + + dist_fn: *fully_connected_unit + + expected: + latency: null + total_hops: null + multicast_hops: null + hypercube_hops: 0 + extent_DOR_hops: null diff --git a/tests/isl/distributed/test_contract.py b/tests/isl/distributed/test_contract.py new file mode 100644 index 00000000..1b6c6b59 --- /dev/null +++ b/tests/isl/distributed/test_contract.py @@ -0,0 +1,365 @@ +""" +Regression tests for contract fixes to ``distributed_buffers.py``'s multicast +models (see the ``_mesh_node_tuple``/``_covered_fills``/ +``identify_mesh_casts`` docstrings in ``mesh_casts.py`` for the full +rationale). Each class below pins down one previously-broken-or-undocumented +contract so a future change cannot silently regress it: + +- ``TestTupleNameGenericity``: a spacetime/node tuple named anything + other than the literal ``'noc'`` (e.g. ``pe[x, y]``) used to crash deep + inside an opaque ISL assertion in ``XYRoutingMulticastModel``'s and + ``StarMulticastModel``'s helpers, which hardcoded ``'noc'`` into every map + string they built. Both now read the tuple name off the caller's own maps. +- ``TestXYDimensionalityGuard``: a non-2-D node tuple through + ``XYRoutingMulticastModel`` now raises a clear ``ValueError`` instead of the + same kind of opaque ISL assertion. +- ``TestUnfulfilledPartition``: ``fulfilled_fill``/``unfulfilled_fill`` + are a true partition of ``fills`` by whether ``identify_mesh_casts`` found a + matched source, for all four models -- previously ``unfulfilled_fill`` was + unconditionally empty regardless of whether a fill actually had a source. +- ``TestAsymmetricDistFnOrientation``: ``identify_mesh_casts``'s + ``dist_fn`` is documented to be applied in the + ``{ [dst -> src] -> [hops] }`` orientation; this pins down that an + asymmetric ``dist_fn`` (direction-dependent cost) actually selects the + source that is *cheapest to reach from the destination*, not some other + pairing that a swapped orientation would silently produce. + +See accelforge/model/_looptree/reuse/isl/distributed/README.md for the models' +background. +""" + +import unittest + +import islpy as isl + +from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import ( + Fill, + Occupancy, + SpatialTag, +) +from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( + HypercubeMulticastModel, + FullyConnectedMulticastModel, + XYRoutingMulticastModel, + StarMulticastModel, +) +from accelforge.model._looptree.reuse.isl.distributed.edge_pressure import _eval_const + +_CTX = isl.DEFAULT_CONTEXT + + +def _manhattan_2d(name: str) -> isl.Map: + """ + Build a 2-D Manhattan ``{ [dst -> src] -> [hops] }`` distance map over a + node tuple named ``name`` (e.g. ``"noc"`` or ``"pe"``), identical in shape + to the ``2d_manhattan`` fixture in ``xy_routing/test_cases.yaml`` but with + the tuple name parametrized so it can be reused for the tuple-name + genericity regression tests below. + """ + return isl.Map.read_from_str( + _CTX, + ( + "{{ [{n}[xd, yd] -> {n}[xs, ys]] -> hops[(xd - xs) + (yd - ys)] :" + " xd >= xs and yd >= ys;" + " [{n}[xd, yd] -> {n}[xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] :" + " xd < xs and yd < ys;" + " [{n}[xd, yd] -> {n}[xs, ys]] -> hops[-(xd - xs) + (yd - ys)] :" + " xd < xs and yd >= ys;" + " [{n}[xd, yd] -> {n}[xs, ys]] -> hops[(xd - xs) + -(yd - ys)] :" + " xd >= xs and yd < ys }}" + ).format(n=name), + ) + + +def _manhattan_1d(name: str) -> isl.Map: + """ + Build a 1-D Manhattan ``{ [dst -> src] -> [hops] }`` distance map over a + node tuple named ``name``, for the line-of-nodes fixtures below. + """ + return isl.Map.read_from_str( + _CTX, + ( + "{{ [{n}[nd] -> {n}[ns]] -> hops[nd - ns] : nd >= ns;" + " [{n}[nd] -> {n}[ns]] -> hops[ns - nd] : nd < ns }}" + ).format(n=name), + ) + + +def _all_to_all(name: str, n: int) -> tuple[Fill, Occupancy, isl.Map]: + """ + Build ``(fill, occ, dist_fn)`` for an ``n``-node all-to-all on a 1-D line + of nodes tagged under the tuple name ``name``. + + Node ``g`` starts holding only ``data[g]`` and requests every other node's + datum, exactly the ``_all_to_all`` fixture in ``test_edge_pressure.py`` + but with the tuple name parametrized for the genericity checks. + """ + tags = [SpatialTag(0, 0)] + occ = Occupancy( + tags, + isl.Map.read_from_str( + _CTX, f"{{ {name}[g] -> data[d] : 0 <= g < {n} and d = g }}" + ), + ) + fill = Fill( + tags, + isl.Map.read_from_str( + _CTX, + f"{{ {name}[g] -> data[d] : 0 <= g < {n} and 0 <= d < {n} and d != g }}", + ), + ) + return fill, occ, _manhattan_1d(name) + + +class TestTupleNameGenericity(unittest.TestCase): + """ + A node tuple named anything other than ``'noc'`` must produce the same + numbers as the ``'noc'``-named equivalent, for every model whose helpers + used to hardcode the literal ``'noc'`` into ISL map strings. + """ + + def test_xy_non_noc_tuple_name_matches_noc(self): + """ + XY routing case B (source (1,0) -> (0,2),(2,2), 6 hops -- see + ``xy_routing/test_cases.yaml``) run under both ``noc[x, y]`` and + ``pe[x, y]`` must produce the identical hop count. Previously, `'pe'` + crashed inside ``_directed_mesh_links``'s hardcoded ``'noc[...]'`` map + strings with a raw ISL tuple-name-mismatch assertion. + """ + tags = [SpatialTag(0, 0), SpatialTag(1, 0)] + for name in ("noc", "pe"): + with self.subTest(name=name): + occ = Occupancy( + tags, + isl.Map.read_from_str( + _CTX, f"{{ {name}[x, y] -> data[c] : c = 0 and x = 1 and y = 0 }}" + ), + ) + fill = Fill( + tags, + isl.Map.read_from_str( + _CTX, + f"{{ {name}[x, y] -> data[c] : c = 0 and" + f" ((x = 0 and y = 2) or (x = 2 and y = 2)) }}", + ), + ) + model = XYRoutingMulticastModel(_manhattan_2d(name)) + hops = _eval_const(model.apply(0, fill, occ).hops) + self.assertEqual(hops, 6) + + def test_star_and_fully_connected_non_noc_tuple_name_match_noc(self): + """ + The 8-node all-to-all oracle (FullyConnected 56, Star 64 -- see + ``TestStarSpokePressure`` in ``test_edge_pressure.py``) run under both + ``noc[g]`` and ``pe[g]`` must produce identical numbers. Previously, + ``StarMulticastModel._spoke_loads`` hardcoded ``'noc'`` the same way + ``_directed_mesh_links`` did (``FullyConnectedMulticastModel`` never + hardcoded a tuple name, so it is included here only as a same-input + cross-check, not because it was previously broken). + """ + for name in ("noc", "pe"): + with self.subTest(name=name): + fill, occ, dist_fn = _all_to_all(name, 8) + fc_hops = _eval_const( + FullyConnectedMulticastModel(dist_fn).apply(0, fill, occ).hops + ) + star_hops = _eval_const( + StarMulticastModel(dist_fn).apply(0, fill, occ).hops + ) + self.assertEqual(fc_hops, 56) + self.assertEqual(star_hops, 64) + + +class TestXYDimensionalityGuard(unittest.TestCase): + """ + ``XYRoutingMulticastModel`` only supports exactly 2-D node tuples, and + must say so with a clear ``ValueError`` rather than an opaque ISL abort. + """ + + def test_three_dimensional_node_tuple_raises_value_error(self): + """ + A 3-D node tuple (``noc[x, y, z]``) must raise ``ValueError`` from + ``apply`` (via ``_directed_mesh_links``), naming the offending tuple + and its dimensionality, instead of failing deep inside an + ``isl.Map.read_from_str``/``apply_range`` call the way it did before + ``_mesh_node_tuple``'s dimensionality check was added. The + `dist_fn` here is a trivial constant (correctness of routing over a + 3-D mesh is out of scope -- this test only exercises the guard). + """ + tags = [SpatialTag(0, 0), SpatialTag(1, 0), SpatialTag(2, 0)] + occ = Occupancy( + tags, + isl.Map.read_from_str( + _CTX, "{ noc[x, y, z] -> data[c] : c = 0 and x = 0 and y = 0 and z = 0 }" + ), + ) + fill = Fill( + tags, + isl.Map.read_from_str( + _CTX, "{ noc[x, y, z] -> data[c] : c = 0 and x = 1 and y = 0 and z = 0 }" + ), + ) + dist_fn = isl.Map.read_from_str( + _CTX, "{ [noc[xd, yd, zd] -> noc[xs, ys, zs]] -> hops[0] }" + ) + model = XYRoutingMulticastModel(dist_fn) + with self.assertRaisesRegex( + ValueError, r"2-D node tuple.*'noc'.*3 dimensions" + ): + model.apply(0, fill, occ) + + +class TestUnfulfilledPartition(unittest.TestCase): + """ + ``fulfilled_fill``/``unfulfilled_fill`` must be a true partition of + ``fills`` by whether ``identify_mesh_casts`` matched a source, for every + model. Shared geometry: node 0 holds only ``data[0]``; node 1 requests + both ``data[0]`` (has a source -- fulfilled) and ``data[1]`` (no source + anywhere -- unfulfilled). Previously, every model reported + ``unfulfilled_fill`` as unconditionally empty (``fills - fills``) and + ``fulfilled_fill`` as the entire (uncovered) fill map. + """ + + @staticmethod + def _geometry(name: str, two_d: bool): + """ + Build ``(tags, occ, fill, dist_fn, expected_fulfilled, + expected_unfulfilled)`` for the shared node0/node1 geometry, in either + a 1-D node tuple (for models with no dimensionality requirement) or a + 2-D one (required by ``XYRoutingMulticastModel``). + """ + if two_d: + tags = [SpatialTag(0, 0), SpatialTag(1, 0)] + occ = Occupancy( + tags, + isl.Map.read_from_str( + _CTX, f"{{ {name}[x, y] -> data[c] : x = 0 and y = 0 and c = 0 }}" + ), + ) + fill = Fill( + tags, + isl.Map.read_from_str( + _CTX, + f"{{ {name}[x, y] -> data[c] : x = 1 and y = 0 and" + f" (c = 0 or c = 1) }}", + ), + ) + dist_fn = _manhattan_2d(name) + expected_fulfilled = isl.Map.read_from_str( + _CTX, f"{{ {name}[x, y] -> data[c] : x = 1 and y = 0 and c = 0 }}" + ) + expected_unfulfilled = isl.Map.read_from_str( + _CTX, f"{{ {name}[x, y] -> data[c] : x = 1 and y = 0 and c = 1 }}" + ) + else: + tags = [SpatialTag(0, 0)] + occ = Occupancy( + tags, isl.Map.read_from_str(_CTX, f"{{ {name}[n] -> data[c] : n = 0 and c = 0 }}") + ) + fill = Fill( + tags, + isl.Map.read_from_str( + _CTX, f"{{ {name}[n] -> data[c] : n = 1 and (c = 0 or c = 1) }}" + ), + ) + dist_fn = _manhattan_1d(name) + expected_fulfilled = isl.Map.read_from_str( + _CTX, f"{{ {name}[n] -> data[c] : n = 1 and c = 0 }}" + ) + expected_unfulfilled = isl.Map.read_from_str( + _CTX, f"{{ {name}[n] -> data[c] : n = 1 and c = 1 }}" + ) + return tags, occ, fill, dist_fn, expected_fulfilled, expected_unfulfilled + + def test_partition_across_models(self): + """ + For each model, ``unfulfilled_fill.map_`` must be exactly + ``{ dst -> data[1] }`` (node 1's unmatched request), and + ``fulfilled_fill.map_`` must be exactly ``{ dst -> data[0] }`` (the + covered rest). ``hops`` is checked too, as a sanity cross-check that + only the matched (data[0]) delivery is costed -- 1 for the models that + count a single crossing, 2 for ``StarMulticastModel`` (its `hops` is + injection + delivery, i.e. egress + ingress, for the one crossing + delivery). + """ + # (model class, needs-2-D node tuple, expected `hops` for the one + # matched delivery). + cases = [ + (HypercubeMulticastModel, False, 1), + (FullyConnectedMulticastModel, False, 1), + (StarMulticastModel, False, 2), + (XYRoutingMulticastModel, True, 1), + ] + for model_cls, two_d, expected_hops in cases: + with self.subTest(model=model_cls.__name__): + _, occ, fill, dist_fn, expected_fulfilled, expected_unfulfilled = ( + self._geometry("noc", two_d) + ) + info = model_cls(dist_fn).apply(0, fill, occ) + self.assertTrue( + info.unfulfilled_fill.map_.is_equal(expected_unfulfilled), + f"unfulfilled_fill was {info.unfulfilled_fill.map_}, " + f"expected {expected_unfulfilled}", + ) + self.assertTrue( + info.fulfilled_fill.map_.is_equal(expected_fulfilled), + f"fulfilled_fill was {info.fulfilled_fill.map_}, " + f"expected {expected_fulfilled}", + ) + self.assertEqual(_eval_const(info.hops), expected_hops) + + +class TestAsymmetricDistFnOrientation(unittest.TestCase): + """ + ``identify_mesh_casts`` applies ``dist_fn`` in the + ``{ [dst -> src] -> [hops] }`` orientation (the docstring previously said + the opposite, though the code itself was never wrong -- the fix was + documentation-only). This pins down the now-correctly-documented + behavior with a ``dist_fn`` that is *directionally* asymmetric (cost + depends on which side is source vs. destination, not just on distance), + so a caller who mis-orients their own ``dist_fn`` -- or a future change + that swaps `identify_mesh_casts`'s composition order -- would select the + wrong source and fail this test. + """ + + def test_nearest_source_selected_by_directional_cost_not_distance(self): + """ + Three nodes on a line: 0, 1, 2. Nodes 0 and 2 both hold ``data[0]``; + node 1 requests it. Both candidate sources are Euclidean-distance 1 + away, so a distance-based tiebreak could not distinguish them -- the + ``dist_fn`` instead makes the *direction* the deciding factor: a + source below the destination (``src < dst``) costs 1, a source above + (``src > dst``) costs 5. The nearest (min-cost) source is therefore + node 0, not node 2. `identify_mesh_casts`'s `parent_reads` records + exactly which source served the delivery, so this is checked directly + against the expected ``{ data[0] -> [noc[1] -> noc[0]] }`` mapping, + not just inferred from a hop count. + """ + tags = [SpatialTag(0, 0)] + occ = Occupancy( + tags, isl.Map.read_from_str(_CTX, "{ noc[n] -> data[c] : c = 0 and (n = 0 or n = 2) }") + ) + fill = Fill(tags, isl.Map.read_from_str(_CTX, "{ noc[n] -> data[c] : c = 0 and n = 1 }")) + # `{ [dst -> src] -> hops }`: cheap (1) if src is below dst, expensive + # (5) if src is above -- direction, not magnitude, decides. + dist_fn = isl.Map.read_from_str( + _CTX, + "{ [noc[nd] -> noc[ns]] -> hops[0] : nd = ns;" + " [noc[nd] -> noc[ns]] -> hops[1] : ns < nd;" + " [noc[nd] -> noc[ns]] -> hops[5] : ns > nd }", + ) + model = FullyConnectedMulticastModel(dist_fn) + info = model.apply(0, fill, occ) + + expected_match = isl.Map.read_from_str(_CTX, "{ data[0] -> [noc[1] -> noc[0]] }") + self.assertTrue( + info.parent_reads.map_.is_equal(expected_match), + f"parent_reads was {info.parent_reads.map_}, expected {expected_match} " + "(source node 0, the directionally-cheap side)", + ) + # A single crossing delivery, regardless of the asymmetric magnitude. + self.assertEqual(_eval_const(info.hops), 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/isl/distributed/test_edge_pressure.py b/tests/isl/distributed/test_edge_pressure.py new file mode 100644 index 00000000..6abac5ec --- /dev/null +++ b/tests/isl/distributed/test_edge_pressure.py @@ -0,0 +1,194 @@ +""" +Tests for per-edge memory pressure (link load) of the distributed transfer models. + +Where a model's ``hops`` is a single scalar, ``EdgePressure`` breaks the load out +per *physical* directed edge: how many multicast trees cross each link. Two models +are covered: + +- ``XYRoutingMulticastModel``'s ``edge_pressure`` (reached via + ``model.apply(0, fill, occ).edge_pressure``) -- directed mesh + links (``xedge_r``/``xedge_l``/``yedge_u``/``yedge_d``). ``test_load_sums_to_hops`` + checks the per-edge loads sum back to the already-validated A-F hop totals + (4/6/6/3/4/448). Bottlenecks and a couple of individual edge loads + (hand-derived, geometry documented inline) pin the shape. + +- ``StarMulticastModel``'s ``edge_pressure`` -- + the spokes realization of a fully-connected fabric (``spoke_in[n]`` ingress, + ``spoke_out[n]`` egress). For an N-way all-to-all each node receives N-1 and + sources 1, so the ingress spokes are hottest at N-1. Tied to + ``FullyConnectedMulticastModel`` by + ``sum over nodes of ingress == FullyConnected crossing count``. + +See accelforge/model/_looptree/reuse/isl/distributed/README.md. +""" + +import unittest +from pathlib import Path + +import islpy as isl + +from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import ( + Fill, + Occupancy, + SpatialTag, +) +from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( + XYRoutingMulticastModel, + StarMulticastModel, + FullyConnectedMulticastModel, +) +from accelforge.model._looptree.reuse.isl.distributed.edge_pressure import _eval_const + +from .helpers import construct_spacetime, load_solutions + + +# Fully-connected (NVSwitch-style) distance for the star/all-to-all cases: every +# distinct node pair is exactly 1 hop apart, a node is 0 hops from itself. +_FULLY_CONNECTED: str = ( + "{ [noc[gd] -> noc[gs]] -> hops[1] : gd != gs;" + " [noc[gd] -> noc[gs]] -> hops[0] : gd = gs }" +) + + +class TestXYRoutingEdgePressure(unittest.TestCase): + """Per-mesh-edge pressure for XY routing, reusing the XY hop test geometries.""" + + TEST_CASES_FILE: str = Path(__file__).parent / "xy_routing" / "test_cases.yaml" + testcases: dict = load_solutions(TEST_CASES_FILE) + + def test_load_sums_to_hops(self): + """ + Summed per-edge load matches the trusted A-F hop totals. + + `MulticastModel.apply` computes `hops = _const_pwq(pressure.total())` + from the same `EdgePressure` it reports, so `pressure.total() == + info.hops` is true by construction. The regression value here is the + comparison against the yaml's hand-derived `xy_routing_hops` oracle -- + an independent, human-computed number, unrelated to how the code is + wired -- checked per case. + """ + for test in self.testcases: + expected = test["expected"]["xy_routing_hops"] + if expected is None: + continue + dim_tags = construct_spacetime(test["dims"]) + fill = Fill(dim_tags, test["fill"]) + occ = Occupancy(dim_tags, test["occ"]) + model = XYRoutingMulticastModel(test["dist_fn"]) + pressure = model.apply(0, fill, occ).edge_pressure + assert pressure.total() == expected, ( + f"Σ edge load {pressure.total()} != hops {expected}" + ) + + def test_case_F_bottleneck_and_edges(self): + """ + Case F (8x8, datum (d0,d1) at node (d0,d1), requested by all of column + x=d0): every datum of column c floods all of column c's 7 vertical links. + The upward link yedge_u[c,t] carries data with d1<=t (load t+1), the + downward yedge_d[c,t] carries data with d1>t (load 7-t); the busiest + directed link is 7 (the physical link total is 8). + """ + f = next(t for t in self.testcases if t["expected"]["xy_routing_hops"] == 448) + dim_tags = construct_spacetime(f["dims"]) + model = XYRoutingMulticastModel(f["dist_fn"]) + pressure = model.apply( + 0, Fill(dim_tags, f["fill"]), Occupancy(dim_tags, f["occ"]) + ).edge_pressure + assert pressure.bottleneck() == 7 + assert pressure.eval_edge("yedge_u", [0, 6]) == 7 # top link, all 7 below + assert pressure.eval_edge("yedge_d", [0, 1]) == 6 # links below row 1 + assert pressure.eval_edge("xedge_r", [0, 0]) == 0 # no horizontal traffic + + def test_monotone_overlap_bottleneck(self): + """ + Regression: the directed load is non-constant (a flooded up-link carries + ``t + 1`` trees), so the bottleneck must enumerate the edge domain, not + sample one point per piece. Three sources stacked up column 0 (rows 2, 1, + 0) all casting to (0, 3): the top up-link (rows 2->3) carries all three, so + the bottleneck is 3 even though lower links carry 1 and 2. + """ + tags = [SpatialTag(0, 0), SpatialTag(1, 0)] + manhattan = isl.Map.read_from_str(isl.DEFAULT_CONTEXT, ( + "{ [noc[xd,yd]->noc[xs,ys]]->hops[(xd-xs)+(yd-ys)] : xd>=xs and yd>=ys;" + " [noc[xd,yd]->noc[xs,ys]]->hops[-(xd-xs)+-(yd-ys)] : xdnoc[xs,ys]]->hops[-(xd-xs)+(yd-ys)] : xd=ys;" + " [noc[xd,yd]->noc[xs,ys]]->hops[(xd-xs)+-(yd-ys)] : xd>=xs and yddata[c] : (c=0 and x=0 and y=2) or (c=1 and x=0 and y=1)" + " or (c=2 and x=0 and y=0) }"))) + fill = Fill(tags, isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, "{ noc[x,y]->data[c] : x=0 and y=3 and 0<=c<3 }")) + pressure = XYRoutingMulticastModel(manhattan).apply(0, fill, occ).edge_pressure + assert pressure.eval_edge("yedge_u", [0, 2]) == 3 # top link, all three + assert pressure.bottleneck() == 3 # NOT 1 or 2 + + def test_single_tree_cases_have_unit_bottleneck(self): + """ + Cases A-E are single multicast trees, so no link is shared by two trees and + every edge carries load exactly 1. + """ + for test in self.testcases: + exp = test["expected"]["xy_routing_hops"] + if exp is None or exp == 448: # F has overlapping trees + continue + dim_tags = construct_spacetime(test["dims"]) + model = XYRoutingMulticastModel(test["dist_fn"]) + pressure = model.apply( + 0, Fill(dim_tags, test["fill"]), Occupancy(dim_tags, test["occ"]) + ).edge_pressure + assert pressure.bottleneck() == 1 + + +class TestStarSpokePressure(unittest.TestCase): + """Per-spoke pressure for the star (FC spokes) model on N-way all-to-all.""" + + @staticmethod + def _all_to_all(n: int): + """Build (fill, occ, dist_fn) for an N-GPU all-to-all on a fully-connected fabric.""" + tags = [SpatialTag(0, 0)] + occ = Occupancy(tags, isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + f"{{ noc[g] -> data[d] : 0 <= g < {n} and d = g }}")) + fill = Fill(tags, isl.Map.read_from_str( + isl.DEFAULT_CONTEXT, + f"{{ noc[g] -> data[d] : 0 <= g < {n} and 0 <= d < {n} and d != g }}")) + dist_fn = isl.Map.read_from_str(isl.DEFAULT_CONTEXT, _FULLY_CONNECTED) + return fill, occ, dist_fn + + def test_all_to_all_spoke_loads(self): + """ + N-way all-to-all: every node receives N-1 (ingress) and sources 1 (egress); + the bottleneck spoke is the ingress at N-1. + """ + for n in (4, 8): + fill, occ, dist_fn = self._all_to_all(n) + pressure = StarMulticastModel(dist_fn).apply(0, fill, occ).edge_pressure + for node in range(n): + assert pressure.eval_edge("spoke_in", [node]) == n - 1 + assert pressure.eval_edge("spoke_out", [node]) == 1 + assert pressure.bottleneck() == n - 1 + + def test_ingress_sum_equals_fully_connected_count(self): + """ + Cross-model invariant: Σ ingress over spokes == FullyConnected crossing + count (every crossing delivery is exactly one node's ingress). + """ + for n in (4, 8): + fill, occ, dist_fn = self._all_to_all(n) + pressure = StarMulticastModel(dist_fn).apply(0, fill, occ).edge_pressure + total_ingress = sum(pressure.eval_edge("spoke_in", [g]) for g in range(n)) + fc_hops = _eval_const( + FullyConnectedMulticastModel(dist_fn).apply(0, fill, occ).hops + ) + assert total_ingress == fc_hops == n * (n - 1) + + def test_star_hops_is_injections_plus_deliveries(self): + """Star scalar hops == Σ egress + Σ ingress == N + N(N-1).""" + for n in (4, 8): + fill, occ, dist_fn = self._all_to_all(n) + hops = _eval_const(StarMulticastModel(dist_fn).apply(0, fill, occ).hops) + assert hops == n + n * (n - 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/isl/distributed/test_fully_connected.py b/tests/isl/distributed/test_fully_connected.py new file mode 100644 index 00000000..3cc0f9af --- /dev/null +++ b/tests/isl/distributed/test_fully_connected.py @@ -0,0 +1,34 @@ +""" +Tests for the FullyConnectedMulticastModel. + +The model costs each delivery that crosses the fabric at one hop and self- +deliveries at zero, so an 8-GPU one-hot all-to-all costs 56 hops (64 chunks - 8 +self-deliveries) -- a third of the HypercubeMulticastModel's 168 on the same +input. See accelforge/model/_looptree/reuse/isl/distributed/README.md. +""" + +import unittest +from pathlib import Path + +from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( + FullyConnectedMulticastModel, +) +from .helpers import run_hops_gamut + + +class TestFullyConnectedMulticastModel(unittest.TestCase): + """ + Tests the FullyConnectedMulticastModel with a series of premade test cases. + """ + + TEST_CASES_FILE: Path = ( + Path(__file__).parent / "fully_connected" / "test_cases.yaml" + ) + + def test_gamut(self): + """ + Tests the entire gamut of test cases we have specified in the yaml. + """ + run_hops_gamut( + FullyConnectedMulticastModel, self.TEST_CASES_FILE, "fully_connected_hops" + ) diff --git a/tests/isl/distributed/test_multicast.py b/tests/isl/distributed/test_multicast.py new file mode 100644 index 00000000..61a41ced --- /dev/null +++ b/tests/isl/distributed/test_multicast.py @@ -0,0 +1,26 @@ +""" +File ported from here: +https://github.com/rengzhengcodes/timeloop/blob/distributed-multicast-dev/src/unit-test/multicast/test-multicast.cpp +""" + +import unittest +from pathlib import Path + +from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( + HypercubeMulticastModel, +) +from .helpers import run_hops_gamut + + +class TestHypercubeMulticastModel(unittest.TestCase): + """ + Tests the HypercubeMulticastModel with a series of premade test cases. + """ + + TEST_CASES_FILE: Path = Path(__file__).parent / "multicast" / "test_cases.yaml" + + def test_gamut(self): + """ + Tests the entire gamut of test cases we have specified in the yaml. + """ + run_hops_gamut(HypercubeMulticastModel, self.TEST_CASES_FILE, "hypercube_hops") diff --git a/tests/isl/distributed/test_xy_routing.py b/tests/isl/distributed/test_xy_routing.py new file mode 100644 index 00000000..6fcfe5f9 --- /dev/null +++ b/tests/isl/distributed/test_xy_routing.py @@ -0,0 +1,33 @@ +""" +Tests for the XYRoutingMulticastModel (dimension-order routing on a 2-D mesh). + +XY routing sends each packet along X then Y, so a multicast tree is an X-segment +along the source row plus an independent Y-segment down each destination column. +The expected hop counts here are HAND-DERIVED (the repo has no XY oracle -- the +yaml's extent_DOR_hops is a free-routing floor, not the XY cost); each case's +geometry is documented in fully_connected/../xy_routing/test_cases.yaml so the +numbers can be re-checked. See +accelforge/model/_looptree/reuse/isl/distributed/README.md. +""" + +import unittest +from pathlib import Path + +from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( + XYRoutingMulticastModel, +) +from .helpers import run_hops_gamut + + +class TestXYRoutingMulticastModel(unittest.TestCase): + """ + Tests the XYRoutingMulticastModel with a series of premade test cases. + """ + + TEST_CASES_FILE: Path = Path(__file__).parent / "xy_routing" / "test_cases.yaml" + + def test_gamut(self): + """ + Tests the entire gamut of test cases we have specified in the yaml. + """ + run_hops_gamut(XYRoutingMulticastModel, self.TEST_CASES_FILE, "xy_routing_hops") diff --git a/tests/isl/distributed/xy_routing/test_cases.yaml b/tests/isl/distributed/xy_routing/test_cases.yaml new file mode 100644 index 00000000..ff192655 --- /dev/null +++ b/tests/isl/distributed/xy_routing/test_cases.yaml @@ -0,0 +1,83 @@ +################################################### +# XY (dimension-order) routing test cases. # +# # +# Packets route along X first, then Y, so a # +# multicast tree = X-segment along the source row # +# + an independent Y-segment down each destination # +# column from the source row. # +# cost = x_extent({xs} u dst columns) # +# + sum_col y_extent({ys} u dsts in col) # +# # +# Expected xy_routing_hops are HAND-DERIVED (no # +# oracle exists in the repo); each case lists the # +# geometry so the number can be re-checked. # +# # +# Ordering: extent_DOR (floor) <= XY <= hypercube. # +################################################### + +# A. Unicast (0,0) -> (2,2): X=2 + col2 Y={0,2}=2 -> 4 (== floor). +- occ: "{ noc[x, y] -> data[c] : c = 0 and x = 0 and y = 0 }" + fill: "{ noc[x, y] -> data[c] : c = 0 and x = 2 and y = 2 }" + dims: &2d_spatial + - type: Spatial + spatial_dim: 0 + target: 0 + - type: Spatial + spatial_dim: 1 + target: 0 + dist_fn: &2d_manhattan | + { + [noc[xd, yd] -> noc[xs, ys]] -> hops[(xd - xs) + (yd - ys)] : + xd >= xs and yd >= ys; + [noc[xd, yd] -> noc[xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] : + xd < xs and yd < ys; + [noc[xd, yd] -> noc[xs, ys]] -> hops[-(xd - xs) + (yd - ys)] : + xd < xs and yd >= ys; + [noc[xd, yd] -> noc[xs, ys]] -> hops[(xd - xs) + -(yd - ys)] : + xd >= xs and yd < ys + } + expected: + xy_routing_hops: 4 + +# B. Source (1,0) -> (0,2),(2,2): X={0,1,2}=2 + col0 {0,2}=2 + col2 {0,2}=2 -> 6. +# Discriminator: floor 4 < XY 6 < hypercube 8. +- occ: "{ noc[x, y] -> data[c] : c = 0 and x = 1 and y = 0 }" + fill: "{ noc[x, y] -> data[c] : c = 0 and ((x = 0 and y = 2) or (x = 2 and y = 2)) }" + dims: *2d_spatial + dist_fn: *2d_manhattan + expected: + xy_routing_hops: 6 + +# C. Three corners from (0,0) -> (2,0),(0,2),(2,2): X={0,2}=2 + col0 {0,2}=2 + col2 {0,2}=2 -> 6. +- occ: "{ noc[x, y] -> data[c] : c = 0 and x = 0 and y = 0 }" + fill: "{ noc[x, y] -> data[c] : c = 0 and ((x = 2 and y = 0) or (x = 0 and y = 2) or (x = 2 and y = 2)) }" + dims: *2d_spatial + dist_fn: *2d_manhattan + expected: + xy_routing_hops: 6 + +# D. 1-D column (0,1) -> column x=0, y=0..3: X=0 + col0 {0..3}=3 -> 3 (== floor). +- occ: "{ noc[x, y] -> data[c] : c = 0 and x = 0 and y = 1 }" + fill: "{ noc[x, y] -> data[c] : c = 0 and x = 0 and 0 <= y < 4 }" + dims: *2d_spatial + dist_fn: *2d_manhattan + expected: + xy_routing_hops: 3 + +# E. Replicated source (0,0)&(2,0) -> (0,2),(2,2): per-dst nearest splits into two +# self-column trees, each 2 -> 4 (a single-root tree would cost 6). +- occ: "{ noc[x, y] -> data[c] : c = 0 and ((x = 0 and y = 0) or (x = 2 and y = 0)) }" + fill: "{ noc[x, y] -> data[c] : c = 0 and ((x = 0 and y = 2) or (x = 2 and y = 2)) }" + dims: *2d_spatial + dist_fn: *2d_manhattan + expected: + xy_routing_hops: 4 + +# F. Scale: 8x8, each datum data[d0,d1] held at (d0,d1), requested by column x=d0. +# Per datum: X=0 + Y=7 -> 7; 64 data -> 448. +- occ: "{ noc[xs, ys] -> data[d0, d1] : d0 = xs and d1 = ys and 0 <= xs < 8 and 0 <= ys < 8 }" + fill: "{ noc[xd, yd] -> data[d0, d1] : d0 = xd and 0 <= d1 < 8 and 0 <= xd < 8 and 0 <= yd < 8 }" + dims: *2d_spatial + dist_fn: *2d_manhattan + expected: + xy_routing_hops: 448 diff --git a/tests/not_working/isl/mapper/__init__.py b/tests/isl/mapper/__init__.py similarity index 100% rename from tests/not_working/isl/mapper/__init__.py rename to tests/isl/mapper/__init__.py diff --git a/tests/not_working/isl/mapper/configs/conv1d/conv1d.mapping.yaml b/tests/isl/mapper/configs/conv1d/conv1d.mapping.yaml similarity index 100% rename from tests/not_working/isl/mapper/configs/conv1d/conv1d.mapping.yaml rename to tests/isl/mapper/configs/conv1d/conv1d.mapping.yaml diff --git a/tests/not_working/isl/mapper/configs/conv1d/conv1d.workload.yaml b/tests/isl/mapper/configs/conv1d/conv1d.workload.yaml similarity index 100% rename from tests/not_working/isl/mapper/configs/conv1d/conv1d.workload.yaml rename to tests/isl/mapper/configs/conv1d/conv1d.workload.yaml diff --git a/tests/not_working/isl/mapper/configs/two_conv1d/two_conv1d.expected.yaml b/tests/isl/mapper/configs/two_conv1d/two_conv1d.expected.yaml similarity index 100% rename from tests/not_working/isl/mapper/configs/two_conv1d/two_conv1d.expected.yaml rename to tests/isl/mapper/configs/two_conv1d/two_conv1d.expected.yaml diff --git a/tests/not_working/isl/mapper/configs/two_conv1d/two_conv1d.mapping.yaml b/tests/isl/mapper/configs/two_conv1d/two_conv1d.mapping.yaml similarity index 100% rename from tests/not_working/isl/mapper/configs/two_conv1d/two_conv1d.mapping.yaml rename to tests/isl/mapper/configs/two_conv1d/two_conv1d.mapping.yaml diff --git a/tests/not_working/isl/mapper/configs/two_conv1d/two_conv1d.workload.yaml b/tests/isl/mapper/configs/two_conv1d/two_conv1d.workload.yaml similarity index 100% rename from tests/not_working/isl/mapper/configs/two_conv1d/two_conv1d.workload.yaml rename to tests/isl/mapper/configs/two_conv1d/two_conv1d.workload.yaml diff --git a/tests/not_working/isl/mapper/test_isl_functions.py b/tests/isl/mapper/test_isl_functions.py similarity index 100% rename from tests/not_working/isl/mapper/test_isl_functions.py rename to tests/isl/mapper/test_isl_functions.py diff --git a/tests/not_working/isl/mapper/test_mapping_to_isl.py b/tests/isl/mapper/test_mapping_to_isl.py similarity index 100% rename from tests/not_working/isl/mapper/test_mapping_to_isl.py rename to tests/isl/mapper/test_mapping_to_isl.py diff --git a/tests/not_working/isl/mapper/test_spatial_reuse_analysis.py b/tests/isl/mapper/test_spatial_reuse_analysis.py similarity index 100% rename from tests/not_working/isl/mapper/test_spatial_reuse_analysis.py rename to tests/isl/mapper/test_spatial_reuse_analysis.py diff --git a/tests/not_working/isl/mapper/test_temporal_reuse_analysis.py b/tests/isl/mapper/test_temporal_reuse_analysis.py similarity index 100% rename from tests/not_working/isl/mapper/test_temporal_reuse_analysis.py rename to tests/isl/mapper/test_temporal_reuse_analysis.py diff --git a/tests/not_working/distribuffers/multicast/test_cases.yaml b/tests/not_working/distribuffers/multicast/test_cases.yaml deleted file mode 100755 index 32dbc8eb..00000000 --- a/tests/not_working/distribuffers/multicast/test_cases.yaml +++ /dev/null @@ -1,482 +0,0 @@ -- occ: "{ noc[xs, ys] -> data[d0, d1] : d0=xs and d1=ys and 0 <= xs < 8 and 0 <= ys < 8 }" - fill: "{ noc[xd, yd] -> data[d0, d1] : d0=xd and 0 <= d1 < 8 and 0 <= xd < 8 and 0 <= yd < 8 }" - dims: &2d_spatial - - type: Spatial - spatial_dim: 0 - target: 0 - - type: Spatial - spatial_dim: 1 - target: 0 - dist_fn: &2d_manhattan | - { - [noc[xd, yd] -> noc[xs, ys]] -> hops[(xd - xs) + (yd - ys)] : - xd >= xs and yd >= ys; - [noc[xd, yd] -> noc[xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] : - xd < xs and yd < ys; - [noc[xd, yd] -> noc[xs, ys]] -> hops[-(xd - xs) + (yd - ys)] : - xd < xs and yd >= ys; - [noc[xd, yd] -> noc[xs, ys]] -> hops[(xd - xs) + -(yd - ys)] : - xd >= xs and yd < ys - } - expected: &equivalent_class_1 - latency: 7 - total_hops: 1344 - multicast_hops: 448 - hypercube_hops: 448 - extent_DOR_hops: 448 -- occ: "{ noc[xs, ys] -> data[d0, d1] : d0=xs and d1=ys and 0 <= xs < 8 and 0 <= ys < 8 }" - fill: "{ noc[xd, yd] -> data[d0, d1] : 0 <= d0 < 8 and d1=yd and 0 <= xd < 8 and 0 <= yd < 8 }" - dims: *2d_spatial - dist_fn: *2d_manhattan - expected: *equivalent_class_1 -- occ: "{ noc[xs, ys] -> data[d0, d1] : d0 = xs and 0 <= d1 < 8 and 0 <= xs < 8 and 0 <= ys < 8 }" - fill: "{ noc[xd, yd] -> data[d0, d1] : d0 = xd and d1 = yd and 0 <= xd < 8 and 0 <= yd < 8 }" - dims: *2d_spatial - dist_fn: *2d_manhattan - expected: &equivalent_class_2 - latency: 0 - total_hops: 0 - multicast_hops: 0 - hypercube_hops: 0 - extent_DOR_hops: 448 -- occ: "{ noc[xs, ys] -> data[d0, d1] : 0 <= d0 < 8 and d1 = ys and 0 <= xs < 8 and 0 <= ys < 8 }" - fill: "{ noc[xd, yd] -> data[d0, d1] : d0 = xd and d1 = yd and 0 <= xd < 8 and 0 <= yd < 8 }" - dims: *2d_spatial - dist_fn: *2d_manhattan - expected: *equivalent_class_2 - -####################### -# Temporal Test Cases # -####################### -##@section 1x1 dummy case to catch temporal integration issues. -# Edge to Src -- occ: &1x1_edge | - { - noc[tm, tn, xs, ys] -> A[m, k] : - 0 <= tm < 1 and 0 <= tn < 1 and - xs=0 and ys=0 and - 0 <= m < 1 and 0 <= k < 1 - } - fill: | - { - noc[tm, tn, xd, yd] -> A[m, k] : - 0 <= tm < 1 and 0 <= tn < 1 and tn = 0 and - 0 <= xd < 1 and 0 <= yd < 1 and - m = (1 * tm) + xd and 0 <= k < 1 - } - dims: &2t-dim_2s-dim - - type: Temporal - - type: Temporal - - type: Spatial - spatial_dim: 0 - target: 0 - - type: Spatial - spatial_dim: 1 - target: 0 - dist_fn: &2t-dim_2s-dim_manhattan | - { - [noc[tm, tn, xd, yd] -> noc[tm, tn, xs, ys]] -> hops[(xd - xs) + (yd - ys)] : - xd >= xs and yd >= ys; - [noc[tm, tn, xd, yd] -> noc[tm, tn, xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] : - xd < xs and yd < ys; - [noc[tm, tn, xd, yd] -> noc[tm, tn, xs, ys]] -> hops[-(xd - xs) + (yd - ys)] : - xd < xs and yd >= ys; - [noc[tm, tn, xd, yd] -> noc[tm, tn, xs, ys]] -> hops[(xd - xs) + -(yd - ys)] : - xd >= xs and yd < ys - } - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 0 - extent_DOR_hops: null -# Src to Dst -- occ: | - { - noc[tm, tn, tk, xs, ys] -> A[m, k] : - 0 <= tm < 1 and 0 <= tn < 1 and 0 <= tk < 1 and - 0 <= xs < 1 and 0 <= ys < 1 and - m= (1 * tm) + xs and 0 <= k < 1 - } - fill: &1x1_fill | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 1 and 0 <= tn < 1 and 0 <= tk < 1 and - 0 <= xd < 1 and 0 <= yd < 1 and - m= (1 * tm) + xd and k=tk - } - dims: &3t-dim_2s-dim - - type: Temporal - - type: Temporal - - type: Temporal - - type: Spatial - spatial_dim: 0 - target: 0 - - type: Spatial - spatial_dim: 1 - target: 0 - dist_fn: &3t-dim_2s-dim_manhattan | - { - [noc[tm, tn, tk, xd, yd] -> noc[tm, tn, tk, xs, ys]] -> hops[(xd - xs) + (yd - ys)] : - xd >= xs and yd >= ys; - [noc[tm, tn, tk, xd, yd] -> noc[tm, tn, tk, xs, ys]] -> hops[-(xd - xs) + -(yd - ys)] : - xd < xs and yd < ys; - [noc[tm, tn, tk, xd, yd] -> noc[tm, tn, tk, xs, ys]] -> hops[-(xd - xs) + (yd - ys)] : - xd < xs and yd >= ys; - [noc[tm, tn, tk, xd, yd] -> noc[tm, tn, tk, xs, ys]] -> hops[(xd - xs) + -(yd - ys)] : - xd >= xs and yd < ys - } - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 0 - extent_DOR_hops: null -##@section 8x8 case for a bigger chip. -##@brief Full duplication to make sure temporal handling is correct. -# Edge to Src -- occ: &8x8_edge | - { - noc[tm, tn, xs, ys] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and - xs=0 and ys=0 and - 0 <= m < 64 and 0 <= k < 64 - } - fill: | - { - noc[tm, tn, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and tn = 0 and - 0 <= xd < 8 and 0 <= yd < 8 and - m = (8 * tm) + xd and 0 <= k < 64 - } - dims: *2t-dim_2s-dim - dist_fn: *2t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 143360 - extent_DOR_hops: null -# Src to Dst -- occ: | - { - noc[tm, tn, tk, xs, ys] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and 0 <= tk < 64 and - 0 <= xs < 8 and 0 <= ys < 8 and - m = (8 * tm) + xs and 0 <= k < 64 - } - fill: &8x8_pe | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and 0 <= tk < 64 and - 0 <= xd < 8 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and k=tk - } - dims: *3t-dim_2s-dim - dist_fn: *3t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 0 - extent_DOR_hops: null -##@brief No duplication, one time step to ensure spatial handling is correct. -# Edge to Src, only 1 time step. -- occ: *8x8_edge - fill: | - { - noc[tm, tn, xd, yd] -> A[m, k] : - 0 <= tm < 8 and tm = 0 and 0 <= tn < 8 and tn = 0 and - 0 <= xd < 8 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and 0 = (yd - k) % 8 - } - dims: *2t-dim_2s-dim - dist_fn: *2t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 9856 - extent_DOR_hops: null -# Src to Dst, only 1 time step. -- occ: | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 8 and tm = 0 and 0 <= tn < 8 and tn = 0 and 0 <= tk < 64 and - 0 <= xd < 8 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and 0 = (yd - k) % 8 - } - fill: | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 8 and tm = 0 and 0 <= tn < 8 and tn = 0 and 0 <= tk < 64 and tk = 0 and - 0 <= xd < 8 and 0 <= yd < 8 and - m = (8 * tm) + xd and k=tk - } - dims: *3t-dim_2s-dim - dist_fn: *3t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 56 - extent_DOR_hops: null -##@brief No duplication, one spatial dimension to ensure temporal handling is correct. -##@note, tn = 0 here because otherwise we recast every tn, which is not fundamental to the problem. -# Edge to Src, only 1 spatial dimension. -- occ: *8x8_edge - fill: | - { - noc[tm, tn, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and tn = 0 and - 0 <= xd < 8 and xd = 0 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and 0 = (yd - k) % 8 - } - dims: *2t-dim_2s-dim - dist_fn: *2t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 1792 - extent_DOR_hops: null -# Src to Dst, only 1 spatial dimension. -- occ: | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and 0 <= tk < 64 and - 0 <= xd < 8 and xd = 0 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and 0 = (yd - k) % 8 - } - fill: | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and 0 <= tk < 64 and - 0 <= xd < 8 and xd = 0 and 0 <= yd < 8 and - m = (8 * tm) + xd and k=tk - } - dims: *3t-dim_2s-dim - dist_fn: *3t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 28672 - extent_DOR_hops: null -##@brief No duplication, full chip to ensure temporal and spatial handling is correct. -# Edge to Src, full chip. -- occ: *8x8_edge - fill: | - { - noc[tm, tn, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and tn = 0 and - 0 <= xd < 8 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and 0 = (yd - k) % 8 - } - dims: *2t-dim_2s-dim - dist_fn: *2t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 78848 - extent_DOR_hops: null -# Src to Dst, full chip. -- occ: | - { - noc[tm, tn, tk, xd, yd] -> A[m, k] : - 0 <= tm < 8 and 0 <= tn < 8 and 0 <= tk < 64 and - 0 <= xd < 8 and 0 <= yd < 8 and - 0 <= m < 64 and m = (8 * tm) + xd and - 0 <= k < 64 and 0 = (yd - k) % 8 - } - fill: *8x8_pe - dims: *3t-dim_2s-dim - dist_fn: *3t-dim_2s-dim_manhattan - expected: - latency: null - total_hops: null - multicast_hops: null - hypercube_hops: 229376 - extent_DOR_hops: null -# - occ: "{ noc[xs, ys] -> data[d0, d1] : 0 <= d0 < 8 and 0 <= d1 < 8 and (xs=0 or 3<=xs<=4 or xs=7) and (ys=0 or 3<=ys<=4 or ys=7) }" -# fill: "{ noc[xd, yd] -> data[d0, d1] : d0 = xd and d1 = yd and 0 <= xd < 8 and 0 <= yd < 8 }" -# dims: *2d_spatial -# dist_fn: *2d_manhattan -# expected: -# latency: 2 -# total_hops: 64 -# multicast_hops: null -# - occ: "{ noc[xs, ys] -> data[d0, d1] : d0 = xs and d1 = ys and 0 <= xs < 8 and 0 <= ys < 8 }" -# fill: "{ noc[xd, yd] -> data[d0, d1] : 0 <= d0 < 8 and 0 <= d1 < 8 and (xd=0 or 3<=xd<=4 or xd=7) and (yd=0 or 3<=yd<=4 or yd=7) }" -# dist_fn: *2d_manhattan -# dims: *2d_spatial -# expected: -# latency: 14 -# total_hops: 5632 -# multicast_hops: null -# - occ: | -# { noc[xs, ys] -> data[d0, d1] : -# 0 <= d0 < 3 and 0 <= d1 < 3 and -# 0 <= xs < 9 and 0 <= ys < 9 and xs % 3 = 1 and ys % 3 = 1 -# } -# fill: "{ noc[xd, yd] -> data[d0, d1] : d0 = xd % 3 and d1 = yd % 3 and 0 <= xd < 9 and 0 <= yd < 9 }" -# dims: *2d_spatial -# dist_fn: *2d_manhattan -# expected: -# latency: 2 -# total_hops: 108 -# multicast_hops: null -# - occ: "{ noc[xs, ys] -> data[d0, d1] : d0 = xs % 3 and d1 = ys % 3 and 0 <= xs < 9 and 0 <= ys < 9 }" -# fill: | -# { noc[xd, yd] -> data[d0, d1] : -# 0 <= d0 < 3 and 0 <= d1 < 3 and -# 0 <= xd < 9 and 0 <= yd < 9 and xd % 3 = 1 and yd % 3 = 1 -# } -# dims: *2d_spatial -# dist_fn: *2d_manhattan -# expected: -# latency: 2 -# total_hops: 108 -# - occ: "{ [xs, ys] -> [d0] : d0=xs and 0 <= xs < 8 and ys = 0 }" -# fill: "{ [xd, yd] -> [d0] : d0=xd and 0 <= xd < 8 and 0 <= yd < 8 }" -# dims: *2d_spatial -# dist_fn: *2d_manhattan -# expected: -# latency: 7 -# total_hops: 224 -# - occ: "{ [xs, ys] -> [d0] : d0=xs and 0 <= xs < 8 and 0 <= ys < 8 }" -# fill: "{ [xd, yd] -> [d0] : d0=xd and 0 <= xd < 8 and yd = 0 }" -# dims: *2d_spatial -# dist_fn: *2d_manhattan -# expected: -# latency: 0 -# total_hops: 0 -# - occ: | -# { [xs, ys, z1s, z2s] -> [d0, d1, d2, d3] : -# d0 = xs and d1 = ys and d2 = z1s and d3 = z2s and -# 0 <= xs < 8 and 0 <= ys < 8 and 0 <= z1s < 8 and 0 <= z2s < 8 -# } -# fill: | -# { [xd, yd, z1d, z2d] -> [d0, d1, d2, d3] : -# 0 <= d0 < 8 and 0 <= d1 < 8 and 0 <= d2 < 8 and 0 <= d3 < 8 and -# xd=0 and yd=0 and z1d=0 and z2d=0 -# } -# dims: &4d_spatial -# - Spatial -# - 0 -# - 0 -# - Spatial -# - 1 -# - 0 -# - Spatial -# - 2 -# - 0 -# - Spatial -# - 3 -# - 0 -# dist_fn: &4d_manhattan | -# { -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + (yd - ys) + (z1d - z1s) + (z2d - z2s)] : -# (xd >= xs) and (yd >= ys) and (z1d >= z1s) and (z2d >= z2s); - -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + (yd - ys) + (z1d - z1s) + (z2d - z2s)] : -# (xd < xs) and (yd >= ys) and (z1d >= z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + -(yd - ys) + (z1d - z1s) + (z2d - z2s)] : -# (xd < xs) and (yd < ys) and (z1d >= z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + -(yd - ys) + -(z1d - z1s) + (z2d - z2s)] : -# (xd < xs) and (yd < ys) and (z1d < z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + -(yd - ys) + -(z1d - z1s) + -(z2d - z2s)] : -# (xd < xs) and (yd < ys) and (z1d < z1s) and (z2d < z2s); - -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + -(yd - ys) + (z1d - z1s) + (z2d - z2s)] : -# (xd >= xs) and (yd < ys) and (z1d >= z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + -(yd - ys) + -(z1d - z1s) + (z2d - z2s)] : -# (xd >= xs) and (yd < ys) and (z1d < z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + -(yd - ys) + -(z1d - z1s) + -(z2d - z2s)] : -# (xd >= xs) and (yd < ys) and (z1d < z1s) and (z2d < z2s); - -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + (yd - ys) + -(z1d - z1s) + (z2d - z2s)] : -# (xd >= xs) and (yd >= ys) and (z1d < z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + (yd - ys) + -(z1d - z1s) + -(z2d - z2s)] : -# (xd >= xs) and (yd >= ys) and (z1d < z1s) and (z2d < z2s); - -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + (yd - ys) + (z1d - z1s) + -(z2d - z2s)] : -# (xd >= xs) and (yd >= ys) and (z1d >= z1s) and (z2d < z2s); - -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + (yd - ys) + -(z1d - z1s) + -(z2d - z2s)] : -# (xd < xs) and (yd >= ys) and (z1d < z1s) and (z2d < z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + -(yd - ys) + (z1d - z1s) + -(z2d - z2s)] : -# (xd < xs) and (yd < ys) and (z1d >= z1s) and (z2d < z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + (yd - ys) + (z1d - z1s) + -(z2d - z2s)] : -# (xd < xs) and (yd >= ys) and (z1d >= z1s) and (z2d < z2s); - -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [-(xd - xs) + (yd - ys) + -(z1d - z1s) + (z2d - z2s)] : -# (xd < xs) and (yd >= ys) and (z1d < z1s) and (z2d >= z2s); -# [[xd, yd, z1d, z2d] -> [xs, ys, z1s, z2s]] -> -# [(xd - xs) + -(yd - ys) + (z1d - z1s) + -(z2d - z2s)] : -# (xd >= xs) and (yd < ys) and (z1d >= z1s) and (z2d < z2s) -# } -# expected: -# latency: 28 -# total_hops: null -# - occ: | -# { [xs, ys, z1s, z2s] -> [d0, d1, d2, d3] : -# 0 <= d0 < 8 and 0 <= d1 < 8 and 0 <= d2 < 8 and 0 <= d3 < 8 and -# xs=0 and ys=0 and z1s=0 and z2s=0 -# } -# fill: | -# { [xd, yd, z1d, z2d] -> [d0, d1, d2, d3] : -# d0 = xd and d1 = yd and d2 = z1d and d3 = z2d and -# 0 <= xd < 8 and 0 <= yd < 8 and 0 <= z1d < 8 and 0 <= z2d < 8 -# } -# dims: *4d_spatial -# dist_fn: *4d_manhattan -# expected: -# latency: 28 -# total_hops: null -# - occ: "{ [xs] -> [d0] : 0 <= d0 < 8 and xs = 0 }" -# fill: "{ [xd] -> [d0] : d0 = xd and 0 <= xd < 8 }" -# dist_fn: &ring_dist_size_8 | -# { -# [[xd] -> [xs]] -> [(xd-xs) % 8] : -# (xd-xs)%8 <= (xs-xd)%8; -# [[xd] -> [xs]] -> [(xs-xd) % 8] : -# (xd-xs)%8 > (xs-xd)%8 -# } -# expected: -# latency: 4 -# total_hops: 16 -# - occ: "{ [xs] -> [d0] : 0 <= xs < 8 and d0 = xs }" -# fill: "{ [xd] -> [d0] : 0 <= d0 < 8 and xd = 0 }" -# dist_fn: *ring_dist_size_8 -# expected: -# latency: 4 -# total_hops: 16 -# - occ: "{ [xs] -> [d0] : xs <= d0 <= xs + 1 and xs % 2 = 0}" -# fill: "{ [xd] -> [d0] : d0 = xd and 0 <= xd < 8 }" -# dist_fn: *ring_dist_size_8 -# expected: -# latency: 1 -# total_hops: 4 \ No newline at end of file diff --git a/tests/not_working/distribuffers/spec/binding/valid_bindings.yaml b/tests/not_working/distribuffers/spec/binding/valid_bindings.yaml deleted file mode 100755 index 5e1c21c4..00000000 --- a/tests/not_working/distribuffers/spec/binding/valid_bindings.yaml +++ /dev/null @@ -1,97 +0,0 @@ -- binding: - nodes: - - logical: - name: ProcessingElement - l_dims: [i] - physical: - name: ProcessingElement - p_dims: [x, y] - relations: - tensorA: i = x + y * 2 # This is a dimension-major compression into the logical. It is bijective. - tensorB: i = x + y * 2 # This is a dimension-major compression into the logical. It is bijective. - - logical: - name: Scratchpad - l_dims: [x, y] - physical: - name: GLB - p_dims: [a, b] - relations: - tensorA: x = a and y = b - tensorB: x = b and y = a - solution: - nodes: - - - tensorA: | - { - [ - tensorA_ranks[c, h, w, p, q, r, s] -> - l_ProcessingElement_dims[i] - ] -> - p_ProcessingElement_dims[x, y] : - i = x + 2y - } - tensorB: | - { - [ - tensorB_ranks[c, h, w, p, q, r, s] -> - l_ProcessingElement_dims[i] - ] -> - p_ProcessingElement_dims[x, y] : - i = x + (y * 2) - } - - - tensorA: | - { - [ - tensorA_ranks[c, h, w, p, q, r, s] -> - l_Scratchpad_dims[x, y] - ] -> - p_GLB_dims[ a, b ] : - x = a and y = b - } - tensorB: | - { - [ - tensorB_ranks[c, h, w, p, q, r, s] -> - l_Scratchpad_dims[x, y] - ] -> - p_GLB_dims[ a, b ] : - x = b and y = a - } - -- binding: - nodes: - - logical: - name: DRAM - l_dims: [i] - physical: - name: DRAM - p_dims: [i] - relation: # Compression relation where less DRAM chips than planned. - weights: i = i // 2 - inputs: i = i // 2 - outputs: i = i // 2 - - logical: - name: Scratchpad - l_dims: [i] - physical: - name: GLB - p_dims: [x, y, z] - relation: # weight stationary relation - weights: c = x and h = y and w = z - inputs: i=x and i=y and i=z - outputs: i=x and i=y and i=z - - logical: - name: PE_Buffer - l_dims: [i] - physical: - name: GLB - l_dims: [x, y, z] - relation: # Some weird bypass shenanigans. - weights: - inputs: - outputs: - - - -- diff --git a/tests/not_working/distribuffers/spec/distributed.yaml b/tests/not_working/distribuffers/spec/distributed.yaml deleted file mode 100755 index 8f7267be..00000000 --- a/tests/not_working/distribuffers/spec/distributed.yaml +++ /dev/null @@ -1,100 +0,0 @@ -networks: - - name: L2 - topology: Mesh - dims: - - x - - y - constraints: - - 0 <= x < 2 - - 0 <= y < 3 - affine: | - { - [L2[x, y] -> L2[x', y']] -> hops[(x - x') + (y - y')] : - x >= x' and y >= y'; - [L2[x, y] -> L2[x', y']] -> hops[-(x - x') + -(y - y')] : - x < x' and y < y'; - [L2[x, y] -> L2[x', y']] -> hops[-(x - x') + (y - y')] : - x < x' and y >= y'; - [L2[x, y] -> L2[x', y']] -> hops[(x - x') + -(y - y')] : - x >= x' and y < y' - } - domain_restriction: | - { - [L2[x, y] -> L2[x', y']] -> hops[(x - x') + (y - y')] : - x >= x' and y >= y' and 0 <= x < 2 and 0 <= x' < 2 and 0 <= y < 3 and 0 <= y' < 3; - [L2[x, y] -> L2[x', y']] -> hops[-(x - x') + (y - y')] : - x < x' and y >= y' and 0 <= x < 2 and 0 <= x' < 2 and 0 <= y < 3 and 0 <= y' < 3; - [L2[x, y] -> L2[x', y']] -> hops[(x - x') + -(y - y')] : - x >= x' and y < y' and 0 <= x < 2 and 0 <= x' < 2 and 0 <= y < 3 and 0 <= y' < 3; - [L2[x, y] -> L2[x', y']] -> hops[-(x - x') + -(y - y')] : - x < x' and y < y' and 0 <= x < 2 and 0 <= x' < 2 and 0 <= y < 3 and 0 <= y' < 3 - } - - name: L1 - topology: Mesh - dims: - - x - - y - - z - constraints: - - 0 <= x < 2027 - - 0 <= y < 2029 - - 0 <= z < 17 - affine: | - { - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') + (y - y') + (z - z') ] : - x >= x' and y >= y' and z >= z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') + (y - y') - (z - z') ] : - x >= x' and y >= y' and z < z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') - (y - y') + (z - z') ] : - x >= x' and y < y' and z >= z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') + (y - y') + (z - z') ] : - x < x' and y >= y' and z >= z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') - (y - y') + (z - z') ] : - x < x' and y < y' and z >= z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') - (y - y') - (z - z') ] : - x >= x' and y < y' and z < z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') + (y - y') - (z - z') ] : - x < x' and y >= y' and z < z'; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') - (y - y') - (z - z') ] : - x < x' and y < y' and z < z' - } - domain_restriction: | - { - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') + (y - y') + (z - z') ] : - x >= x' and y >= y' and z >= z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') + (y - y') - (z - z') ] : - x >= x' and y >= y' and z < z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') - (y - y') + (z - z') ] : - x >= x' and y < y' and z >= z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') + (y - y') + (z - z') ] : - x < x' and y >= y' and z >= z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') - (y - y') + (z - z') ] : - x < x' and y < y' and z >= z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ (x - x') - (y - y') - (z - z') ] : - x >= x' and y < y' and z < z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') + (y - y') - (z - z') ] : - x < x' and y >= y' and z < z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17; - [L1[x, y, z] -> L1[x', y', z']] -> hops[ -(x - x') - (y - y') - (z - z') ] : - x < x' and y < y' and z < z' and - 0 <= x < 2027 and 0 <= y < 2029 and 0 <= z < 17 and - 0 <= x' < 2027 and 0 <= y' < 2029 and 0 <= z' < 17 - } -placement: - - level: DRAM - placement: "DRAM[i] -> L2[x, y] : i = x and y = 0" - - level: MAC - placement: "MAC[i] -> L1[x, y, z] : i = x and y = 0 and z = 0" \ No newline at end of file diff --git a/tests/not_working/distribuffers/spec/logical_arch.yaml b/tests/not_working/distribuffers/spec/logical_arch.yaml deleted file mode 100755 index 51053db7..00000000 --- a/tests/not_working/distribuffers/spec/logical_arch.yaml +++ /dev/null @@ -1,32 +0,0 @@ -arch: - nodes: - - !Component - name: DRAM # offchip DRAM is the source of all datatypes - class: DRAM # assume DRAM is large enough to store all the data, so no depth specification needed - attributes: - width: 64 # width in bits - - - !Container - name: ProcessingElement - spatial: {meshX: 1, meshY: 2} - - # registers for the mac unit - - !Component - name: weight_reg - class: reg_storage - attributes: {depth: 1, width: 8} - - - !Component - name: input_activation_reg - class: reg_storage - attributes: {depth: 1, width: 8} - - - !Component - name: output_activation_reg - class: reg_storage - attributes: {depth: 1, width: 8} - - - !Component - name: mac - class: mac_compute - attributes: {n_pipline_stages: 2} \ No newline at end of file diff --git a/tests/not_working/distribuffers/spec/physical_arch.yaml b/tests/not_working/distribuffers/spec/physical_arch.yaml deleted file mode 100755 index ab835911..00000000 --- a/tests/not_working/distribuffers/spec/physical_arch.yaml +++ /dev/null @@ -1,69 +0,0 @@ -arch: - name: "test_distributed_spec" - nodes: - - !Container - name: system_arch - attributes: - # Top-level attributes inherited by all components unless overridden - technology: "45nm" - cycle_period: 1e-9 - - - !Network - name: L2 - topology: Mesh - dims: - - x - constraints: - - 0 <= x < 2 - - !Network - name: L1 - topology: Mesh - dims: - - x - - y - constraints: - - 0 <= x < 1 - - -1 <= y <= 1 - port: | - {L2[x] -> L1[x', y'] : x = 1 and x' = 0 and y' = 0} - - - !Component - name: DRAM # offchip DRAM is the source of all datatypes - class: DRAM # assume DRAM is large enough to store all the data, so no depth specification needed - attributes: - width: 64 # width in bits - network: - level: L2 - placement: "{ DRAM[i] -> L2[i] | i = 1 }" - - - !Container - name: ProcessingElement - network: - level: L1 - placement: | - { - ProcessingElement[i, j] -> L1[x, y] : - j = y and x < 0 and i = -x - 1; - j = y and x > 0 and i = x; - } - - # registers for the mac unit - - !Component - name: weight_reg - class: reg_storage - attributes: {depth: 1, width: 8} - - - !Component - name: input_activation_reg - class: reg_storage - attributes: {depth: 1, width: 8} - - - !Component - name: output_activation_reg - class: reg_storage - attributes: {depth: 1, width: 8} - - - !Component - name: mac - class: mac_compute - attributes: {n_pipline_stages: 2} \ No newline at end of file diff --git a/tests/not_working/distribuffers/test_binding.py b/tests/not_working/distribuffers/test_binding.py deleted file mode 100755 index 528c93f4..00000000 --- a/tests/not_working/distribuffers/test_binding.py +++ /dev/null @@ -1,49 +0,0 @@ -from pathlib import Path -import unittest - -from typing import Dict, List -from islpy import DEFAULT_CONTEXT, Map -from ruamel.yaml import YAML - -from accelforge.frontend._binding import Binding, BindingNode - -TESTS_DIR = Path(__file__).parent / "spec" / "binding" -yaml = YAML(typ="safe") - - -class TestBindingMapper(unittest.TestCase): - def test_valid_bindings(self): - """ - Tests that the valid bindings translate into the appropriate - ISL strings. - """ - specs_file: str = TESTS_DIR / "valid_bindings.yaml" - with open(specs_file, mode="r", encoding="utf-8") as f: - specs: List = yaml.load(f) - - spec: Dict - for spec in specs: - binding: Binding = Binding.model_validate(spec["binding"]) - - soln: Dict = spec["solution"] - - soln_node: Dict[str, str] - binding_node: BindingNode - for soln_node, binding_node in zip(soln["nodes"], binding.nodes): - isl_relations: Dict[str, Map] = binding_node.isl_relations - assert soln_node.keys() == isl_relations.keys(), ( - "Not all isl_relations read in properly. Missing \n" - f"{set(soln_node.keys()).difference(isl_relations.keys())} " - "\nfrom isl_relations and \n" - f"{set(isl_relations.keys()).difference(soln_node.keys())} " - "\nfrom solutions.\n" - ) - - tensor: str - for tensor in soln_node: - soln_relation: Map = Map.read_from_str( - DEFAULT_CONTEXT, soln_node[tensor] - ) - assert soln_relation.is_equal( - isl_relations[tensor] - ), f"\n{soln_relation} != \n{isl_relations[tensor]}" diff --git a/tests/not_working/test_multicast.py b/tests/not_working/test_multicast.py deleted file mode 100644 index 6916de5b..00000000 --- a/tests/not_working/test_multicast.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -File ported from here: -https://github.com/rengzhengcodes/timeloop/blob/distributed-multicast-dev/src/unit-test/multicast/test-multicast.cpp -""" - -import unittest -from pathlib import Path - -import islpy as isl - -from accelforge.model._looptree.reuse.isl.mapping_to_isl.types import ( - # Data movement descriptors. - Fill, - Occupancy, - # Tags - Tag, - SpatialTag, - TemporalTag, -) -from accelforge.model._looptree.reuse.isl.distributed.distributed_buffers import ( - HypercubeMulticastModel, -) -from accelforge.model._looptree.reuse.isl.spatial import TransferInfo -from .util import load_solutions - - -def construct_spacetime(dims: list) -> list[Tag]: - """ - Given a list of dimension tags as strings, convert them into the proper `Tag` - objects. - - Parameters - ---------- - dims: - The list of dim tags as strings. - - Returns - ------- - list[Tag] where list[i] is the tag corresponding to dims[i]. - """ - spacetime: list[Tag] = [] - for dim in dims: - if dim["type"] == "Temporal": - spacetime.append(TemporalTag()) - elif dim["type"] == "Spatial": - spacetime.append(SpatialTag(dim["spatial_dim"], dim["target"])) - - return spacetime - - -class TestHypercubeMulticastModel(unittest.TestCase): - """ - Tests the HypercubeMulticastModel with a series of premade test cases. - """ - - TEST_CASES_FILE: str = Path(__file__).parent / "multicast" / "test_cases.yaml" - testcases: dict = load_solutions(TEST_CASES_FILE) - - def test_gamut(self): - """ - Tests the entire gamut of test cases we have specified in the yaml. - """ - for test in self.testcases: - # Reads test case parameters and constructs the necessary objects. - dim_tags: list[Tag] = construct_spacetime(test["dims"]) - fill: Fill = Fill(dim_tags, test["fill"]) - occ: Occupancy = Occupancy(dim_tags, test["occ"]) - dist_fn: isl.Map = test["dist_fn"] - multicast_model: HypercubeMulticastModel = HypercubeMulticastModel(dist_fn) - - # Applies the model. - info: TransferInfo = multicast_model.apply(0, fill, occ) - # Checks the results. - sum_extract: int = info.hops.eval( - isl.Point.zero(info.hops.domain().get_space()) - ) - - # The block is used for debugging test cases not yet implemented. - if test["expected"]["hypercube_hops"] is None: - print("~~~Test case in progress:~~~") - print(f"Fill: {fill}") - print(f"Occ: {occ}") - print(f"Dist Fn: {dist_fn}") - print(f"Returned: {sum_extract}") - else: - assert sum_extract == test["expected"]["hypercube_hops"]