Skip to content

Commit fabcf0e

Browse files
committed
Added benchmarks
1 parent be4950b commit fabcf0e

7 files changed

Lines changed: 321 additions & 249 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 141 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ crate-type = ["lib"]
2020
#togo = "0.6"
2121

2222
[dev-dependencies]
23-
rand = "0.9"
24-
2523

2624
[profile.release]
2725
lto = true
@@ -30,3 +28,15 @@ panic = "abort"
3028
opt-level = 3
3129
# for samply
3230
#debug = 1
31+
32+
[[bench]]
33+
name = "nfp_bench100"
34+
harness = false
35+
36+
[[bench]]
37+
name = "nfp_bench200"
38+
harness = false
39+
40+
[[bench]]
41+
name = "nfp_bench500"
42+
harness = false

benches/nfp_bench100.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use nfp::prelude::*;
2+
use std::time::Instant;
3+
4+
/// Number of iterations to run the NFP calculation
5+
const ITERATIONS: usize = 1000;
6+
7+
fn main() {
8+
println!("NFP Benchmark");
9+
println!("=============");
10+
println!("Iterations: {}\n", ITERATIONS);
11+
12+
// Generate two different 100-edge polygons with fixed seeds
13+
println!("Generating polygons...");
14+
let poly_a = generate_100_edge_polygon(42);
15+
let poly_b = generate_100_edge_polygon(43);
16+
println!("Polygon A: {} vertices", poly_a.len());
17+
println!("Polygon B: {} vertices", poly_b.len());
18+
19+
// Warm up
20+
let _ = NFP::nfp(&poly_a, &poly_b);
21+
22+
// Run benchmark
23+
println!("\nRunning benchmark ({} iterations)...", ITERATIONS);
24+
let start = Instant::now();
25+
26+
for _ in 0..ITERATIONS {
27+
let _ = NFP::nfp(&poly_a, &poly_b);
28+
}
29+
30+
let elapsed = start.elapsed();
31+
32+
// Print results
33+
println!("\nResults:");
34+
println!("--------");
35+
println!("Total time: {:?}", elapsed);
36+
println!("Time per run: {:.3} ms", elapsed.as_secs_f64() * 1000.0 / ITERATIONS as f64);
37+
println!("Runs per sec: {:.0}", ITERATIONS as f64 / elapsed.as_secs_f64());
38+
}
39+
40+
/// Generate a 100-edge polygon using a fixed seed via bit manipulation
41+
/// to avoid runtime dependency on DataGen
42+
fn generate_100_edge_polygon(seed: u64) -> Vec<Point> {
43+
use std::f64::consts::PI;
44+
45+
let mut points = Vec::new();
46+
let mut rng_state = seed;
47+
48+
// Simple LCG (Linear Congruential Generator) for reproducible randomness
49+
let lcg_next = |state: &mut u64| {
50+
*state = state.wrapping_mul(1664525).wrapping_add(1013904223);
51+
(*state >> 32) as f32 as f64 / (u32::MAX as f64)
52+
};
53+
54+
// Generate 100 points in polar coordinates
55+
for _ in 0..100 {
56+
let angle = lcg_next(&mut rng_state) * 2.0 * PI;
57+
let radius = 0.5 + lcg_next(&mut rng_state) * 1.5;
58+
points.push(point(radius * angle.cos(), radius * angle.sin()));
59+
}
60+
61+
// Sort by angle from centroid to ensure CCW ordering
62+
let centroid = compute_centroid(&points);
63+
points.sort_by(|a, b| {
64+
let angle_a = (a.y - centroid.y).atan2(a.x - centroid.x);
65+
let angle_b = (b.y - centroid.y).atan2(b.x - centroid.x);
66+
angle_a.partial_cmp(&angle_b).unwrap_or(std::cmp::Ordering::Equal)
67+
});
68+
69+
points
70+
}
71+
72+
fn compute_centroid(points: &[Point]) -> Point {
73+
if points.is_empty() {
74+
return point(0.0, 0.0);
75+
}
76+
77+
let sum_x: f64 = points.iter().map(|p| p.x).sum();
78+
let sum_y: f64 = points.iter().map(|p| p.y).sum();
79+
let len = points.len() as f64;
80+
81+
point(sum_x / len, sum_y / len)
82+
}
83+
84+
/*
85+
cargo bench --bench nfp_benchmark
86+
87+
88+
Iterations: 1000
89+
90+
Generating polygons...
91+
Polygon A: 100 vertices
92+
Polygon B: 100 vertices
93+
94+
Running benchmark (1000 iterations)...
95+
96+
Results:
97+
--------
98+
Total time: 4.152361987s
99+
Time per run: 4.152 ms
100+
Runs per sec: 241
101+
_______________________________________________
102+
103+
*/

benches/nfp_bench200.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use nfp::prelude::*;
2+
use std::time::Instant;
3+
4+
/// Number of iterations to run the NFP calculation
5+
const ITERATIONS: usize = 300;
6+
7+
fn main() {
8+
println!("NFP Benchmark");
9+
println!("=============");
10+
println!("Iterations: {}\n", ITERATIONS);
11+
12+
// Generate two different 200-edge polygons with fixed seeds
13+
println!("Generating polygons...");
14+
let poly_a = generate_200_edge_polygon(44);
15+
let poly_b = generate_200_edge_polygon(45);
16+
println!("Polygon A: {} vertices", poly_a.len());
17+
println!("Polygon B: {} vertices", poly_b.len());
18+
19+
// Warm up
20+
let _ = NFP::nfp(&poly_a, &poly_b);
21+
22+
// Run benchmark
23+
println!("\nRunning benchmark ({} iterations)...", ITERATIONS);
24+
let start = Instant::now();
25+
26+
for _ in 0..ITERATIONS {
27+
let _ = NFP::nfp(&poly_a, &poly_b);
28+
}
29+
30+
let elapsed = start.elapsed();
31+
32+
// Print results
33+
println!("\nResults:");
34+
println!("--------");
35+
println!("Total time: {:?}", elapsed);
36+
println!("Time per run: {:.3} ms", elapsed.as_secs_f64() * 1000.0 / ITERATIONS as f64);
37+
println!("Runs per sec: {:.0}", ITERATIONS as f64 / elapsed.as_secs_f64());
38+
}
39+
40+
/// Generate a 200-edge polygon using a fixed seed via bit manipulation
41+
/// to avoid runtime dependency on DataGen
42+
fn generate_200_edge_polygon(seed: u64) -> Vec<Point> {
43+
use std::f64::consts::PI;
44+
45+
let mut points = Vec::new();
46+
let mut rng_state = seed;
47+
48+
// Simple LCG (Linear Congruential Generator) for reproducible randomness
49+
let lcg_next = |state: &mut u64| {
50+
*state = state.wrapping_mul(1664525).wrapping_add(1013904223);
51+
(*state >> 32) as f32 as f64 / (u32::MAX as f64)
52+
};
53+
54+
// Generate 200 points in polar coordinates
55+
for _ in 0..200 {
56+
let angle = lcg_next(&mut rng_state) * 2.0 * PI;
57+
let radius = 0.5 + lcg_next(&mut rng_state) * 1.5;
58+
points.push(point(radius * angle.cos(), radius * angle.sin()));
59+
}
60+
61+
// Sort by angle from centroid to ensure CCW ordering
62+
let centroid = compute_centroid(&points);
63+
points.sort_by(|a, b| {
64+
let angle_a = (a.y - centroid.y).atan2(a.x - centroid.x);
65+
let angle_b = (b.y - centroid.y).atan2(b.x - centroid.x);
66+
angle_a.partial_cmp(&angle_b).unwrap_or(std::cmp::Ordering::Equal)
67+
});
68+
69+
points
70+
}
71+
72+
fn compute_centroid(points: &[Point]) -> Point {
73+
if points.is_empty() {
74+
return point(0.0, 0.0);
75+
}
76+
77+
let sum_x: f64 = points.iter().map(|p| p.x).sum();
78+
let sum_y: f64 = points.iter().map(|p| p.y).sum();
79+
let len = points.len() as f64;
80+
81+
point(sum_x / len, sum_y / len)
82+
}
83+
84+
/*
85+
cargo bench --bench nfp_benchmark
86+
87+
88+
Iterations: 300
89+
90+
Generating polygons...
91+
Polygon A: 200 vertices
92+
Polygon B: 200 vertices
93+
94+
Running benchmark (300 iterations)...
95+
96+
Results:
97+
--------
98+
Total time: 5.604518697s
99+
Time per run: 18.682 ms
100+
Runs per sec: 54
101+
_______________________________________________
102+
103+
*/

0 commit comments

Comments
 (0)