1use ferrum_types::Device;
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
10pub enum ParallelismType {
11 #[default]
13 None,
14 Tensor,
16 Pipeline,
18 Data,
20 Hybrid,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ParallelConfig {
27 pub parallelism_type: ParallelismType,
29 pub devices: Vec<Device>,
31 pub tensor_parallel_size: usize,
33 pub pipeline_parallel_size: usize,
35 pub enable_memory_optimization: bool,
37 pub communication_backend: String,
39 pub max_chunk_size: usize,
41 pub overlap_communication: bool,
43}
44
45impl Default for ParallelConfig {
46 fn default() -> Self {
47 Self {
48 parallelism_type: ParallelismType::None,
49 devices: vec![Device::CPU],
50 tensor_parallel_size: 1,
51 pipeline_parallel_size: 1,
52 enable_memory_optimization: true,
53 communication_backend: "cpu".to_string(),
54 max_chunk_size: 1024 * 1024, overlap_communication: true,
56 }
57 }
58}
59
60impl ParallelConfig {
61 pub fn single_gpu(device: Device) -> Self {
63 Self {
64 parallelism_type: ParallelismType::None,
65 devices: vec![device],
66 ..Default::default()
67 }
68 }
69
70 pub fn tensor_parallel(devices: Vec<Device>) -> Self {
72 let size = devices.len();
73 Self {
74 parallelism_type: ParallelismType::Tensor,
75 devices,
76 tensor_parallel_size: size,
77 pipeline_parallel_size: 1,
78 ..Default::default()
79 }
80 }
81
82 pub fn pipeline_parallel(devices: Vec<Device>) -> Self {
84 let size = devices.len();
85 Self {
86 parallelism_type: ParallelismType::Pipeline,
87 devices,
88 tensor_parallel_size: 1,
89 pipeline_parallel_size: size,
90 ..Default::default()
91 }
92 }
93
94 pub fn data_parallel(devices: Vec<Device>) -> Self {
96 Self {
97 parallelism_type: ParallelismType::Data,
98 devices,
99 tensor_parallel_size: 1,
100 pipeline_parallel_size: 1,
101 ..Default::default()
102 }
103 }
104
105 pub fn hybrid(devices: Vec<Device>, tp_size: usize, pp_size: usize) -> Self {
107 Self {
108 parallelism_type: ParallelismType::Hybrid,
109 devices,
110 tensor_parallel_size: tp_size,
111 pipeline_parallel_size: pp_size,
112 ..Default::default()
113 }
114 }
115
116 pub fn world_size(&self) -> usize {
118 self.tensor_parallel_size * self.pipeline_parallel_size
119 }
120
121 pub fn is_parallel(&self) -> bool {
123 self.parallelism_type != ParallelismType::None && self.world_size() > 1
124 }
125
126 pub fn device_for_rank(&self, rank: usize) -> Option<&Device> {
128 self.devices.get(rank)
129 }
130
131 pub fn tp_rank(&self, global_rank: usize) -> usize {
133 global_rank % self.tensor_parallel_size
134 }
135
136 pub fn pp_rank(&self, global_rank: usize) -> usize {
138 global_rank / self.tensor_parallel_size
139 }
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
144pub struct LayerDistribution {
145 pub stage_layers: Vec<LayerRange>,
147 pub stage_memory: Vec<usize>,
149}
150
151#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
153pub struct LayerRange {
154 pub start: usize,
156 pub end: usize,
158}
159
160impl LayerRange {
161 pub fn new(start: usize, end: usize) -> Self {
162 Self { start, end }
163 }
164
165 pub fn len(&self) -> usize {
166 self.end - self.start
167 }
168
169 pub fn is_empty(&self) -> bool {
170 self.start >= self.end
171 }
172
173 pub fn contains(&self, layer: usize) -> bool {
174 layer >= self.start && layer < self.end
175 }
176}
177
178impl LayerDistribution {
179 pub fn even_distribution(num_layers: usize, num_stages: usize) -> Self {
181 let layers_per_stage = num_layers / num_stages;
182 let remainder = num_layers % num_stages;
183
184 let mut stage_layers = Vec::with_capacity(num_stages);
185 let mut start = 0;
186
187 for stage in 0..num_stages {
188 let extra = if stage < remainder { 1 } else { 0 };
189 let end = start + layers_per_stage + extra;
190 stage_layers.push(LayerRange::new(start, end));
191 start = end;
192 }
193
194 Self {
195 stage_layers,
196 stage_memory: vec![0; num_stages], }
198 }
199
200 pub fn stage_for_layer(&self, layer: usize) -> Option<usize> {
202 self.stage_layers
203 .iter()
204 .position(|range| range.contains(layer))
205 }
206}
207
208#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn test_single_gpu_config() {
218 let config = ParallelConfig::single_gpu(Device::CPU);
219 assert_eq!(config.parallelism_type, ParallelismType::None);
220 assert_eq!(config.world_size(), 1);
221 assert!(!config.is_parallel());
222 }
223
224 #[test]
225 fn test_tensor_parallel_config() {
226 let config = ParallelConfig::tensor_parallel(vec![Device::CUDA(0), Device::CUDA(1)]);
227 assert_eq!(config.parallelism_type, ParallelismType::Tensor);
228 assert_eq!(config.tensor_parallel_size, 2);
229 assert_eq!(config.world_size(), 2);
230 assert!(config.is_parallel());
231 }
232
233 #[test]
234 fn test_hybrid_config() {
235 let config = ParallelConfig::hybrid(
236 vec![
237 Device::CUDA(0),
238 Device::CUDA(1),
239 Device::CUDA(2),
240 Device::CUDA(3),
241 ],
242 2, 2, );
245 assert_eq!(config.world_size(), 4);
246 assert_eq!(config.tp_rank(0), 0);
247 assert_eq!(config.tp_rank(1), 1);
248 assert_eq!(config.tp_rank(2), 0);
249 assert_eq!(config.tp_rank(3), 1);
250 assert_eq!(config.pp_rank(0), 0);
251 assert_eq!(config.pp_rank(1), 0);
252 assert_eq!(config.pp_rank(2), 1);
253 assert_eq!(config.pp_rank(3), 1);
254 }
255
256 #[test]
257 fn test_layer_distribution() {
258 let dist = LayerDistribution::even_distribution(32, 4);
259 assert_eq!(dist.stage_layers.len(), 4);
260 assert_eq!(dist.stage_layers[0].start, 0);
261 assert_eq!(dist.stage_layers[0].end, 8);
262 assert_eq!(dist.stage_layers[3].start, 24);
263 assert_eq!(dist.stage_layers[3].end, 32);
264 }
265
266 #[test]
267 fn test_layer_distribution_uneven() {
268 let dist = LayerDistribution::even_distribution(33, 4);
269 assert_eq!(dist.stage_layers[0].len(), 9);
272 assert_eq!(dist.stage_layers[1].len(), 8);
273 }
274
275 #[test]
276 fn test_stage_for_layer() {
277 let dist = LayerDistribution::even_distribution(32, 4);
278 assert_eq!(dist.stage_for_layer(0), Some(0));
279 assert_eq!(dist.stage_for_layer(7), Some(0));
280 assert_eq!(dist.stage_for_layer(8), Some(1));
281 assert_eq!(dist.stage_for_layer(31), Some(3));
282 assert_eq!(dist.stage_for_layer(32), None);
283 }
284}