forked from sparsemat/sprs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
378,400 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,180 @@ | ||
use bencher::{benchmark_group, benchmark_main, Bencher}; | ||
use ndarray::{Array, Array2, ShapeBuilder}; | ||
use sprs::{CsMat, CsVec}; | ||
|
||
fn sparse_dense_dotprod_default(bench: &mut Bencher) { | ||
let w = Array::range(0., 10., 0.00001); | ||
let x = CsVec::new(1000000, vec![0, 200000, 800000], vec![1., 2., 3.]); | ||
bench.iter(|| { | ||
x.dot(&w); | ||
}); | ||
use criterion::{ | ||
criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, | ||
BenchmarkId, Criterion, | ||
}; | ||
use ndarray::Array2; | ||
use rand::Rng; | ||
use rand_xoshiro::rand_core::SeedableRng; | ||
use rand_xoshiro::Xoshiro256Plus; | ||
use sprs::CsMat; | ||
|
||
fn generate_random_array( | ||
shape: sprs::Shape, | ||
seed: u64, | ||
) -> ndarray::Array2<f64> { | ||
// reproducible fast generator for f64s | ||
let mut rng = Xoshiro256Plus::seed_from_u64(seed); | ||
let data = (0..shape.0 * shape.1) | ||
.map(|_| rng.gen()) | ||
.collect::<Vec<f64>>(); | ||
ndarray::Array2::from_shape_vec(shape, data).unwrap() | ||
} | ||
|
||
fn sparse_dense_dotprod_specialized(bench: &mut Bencher) { | ||
let w = Array::range(0., 10., 0.00001); | ||
let x = CsVec::new(1000000, vec![0, 200000, 800000], vec![1., 2., 3.]); | ||
bench.iter(|| { | ||
x.dot_dense(w.view()); | ||
}); | ||
fn generate_random_csr(shape: sprs::Shape, seed: u64) -> sprs::CsMat<f64> { | ||
let mut rng = Xoshiro256Plus::seed_from_u64(seed); | ||
let (rows, cols) = shape; | ||
let nnz = rng.gen_range(1..rows * cols / 2); | ||
|
||
let mut mat = sprs::TriMat::<f64>::new(shape); | ||
for _ in 0..nnz { | ||
let r = rng.gen_range(0..rows); | ||
let c = rng.gen_range(0..cols); | ||
let v = rng.gen::<f64>(); | ||
mat.add_triplet(r, c, v); | ||
} | ||
|
||
mat.to_csr() | ||
} | ||
|
||
fn sparse_dense_vec_matprod_default(bench: &mut Bencher) { | ||
let w = Array::range(0., 10., 0.00001); | ||
let a = CsMat::new( | ||
(3, 1000000), | ||
vec![0, 2, 4, 5], | ||
vec![0, 1, 0, 2, 2], | ||
vec![1., 2., 3., 4., 5.], | ||
); | ||
bench.iter(|| { | ||
let _ = &a * &w; | ||
}); | ||
// CSR-dense colmaj mulitplication | ||
fn csr_dense_colmaj_mullacc(c: &mut Criterion) { | ||
let mut group = c.benchmark_group("csr * dense (column major)"); | ||
group.sample_size(10); | ||
group.measurement_time(std::time::Duration::from_secs(5)); | ||
|
||
// Testing on a finite element matrices | ||
let mat = sprs::io::read_matrix_market::<f64, usize, _>( | ||
"./data/matrix_market/bench/poisson4009.mtx", | ||
) | ||
.unwrap() | ||
.to_csr::<usize>(); | ||
|
||
let shape = mat.shape(); | ||
let rhs = generate_random_array((shape.1, 200), 85); | ||
let out = ndarray::Array2::<f64>::zeros((shape.0, 200)); | ||
run_benches(&mut group, &mat, &rhs, out, "FEM matrix"); | ||
|
||
// Testing on random generated matrices | ||
const N_LOOP: usize = 10; | ||
const MAX_LEFT_DIM: usize = 200; | ||
const MAX_RIGHT_DIM: usize = 200; | ||
const MAX_INNER_DIM: usize = 5000; | ||
|
||
let mut rng = Xoshiro256Plus::seed_from_u64(150); | ||
|
||
for _ in 0..N_LOOP { | ||
let left_shape: sprs::Shape = ( | ||
rng.gen_range(10..=MAX_LEFT_DIM), | ||
rng.gen_range(10..=MAX_INNER_DIM), | ||
); | ||
let right_shape: sprs::Shape = | ||
(left_shape.1, rng.gen_range(1..=MAX_RIGHT_DIM)); | ||
let mat = generate_random_csr(left_shape, 24); | ||
let rhs = generate_random_array(right_shape, 42); | ||
let out = ndarray::Array2::<f64>::zeros((left_shape.0, right_shape.1)); | ||
|
||
let size = format!( | ||
"{}x{} times {}x{}", | ||
left_shape.0, left_shape.1, right_shape.0, right_shape.1 | ||
); | ||
|
||
run_benches(&mut group, &mat, &rhs, out, &size); | ||
} | ||
|
||
group.finish(); | ||
} | ||
|
||
fn sparse_dense_vec_matprod_specialized(bench: &mut Bencher) { | ||
let w = Array::range(0., 10., 0.00001); | ||
let a = CsMat::new( | ||
(3, 1000000), | ||
vec![0, 2, 4, 5], | ||
vec![0, 1, 0, 2, 2], | ||
vec![1., 2., 3., 4., 5.], | ||
fn run_benches( | ||
group: &mut BenchmarkGroup<WallTime>, | ||
mat: &CsMat<f64>, | ||
rhs: &Array2<f64>, | ||
out: Array2<f64>, | ||
label: &str, | ||
) { | ||
group.bench_with_input( | ||
BenchmarkId::new("heap access", label), | ||
&(mat, rhs, out.clone()), | ||
|b, (mat, rhs, out)| { | ||
b.iter(|| { | ||
sprs::prod::csr_mulacc_dense_colmaj( | ||
mat.view(), | ||
rhs.view(), | ||
out.clone().view_mut(), | ||
) | ||
}) | ||
}, | ||
); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::new("cloned", label), | ||
&(mat, rhs, out.clone()), | ||
|b, (mat, rhs, out)| { | ||
b.iter(|| { | ||
sprs::prod::csr_mulacc_dense_colmaj_cloned( | ||
mat.view(), | ||
rhs.view(), | ||
out.clone().view_mut(), | ||
) | ||
}) | ||
}, | ||
); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::new("copied", label), | ||
&(mat, rhs, out.clone()), | ||
|b, (mat, rhs, out)| { | ||
b.iter(|| { | ||
sprs::prod::csr_mulacc_dense_colmaj_cloned( | ||
mat.view(), | ||
rhs.view(), | ||
out.clone().view_mut(), | ||
) | ||
}) | ||
}, | ||
); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::new("heap access no mul_add", label), | ||
&(mat, rhs, out.clone()), | ||
|b, (mat, rhs, out)| { | ||
b.iter(|| { | ||
sprs::prod::csr_dense_colmaj( | ||
mat.view(), | ||
rhs.view(), | ||
out.clone().view_mut(), | ||
) | ||
}) | ||
}, | ||
); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::new("cloned no mul_add", label), | ||
&(mat, rhs, out.clone()), | ||
|b, (mat, rhs, out)| { | ||
b.iter(|| { | ||
sprs::prod::csr_dense_colmaj_cloned( | ||
mat.view(), | ||
rhs.view(), | ||
out.clone().view_mut(), | ||
) | ||
}) | ||
}, | ||
); | ||
|
||
group.bench_with_input( | ||
BenchmarkId::new("copied no mul_add", label), | ||
&(mat, rhs, out.clone()), | ||
|b, (mat, rhs, out)| { | ||
b.iter(|| { | ||
sprs::prod::csr_dense_colmaj_cloned( | ||
mat.view(), | ||
rhs.view(), | ||
out.clone().view_mut(), | ||
) | ||
}) | ||
}, | ||
); | ||
let rows = a.rows(); | ||
let cols = w.shape()[0]; | ||
let w_reshape = w.view().into_shape((1, cols)).unwrap(); | ||
let w_t = w_reshape.t(); | ||
let mut res = Array2::<f64>::zeros((rows, 1).f()); | ||
bench.iter(|| { | ||
sprs::prod::csr_mulacc_dense_colmaj( | ||
a.view(), | ||
w_t.view(), | ||
res.view_mut(), | ||
); | ||
}); | ||
} | ||
|
||
benchmark_group!( | ||
benches, | ||
sparse_dense_dotprod_default, | ||
sparse_dense_dotprod_specialized, | ||
sparse_dense_vec_matprod_specialized, | ||
sparse_dense_vec_matprod_default | ||
); | ||
benchmark_main!(benches); | ||
criterion_group!(benches, csr_dense_colmaj_mullacc); | ||
criterion_main!(benches); |
Oops, something went wrong.