1use std::collections::{HashMap, HashSet};
4
5use superfluid_abi::encoding;
6
7use crate::primitives::{SampleSpec,
8 Feed, Input, MemCounters, PrimError, RuntimeDescriptor, RuntimePrimitives, SamplingDefaults, Seq, Vocabulary,
9};
10
11#[derive(Debug, Clone)]
12pub struct FakeConfig {
13 pub vocab: u32,
14 pub eos: u32,
15 pub page: u32,
16 pub max_batch: u32,
17 pub max_seq_len: u64,
18 pub kv_bytes_per_token: u64,
19 pub cells_total: u64,
20 pub truncate_partial: bool,
21 pub max_seqs: u32,
22 pub identity: u8,
23 pub engine_sampling: bool,
24 pub copy_shares_cells: bool,
25 pub takeover_preferred: bool,
26 pub seed_min_tokens: u64,
27 pub cache_resident_cells: u64,
31 pub cache_exported_cells: u64,
32 pub vocabulary: Option<Vocabulary>,
33 pub sampling_defaults: SamplingDefaults,
34 pub step_delay: std::time::Duration,
36 pub verify_rows: bool,
38 pub copy_model: bool,
41 pub copy_miss_every: usize,
44 pub prefill_step_tokens: u32,
46}
47
48impl Default for FakeConfig {
49 fn default() -> Self {
50 FakeConfig {
51 vocab: 32000,
52 eos: 31999,
53 page: 16,
54 max_batch: 8,
55 max_seq_len: 4096,
56 kv_bytes_per_token: 64,
57 cells_total: 0,
58 truncate_partial: true,
59 max_seqs: 0,
60 identity: 0xFA,
61 engine_sampling: true,
62 copy_shares_cells: false,
63 takeover_preferred: false,
64 seed_min_tokens: 0,
65 cache_resident_cells: 0,
66 cache_exported_cells: 0,
67 vocabulary: None,
68 sampling_defaults: SamplingDefaults::default(),
69 step_delay: std::time::Duration::ZERO,
70 verify_rows: false,
71 copy_model: false,
72 copy_miss_every: 0,
73 prefill_step_tokens: 0,
74 }
75 }
76}
77
78pub struct FakePrimitives {
79 pub cfg: FakeConfig,
80 seqs: HashMap<Seq, Vec<u32>>,
81 next_seq: Seq,
82 scripted: HashMap<Seq, Vec<u32>>,
83 fail_next: Option<PrimError>,
84 poison_import: bool,
85 pub feeds: Vec<(usize, bool)>,
86 pub beside: Vec<u64>,
90 cells: HashMap<Seq, Vec<u64>>,
91 holders: HashMap<u64, u32>,
92 next_cell: u64,
93 pub synced: Option<bool>,
95}
96
97impl Default for FakePrimitives {
98 fn default() -> Self {
99 FakePrimitives::new(FakeConfig::default())
100 }
101}
102
103const SEED: u64 = 0xCBF2_9CE4_8422_2325;
104
105fn hash(content: &[u32], salt: u64) -> u64 {
106 let mut h = superfluid_fingerprint::fnv1a64(&salt.to_le_bytes(), SEED);
107 for &t in content {
108 h = superfluid_fingerprint::fnv1a64(&t.to_le_bytes(), h);
109 }
110 h
111}
112
113impl FakePrimitives {
114 pub fn new(cfg: FakeConfig) -> FakePrimitives {
115 FakePrimitives {
116 cfg,
117 seqs: HashMap::new(),
118 next_seq: 1,
119 scripted: HashMap::new(),
120 fail_next: None,
121 poison_import: false,
122 feeds: Vec::new(),
123 beside: Vec::new(),
124 cells: HashMap::new(),
125 holders: HashMap::new(),
126 next_cell: 1,
127 synced: None,
128 }
129 }
130
131 fn room_for(&self, more: u64, freed: u64) -> Result<(), PrimError> {
132 let used = (self.holders.len() as u64).saturating_sub(freed);
133 if self.cfg.cells_total > 0 && used + more > self.cfg.cells_total {
134 return Err(PrimError::Capacity);
135 }
136 Ok(())
137 }
138
139 fn take_cells(&mut self, seq: Seq, n: u64) {
140 let ids: Vec<u64> = (0..n).map(|k| self.next_cell + k).collect();
141 self.next_cell += n;
142 for &id in &ids {
143 self.holders.insert(id, 1);
144 }
145 self.cells.entry(seq).or_default().extend(ids);
146 }
147
148 fn drop_cells(&mut self, seq: Seq, from: usize) {
149 let Some(own) = self.cells.get_mut(&seq) else { return };
150 let gone: Vec<u64> = own.drain(from.min(own.len())..).collect();
151 for id in gone {
152 if let Some(n) = self.holders.get_mut(&id) {
153 *n -= 1;
154 if *n == 0 {
155 self.holders.remove(&id);
156 }
157 }
158 }
159 }
160
161 pub fn token_for(&self, content: &[u32]) -> u32 {
162 let miss = self.cfg.copy_miss_every > 0 && content.len().is_multiple_of(self.cfg.copy_miss_every);
163 if self.cfg.copy_model && !miss {
164 if let Some((&last, before)) = content.split_last() {
165 if let Some(i) = before.iter().rposition(|&t| t == last) {
166 return content[i + 1];
167 }
168 }
169 }
170 (hash(content, 1) % (self.cfg.vocab as u64 - 1)) as u32
171 }
172
173 pub fn row_for(&self, content: &[u32]) -> Vec<f32> {
174 let best = self.token_for(content);
175 let base = hash(content, 2);
176 let mut row: Vec<f32> = (0..self.cfg.vocab)
177 .map(|i| ((base.wrapping_mul(i as u64 + 1) >> 40) % 1000) as f32 / 1000.0 - 0.5)
178 .collect();
179 row[best as usize] = 10.0;
180 row
181 }
182
183 pub fn contents(&self, seq: Seq) -> Option<&[u32]> {
184 self.seqs.get(&seq).map(|v| v.as_slice())
185 }
186
187 pub fn script(&mut self, seq: Seq, tokens: Vec<u32>) {
188 self.scripted.insert(seq, tokens);
189 }
190
191 pub fn fault_next_step(&mut self, code: u32) {
192 self.fail_next = Some(PrimError::Fault(code));
193 }
194
195 pub fn fail_next_step(&mut self, e: PrimError) {
196 self.fail_next = Some(e);
197 }
198
199 fn count_beside(&mut self, feeds: &[Feed<'_>]) {
200 let fed: HashSet<u64> = feeds.iter().flat_map(|f| self.cells.get(&f.seq).into_iter().flatten().copied()).collect();
201 self.beside.push(self.holders.keys().filter(|id| !fed.contains(id)).count() as u64);
202 }
203
204 pub fn poison_next_import(&mut self) {
205 self.poison_import = true;
206 }
207
208 fn cut_ok(&self, len: u64, cur: u64) -> bool {
209 len == 0 || (len <= cur && (self.cfg.truncate_partial || len == cur))
210 }
211}
212
213impl RuntimePrimitives for FakePrimitives {
214 fn sync_steps(&mut self, on: bool) {
215 self.synced = Some(on);
216 }
217
218 fn describe(&self) -> RuntimeDescriptor {
219 RuntimeDescriptor {
220 runtime_id: "fake".into(),
221 runtime_version: "1".into(),
222 max_batch: self.cfg.max_batch,
223 max_seqs: self.cfg.max_seqs,
224 max_seq_len: self.cfg.max_seq_len,
225 vocab_size: self.cfg.vocab,
226 page_size_tokens: self.cfg.page,
227 kv_bytes_per_token: self.cfg.kv_bytes_per_token,
228 cells_total: self.cfg.cells_total,
229 truncate_partial: self.cfg.truncate_partial,
230 copy_shares_cells: self.cfg.copy_shares_cells,
231 takeover_preferred: self.cfg.takeover_preferred,
232 seed_min_tokens: self.cfg.seed_min_tokens,
233 cache_resident_cells: self.cfg.cache_resident_cells,
234 cache_exported_cells: self.cfg.cache_exported_cells,
235 recurrent: !self.cfg.truncate_partial,
236 export_encodings: vec![encoding::LOSSLESS],
237 engine_sampling: self.cfg.engine_sampling,
238 engine_draws: false,
239 verify_rows: self.cfg.verify_rows,
240 verify_batches: true,
241 prefill_step_tokens: self.cfg.prefill_step_tokens,
242 weights_identity: [self.cfg.identity; 32],
243 architecture: "fake".into(),
244 backend: "cpu".into(),
245 sampling_defaults: self.cfg.sampling_defaults,
246 }
247 }
248
249 fn is_eos(&self, token: u32) -> bool {
250 token == self.cfg.eos
251 }
252
253 fn mem_counters(&self) -> MemCounters {
254 let cells_used = self.holders.len() as u64;
255 MemCounters {
256 allocated_bytes: cells_used * self.cfg.kv_bytes_per_token,
257 cells_used,
258 cells_total: self.cfg.cells_total,
259 }
260 }
261
262 fn seq_create(&mut self) -> Result<Seq, PrimError> {
263 if self.cfg.max_seqs > 0 && self.seqs.len() as u32 >= self.cfg.max_seqs {
264 return Err(PrimError::Capacity);
265 }
266 let s = self.next_seq;
267 self.next_seq += 1;
268 self.seqs.insert(s, Vec::new());
269 self.cells.insert(s, Vec::new());
270 Ok(s)
271 }
272
273 fn seq_free(&mut self, seq: Seq) {
274 self.drop_cells(seq, 0);
275 self.cells.remove(&seq);
276 self.seqs.remove(&seq);
277 self.scripted.remove(&seq);
278 }
279
280 fn seq_len(&self, seq: Seq) -> u64 {
281 self.seqs.get(&seq).map(|v| v.len() as u64).unwrap_or(0)
282 }
283
284 fn cells_released(&self, seqs: &[Seq]) -> u64 {
285 let set: HashSet<Seq> = seqs.iter().copied().collect();
286 let mut held: HashMap<u64, u32> = HashMap::new();
287 for s in &set {
288 for &id in self.cells.get(s).into_iter().flatten() {
289 *held.entry(id).or_default() += 1;
290 }
291 }
292 held.iter().filter(|(id, n)| self.holders.get(id) == Some(n)).count() as u64
293 }
294
295 fn seq_copy(&mut self, src: Seq, dst: Seq, len: u64) -> Result<(), PrimError> {
296 let s = self.seqs.get(&src).ok_or(PrimError::UnknownSeq)?;
297 if !self.cut_ok(len, s.len() as u64) {
298 return Err(PrimError::OutOfBoundary);
299 }
300 if !self.seqs.contains_key(&dst) {
301 return Err(PrimError::UnknownSeq);
302 }
303 let prefix = s[..len as usize].to_vec();
304 if self.cfg.copy_shares_cells {
305 let shared: Vec<u64> = self.cells[&src][..len as usize].to_vec();
306 self.drop_cells(dst, 0);
307 for &id in &shared {
308 *self.holders.get_mut(&id).expect("held by src") += 1;
309 }
310 self.cells.insert(dst, shared);
311 } else {
312 self.room_for(len, self.cells_released(&[dst]))?;
313 self.drop_cells(dst, 0);
314 self.take_cells(dst, len);
315 }
316 *self.seqs.get_mut(&dst).expect("checked") = prefix;
317 Ok(())
318 }
319
320 fn seq_truncate(&mut self, seq: Seq, new_len: u64) -> Result<(), PrimError> {
321 let cur = self.seq_len(seq);
322 if !self.seqs.contains_key(&seq) {
323 return Err(PrimError::UnknownSeq);
324 }
325 if !self.cut_ok(new_len, cur) {
326 return Err(PrimError::OutOfBoundary);
327 }
328 self.seqs.get_mut(&seq).expect("checked").truncate(new_len as usize);
329 self.drop_cells(seq, new_len as usize);
330 Ok(())
331 }
332
333 fn seq_boundary(&self, seq: Seq, cap: u64) -> u64 {
334 let len = self.seq_len(seq);
335 if self.cfg.truncate_partial {
336 cap.min(len)
337 } else if len <= cap {
338 len
339 } else {
340 0
341 }
342 }
343
344 fn seq_export(&mut self, seq: Seq, len: u64, enc: u8) -> Result<Vec<u8>, PrimError> {
345 if enc != encoding::LOSSLESS {
346 return Err(PrimError::Unsupported);
347 }
348 let s = self.seqs.get(&seq).ok_or(PrimError::UnknownSeq)?;
349 if !self.cut_ok(len, s.len() as u64) {
350 return Err(PrimError::OutOfBoundary);
351 }
352 Ok(s[..len as usize].iter().flat_map(|t| t.to_le_bytes()).collect())
353 }
354
355 fn seq_import(&mut self, seq: Seq, payload: &[u8]) -> Result<u64, PrimError> {
356 let s = self.seqs.get(&seq).ok_or(PrimError::UnknownSeq)?;
357 if !s.is_empty() || !payload.len().is_multiple_of(4) {
358 return Err(PrimError::OutOfBoundary);
359 }
360 self.room_for(payload.len() as u64 / 4, 0)?;
361 self.take_cells(seq, payload.len() as u64 / 4);
362 let s = self.seqs.get_mut(&seq).expect("checked");
363 *s = payload.as_chunks::<4>().0.iter().map(|c| u32::from_le_bytes(*c)).collect();
364 if std::mem::take(&mut self.poison_import) {
365 return Err(PrimError::Fatal);
366 }
367 Ok(s.len() as u64)
368 }
369
370 fn step(&mut self, feeds: &[Feed<'_>]) -> Result<Vec<Vec<f32>>, PrimError> {
371 if let Some(e) = self.fail_next.take() {
372 return Err(e);
373 }
374 if !self.cfg.step_delay.is_zero() {
375 std::thread::sleep(self.cfg.step_delay);
376 }
377 let mut more = 0u64;
378 for f in feeds {
379 let Input::Tokens(t) = f.input else { return Err(PrimError::Unsupported) };
380 if !self.seqs.contains_key(&f.seq) {
381 return Err(PrimError::UnknownSeq);
382 }
383 more += t.len() as u64;
384 }
385 self.room_for(more, 0)?;
386 self.count_beside(feeds);
387 let mut rows = Vec::new();
388 for f in feeds {
389 let Input::Tokens(t) = f.input else { return Err(PrimError::Unsupported) };
390 self.take_cells(f.seq, t.len() as u64);
391 self.feeds.push((t.len(), f.wants_row));
392 let s = self.seqs.get_mut(&f.seq).expect("checked");
393 s.extend_from_slice(t);
394 if f.wants_row {
395 let content = s.clone();
396 let mut row = self.row_for(&content);
397 if let Some(script) = self.scripted.get_mut(&f.seq) {
398 if !script.is_empty() {
399 let next = script.remove(0);
400 for x in row.iter_mut() {
401 *x = -1.0;
402 }
403 row[next as usize] = 10.0;
404 }
405 }
406 rows.push(row);
407 }
408 }
409 Ok(rows)
410 }
411
412 fn step_rows(&mut self, feeds: &[Feed<'_>]) -> Result<Option<Vec<Vec<Vec<f32>>>>, PrimError> {
413 if !self.cfg.verify_rows {
414 return Ok(None);
415 }
416 if let Some(e) = self.fail_next.take() {
417 return Err(e);
418 }
419 if !self.cfg.step_delay.is_zero() {
420 std::thread::sleep(self.cfg.step_delay);
421 }
422 let mut more = 0u64;
423 for f in feeds {
424 let Input::Tokens(t) = f.input else { return Err(PrimError::Unsupported) };
425 if !self.seqs.contains_key(&f.seq) {
426 return Err(PrimError::UnknownSeq);
427 }
428 more += t.len() as u64;
429 }
430 self.room_for(more, 0)?;
431 self.count_beside(feeds);
432 let mut out = Vec::new();
433 for f in feeds {
434 let Input::Tokens(t) = f.input else { return Err(PrimError::Unsupported) };
435 self.take_cells(f.seq, t.len() as u64);
436 self.feeds.push((t.len(), f.wants_row));
437 let s = self.seqs.get_mut(&f.seq).expect("checked");
438 let base = s.len();
439 s.extend_from_slice(t);
440 if f.wants_row {
441 let content = s.clone();
442 out.push((1..=t.len()).map(|i| self.row_for(&content[..base + i])).collect());
443 }
444 }
445 Ok(Some(out))
446 }
447
448 fn step_sampled(&mut self, feeds: &[Feed<'_>], specs: &[SampleSpec]) -> Result<Option<Vec<u32>>, PrimError> {
449 if !self.cfg.engine_sampling || specs.len() != feeds.len() || specs.iter().any(|s| s.temperature > 0.0) {
450 return Ok(None);
451 }
452 let rows = self.step(feeds)?;
453 Ok(Some(rows.iter().map(|r| crate::sampling::argmax(r)).collect()))
454 }
455
456 fn vocabulary(&self) -> Option<Vocabulary> {
457 self.cfg.vocabulary.clone()
458 }
459}