ruccl/tensor_device/
tensor.rs1use super::{TensorDevice, TensorDeviceError, TensorElement, storage};
2use crate::ReduceOperation;
3use crate::rank::{ReductionOperation, communicator::RankCommunicator};
4use ruda_tensor::{Backend, DType, Shape, TensorMetadata, bf16, f16};
5
6impl<B: Backend> RankCommunicator<TensorDevice<B>> {
7 pub fn all_reduce_float(
14 &self,
15 value: B::FloatTensorPrimitive,
16 operation: ReduceOperation,
17 ) -> Result<B::FloatTensorPrimitive, TensorDeviceError> {
18 match value.dtype() {
19 DType::F32 => self.reduce_float::<f32>(value, operation),
20 DType::F16 => self.reduce_float::<f16>(value, operation),
21 DType::BF16 => self.reduce_float::<bf16>(value, operation),
22 dtype => Err(TensorDeviceError::UnsupportedDType(dtype)),
23 }
24 }
25
26 fn reduce_float<T: TensorElement>(
27 &self,
28 value: B::FloatTensorPrimitive,
29 operation: ReduceOperation,
30 ) -> Result<B::FloatTensorPrimitive, TensorDeviceError> {
31 let execution = self.execution();
32 execution.validate_type::<T>()?;
33 if &B::float_device(&value) != execution.device() {
34 return Err(TensorDeviceError::DeviceMismatch);
35 }
36 let shape = value.shape();
37 let length = shape.iter().try_fold(1_usize, |length, dim| {
38 length.checked_mul(*dim).ok_or(TensorDeviceError::InvalidBuffer(
39 "collective tensor element count overflow",
40 ))
41 })?;
42 storage::checked_length::<T>(length)?;
43 let value = B::float_reshape(value, Shape::new([length]));
44 let buffer = execution.import_float::<T>(value)?;
45 self.tensor_collective::<T>().all_reduce(
46 &buffer,
47 ReductionOperation::Sum,
48 &ReductionOperation::Sum,
49 )?;
50 let mut value = buffer.float_tensor()?;
51 if operation == ReduceOperation::Mean {
52 value = B::float_div_scalar(value, (self.world_size() as f32).into());
53 }
54 Ok(B::float_reshape(value, shape))
55 }
56}