growth_main/
growth_main.rs1use std::collections::BTreeMap;
18use std::io::{self, Read};
19use std::process::ExitCode;
20
21use subms::{SubMsGrowthClass, SubMsGrowthRecipe, grow, growth_to_json};
22use subms_timer_wheel::TimerWheel;
23
24const ENTRY_BYTES: u64 = 48;
27
28struct WheelChurn {
29 wheel: TimerWheel<u64>,
30 num_slots: usize,
31 rounds: usize,
32 ops_per_round: usize,
33 seq: u64,
34}
35
36impl SubMsGrowthRecipe for WheelChurn {
37 fn name(&self) -> &str {
38 "subms-timer-wheel"
39 }
40 fn op_name(&self) -> &str {
41 "schedule"
42 }
43 fn rounds(&self) -> usize {
44 self.rounds
45 }
46 fn ops_per_round(&self) -> usize {
47 self.ops_per_round
48 }
49 fn op(&mut self, _round: usize, i: usize) {
50 let delay = (i % (self.num_slots - 1)) + 1;
54 self.wheel.schedule(delay, self.seq);
55 self.seq += 1;
56 let _ = self.wheel.tick();
57 }
58 fn memory_bytes(&mut self) -> u64 {
59 self.wheel.pending() as u64 * ENTRY_BYTES
60 }
61 fn live_bytes(&mut self) -> u64 {
62 self.wheel.pending() as u64 * ENTRY_BYTES
65 }
66 fn structures(&mut self) -> Vec<(String, u64)> {
67 vec![("pending".to_string(), self.wheel.pending() as u64)]
68 }
69 fn expected(&self) -> (SubMsGrowthClass, f64) {
70 (SubMsGrowthClass::PlateauBounded, 1.5)
73 }
74}
75
76fn parse_usize(map: &BTreeMap<String, String>, key: &str, default: usize) -> usize {
77 map.get(key)
78 .and_then(|v| v.trim().parse().ok())
79 .unwrap_or(default)
80}
81
82fn main() -> ExitCode {
83 let mut raw = String::new();
84 if io::stdin().read_to_string(&mut raw).is_err() {
85 eprintln!("growth_main: failed to read stdin");
86 return ExitCode::FAILURE;
87 }
88 let mut map = BTreeMap::new();
89 for line in raw.lines() {
90 let line = line.trim();
91 if line.is_empty() || line.starts_with('#') {
92 continue;
93 }
94 if let Some((k, v)) = line.split_once('=') {
95 map.insert(k.trim().to_string(), v.trim().to_string());
96 }
97 }
98 let rounds = parse_usize(&map, "rounds", 50);
99 let num_slots = parse_usize(&map, "num_slots", 256).max(4);
100 let ops_per_round = parse_usize(&map, "ops_per_round", 20_000);
101
102 let mut recipe = WheelChurn {
103 wheel: TimerWheel::new(num_slots),
104 num_slots,
105 rounds,
106 ops_per_round,
107 seq: 0,
108 };
109 let report = grow(&mut recipe, "rust");
110
111 if growth_to_json(&report, &mut io::stdout().lock()).is_err() {
112 eprintln!("growth_main: failed to write json");
113 return ExitCode::FAILURE;
114 }
115 ExitCode::SUCCESS
116}