1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use std::{fs, io, io::Read};
use zip::ZipArchive;
const QADIM_LOG: &str = "tests/logs/qadim-20200427.zevtc";
/// This benchmark tests the overall performance of process_file.
///
/// This is important because for many applications that just want to read a log, this is the
/// easiest and preferred way to do it. We want to ensure that we internally use a fast method
/// (such as a buffered reader or a memory mapped file) so that the downstream application will
/// receive the log fast.
fn zipped_qadim_benchmark(c: &mut Criterion) {
let file_size = fs::metadata(QADIM_LOG).unwrap().len();
let mut group = c.benchmark_group("parsing/qadim/zipped");
group.throughput(Throughput::Bytes(file_size));
group.bench_function("disk", |b| {
b.iter(|| evtclib::process_file(black_box(QADIM_LOG), evtclib::Compression::Zip).unwrap())
});
}
/// This benchmark tests the process_stream on a pre-loaded zipped log.
///
/// This is important because it contains the slowdown imposed by decompression, but without I/O
/// slowdowns. This is the most realistic target to strive for with our process_file function, as
/// we can try to work around I/O (assuming prefetching, memory mapped files, ...), but we probably
/// have to de-compress logs at some point.
fn zipped_qadim_ram_benchmark(c: &mut Criterion) {
let log_data = &fs::read(QADIM_LOG).unwrap();
let file_size = log_data.len();
let mut group = c.benchmark_group("parsing/qadim/zipped");
group.throughput(Throughput::Bytes(file_size as u64));
group.bench_function("memory", |b| {
b.iter(|| {
evtclib::process_stream(io::Cursor::new(log_data), evtclib::Compression::Zip).unwrap()
})
});
}
/// This benchmark tests the process_stream on a pre-extracted log.
///
/// This is important because it gets rid of any I/O and decompression slowdown. This probably
/// measures our parsing performance most accurately, assuming that all data is readily available,
/// the only slowdown that remains is our parsing and processing algorithm.
fn unzipped_qadim_benchmark(c: &mut Criterion) {
let mut log_data = Vec::new();
let zip_data = fs::read(QADIM_LOG).unwrap();
let mut archive = ZipArchive::new(io::Cursor::new(zip_data)).unwrap();
archive
.by_index(0)
.unwrap()
.read_to_end(&mut log_data)
.unwrap();
let log_data = &log_data;
let mut group = c.benchmark_group("parsing/qadim/unzipped");
group.throughput(Throughput::Bytes(log_data.len() as u64));
group.bench_function("memory", |b| {
b.iter(|| {
evtclib::process_stream(io::Cursor::new(log_data), evtclib::Compression::None).unwrap()
})
});
}
/// This benchmark tests the performance of process on a pre-parsed log.
///
/// This is important because it is the point where we can change the most. Parsing the input file
/// is a lot of bit-twiddling and there's probably not a lot of performance that we can gain
/// (especially in the case where I/O slowdown is minimal), but when going from a RawEvtc to a Log,
/// it is the first time that we actually do some work in converting all of the values from
/// low-level to high-level.
fn process_qadim(c: &mut Criterion) {
let file = io::BufReader::new(fs::File::open(QADIM_LOG).unwrap());
let raw_evtc = evtclib::raw::parse_zip(file).unwrap();
c.bench_function("process/qadim", |b| {
b.iter(|| evtclib::process(&raw_evtc).unwrap())
});
}
criterion_group! {
name = benches;
config = Criterion::default().sample_size(30);
targets = zipped_qadim_benchmark, zipped_qadim_ram_benchmark, unzipped_qadim_benchmark, process_qadim
}
criterion_main!(benches);
|