use alloc::vec::Vec;
use burn_backend::TensorMetadata;
use burn_backend::{DeviceOps, distributed::DistributedOps};
use burn_dispatch::{Dispatch, DispatchTensor};
pub use burn_std::distributed::*;
use crate::{Device, Tensor, ops::BridgeTensor};
#[derive(Debug)]
pub struct DistributedContext {
devices: Vec<Device>,
}
impl DistributedContext {
pub fn init(devices: Vec<Device>, config: DistributedConfig) -> Self {
let dispatch_devices = devices
.iter()
.map(|d| d.as_dispatch().clone())
.collect::<Vec<_>>();
Dispatch::start_communication_server(&dispatch_devices, config);
Self { devices }
}
}
impl Drop for DistributedContext {
fn drop(&mut self) {
if !self.devices.is_empty() {
Dispatch::close_communication_server(self.devices[0].as_dispatch());
}
}
}
#[derive(new, Clone)]
pub struct CollectiveTensor<const D: usize> {
handle: DispatchTensor,
}
impl<const D: usize> CollectiveTensor<D> {
pub fn resolve(self) -> Tensor<D> {
Dispatch::sync_collective(&self.handle.device());
Tensor::new(BridgeTensor::float(self.handle))
}
pub unsafe fn assume_resolved(self) -> Tensor<D> {
Tensor::new(BridgeTensor::float(self.handle))
}
}
pub fn all_reduce<const D: usize>(
input: Tensor<D>,
op: ReduceOperation,
device_ids: Vec<Device>,
) -> CollectiveTensor<D> {
let device_ids = device_ids.iter().map(|d| d.as_dispatch().id()).collect();
let collective = Dispatch::all_reduce(input.primitive.into_float(), op, device_ids);
CollectiveTensor::new(unsafe { collective.assume_resolved() })
}