Skip to content

Add CPU/GPU Combine/Reduction/Repartition/Replicate support to realm-execution backend - #1665

Open
seemamirch wants to merge 7 commits into
flexflow:masterfrom
seemamirch:sm/parallel-ops-realm-update
Open

Add CPU/GPU Combine/Reduction/Repartition/Replicate support to realm-execution backend #1665
seemamirch wants to merge 7 commits into
flexflow:masterfrom
seemamirch:sm/parallel-ops-realm-update

Conversation

@seemamirch

@seemamirch seemamirch commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds CPU and GPU Combine, Reduction, and Repartition and Replicate GPU parallel-operator support to the
realm-execution backend and support the latest FlexFlow master branch, previously Replicate-only CPU.

  • Generalizes the dynamic-graph pipeline (pass_expansioncopy_insertion
    shard_expansion) and Realm dispatch (pcg_instance) around a single
    shared abstraction, ParallelOpMovementKind (BROADCAST/GATHER/
    SUM_REDUCE/RESHUFFLE), so all four parallel ops go through the same
    code paths instead of Replicate-specific special cases.
  • Add GPU reduction support
  • Add CPU & GPU e2e tests
    for all four ops

Add Combine/Reduction/Repartition support to realm-execution backend

Generalizes the previously Replicate-only parallel-op handling in the
dynamic-graph pipeline and Realm execution dispatch into
ParallelOpMovementKind (1→N copy, N→1 copy, N→1 sum, N→N reshuffle):

Op FWD BWD
Replicate BROADCAST SUM_REDUCE
Combine GATHER BROADCAST
Reduction SUM_REDUCE BROADCAST
Repartition RESHUFFLE RESHUFFLE
  • pass_expansion.cc — BWD expansion for all parallel ops is now the
    generic is_parallel_training_op case (was Replicate-only): gradient
    flows in reverse with no forward activations needed, so BWD inputs are
    just the grad of FWD outputs and vice versa.
  • copy_insertion.cc — resolves each value's ParallelTensorMapping
  • shard_expansion.cc — RESHUFFLE splits into N separate per-device
    invocations (same shape as a normal op), while BROADCAST/GATHER/
    SUM_REDUCE stay as a single invocation with the many-valued side
    represented as repeated same-slot-name entries distinguished by
    task_shard — matching how Replicate was already represented
  • pcg_instance.ccspawn_dynamic_node_invocation dispatches to
    issue_broadcast/issue_gather/issue_sum_reduce/issue_copy based
    on ParallelOpMovementKind rather than switching on each op's attrs
    type. issue_gather chains its N copies since they all target the
    same destination instance.
  • tasks/task_id_t.cc, tasks/realm_task_registry.cc
    Combine/Reduction/Repartition never spawn a task (dispatch is pure Realm
    copies/reductions), so their task-ID lookups return nullopt and the
    corresponding (dead) task registrations are removed.

Register CUDA-visible reduction kernels for realm-execution redops

  • redops/realm_redop_registry.cc - (added to the CMake
    target as a CUDA-language source, mirroring lib/kernels), added
    apply_cuda/fold_cuda kernel methods to each SumReduction<T>, and
    rebuilt registration around create_reduction_op<T>() +
    add_cuda_redop_kernels<T>() + register_reduction.

Confirmed on real hardware (2× Tesla P100): all four parallel-op GPU e2e
tests pass

Add parallel-op tests: gather-shaped RESHUFFLE, GPU e2e, base-test fix

  • copy_insertion.cc tests — added a gather-shaped Repartition test
    case. resolve_tensor_mappings previously only tested a pure-shuffle-
    shaped Repartition (both INPUT and OUTPUT unique)
  • test_e2e.cc — added GPU (cuda-realm-execution-tests) e2e training
    test cases for Replicate/Combine/Reduction/Repartition

Test plan

  • task-spec-tests
  • realm-execution-testscpu-realm-execution-tests (per test case)
  • realm-execution-testscuda-realm-execution-tests on real GPU
    hardware (per test case)

This change is Reviewable

Seema Mirchandaney added 7 commits August 13, 2026 14:59
Generalizes the previously Replicate-only parallel-op handling in the
dynamic-graph pipeline (pass_expansion, copy_insertion, shard_expansion)
and Realm execution dispatch (pcg_instance) into a single, shared
ParallelOpMovementKind abstraction (BROADCAST/GATHER/SUM_REDUCE/RESHUFFLE:
1->N copy, N->1 copy, N->1 sum, N->N reshuffle) that all four parallel ops
now go through uniformly:

  Replicate FWD=BROADCAST BWD=SUM_REDUCE | Combine FWD=GATHER BWD=BROADCAST
  Reduction FWD=SUM_REDUCE BWD=BROADCAST | Repartition FWD/BWD=RESHUFFLE

pass_expansion.cc: BWD expansion for all parallel ops is now the generic
is_parallel_training_op case (was Replicate-only) — gradient flows in
reverse with no forward activations needed, so BWD inputs are just the
grad of FWD outputs and vice versa.

copy_insertion.cc: resolves each value's ParallelTensorMapping either
directly from the op's own node mapping (only possible on the side whose
per-device coordinates are unique — the bidict requirement) or from an
adjacent already-resolved value (source, for the non-unique side of
BROADCAST; sink, for the non-unique side of GATHER/SUM_REDUCE). RESHUFFLE
has no fixed fan-in/fan-out direction (Repartition can scatter, gather, or
purely shuffle depending on its degree change), so which side is unique is
checked dynamically per-invocation rather than assumed from the movement
kind; it also accepts LOSS as a valid sink for the adjacent-value case,
since a parallel op's FWD output can feed directly into the loss as the
model's terminal output.

shard_expansion.cc: RESHUFFLE splits into N separate per-device
invocations (like a normal op), while BROADCAST/GATHER/SUM_REDUCE stay as
a single invocation with the many-valued side represented as repeated
same-slot-name entries distinguished by task_shard — matching how
Replicate was already represented, per DynamicTensorSlot.task_shard's
docstring. RESHUFFLE pairs each device's input/output coordinates by
looking up its own shard binding directly by slot name (coordinate values
can otherwise collide between the input and output coordinate spaces).
Also removes shard_invocation_for_binding and
restrict_tensor_mapping_keys_to_coord (dead code — never called;
apply_dynamic_node_invocation_sharding_info is the real path) plus the
#includes that became unused as a result.

pcg_instance.cc: spawn_dynamic_node_invocation dispatches to
issue_broadcast/issue_gather/issue_sum_reduce/issue_copy based on
ParallelOpMovementKind rather than switching on each op's attrs type.
issue_gather chains its N copies sequentially rather than firing them
concurrently, since they all target the same destination instance.
Combine/Reduction/Repartition never spawn a task (dispatch is pure Realm
copies/reductions), so their now-dead task_id_t.cc entries return nullopt
and their realm_task_registry.cc registrations are removed; a few
unused lambda-parameter names in task_id_t.cc were tidied at the same
time.
Renames redops/realm_redop_registry.cc to .cu (added to the CMake target
as a CUDA-language source, mirroring lib/kernels), adds apply_cuda/fold_cuda
kernel methods to each SumReduction<T>, and rebuilds registration around
create_reduction_op<T>() + add_cuda_redop_kernels<T>() + register_reduction.

Two secondary issues had to be worked around to get the new .cu file to
compile under nvcc at all: PRealm's prealm.h (realm-execution/realm.h's
namespace Realm = ::PRealm alias, used everywhere else in this codebase)
fails a static_assert when parsed by nvcc, unrelated to reductions — the
.cu file avoids it entirely and uses ::Realm:: fully-qualified throughout,
so register_all_redops() also dropped its Realm::Runtime parameter (fetches
::Realm::Runtime::get_runtime() itself instead). And the borrowed-from-
Legion SumReduction<bool>/SumReduction<int64_t> non-exclusive apply/fold
paths called __uint2bool/__bool2uint/__longlong_as_ulonglong/
__ulonglong_as_longlong, which aren't real CUDA builtins (Legion-internal
helpers) — implemented locally.

Confirmed on real hardware (2x Tesla P100): all four parallel-op GPU e2e
tests pass.
resolve_tensor_mappings previously only tested a pure-shuffle-shaped
Repartition (both INPUT and OUTPUT unique); copy_insertion's RESHUFFLE
handling determines which side is unique dynamically per-invocation, and
that shape never exercised the OUTPUT-has-dup-coords branch. Adds a
gather-shaped case that does.

Adds GPU (cuda-realm-execution-tests) e2e training test cases for
Replicate/Combine/Reduction/Repartition, and fixes the pre-existing
(unrelated to this branch) base "GPU Model Parallelism" test, which
requested only 1 GPU from Realm despite its config using two device
coordinates.
@seemamirch

Copy link
Copy Markdown
Contributor Author

@elliottslaughter @lockshaw - please review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant