Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-graph3d/examples/aos_crossover.rs

//! **Where does the parked pool actually beat one core — over the REAL node array?**
//!
//! `split_probe` fed both lanes a packed `Vec<[f32;3]>`. The crate does not have one: it
//! projects out of `&[Node3]`, which is `{ String, Color32, [f32;3] }` — so every 12
//! useful bytes drag a ~40-byte struct, and a 64-byte cache line carries barely one
//! point. Setting `PROJ_PARALLEL_MIN` from the packed number was measuring a layout the
//! shipped code does not use.
//!
//! Run: cargo run --release -p facett-graph3d --example aos_crossover

use std::time::Instant;

use egui::Pos2;
use facett_graph3d::{dataset, Graph3D, Layout3D};

const FRAMES: usize = 60;

#[inline]
fn project_pt(p: [f32; 3], center: Pos2, scale: f32, s: f32, c: f32) -> (Pos2, f32) {
    let x = p[0] * c + p[2] * s;
    let z = -p[0] * s + p[2] * c;
    (Pos2::new(center.x + x * scale, center.y - p[1] * scale), z)
}

fn main() {
    let pool = znippy_zoomies::gatling_map::Pool::new(0);
    println!("# AoS crossover — serial vs parked pool over the REAL &[Node3]");
    println!(
        "machine = {} threads, workers = {}",
        std::thread::available_parallelism().map(|n| n.get()).unwrap_or(0),
        pool.workers()
    );
    println!();
    println!("{:>9}  {:>13}  {:>13}  {:>9}  {:>13}  {:>9}", "n", "serial AoS", "pooled AoS", "speedup", "pooled SoA", "SoA gain");

    let (w, h) = (1280.0f32, 800.0f32);
    let center = Pos2::new(w * 0.5, h * 0.5);
    let scale = w.min(h) * 0.40;

    for &want in &[30_000usize, 100_000, 300_000, 1_000_000] {
        let d = dataset::generate(&dataset::GraphSpec::sized(want));
        let g = Graph3D::new(d.nodes, d.edges, Layout3D::Sphere);
        let n = g.nodes.len();
        let soa: Vec<[f32; 3]> = g.nodes.iter().map(|nd| nd.pos).collect();
        let yaws: Vec<f32> = (0..FRAMES).map(|f| f as f32 * 0.05).collect();
        let per = |ms: f64| ms / FRAMES as f64;
        let mut out = vec![(Pos2::ZERO, 0.0f32); n];

        let t = Instant::now();
        for &yaw in &yaws {
            let (s, c) = yaw.sin_cos();
            for (o, nd) in out.iter_mut().zip(g.nodes.iter()) {
                *o = project_pt(nd.pos, center, scale, s, c);
            }
            std::hint::black_box(&out);
        }
        let ser = per(t.elapsed().as_secs_f64() * 1000.0);

        let t = Instant::now();
        for &yaw in &yaws {
            let (s, c) = yaw.sin_cos();
            pool.map_slice(&g.nodes, &mut out, |nd| project_pt(nd.pos, center, scale, s, c));
            std::hint::black_box(&out);
        }
        let par_aos = per(t.elapsed().as_secs_f64() * 1000.0);

        let t = Instant::now();
        for &yaw in &yaws {
            let (s, c) = yaw.sin_cos();
            pool.map_slice(&soa, &mut out, |p| project_pt(*p, center, scale, s, c));
            std::hint::black_box(&out);
        }
        let par_soa = per(t.elapsed().as_secs_f64() * 1000.0);

        println!(
            "{:>9}  {:>10.3} ms  {:>10.3} ms  {:>8.2}x  {:>10.3} ms  {:>8.2}x",
            n, ser, par_aos, ser / par_aos.max(1e-9), par_soa, par_aos / par_soa.max(1e-9)
        );
    }
    println!();
    println!("`speedup` > 1.00x means the pool beat one core AT THAT LAYOUT. `SoA gain` is what");
    println!("packing the positions alone buys the SAME pooled lane — the cost of striding Node3.");
}