1use anyhow::{Context, Result, bail};
14use serde::{Deserialize, Serialize};
15
16use crate::expert::ExpertKey;
17use crate::expert::{ExpertLayout, ExpertRecordHeader, ExpertRecordSpec, Proj};
18
19#[derive(Clone, Copy, Debug)]
22pub struct ProjData<'a> {
23 pub packed: &'a [u8],
24 pub scale: &'a [u8],
25}
26
27#[derive(Clone, Copy, Debug)]
29pub struct ProjView<'a> {
30 pub packed: &'a [u8],
31 pub scale: &'a [u8],
32}
33
34pub fn pack_record(
39 spec: &ExpertRecordSpec,
40 stride: u64,
41 header: &ExpertRecordHeader,
42 projs: &[ProjData; 3],
43) -> Result<Vec<u8>> {
44 let stride = stride as usize;
45 if (spec.raw_bytes() as usize) > stride {
46 bail!(
47 "record stride {} smaller than raw record bytes {}",
48 stride,
49 spec.raw_bytes()
50 );
51 }
52 let mut buf = vec![0u8; stride];
53 let hdr = header.to_bytes();
54 buf[..hdr.len()].copy_from_slice(&hdr);
55
56 for p in Proj::ALL {
57 let pb = spec.proj_bytes(p);
58 let d = &projs[p as usize];
59 if d.packed.len() as u64 != pb.packed_bytes {
60 bail!(
61 "{:?} packed len {} != expected {}",
62 p,
63 d.packed.len(),
64 pb.packed_bytes
65 );
66 }
67 if d.scale.len() as u64 != pb.scale_bytes {
68 bail!(
69 "{:?} scale len {} != expected {}",
70 p,
71 d.scale.len(),
72 pb.scale_bytes
73 );
74 }
75 let po = spec.packed_off(p) as usize;
76 let so = spec.scale_off(p) as usize;
77 buf[po..po + d.packed.len()].copy_from_slice(d.packed);
78 buf[so..so + d.scale.len()].copy_from_slice(d.scale);
79 }
80 Ok(buf)
81}
82
83pub fn unpack_record<'a>(
87 spec: &ExpertRecordSpec,
88 buf: &'a [u8],
89) -> Result<(ExpertRecordHeader, [ProjView<'a>; 3])> {
90 if (buf.len() as u64) < spec.raw_bytes() {
91 bail!(
92 "record buffer {} smaller than raw record bytes {}",
93 buf.len(),
94 spec.raw_bytes()
95 );
96 }
97 let header = ExpertRecordHeader::from_bytes(buf)
98 .context("record header magic/version mismatch (wrong file or format version?)")?;
99 let mut views = [ProjView {
100 packed: &[],
101 scale: &[],
102 }; 3];
103 for p in Proj::ALL {
104 let pb = spec.proj_bytes(p);
105 let po = spec.packed_off(p) as usize;
106 let so = spec.scale_off(p) as usize;
107 views[p as usize] = ProjView {
108 packed: &buf[po..po + pb.packed_bytes as usize],
109 scale: &buf[so..so + pb.scale_bytes as usize],
110 };
111 }
112 Ok((header, views))
113}
114
115#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
119pub struct ExpertIndex {
120 pub version: u32,
123 pub num_moe_layers: u32,
124 pub num_experts: u32,
125 pub inter: u64,
126 pub hidden: u64,
127 pub group_size: u64,
128 pub sub_align: u64,
129 pub fs_block_size: u64,
130 pub record_stride: u64,
131 pub record_raw_bytes: u64,
132 pub file_template: String,
135 pub moe_layer_to_model_layer: Vec<u32>,
138}
139
140impl ExpertIndex {
141 pub const FILE_TEMPLATE: &'static str = "experts_{:05}.xpr";
142 pub const MANIFEST_NAME: &'static str = "manifest.json";
143
144 pub fn new(
145 inter: u64,
146 hidden: u64,
147 group_size: u64,
148 sub_align: u64,
149 fs_block_size: u64,
150 moe_layer_to_model_layer: Vec<u32>,
151 num_experts: u32,
152 ) -> Self {
153 let spec = ExpertRecordSpec::new(inter, hidden, group_size, sub_align);
154 let layout = ExpertLayout::from_spec(
155 moe_layer_to_model_layer.len() as u32,
156 num_experts,
157 &spec,
158 fs_block_size,
159 );
160 Self {
161 version: ExpertRecordHeader::VERSION,
162 num_moe_layers: moe_layer_to_model_layer.len() as u32,
163 num_experts,
164 inter,
165 hidden,
166 group_size,
167 sub_align,
168 fs_block_size,
169 record_stride: layout.record_stride,
170 record_raw_bytes: spec.raw_bytes(),
171 file_template: Self::FILE_TEMPLATE.to_string(),
172 moe_layer_to_model_layer,
173 }
174 }
175
176 #[cfg(unix)]
179 pub fn load(dir: &std::path::Path) -> Result<Self> {
180 let p = dir.join(Self::MANIFEST_NAME);
181 let json = std::fs::read_to_string(&p).with_context(|| format!("read {}", p.display()))?;
182 let index: ExpertIndex =
183 serde_json::from_str(&json).with_context(|| format!("parse {}", p.display()))?;
184 if index.version != ExpertRecordHeader::VERSION {
185 bail!(
186 "manifest version {} != supported {}",
187 index.version,
188 ExpertRecordHeader::VERSION
189 );
190 }
191 Ok(index)
192 }
193
194 pub fn spec(&self) -> ExpertRecordSpec {
195 ExpertRecordSpec::new(self.inter, self.hidden, self.group_size, self.sub_align)
196 }
197
198 pub fn layout(&self) -> ExpertLayout {
199 ExpertLayout::from_spec(
200 self.num_moe_layers,
201 self.num_experts,
202 &self.spec(),
203 self.fs_block_size,
204 )
205 }
206
207 pub fn file_name(&self, moe_layer: u32) -> String {
209 format!("experts_{moe_layer:05}.xpr")
210 }
211
212 pub fn total_bytes(&self) -> u64 {
214 (self.num_moe_layers as u64) * self.layout().bytes_per_layer()
215 }
216}
217
218pub use fs_impl::{ExpertFileReader, ExpertFileWriter};
219
220#[path = "expert_pack_fs.rs"]
221mod fs_impl;
222
223#[cfg(test)]
224#[path = "expert_pack_tests.rs"]
225mod tests;