pub struct ClusterConfig {
pub controller: ClusterController,
pub workers: Vec<ClusterWorker>,
pub env: BTreeMap<String, String>,
}Expand description
Cluster topology, parsed from the cluster: block at the project
root. Two role-separated sub-blocks:
controller: the orchestrator host fdl-cli runs on. Holds the rendezvous bind point (host/port) plus the controller-local fields needed for pre-flight build and the ClusterController TCP listener. The controller is NOT a NCCL rank.workers: every rank-carrying host. Each entry binds one or more global ranks and their CUDA device indices.
This is the controller-side full topology; per-worker slim
envelopes are derived from it and shipped to each node, where the
library reads them via flodl::distributed::LocalCluster::from_env.
Launcher-only fields (ssh:) are not propagated to the envelope.
The library re-validates after reading; this validation runs earlier
so errors surface before fdl-cli opens any SSH connection.
Fields§
§controller: ClusterController§workers: Vec<ClusterWorker>§env: BTreeMap<String, String>Cluster-scope env vars exported into every rank child on every
worker. Mapping NAME: VALUE (string→string). Use for tuning
the launcher itself shouldn’t hardcode — e.g. on the Pascal-
under-VFIO rig, set NCCL_P2P_DISABLE: "1" +
NCCL_SHM_DISABLE: "1" so NCCL falls back to socket transport
(the direct-IPC transports fail under VFIO on consumer Pascal).
Worker-scope ClusterWorker::env takes precedence for matching
keys.
Implementations§
Source§impl ClusterConfig
impl ClusterConfig
Sourcepub fn world_size(&self) -> usize
pub fn world_size(&self) -> usize
Total ranks across the cluster.
Sourcepub fn spans_multiple_hosts(&self) -> bool
pub fn spans_multiple_hosts(&self) -> bool
Whether the cluster spans more than one physical worker.
Single-worker clusters don’t require NCCL_SOCKET_IFNAME.
Sourcepub fn validate(&self) -> Result<(), String>
pub fn validate(&self) -> Result<(), String>
Pre-flight validation. Mirrors the library check so failures surface before SSH dispatch instead of from a stack trace on a remote host:
controller.hostnon-empty,controller.pathnon-emptyworkersnon-empty- per worker:
hostnon-empty,nccl_socket_ifnamenon-empty (when cluster spans multiple workers),pathnon-empty
Ranks are NOT user input — they’re computed by
Self::populate_ranks from probed device counts. When this
runs pre-probe (ranks empty), the rank-shape check is skipped;
when called post-probe (ranks populated), the
0..world_size + length-match-vs-local_devices invariant is
enforced.
Sourcepub fn populate_ranks(&mut self, device_counts: &[usize]) -> Result<(), String>
pub fn populate_ranks(&mut self, device_counts: &[usize]) -> Result<(), String>
Populate workers[i].ranks from probed device counts.
Sequential assignment by worker order: worker 0 owns
[0..counts[0]), worker 1 owns
[counts[0]..counts[0]+counts[1]), etc.
Errors when device_counts.len() != workers.len() or any
count is 0. Workers’ existing ranks are unconditionally
overwritten — they’re not user input, the probe is
authoritative.
Caller orchestration (see prepare_cluster_env):
- parse YAML → ClusterConfig (ranks empty by serde default)
- probe device counts per worker
- call
populate_ranksto fill in - validate (now ranks are non-empty → shape checks run)
- serialize and ship via FLODL_INTERNAL_FULL_CLUSTER_JSON
Sourcepub fn canonical_json(&self) -> Result<String, String>
pub fn canonical_json(&self) -> Result<String, String>
Canonical JSON of the full topology. Used for debug-dumping the
controller-side view; per-worker envelopes go through
Self::local_envelope_for instead.
Sourcepub fn local_envelope_for(&self, worker: &ClusterWorker) -> Value
pub fn local_envelope_for(&self, worker: &ClusterWorker) -> Value
Build the slim per-worker envelope the library reads via
flodl::distributed::LocalCluster::from_env.
The envelope strips launcher-only fields (ssh*), embeds derived
world metadata (world_size, num_workers), and carries only
the requested worker’s slice. The launcher hex-encodes the
resulting JSON into FLODL_INTERNAL_CLUSTER_JSON per ssh invocation, so
each remote process sees only itself + the controller
coordinates.
Sourcepub fn ssh_target<'a>(&'a self, worker: &'a ClusterWorker) -> &'a str
pub fn ssh_target<'a>(&'a self, worker: &'a ClusterWorker) -> &'a str
Look up the SSH target for a worker, defaulting to host if
ssh: is not set. Used by the launcher; library callers don’t
need this.
Trait Implementations§
Source§impl Clone for ClusterConfig
impl Clone for ClusterConfig
Source§fn clone(&self) -> ClusterConfig
fn clone(&self) -> ClusterConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more