QuOp MPI Communicator Structure (Current)
Overview
The communicator hierarchy is implemented in
native/comm_info/comm_info_module.f90 with two core objects:
split_info_t: pre/post-negotiate worker metadata (SUBCOMM,ROOTCOMM,JACCOMM, worker ids)quop_mpi_layout_t: active execution layout (partitioning + owned runtime communicators)
The current code path is backend-aware:
MPI backend:
NODECOMMis created,DEVCOMM/DEVCOMM_NODEstayMPI_COMM_NULLWavefront backend:
NODECOMM,DEVCOMM, andDEVCOMM_NODEare created and can be rebuilt during negotiate
Communicator Set
Name |
Owner |
Meaning |
|---|---|---|
|
Borrowed by both objects |
Root communicator passed in by caller. Never freed by QuOp. |
|
|
Per-worker communicator used by negotiate and runtime collectives. |
|
|
Shared-memory node-local communicator derived from |
|
|
All active GPU ranks across nodes (wavefront only). |
|
|
Active GPU ranks on the local node (wavefront only). |
|
|
Rank-0 leader from each post-negotiate |
|
|
Optional Jacobian communicator (optimizer rank + Jacobian worker ranks);
typically created only when |
Ownership Model
Object |
Owns |
Destroy behavior |
|---|---|---|
|
|
|
|
|
|
MPI_COMM is never freed by either object.
Lifecycle
discover_topology(MPI_COMM, backend_flag)detects node/global topology, with wavefront additionally building hardware GPU topology metadata.split_workers(...)creates workerSUBCOMM(single-worker case usesMPI_Comm_dup), creates an initialROOTCOMMfrom pre-negotiate subcomm leaders, and storesworker_id/n_workersinsplit_info_t.negotiate(...)allocatesquop_mpi_layout_t, transfersSUBCOMMownership fromsplit_info_t, createsNODECOMM(all backends), createsDEVCOMM/DEVCOMM_NODEon wavefront, refreshes communicator-derived topology fields in the layout, and may filter or shrinkSUBCOMMwith child-communicator rebuilds.create_rootcomm(MPI_COMM, split_ptr, layout_ptr)rebuildsROOTCOMMfrom rank 0 of each post-negotiateSUBCOMM.create_jaccomm(MPI_COMM, split_ptr, layout_ptr)buildsJACCOMMwith current worker-role semantics (worker_id == 0joins only onSUBCOMMrank 0, whileworker_id > 0joins on all ranks). In the current PythonAnsatzpath, this step is skipped whenn_workers == 1.
Current Flow
flowchart TD
A[MPI_COMM] --> B[discover_topology]
B --> C[split_workers]
C --> D[split_info_t: SUBCOMM and ROOTCOMM]
D --> E[negotiate]
E --> F[quop_mpi_layout_t: SUBCOMM, NODECOMM, DEVCOMM on wavefront]
F --> G[create_rootcomm]
F --> H[create_jaccomm optional]
G --> I[split_info_t ROOTCOMM refreshed]
H --> J[split_info_t JACCOMM ready]
Backend-Specific Notes
layout_shrinkalways rebuildsSUBCOMMandNODECOMM; wavefront also rebuildsDEVCOMMandDEVCOMM_NODE.layout_filter_active_ranksrebuildsSUBCOMMby predicatelocal_i > 0instead of prefix size and then refreshes child communicators/topology from the filtered active set.layout_rebuild_communicatorsis wavefront-only in practice (MPI backend is a no-op for device communicators).device_n_processesin the layout tracks active device ranks onNODECOMM(node-local count), not globalDEVCOMMsize.
Collective Requirements
Operation |
Collective communicator |
|---|---|
|
|
|
|
|
Active ranks on |
|
|
|
|
Destruction Order
For safe teardown, destroy in this order:
Propagator/context users that borrow layout communicators
quop_mpi_layout_t(frees runtime communicators)split_info_t(freesROOTCOMM/JACCOMMand any remainingSUBCOMM)
This order avoids dangling communicator handles in borrowed objects.