memo_workload/
memo_workload.rs1use fusor::{derived, effect, memo, signal};
4use std::{cell::Cell, hint::black_box, rc::Rc, time::Instant};
5
6fn run(name: &str, cached: bool, consumers: usize, updates: u64, work: u64, group: u64) {
7 let input = signal(0_u64);
8 let computations = Rc::new(Cell::new(0_u64));
9 let renders = Rc::new(Cell::new(0_u64));
10 let compute = {
11 let (input, computations) = (input.clone(), computations.clone());
12 move || {
13 computations.set(computations.get() + 1);
14 let mut n = input.get() / group;
15 for _ in 0..work {
16 n = black_box(n.wrapping_mul(6364136223846793005).wrapping_add(1));
17 }
18 n
19 }
20 };
21 let read: Rc<dyn Fn() -> u64> = if cached {
22 let value = memo(compute);
23 Rc::new(move || value.get())
24 } else {
25 let value = derived(compute);
26 Rc::new(move || value.get())
27 };
28 let subscriptions: Vec<_> = (0..consumers)
29 .map(|_| {
30 let (read, renders) = (read.clone(), renders.clone());
31 effect(move || {
32 black_box(read());
33 renders.set(renders.get() + 1);
34 })
35 })
36 .collect();
37 computations.set(0);
38 renders.set(0);
39 let start = Instant::now();
40 for value in 1..=updates {
41 input.set(black_box(value));
42 }
43 let elapsed = start.elapsed().as_micros();
44 let mode = if cached { "Memo" } else { "Derived" };
45 println!(
46 "{name},{mode},{consumers},{updates},{},{},{elapsed}",
47 computations.get(),
48 renders.get()
49 );
50 assert_eq!(
51 computations.get(),
52 updates * if cached { 1 } else { consumers as u64 }
53 );
54 assert_eq!(
55 renders.get(),
56 if cached { updates / group } else { updates } * consumers as u64
57 );
58 drop(subscriptions);
59}
60
61fn main() {
62 println!("workload,mode,consumers,updates,computations,effects,microseconds");
63 for cached in [false, true] {
64 run("cheap scalar", cached, 1, 100_000, 0, 1);
65 run("shared costly projection", cached, 8, 2_000, 10_000, 1);
66 run("mostly equal projection", cached, 8, 20_000, 0, 100);
67 }
68}