Skip to content

Commit

Permalink
improve benchmarks, add more info to readme
Browse files Browse the repository at this point in the history
  • Loading branch information
TudbuT committed Dec 16, 2022
1 parent 91a67b7 commit 5972021
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 38 deletions.
94 changes: 79 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,94 @@
# micro_ndarray

Most likely the smallest ndarray rust implementation with the best feature/size ratio you will
find.
find. Did you know `micro_ndarray` is almost exactly 100x smaller than `ndarray` and has no
dependencies (except for std)?

## Benchmarks

Both implementations are extremely fast considering the number of elements each iteration of
the benchmark goes through: 10_000_000 relatively equally distributed across the dimensions of the
arrays. However, this changes in 7D, as ndarray only has a man-made fast implementation for up to
7D, while micro_ndarray relies on a single implementation for all dimensions. This makes it slower
in smaller dimensions, but much, much faster in higher dimensions. micro_ndarray only has few
dimension-dependent optimizations and only for 1D, 2D, and 3D.

In short:
```
micro_ndarry time: [24.460 ms 24.602 ms 24.777 ms]
ndarry time: [6.2882 ms 6.3008 ms 6.3148 ms]
micro_ndarry 3D time: [43.007 ms 43.054 ms 43.101 ms]
ndarry 3D time: [25.750 ms 25.778 ms 25.806 ms]
micro_ndarry 4D time: [47.875 ms 47.958 ms 48.043 ms]
ndarry 4D time: [39.701 ms 39.756 ms 39.810 ms]
micro_ndarry 7D time: [46.657 ms 46.724 ms 46.790 ms]
ndarry 7D time: [1.6210 s 1.6228 s 1.6247 s] <- Boom
```
In order by speed:
```
ndarry time: [6.2882 ms 6.3008 ms 6.3148 ms]
...
micro_ndarry time: [24.460 ms 24.602 ms 24.777 ms]
ndarry 3D time: [25.750 ms 25.778 ms 25.806 ms]
ndarry 4D time: [39.701 ms 39.756 ms 39.810 ms]
micro_ndarry 3D time: [43.007 ms 43.054 ms 43.101 ms]
micro_ndarry 7D time: [46.657 ms 46.724 ms 46.790 ms] <-\ the difference here is most likely noise
micro_ndarry 4D time: [47.875 ms 47.958 ms 48.043 ms] <-/¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
...
...
[some more ...]
...
...
ndarry 7D time: [1.6210 s 1.6228 s 1.6247 s] <- Boom
```

In long:
```
Running benches/benchmarks.rs (target/release/deps/benchmarks-1e1fde2e14bfecef)
micro_ndarry time: [24.670 ms 24.819 ms 24.984 ms]
Found 5 outliers among 100 measurements (5.00%)
Running benches/benchmarks.rs (target/release/deps/benchmarks-37dfbc027b120770)
micro_ndarry time: [24.460 ms 24.602 ms 24.777 ms]
change: [+0.8630% +1.4891% +2.2669%] (p = 0.00 < 0.05)
Change within noise threshold.
Found 8 outliers among 100 measurements (8.00%)
4 (4.00%) high mild
4 (4.00%) high severe
ndarry time: [6.2882 ms 6.3008 ms 6.3148 ms]
change: [-0.7727% -0.5346% -0.2994%] (p = 0.00 < 0.05)
Change within noise threshold.
Found 3 outliers among 100 measurements (3.00%)
2 (2.00%) high mild
1 (1.00%) high severe
ndarry time: [6.5414 ms 6.5628 ms 6.5856 ms]
Found 20 outliers among 100 measurements (20.00%)
1 (1.00%) high mild
19 (19.00%) high severe
micro_ndarry 3D time: [43.007 ms 43.054 ms 43.101 ms]
change: [-1.1832% -1.0392% -0.8876%] (p = 0.00 < 0.05)
Change within noise threshold.
ndarry 3D time: [25.750 ms 25.778 ms 25.806 ms]
change: [-0.6465% -0.5203% -0.3904%] (p = 0.00 < 0.05)
Change within noise threshold.
micro_ndarry 4D time: [47.875 ms 47.958 ms 48.043 ms]
change: [-0.3193% -0.1150% +0.0840%] (p = 0.27 > 0.05)
No change in performance detected.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
micro_ndarry 7D time: [37.230 ms 37.307 ms 37.386 ms]
ndarry 4D time: [39.701 ms 39.756 ms 39.810 ms]
change: [-0.7251% -0.5708% -0.4248%] (p = 0.00 < 0.05)
Change within noise threshold.
micro_ndarry 7D time: [46.657 ms 46.724 ms 46.790 ms]
change: [-0.3268% -0.1459% +0.0485%] (p = 0.14 > 0.05)
No change in performance detected.
Benchmarking ndarry 7D: Warming up for 3.0000 s
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 75.9s, or reduce sample count to 10.
ndarry 7D time: [771.93 ms 775.16 ms 778.87 ms]
Found 10 outliers among 100 measurements (10.00%)
4 (4.00%) high mild
6 (6.00%) high severe
Warning: Unable to complete 100 samples in 5.0s. You may wish to increase target time to 170.6s, or reduce sample count to 10.
ndarry 7D time: [1.6210 s 1.6228 s 1.6247 s]
change: [+0.4095% +1.6176% +2.8514%] (p = 0.01 < 0.05)
Change within noise threshold.
Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) high mild
```

micro_ndarray is very consistent even with higher dimensions, while ndarray is extremely fast in 2D and exteremely slow in 7D
As you can see, micro_ndarray is very consistent even with higher dimensions, while ndarray is
extremely fast in 2D and exteremely slow in 7D.
90 changes: 73 additions & 17 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
use std::hint::black_box;

use criterion::{criterion_group, criterion_main, Criterion};

use micro_ndarray::Array as MicroArray;
use ndarray::{Array2, ArrayD, Dimension, IxDyn};
use ndarray::{Array2, Array3, Array4, ArrayD, Dimension, IxDyn};

fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("micro_ndarry", |b| b.iter(micro_ndarry));
c.bench_function("ndarry", |b| b.iter(ndarry));

c.bench_function("micro_ndarry 3D", |b| b.iter(micro_ndarry_3));
c.bench_function("ndarry 3D", |b| b.iter(ndarry_3));

c.bench_function("micro_ndarry 4D", |b| b.iter(micro_ndarry_4));
c.bench_function("ndarry 4D", |b| b.iter(ndarry_4));

c.bench_function("micro_ndarry 7D", |b| b.iter(micro_ndarry_7));
c.bench_function("ndarry 7D", |b| b.iter(ndarry_7));
}
Expand All @@ -29,22 +37,6 @@ fn micro_ndarry() {
}
}

fn micro_ndarry_7() {
let mut array = MicroArray::new_with([10; 7], 0);
array
.iter_mut()
.filter(|([x, ..], _)| x == &1)
.for_each(|([_, y, ..], ele)| *ele += y);

for ([x, y, ..], ele) in array.iter_mut() {
if x == 1 {
continue;
}

*ele += y;
}
}

fn ndarry() {
let mut array = Array2::<usize>::zeros((5000, 2000));
array
Expand All @@ -60,6 +52,66 @@ fn ndarry() {
}
}

fn micro_ndarry_3() {
let mut array = MicroArray::new_with([200, 200, 250], 0);
array
.iter_mut()
.filter(|([x, ..], _)| x == &1)
.for_each(|([_, y, ..], ele)| *ele += y);

for (dim, ele) in array.iter() {
black_box((dim, ele));
}
}

fn ndarry_3() {
let mut array = Array3::<usize>::zeros((200, 200, 250));
array
.indexed_iter_mut()
.filter(|((x, _, _), _)| x == &1)
.for_each(|((_, y, _), ele)| *ele += y);

for (dim, ele) in array.indexed_iter() {
black_box((dim, ele));
}
}

fn micro_ndarry_4() {
let mut array = MicroArray::new_with([50, 50, 50, 80], 0);
array
.iter_mut()
.filter(|([x, ..], _)| x == &1)
.for_each(|([_, y, ..], ele)| *ele += y);

for (dim, ele) in array.iter() {
black_box((dim, ele));
}
}

fn ndarry_4() {
let mut array = Array4::<usize>::zeros((50, 50, 50, 80));
array
.indexed_iter_mut()
.filter(|((x, ..), _)| x == &1)
.for_each(|((_, y, ..), ele)| *ele += y);

for (dim, ele) in array.indexed_iter() {
black_box((dim, ele));
}
}

fn micro_ndarry_7() {
let mut array = MicroArray::new_with([10; 7], 0);
array
.iter_mut()
.filter(|([x, ..], _)| x == &1)
.for_each(|([_, y, ..], ele)| *ele += y);

for (dim, ele) in array.iter() {
black_box((dim, ele));
}
}

fn ndarry_7() {
let mut array = ArrayD::<usize>::zeros(IxDyn(&[10; 7]));

Expand All @@ -73,4 +125,8 @@ fn ndarry_7() {

*ele += slice[1];
}

for (dim, ele) in array.indexed_iter() {
black_box((dim, ele));
}
}
14 changes: 8 additions & 6 deletions src/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@ impl<I: Iterator, const D: usize> Iter<I, D> {
}
3 => {
self.ptr[0] += 1;
if self.ptr[0] == self.size[0] {
self.ptr[0] = 0;
self.ptr[1] += 1;
if self.ptr[0] != self.size[0] {
return;
}
if self.ptr[1] == self.size[1] {
self.ptr[1] = 0;
self.ptr[2] += 1;
self.ptr[0] = 0;
self.ptr[1] += 1;
if self.ptr[1] != self.size[1] {
return;
}
self.ptr[1] = 0;
self.ptr[2] += 1;
}
_ => {
#[allow(clippy::needless_range_loop)] // clippy bug
Expand Down

0 comments on commit 5972021

Please sign in to comment.