Skip to content

Commit 44b244c

Browse files
authored
Add Pprof Profiling to Existing Benchmarks (rust-ml#273)
* add pprof profiling * add missing config * target spec dev-dep * cfg targets * add missing criterion_main! * add space for readability * update Benchmarking Section * add profiling to all existing benchmarks
1 parent c301cee commit 44b244c

File tree

18 files changed

+143
-8
lines changed

18 files changed

+143
-8
lines changed

CONTRIBUTE.md

+29
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ let sol = decomp
156156

157157
## Benchmarking
158158

159+
### Building Benchmarks
159160
It is important to the project that we have benchmarks in place to evaluate the benefit of performance related changes. To make that process easier we provide some guidelines for writing benchmarks.
160161

161162
1. Test for a variety of sample sizes for most algorithms [1_000, 10_000, 20_000] will be sufficient. For algorithms where it's not too slow, use 100k instead of 20k.
@@ -169,3 +170,31 @@ It is important to the project that we have benchmarks in place to evaluate the
169170
6. When benchmarking multi-target the target count should be within the following range: [2, 4].
170171
7. In `BenchmarkId` include the values used to parametrize the benchmark. For example if we're doing Pls then we may have something like `Canonical-Nipals-5feats-1_000samples`
171172
8. Pass data as an argument to the function being benched. This will prevent Criterion from including data creation time as part of the benchmark.
173+
9. Add a profiler see [here](https://github.com/tikv/pprof-rs#integrate-with-criterion) for an example on how to do so with pprof, Criterion, and Flamegraph.
174+
175+
### Running Benchmarks
176+
When running benchmarks sometimes you will want to profile the code execution. Assuming you have followed step 9 to add a pprof profiling hook for the linfa-ica package you can run the following to get your profiling results as a flamegraph.
177+
178+
`cargo bench -p linfa-ica --bench fast_ica -q -- --profile-time 30`
179+
180+
If you are interested in running a regular criterion bench for linfa-ica then you can run the following
181+
182+
`cargo bench -p linfa-ica`
183+
184+
### Reporting Benchmark Metrics
185+
It is important that we have a consistent methodology for reporting benchmarks below is a template that should aid reviewers.
186+
187+
```
188+
### Context
189+
In a bullet list describe the following:
190+
1. Run on battery charge or while plugged in
191+
2. Power saving mode
192+
3. If the computer was idle during benchmark
193+
4. If the computer was overheating
194+
5. Hardware specs
195+
196+
### Bench Command Run
197+
bench results (code format)
198+
199+
[Attached Flamegraphs if profile runs were also done]
200+
```

algorithms/linfa-clustering/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ serde_json = "1"
5050
approx = "0.4"
5151
lax = "0.15.0"
5252

53+
[target.'cfg(not(windows))'.dev-dependencies]
54+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
55+
5356
[[bench]]
5457
name = "k_means"
5558
harness = false

algorithms/linfa-clustering/benches/appx_dbscan.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use ndarray::Array2;
99
use ndarray_rand::rand::SeedableRng;
1010
use ndarray_rand::rand_distr::Uniform;
1111
use ndarray_rand::RandomExt;
12+
#[cfg(not(target_os = "windows"))]
13+
use pprof::criterion::{Output, PProfProfiler};
1214
use rand_xoshiro::Xoshiro256Plus;
1315

1416
fn appx_dbscan_bench(c: &mut Criterion) {
@@ -48,9 +50,13 @@ fn appx_dbscan_bench(c: &mut Criterion) {
4850
benchmark.finish();
4951
}
5052

53+
#[cfg(not(target_os = "windows"))]
5154
criterion_group! {
5255
name = benches;
53-
config = Criterion::default();
56+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
5457
targets = appx_dbscan_bench
5558
}
59+
#[cfg(target_os = "windows")]
60+
criterion_group!(benches, appx_dbscan_bench);
61+
5662
criterion_main!(benches);

algorithms/linfa-clustering/benches/dbscan.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use ndarray::Array2;
99
use ndarray_rand::rand::SeedableRng;
1010
use ndarray_rand::rand_distr::Uniform;
1111
use ndarray_rand::RandomExt;
12+
#[cfg(not(target_os = "windows"))]
13+
use pprof::criterion::{Output, PProfProfiler};
1214
use rand_xoshiro::Xoshiro256Plus;
1315

1416
fn dbscan_bench(c: &mut Criterion) {
@@ -44,9 +46,13 @@ fn dbscan_bench(c: &mut Criterion) {
4446
benchmark.finish()
4547
}
4648

49+
#[cfg(not(target_os = "windows"))]
4750
criterion_group! {
4851
name = benches;
49-
config = Criterion::default();
52+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
5053
targets = dbscan_bench
5154
}
55+
#[cfg(target_os = "windows")]
56+
criterion_group!(benches, dbscan_bench);
57+
5258
criterion_main!(benches);

algorithms/linfa-clustering/benches/gaussian_mixture.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use ndarray::Array2;
1010
use ndarray_rand::rand::SeedableRng;
1111
use ndarray_rand::rand_distr::Uniform;
1212
use ndarray_rand::RandomExt;
13+
#[cfg(not(target_os = "windows"))]
14+
use pprof::criterion::{Output, PProfProfiler};
1315
use rand_xoshiro::Xoshiro256Plus;
1416

1517
fn gaussian_mixture_bench(c: &mut Criterion) {
@@ -46,9 +48,13 @@ fn gaussian_mixture_bench(c: &mut Criterion) {
4648
benchmark.finish();
4749
}
4850

51+
#[cfg(not(target_os = "windows"))]
4952
criterion_group! {
5053
name = benches;
51-
config = Criterion::default();
54+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
5255
targets = gaussian_mixture_bench
5356
}
57+
#[cfg(target_os = "windows")]
58+
criterion_group!(benches, gaussian_mixture_bench);
59+
5460
criterion_main!(benches);

algorithms/linfa-clustering/benches/k_means.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use linfa_datasets::generate;
99
use ndarray::Array2;
1010
use ndarray_rand::RandomExt;
1111
use ndarray_rand::{rand::SeedableRng, rand_distr::Uniform};
12+
#[cfg(not(target_os = "windows"))]
13+
use pprof::criterion::{Output, PProfProfiler};
1214
use rand_xoshiro::Xoshiro256Plus;
1315

1416
#[derive(Default)]
@@ -155,9 +157,18 @@ fn k_means_init_bench(c: &mut Criterion) {
155157
}
156158
}
157159

160+
#[cfg(not(target_os = "windows"))]
158161
criterion_group! {
159162
name = benches;
160-
config = Criterion::default();
163+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
161164
targets = k_means_bench, k_means_init_bench, k_means_incr_bench
162165
}
166+
#[cfg(target_os = "windows")]
167+
criterion_group!(
168+
benches,
169+
k_means_bench,
170+
k_means_init_bench,
171+
k_means_incr_bench
172+
);
173+
163174
criterion_main!(benches);

algorithms/linfa-ftrl/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ criterion = "0.4.0"
2929
approx = "0.4"
3030
linfa-datasets = { version = "0.6.0", path = "../../datasets", features = ["winequality"] }
3131

32+
[target.'cfg(not(windows))'.dev-dependencies]
33+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
34+
3235
[[bench]]
3336
name = "ftrl"
3437
harness = false

algorithms/linfa-ftrl/benches/ftrl.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use ndarray::{Array1, Array2};
77
use ndarray_rand::{
88
rand::distributions::Uniform, rand::rngs::SmallRng, rand::SeedableRng, RandomExt,
99
};
10+
#[cfg(not(target_os = "windows"))]
11+
use pprof::criterion::{Output, PProfProfiler};
1012

1113
fn fit_without_prior_model(c: &mut Criterion) {
1214
let mut rng = SmallRng::seed_from_u64(42);
@@ -86,9 +88,18 @@ fn get_dataset(
8688
Dataset::new(features, target)
8789
}
8890

91+
#[cfg(not(target_os = "windows"))]
8992
criterion_group! {
9093
name = benches;
91-
config = Criterion::default();
94+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
9295
targets = fit_without_prior_model, fit_with_prior_model, predict
9396
}
97+
#[cfg(target_os = "windows")]
98+
criterion_group!(
99+
benches,
100+
fit_without_prior_model,
101+
fit_with_prior_model,
102+
predict
103+
);
104+
94105
criterion_main!(benches);

algorithms/linfa-ica/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ ndarray-npy = { version = "0.8", default-features = false }
4141
paste = "1.0"
4242
criterion = "0.4.0"
4343

44+
[target.'cfg(not(windows))'.dev-dependencies]
45+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
46+
4447
[[bench]]
4548
name = "fast_ica"
4649
harness = false

algorithms/linfa-ica/benches/fast_ica.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@ use linfa_ica::fast_ica::{FastIca, GFunc};
44
use ndarray::{array, concatenate};
55
use ndarray::{Array, Array2, Axis};
66
use ndarray_rand::{rand::SeedableRng, rand_distr::Uniform, RandomExt};
7+
#[cfg(not(target_os = "windows"))]
8+
use pprof::criterion::{Output, PProfProfiler};
79
use rand_xoshiro::Xoshiro256Plus;
810

911
fn perform_ica(size: usize, gfunc: GFunc) {
1012
let sources_mixed = create_data(size);
1113

1214
let ica = FastIca::params().gfunc(gfunc).random_state(10);
1315

14-
let ica = ica.fit(&DatasetBase::from(sources_mixed.view()));
16+
ica.fit(&DatasetBase::from(sources_mixed.view())).unwrap();
1517
}
1618

1719
fn create_data(nsamples: usize) -> Array2<f64> {
@@ -64,5 +66,13 @@ fn bench(c: &mut Criterion) {
6466
}
6567
}
6668

69+
#[cfg(not(target_os = "windows"))]
70+
criterion_group! {
71+
name = benches;
72+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
73+
targets = bench
74+
}
75+
#[cfg(target_os = "windows")]
6776
criterion_group!(benches, bench);
77+
6878
criterion_main!(benches);

algorithms/linfa-linear/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ approx = "0.4"
3636
criterion = "0.4.0"
3737
statrs = "0.16.0"
3838

39+
[target.'cfg(not(windows))'.dev-dependencies]
40+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
41+
3942
[[bench]]
4043
name = "ols_bench"
4144
harness = false

algorithms/linfa-linear/benches/ols_bench.rs

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use linfa::Dataset;
44
use linfa_datasets::generate::make_dataset;
55
use linfa_linear::{LinearRegression, TweedieRegressor};
66
use ndarray::Ix1;
7+
#[cfg(not(target_os = "windows"))]
8+
use pprof::criterion::{Output, PProfProfiler};
79
use statrs::distribution::{DiscreteUniform, Laplace};
810

911
#[allow(unused_must_use)]
@@ -57,5 +59,13 @@ fn bench(c: &mut Criterion) {
5759
group.finish();
5860
}
5961

62+
#[cfg(not(target_os = "windows"))]
63+
criterion_group! {
64+
name = benches;
65+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
66+
targets = bench
67+
}
68+
#[cfg(target_os = "windows")]
6069
criterion_group!(benches, bench);
70+
6171
criterion_main!(benches);

algorithms/linfa-nn/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ criterion = "0.4.0"
4141
rand_xoshiro = "0.6"
4242
ndarray-rand = "0.14"
4343

44+
[target.'cfg(not(windows))'.dev-dependencies]
45+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
46+
4447
[[bench]]
4548
name = "nn"
4649
harness = false

algorithms/linfa-nn/benches/nn.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
22
use linfa_nn::{distance::*, CommonNearestNeighbour, NearestNeighbour};
33
use ndarray::{Array1, Array2};
44
use ndarray_rand::{rand::SeedableRng, rand_distr::Uniform, RandomExt};
5+
#[cfg(not(target_os = "windows"))]
6+
use pprof::criterion::{Output, PProfProfiler};
57
use rand_xoshiro::Xoshiro256Plus;
68

79
fn nn_build_bench(c: &mut Criterion) {
@@ -96,9 +98,13 @@ fn within_range_bench(c: &mut Criterion) {
9698
}
9799
}
98100

101+
#[cfg(not(target_os = "windows"))]
99102
criterion_group! {
100103
name = benches;
101-
config = Criterion::default();
104+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
102105
targets = nn_build_bench, k_nearest_bench, within_range_bench
103106
}
107+
#[cfg(target_os = "windows")]
108+
criterion_group!(benches, nn_build_bench, k_nearest_bench, within_range_bench);
109+
104110
criterion_main!(benches);

algorithms/linfa-pls/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ rand_xoshiro = "0.6"
4242
criterion = "0.4.0"
4343
statrs = "0.16.0"
4444

45+
[target.'cfg(not(windows))'.dev-dependencies]
46+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
47+
4548
[[bench]]
4649
name = "pls"
4750
harness = false

algorithms/linfa-pls/benches/pls.rs

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use linfa::Dataset;
44
use linfa_datasets::generate::make_dataset;
55
use linfa_pls::Algorithm;
66
use linfa_pls::{PlsCanonical, PlsCca, PlsRegression};
7+
#[cfg(not(target_os = "windows"))]
8+
use pprof::criterion::{Output, PProfProfiler};
79
use statrs::distribution::{DiscreteUniform, Laplace};
810

911
#[allow(unused_must_use)]
@@ -86,5 +88,13 @@ fn bench(c: &mut Criterion) {
8688
group.finish();
8789
}
8890

91+
#[cfg(not(target_os = "windows"))]
92+
criterion_group! {
93+
name = benches;
94+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
95+
targets = bench
96+
}
97+
#[cfg(target_os = "windows")]
8998
criterion_group!(benches, bench);
99+
90100
criterion_main!(benches);

algorithms/linfa-trees/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ linfa = { version = "0.6.0", path = "../.." }
3333
rand = { version = "0.8", features = ["small_rng"] }
3434
criterion = "0.4.0"
3535
approx = "0.4"
36-
3736
linfa-datasets = { version = "0.6.0", path = "../../datasets/", features = ["iris"] }
3837

38+
[target.'cfg(not(windows))'.dev-dependencies]
39+
pprof = { version = "0.11.0", features = ["flamegraph", "criterion"] }
40+
3941
[[bench]]
4042
name = "decision_tree"
4143
harness = false

algorithms/linfa-trees/benches/decision_tree.rs

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use ndarray::{concatenate, Array, Array1, Array2, Axis};
55
use ndarray_rand::rand::SeedableRng;
66
use ndarray_rand::rand_distr::{StandardNormal, Uniform};
77
use ndarray_rand::RandomExt;
8+
#[cfg(not(target_os = "windows"))]
9+
use pprof::criterion::{Output, PProfProfiler};
810
use rand::rngs::SmallRng;
911

1012
fn generate_blobs(means: &Array2<f64>, samples: usize, mut rng: &mut SmallRng) -> Array2<f64> {
@@ -52,5 +54,13 @@ fn decision_tree_bench(c: &mut Criterion) {
5254
group.finish();
5355
}
5456

57+
#[cfg(not(target_os = "windows"))]
58+
criterion_group! {
59+
name = benches;
60+
config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None)));
61+
targets = decision_tree_bench
62+
}
63+
#[cfg(target_os = "windows")]
5564
criterion_group!(benches, decision_tree_bench);
65+
5666
criterion_main!(benches);

0 commit comments

Comments
 (0)