use std::{collections::HashMap, sync::Arc};
use crate::{NodeId, global::shared::GlobalCollectiveError, node::sync::SyncService};
use ruda_tensor::{Backend, TensorMetadata};
use ruda_communication::data_service::TensorDataService;
use ruda_communication::{Address, Protocol};
use futures::StreamExt;
use futures::stream::FuturesUnordered;
pub(crate) async fn centralized_all_reduce_sum<B, P>(
node: NodeId,
nodes: &HashMap<NodeId, Address>,
data_service: &Arc<TensorDataService<B, P>>,
sync_service: Arc<SyncService<P>>,
tensor: B::FloatTensorPrimitive,
) -> Result<B::FloatTensorPrimitive, GlobalCollectiveError>
where
B: Backend,
P: Protocol,
{
let ids = nodes.keys().cloned().collect::<Vec<_>>();
let central = get_central_node(ids.clone());
let shape = tensor.shape();
let device = &B::float_device(&tensor);
let res = if central == node {
let mut futures = ids
.iter()
.filter(|id| **id != central) .map(|id| {
let address = nodes.get(id).unwrap();
let device = device.clone();
let data_service = data_service.clone();
async move {
let data = data_service
.download_tensor((*address).clone(), 0.into())
.await
.expect("Couldn't find the tensor for transfer id 0");
B::float_from_data(data, &device)
}
})
.collect::<FuturesUnordered<_>>();
let mut sum = tensor;
while let Some(res) = futures.next().await {
if shape != res.shape() {
return Err(GlobalCollectiveError::PeerSentIncoherentTensor);
}
sum = B::float_add(sum, res);
}
let other_nodes_count = ids.len() as u32 - 1;
data_service
.expose(sum.clone(), other_nodes_count, 1.into())
.await;
sum
} else {
data_service.expose(tensor, 1, 0.into()).await;
let central_addr = nodes.get(¢ral).unwrap().clone();
let data = data_service
.download_tensor(central_addr, 1.into())
.await
.expect("Couldn't find the tensor for transfer id 1");
let res = B::float_from_data(data, device);
if shape != res.shape() {
return Err(GlobalCollectiveError::PeerSentIncoherentTensor);
}
res
};
sync_service.sync().await;
Ok(res)
}
pub(crate) fn get_central_node(mut nodes: Vec<NodeId>) -> NodeId {
nodes.sort();
*nodes.first().unwrap()
}