Skip to content

Commit 88c74a8

Browse files
evilsocketclaude
andcommitted
flash-moe: inline shape storage in TensorMeta
Replace Vec<usize> shape with inline [usize; 4] + ndim. Eliminates heap allocation per TensorMeta clone during read_tensor/read_tensors calls. Expert tensors are always 2D, so 4 dims is more than sufficient. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7e3736f commit 88c74a8

1 file changed

Lines changed: 38 additions & 8 deletions

File tree

cake-core/src/utils/tensor_storage.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,36 @@ pub trait TensorStorageProvider: Send + Sync {
4747
fn tensor_names(&self) -> Vec<String>;
4848
}
4949

50+
/// Max tensor dimensions supported (covers all practical shapes).
51+
const MAX_DIMS: usize = 4;
52+
53+
/// Inline shape storage — avoids Vec heap allocation for shapes up to 4 dims.
54+
#[derive(Debug, Clone, Copy)]
55+
struct InlineShape {
56+
dims: [usize; MAX_DIMS],
57+
ndim: u8,
58+
}
59+
60+
impl InlineShape {
61+
fn from_vec(v: &[usize]) -> Self {
62+
let mut dims = [0usize; MAX_DIMS];
63+
let ndim = v.len().min(MAX_DIMS);
64+
dims[..ndim].copy_from_slice(&v[..ndim]);
65+
Self {
66+
dims,
67+
ndim: ndim as u8,
68+
}
69+
}
70+
71+
fn as_slice(&self) -> &[usize] {
72+
&self.dims[..self.ndim as usize]
73+
}
74+
75+
fn to_vec(self) -> Vec<usize> {
76+
self.as_slice().to_vec()
77+
}
78+
}
79+
5080
/// Metadata for a single tensor within a safetensors shard file.
5181
#[derive(Debug, Clone)]
5282
struct TensorMeta {
@@ -58,8 +88,8 @@ struct TensorMeta {
5888
byte_size: u64,
5989
/// Data type.
6090
dtype: DType,
61-
/// Shape.
62-
shape: Vec<usize>,
91+
/// Shape (inline, no heap allocation for shapes <= 4 dims).
92+
shape: InlineShape,
6393
}
6494

6595
/// Reads individual tensors from safetensors files using `pread()`.
@@ -238,7 +268,7 @@ impl SafetensorsStorage {
238268
}
239269
};
240270

241-
let shape: Vec<usize> = meta
271+
let shape_vec: Vec<usize> = meta
242272
.get("shape")
243273
.and_then(|v| v.as_array())
244274
.map(|arr| {
@@ -253,7 +283,7 @@ impl SafetensorsStorage {
253283
abs_offset,
254284
byte_size,
255285
dtype,
256-
shape,
286+
shape: InlineShape::from_vec(&shape_vec),
257287
}))
258288
}
259289
}
@@ -290,7 +320,7 @@ impl TensorStorageProvider for SafetensorsStorage {
290320
Ok(TensorData {
291321
bytes: buf,
292322
dtype: meta.dtype,
293-
shape: meta.shape.clone(),
323+
shape: meta.shape.to_vec(),
294324
})
295325
}
296326

@@ -352,7 +382,7 @@ impl TensorStorageProvider for SafetensorsStorage {
352382
results.push(TensorData {
353383
bytes,
354384
dtype: meta.dtype,
355-
shape: meta.shape.clone(),
385+
shape: meta.shape.to_vec(),
356386
});
357387
offset += size;
358388
}
@@ -403,7 +433,7 @@ mod tests {
403433
assert_eq!(tm.abs_offset, 8 + 200);
404434
assert_eq!(tm.byte_size, 1048576);
405435
assert_eq!(tm.dtype, DType::F16);
406-
assert_eq!(tm.shape, vec![1024, 512]);
436+
assert_eq!(tm.shape.to_vec(), vec![1024, 512]);
407437
}
408438

409439
#[test]
@@ -430,7 +460,7 @@ mod tests {
430460
abs_offset: 108,
431461
byte_size: 1024,
432462
dtype: DType::F32,
433-
shape: vec![16, 16],
463+
shape: InlineShape::from_vec(&[16, 16]),
434464
},
435465
);
436466
m

0 commit comments

Comments
 (0)