Skip to main content

bench_groupby_shift/
bench_groupby_shift.rs

1//! Bench + golden digest for SeriesGroupBy::shift (br-frankenpandas-gbcum).
2//!
3//! Run: cargo run -p fp-frame --example bench_groupby_shift --release -- <n> <iters>
4//!
5//! The dense path (dense gid + per-gid ring buffer) replaces the generic
6//! build_groups + per-group Vec<Scalar> shift. `FP_NO_GBSHIFT=1` forces the
7//! generic path for the baseline; the printed `chk` is an order-sensitive FNV
8//! digest of the full output (incl. group-boundary nulls) so the two runs prove
9//! bit-identicality.
10
11use std::hint::black_box;
12use std::time::Instant;
13
14use fp_columnar::Column;
15use fp_frame::Series;
16use fp_index::{Index, IndexLabel};
17use fp_types::Scalar;
18
19fn main() {
20    let args: Vec<String> = std::env::args().collect();
21    let n: usize = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(1_000_000);
22    let iters: usize = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(30);
23    let groups = 100usize;
24
25    let labels: Vec<IndexLabel> = (0..n as i64).map(IndexLabel::Int64).collect();
26    let keys: Vec<i64> = (0..n).map(|i| (i % groups) as i64).collect();
27    let vals: Vec<f64> = (0..n).map(|i| (i.wrapping_mul(37) % 9973) as f64 * 0.25).collect();
28    let value = Series::new(
29        "v".to_string(),
30        Index::new(labels.clone()),
31        Column::from_f64_values(vals),
32    )
33    .unwrap();
34    let key = Series::new(
35        "k".to_string(),
36        Index::new(labels),
37        Column::from_i64_values(keys),
38    )
39    .unwrap();
40
41    let out = value.groupby(&key).unwrap().shift(1).unwrap();
42    let mut chk: u64 = 0xcbf29ce484222325;
43    for v in out.values() {
44        let bits = match v {
45            Scalar::Float64(f) => f.to_bits(),
46            _ => 0xDEAD_BEEF_DEAD_BEEF,
47        };
48        chk = (chk ^ bits).wrapping_mul(0x100000001b3);
49    }
50
51    let mut sink = 0usize;
52    let start = Instant::now();
53    for _ in 0..iters {
54        let s = black_box(value.groupby(&key).unwrap().shift(1).unwrap());
55        sink ^= s.len();
56    }
57    let elapsed = start.elapsed();
58    println!(
59        "groupby_shift n={n} iters={iters}: {:.3} ms/iter (chk={chk:016x} sink={sink})",
60        elapsed.as_secs_f64() * 1000.0 / iters as f64
61    );
62}