indexedlog: add some benchmarks

Summary:
Add benchmarks inserting / looking up 20K entries.

Benchmark results on my laptop are:

  index insertion         time:   [6.5339 ms 6.8174 ms 7.1805 ms]
  index flush             time:   [15.651 ms 16.103 ms 16.537 ms]
  index lookup (memory)   time:   [3.6995 ms 4.0252 ms 4.3046 ms]
  index lookup (disk)     time:   [1.9986 ms 2.1224 ms 2.2464 ms]
  index clone (memory)    time:   [2.5943 ms 2.6866 ms 2.7749 ms]
  index clone (disk)      time:   [5.2302 us 5.5477 us 5.9518 us]

Comparing with highly optimized radixbuf:

  index insertion         time:   [991.89 us 1.1708 ms 1.3844 ms]
  index lookup            time:   [863.83 us 945.69 us 1.0304 ms]

Insertion takes 6x time. Lookup from memory takes 1.4x time, from disk takes
2.2x time. Flushing is the slowest - it needs 16x radixbuf insertion time.

Note: need to subtract "clone" time from "lookup" to get meaningful values
about "lookup". This cannot be done automatically due to the limitation of the
benchmark framework.

Although it's slower than radixbuf, the index is still faster than gdbm and
rocksdb. Note: the index does less than gdbm/rocksdb since it does not return
a `[u8]`-ish which requires extra lookups. So it's not a very fair comparison.

  gdbm insertion          time:   [69.607 ms 75.102 ms 79.334 ms]
  gdbm lookup             time:   [9.0855 ms 9.8480 ms 10.637 ms]
  gdbm prepare            time:   [110.35 us 120.40 us 135.63 us]
  rocksdb insertion       time:   [117.96 ms 123.42 ms 127.85 ms]
  rocksdb lookup          time:   [24.413 ms 26.147 ms 28.153 ms]
  rocksdb prepare         time:   [3.8316 ms 4.1776 ms 4.5039 ms]

Note: Subtract "prepare" from "insertion" to get meaningful values.

Code to benchmark rocksdb and gdbm:

```
extern crate criterion;
extern crate gnudbm;
extern crate rand;
extern crate rocksdb;
extern crate tempdir;

use criterion::Criterion;
use gnudbm::GdbmOpener;
use rand::{ChaChaRng, Rng};
use rocksdb::DB;
use tempdir::TempDir;

const N: usize = 20480;

/// Generate random buffer
fn gen_buf(size: usize) -> Vec<u8> {
    let mut buf = vec![0u8; size];
    ChaChaRng::new_unseeded().fill_bytes(buf.as_mut());
    buf
}

fn criterion_benchmark(c: &mut Criterion) {
    c.bench_function("rocksdb prepare", |b| {
        b.iter(move || {
            let dir = TempDir::new("index").expect("TempDir::new");
            let _db = DB::open_default(dir.path().join("a")).unwrap();
        });
    });

    c.bench_function("rocksdb insertion", |b| {
        let buf = gen_buf(N * 20);
        b.iter(move || {
            let dir = TempDir::new("index").expect("TempDir::new");
            let db = DB::open_default(dir.path().join("a")).unwrap();
            for i in 0..N {
                db.put(&&buf[20 * i..20 * (i + 1)], b"v").unwrap();
            }
        });
    });

    c.bench_function("rocksdb lookup", |b| {
        let dir = TempDir::new("index").expect("TempDir::new");
        let db = DB::open_default(dir.path().join("a")).unwrap();
        let buf = gen_buf(N * 20);
        for i in 0..N {
            db.put(&&buf[20 * i..20 * (i + 1)], b"v").unwrap();
        }
        b.iter(move || {
            for i in 0..N {
                db.get(&&buf[20 * i..20 * (i + 1)]).unwrap();
            }
        });
    });

    c.bench_function("gdbm prepare", |b| {
        let buf = gen_buf(N * 20);
        b.iter(move || {
            let dir = TempDir::new("index").expect("TempDir::new");
            let _db = GdbmOpener::new().create(true).readwrite(dir.path().join("a")).unwrap();
        });
    });

    c.bench_function("gdbm insertion", |b| {
        let buf = gen_buf(N * 20);
        b.iter(move || {
            let dir = TempDir::new("index").expect("TempDir::new");
            let mut db = GdbmOpener::new().create(true).readwrite(dir.path().join("a")).unwrap();
            for i in 0..N {
                db.store(&&buf[20 * i..20 * (i + 1)], b"v").unwrap();
            }
        });
    });

    c.bench_function("gdbm lookup", |b| {
        let dir = TempDir::new("index").expect("TempDir::new");
        let mut db = GdbmOpener::new().create(true).readwrite(dir.path().join("a")).unwrap();
        let buf = gen_buf(N * 20);
        for i in 0..N {
            db.store(&&buf[20 * i..20 * (i + 1)], b"v").unwrap();
        }
        b.iter(move || {
            for i in 0..N {
                db.fetch(&&buf[20 * i..20 * (i + 1)]).unwrap();
            }
        });
    });
}

criterion_group!{
    name=benches;
    config=Criterion::default().sample_size(20);
    targets=criterion_benchmark
}
criterion_main!(benches);
```

Reviewed By: DurhamG

Differential Revision: D7404532

fbshipit-source-id: ff39f520b78ad1b71eb36970506b313bb2ff426b
This commit is contained in:
Jun Wu 2018-03-29 03:12:46 -07:00 committed by Saurabh Singh
parent 5576402ea9
commit 3332522d43
2 changed files with 108 additions and 1 deletions

View File

@ -1,9 +1,23 @@
#[macro_use]
extern crate criterion;
extern crate indexedlog;
extern crate rand;
extern crate tempdir;
use criterion::Criterion;
use indexedlog::Index;
use indexedlog::base16::Base16Iter;
use rand::{ChaChaRng, Rng};
use tempdir::TempDir;
const N: usize = 20480;
/// Generate random buffer
fn gen_buf(size: usize) -> Vec<u8> {
let mut buf = vec![0u8; size];
ChaChaRng::new_unseeded().fill_bytes(buf.as_mut());
buf
}
fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("base16 iterating 1M bytes", |b| {
@ -13,7 +27,98 @@ fn criterion_benchmark(c: &mut Criterion) {
assert_eq!(y, (4 * 1000000) as u8);
})
});
c.bench_function("index insertion", |b| {
let dir = TempDir::new("index").expect("TempDir::new");
let idx = Index::open(dir.path().join("i"), 0).expect("open");
let buf = gen_buf(N * 20);
b.iter(move || {
let mut idx = idx.clone().unwrap();
for i in 0..N {
idx.insert(&&buf[20 * i..20 * (i + 1)], i as u64)
.expect("insert");
}
});
});
c.bench_function("index flush", |b| {
let dir = TempDir::new("index").expect("TempDir::new");
let mut idx = Index::open(dir.path().join("i"), 0).expect("open");
let buf = gen_buf(N * 20);
for i in 0..N {
idx.insert(&&buf[20 * i..20 * (i + 1)], i as u64)
.expect("insert");
}
b.iter(|| {
let mut idx = idx.clone().unwrap();
idx.flush().expect("flush")
});
});
c.bench_function("index lookup (memory)", |b| {
let dir = TempDir::new("index").expect("TempDir::new");
let mut idx = Index::open(dir.path().join("i"), 0).expect("open");
let buf = gen_buf(N * 20);
for i in 0..N {
idx.insert(&&buf[20 * i..20 * (i + 1)], i as u64)
.expect("insert");
}
b.iter(move || {
let idx = idx.clone().unwrap();
for i in 0..N {
idx.get(&&buf[20 * i..20 * (i + 1)]).expect("lookup");
}
});
});
c.bench_function("index lookup (disk)", |b| {
let dir = TempDir::new("index").expect("TempDir::new");
let mut idx = Index::open(dir.path().join("i"), 0).expect("open");
let buf = gen_buf(N * 20);
for i in 0..N {
idx.insert(&&buf[20 * i..20 * (i + 1)], i as u64)
.expect("insert");
}
idx.flush().expect("flush");
b.iter(move || {
let idx = idx.clone().unwrap();
for i in 0..N {
idx.get(&&buf[20 * i..20 * (i + 1)]).expect("lookup");
}
});
});
c.bench_function("index clone (memory)", |b| {
let dir = TempDir::new("index").expect("TempDir::new");
let mut idx = Index::open(dir.path().join("i"), 0).expect("open");
let buf = gen_buf(N * 20);
for i in 0..N {
idx.insert(&&buf[20 * i..20 * (i + 1)], i as u64)
.expect("insert");
}
b.iter(move || {
let mut _idx = idx.clone().unwrap();
});
});
c.bench_function("index clone (disk)", |b| {
let dir = TempDir::new("index").expect("TempDir::new");
let mut idx = Index::open(dir.path().join("i"), 0).expect("open");
let buf = gen_buf(N * 20);
for i in 0..N {
idx.insert(&&buf[20 * i..20 * (i + 1)], i as u64)
.expect("insert");
}
idx.flush().expect("flush");
b.iter(move || {
let mut _idx = idx.clone().unwrap();
});
});
}
criterion_group!(benches, criterion_benchmark);
criterion_group!{
name=benches;
config=Criterion::default().sample_size(20);
targets=criterion_benchmark
}
criterion_main!(benches);

View File

@ -18,3 +18,5 @@ mod checksum_table;
mod index;
mod lock;
mod utils;
pub use index::Index;