Skip to content

[STF] pytorch.localized with locality domains - #10705

Draft
caugonnet wants to merge 807 commits into
NVIDIA:mainfrom
caugonnet:x-9892-integration
Draft

[STF] pytorch.localized with locality domains#10705
caugonnet wants to merge 807 commits into
NVIDIA:mainfrom
caugonnet:x-9892-integration

Conversation

@caugonnet

Copy link
Copy Markdown
Contributor

Description

Experiments with locality domains with in pytorch.localized. This PR combines #9892 and #10703 (and by transitivity #5315 and #10658)

closes

Checklist

  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

caugonnet and others added 30 commits June 11, 2026 09:07
Validate Burger reference step grouping so environment overrides cannot silently drop tail steps, and clean up minor stale test code noted in review.
Tighten STF Python lifecycle cleanup, lazy imports, binding shims, CI diagnostics, and API docs based on the comprehensive follow-up review.
Describe the Burger reference example as a PyTorch baseline for the same solver rather than explaining prior planning context.
green_ctx_data_place_impl had no mem_create override, so it inherited the
data_place_interface default returning CUDA_ERROR_NOT_SUPPORTED. A composite/
localized_array allocation whose affine places are green contexts therefore
failed at cuMemCreate. Add a device-style mem_create (PINNED, DEVICE,
location.id = view_.devid) mirroring data_place_device, so each partition gets
its own physical VMM chunk.

Also include the CUgreenCtx handle in to_string() so distinct contexts no
longer render identically as "green_ctx(dev=0)" -- the localized allocation
stats now report them as separate places.

Assisted-by: Cursor (Claude Opus 4.8)
Signed-off-by: Cedric AUGONNET <caugonnet@nvidia.com>
Reuse the existing cuda.compute stream protocol handling in STF Python bindings so stream arguments honor __cuda_stream__ objects while preserving raw pointer support.
Keep CUDA Array Interface descr metadata when STF exports structured task arguments, and centralize STF CAI dtype parsing to avoid losing field layout information.
Destroy the opaque exec_place_resources handle returned by ctx.place_resources so the wrapper is released while the context keeps owning the underlying stream pools.
Raise Python ValueError when a task or host launch receives logical data from another context, avoiding later C++ aborts on context mismatches.
Run cuda.stf._experimental Python tests on the h100_2gpu runner so PR CI covers multi-GPU STF behavior.
Move the Linux-only cuda.stf._experimental bindings out of the cuda-cccl
wheel into a new, optional python/cuda_stf distribution, following the
split-package model used by cuda-coop. The runtime import path
cuda.stf._experimental is preserved; users now install cuda-stf[cu12|cu13].

- Move cuda/stf source and STF tests to python/cuda_stf, dropping the empty
  cuda/stf/__init__.py so cuda/cuda.stf/cuda.cccl remain shared namespaces.
- Add cuda-stf packaging (pyproject, CMakeLists, README, LICENSE, wheel
  merger). cuda-stf depends on cuda-cccl for headers and CUDA-version
  detection, and ships only the cudax/C-STF headers cuda-cccl does not
  provide to avoid file-ownership conflicts.
- Remove STF build/install and wheel-merge behavior from cuda-cccl and drop
  STF from its examples runner.
- Wire CI: build_cuda_stf_{python,wheel}.sh, a build_py_stf_wheel job, a
  distinct STF wheel artifact (CCCL_WHEEL_KIND), and a test_py_stf lane that
  installs both wheels and runs python/cuda_stf/tests.
- Update docs and AGENTS.md to document the cuda-stf install path.
cuda-stf previously required cuda-cccl at runtime for CUDA version
detection (cuda.cccl._cuda_version_utils) and header discovery
(cuda.cccl.headers). This copies the tiny version-detection helper into
cuda-stf, ships STF's own cudax + C-STF headers under
cuda/stf/_experimental/include, and makes cuda-cccl an optional peer used
only to supply libcudacxx/CUB/Thrust include paths for external C++
compilation. cuda-cccl remains in the test extras for the cuda.compute
interop tests.

This also fixes the broken CI matrix parse: test_py_stf now depends on a
single producer (build_py_stf_wheel) instead of a list of producers,
which the workflow-build machinery does not support (TypeError:
unhashable type: 'list').
(cherry picked from commit 9d37b5e)
caugonnet and others added 15 commits August 7, 2026 09:13
The missing entry point for "give me a grid for this machine":
granularity="device" (one place per CUDA device, like from_devices over
all of them) or granularity="locality_domain" (one place per locality
domain of every device, device-major). A device without native support
contributes its single whole-device domain, so the domain granularity
degrades to the device one exactly where domains are unavailable -- one
code path for callers, per the never-0 count contract.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Parametrize the example suite's grid over two granularities: the repeat
device grid, and the machine's locality domains (via
exec_place_grid.machine(granularity="locality_domain") when the PR NVIDIA#10703
bindings are present, locality_domains(0) as fallback, clean skip
otherwise). The whole programming-model spectrum -- compiled pointwise,
unsplit-dim softmax, partials+fold, misalignment, CUDA-graph capture,
TinyMLP -- now exercises the substrate the placement work is for. The
partials assert becomes grid-size-agnostic (domain counts vary by
machine).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d 'origin/stf-cute-partitions-python' into x-9892-integration
A create()-built grid has no affine data place; a dependency without an
explicit place then throws C++-side and TERMINATES through the void C API
instead of raising -- the known 5315-family error-channel gap, hit here on
GB300. Use the proven replicated-read pattern and document the constraint
in the test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Design decision (Cedric): blocked along dimension 0 is the natural
strategy for a machine-level grid, so machine() attaches it as the grid's
affine data place (native stf_partition_fn_blocked, no callback
trampoline). Bare dependencies -- lX.rw() with no explicit data place --
now resolve on machine grids instead of terminating through the void C API
for lack of an affine; the test exercises exactly the case that aborted on
GB300, alongside an explicit replicated read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ntyped access)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…er test

Found on GB300 while validating machine()'s default affine: a replicated
read whose valid source instance lives at a composite place terminates in
the device exec-place deactivate with "invalid device ordinal" -- the
broadcast-copy path derives a restore ordinal from a composite affine.
machine() merely makes the sequence (composite write, then replicated
read) easy to reach; the interplay predates it. The reproducer is recorded
in the test comment; the test sources the replicated read from the host
instance until the C++ path is fixed. Bare rw at the default blocked
affine works and stays covered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
GB300 bisection: the aborts were NOT a replicated-broadcast issue (that
sequence passes) but affine mutation on a SHARED place. make_grid
degenerates a size-1 grid to the place itself; for the device granularity
that is the process-shared exec_place::device(0), so attaching the blocked
composite affine mutated the shared scalar place -- and every later
deactivate derived its restore ordinal from a composite affine
(cudaSetDevice(-5), invalid device ordinal). Attach the default affine
only when the machine grid has more than one place; a scalar place's own
device affine already resolves bare dependencies. Corrects the earlier
misdiagnosis recorded in the test comment; the write-then-replicated-read
sequence is restored in the test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The controlled experiments behind the 2026-08-08 GB300 findings, as one
reproducible script (benchmarks/localization_ab.py): streaming fused
compiled pointwise (vanilla loses under caps: near/vanilla 1.27x at
250-400 W, wins 1.22x at the wall), DRAM- and L2-resident random gathers
(placement-neutral at nn concurrency), and sustained-power energy
(near ~0.95x J/GB uncapped). Requires the locality-domain bindings and
skips cleanly without them; confinement via exec_place.pick_stream domain
streams; power caps external (powerbot).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"""Stock torch.compile when triton is available, eager otherwise --
map treats both identically (any callable)."""
try:
import triton # noqa: F401, PLC0415

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This probably makes more sense to skip the test entirely if triton is not available using pytest ?

return eg.machine(granularity="locality_domain")
if hasattr(eg, "locality_domains"):
return eg.locality_domains(0)
pytest.skip("locality-domain bindings not available (PR #10703)")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

the PR name should ultimately disappear

@caugonnet caugonnet mentioned this pull request Aug 7, 2026
2 tasks
caugonnet and others added 11 commits August 7, 2026 20:26
Expose checked grid reshaping and contiguous-axis collapse through the C and
Python APIs. Keep transformed grid handles independently owned and convert
invalid shape errors into clean FFI failures instead of process termination.
A grid_dims product that does not match the number of places now raises
a ValueError in the Python binding (stf_c_api review change) instead of
a RuntimeError from the C layer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow the C-order Python contract from the structured-partition work:
reshape() takes a public C-order shape (linear place order is preserved
because the public C-order enumeration and the native dimension-0-fastest
enumeration coincide after reversal), collapse_axes() takes public axes
mapped onto the native inclusive range [rank-1-last, rank-1-first] and
validated against the grid's rank, and both stamp the result's grid rank
so dims stays rank-aware.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e bindings assume

The reshape/collapse bindings cherry-picked from NVIDIA#9899 were written on top
of the C-order public-shape contract, whose plumbing lived in the
stf-cute-partitions-python branch. Hoist that slice here, matching its
text exactly so the later NVIDIA#9892 merge is trivial:

- _validate_extents/_fill_dim4_c_order/_native_to_public helpers (the one
  place the public C order and the native dimension-0-fastest ABI meet);
- exec_place.dims returns a C-order tuple of the grid rank (scalar: (1,));
- exec_place_grid tracks _grid_rank (grid_rank property; set by create/
  reshape/collapse_axes, 1-D creation paths default to 1);
- create(grid_dims=) validates through the shared helpers;
- task tracks the rank from set_exec_place; get_grid_dims returns the
  C-order shape; get_stream_ptrs sizes from the rank-length tuple;
- test expectations updated to the contract ((2, 2) grids, scalar (1,)).

The C++ reshape/collapse machinery itself is already in main (with
_CCCL_HOST_API annotations), so the NVIDIA#9899 C++ commit was dropped as
redundant during the fold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

2 participants