1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
//! Generates `generated.rs` — the dispatch benchmark matrix
//! (command length × command count × command-name type × {dispatch_linear,
//! dispatch_tree, dispatch_phf}).
//!
//! The heavy lifting (dispatch generation) happens inside the `bench_cell!`
//! proc macro from `mingling_macros` (enabled via its `bench_support`
//! feature); this script only writes the invocations and the glue.
use std::fmt::Write as _;
use std::path::Path;
// Full length axis (4/8/16/32) × count {128, 256} × {single, multi,
// nested4, nested10}, keeping the agreed max-256 / depth-10 bound so the
// whole matrix compiles in a few minutes.
const LENGTHS: [usize; 4] = [4, 8, 16, 32];
const COUNTS: [usize; 2] = [128, 256];
// (label, kind, chain_depth) — chain_depth only applies to the "nested" kind.
const TYPES: [(&str, &str, usize); 4] = [
("single", "single", 0),
("multi", "multi", 0),
("nested4", "nested", 4),
("nested10", "nested", 10),
];
const STRATEGIES: [&str; 4] = [
"dispatch_linear",
"dispatch_tree",
"dispatch_phf",
"dispatch_auto",
];
fn zero_pad(i: usize, w: usize) -> String {
let s = i.to_string();
let mut out = String::with_capacity(w);
for _ in 0..w.saturating_sub(s.len()) {
out.push('0');
}
out.push_str(&s);
out
}
fn make_names(len: usize, count: usize, kind: &str, depth: usize) -> Vec<String> {
let digits = |n: usize| n.to_string().len();
let mut names = Vec::new();
match kind {
// Single-word commands with no shared prefixes.
"single" => {
let w = len.saturating_sub(1).max(3).max(digits(count));
for i in 0..count {
names.push(format!("c{}", zero_pad(i, w)));
}
}
// Two-word commands sharing the first word ("cmd ..."), git-style.
"multi" => {
let w = len.saturating_sub(4).max(3).max(digits(count));
for i in 0..count {
names.push(format!("cmd {}", zero_pad(i, w)));
}
}
// Nested-prefix chains of `depth`: base, base w1, base w1 w2, ...
// The base word length follows the `len` axis.
"nested" => {
let groups = count.div_ceil(depth);
let bw = len.saturating_sub(1).max(3).max(digits(groups));
'outer: for g in 0..groups {
let base = format!("n{}", zero_pad(g, bw));
for d in 0..depth {
let mut name = base.clone();
for k in 1..=d {
let _ = write!(name, " w{k}");
}
names.push(name);
if names.len() == count {
break 'outer;
}
}
}
}
_ => unreachable!(),
}
names
}
fn entries_tokens(names: &[String]) -> String {
names
.iter()
.enumerate()
.map(|(i, n)| format!("\"{n}\" => D{i}"))
.collect::<Vec<_>>()
.join(", ")
}
fn main() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is set by cargo");
let mut src = String::from("// @generated by mingling_bench/build.rs — do not edit.\n\n");
let mut meta = String::new();
let mut run_cell = String::new();
let mut run_cell_pick = String::new();
let mut meta_entries: Vec<String> = Vec::new();
let mut cell_id = 0usize;
for &len in &LENGTHS {
for &count in &COUNTS {
for &(ty, kind, depth) in &TYPES {
let label = format!("len{len:03}_cnt{count:04}_ty_{ty}");
let names = make_names(len, count, kind, depth);
for &strat in &STRATEGIES {
let _ = writeln!(
src,
"mingling_macros::bench_cell!({strat}, cell_{cell_id:03}, [{}]);\n",
entries_tokens(&names)
);
meta_entries.push(format!(
"(\"{label}\", \"{strat}\", cell_{cell_id:03}::NAMES),"
));
let _ = writeln!(
run_cell,
" {cell_id} => cell_{cell_id:03}::measure(hits, misses),"
);
let _ = writeln!(
run_cell_pick,
" {cell_id} => cell_{cell_id:03}::STRATEGY,"
);
cell_id += 1;
}
}
}
}
let _ = writeln!(
meta,
"pub static CELL_META: &[(&str, &str, &'static [&'static str])] = &[\n{}\n];",
meta_entries.join("\n")
);
let _ = writeln!(
src,
"{meta}\n\
pub fn run_cell(id: usize, hits: &[Vec<String>], misses: &[Vec<String>]) -> (f64, f64) {{\n\
match id {{\n\
{run_cell} _ => panic!(\"unknown cell {{id}}\"),\n\
}}\n\
}}\n\
pub fn run_cell_pick(id: usize) -> &'static str {{\n\
match id {{\n\
{run_cell_pick} _ => \"\",\n\
}}\n\
}}"
);
std::fs::write(Path::new(&out_dir).join("generated.rs"), src)
.expect("failed to write generated.rs");
}
|