Skip to main content

ClusterConfig

Struct ClusterConfig 

Source
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

Source

pub fn world_size(&self) -> usize

Total ranks across the cluster.

Source

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.

Source

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.host non-empty, controller.path non-empty
  • workers non-empty
  • per worker: host non-empty, nccl_socket_ifname non-empty (when cluster spans multiple workers), path non-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.

Source

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):

  1. parse YAML → ClusterConfig (ranks empty by serde default)
  2. probe device counts per worker
  3. call populate_ranks to fill in
  4. validate (now ranks are non-empty → shape checks run)
  5. serialize and ship via FLODL_INTERNAL_FULL_CLUSTER_JSON
Source

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.

Source

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.

Source

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

Source§

fn clone(&self) -> ClusterConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClusterConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for ClusterConfig

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Serialize for ClusterConfig

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.