blob: a9f446d6831443a5e3f78c7d64c49b7828c91155 [file] [log] [blame] [edit]
// Copyright 2019 The Wuffs Authors.
//
//// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
// ----------------
// This program exercises the Rust Deflate decoder at
// https://github.com/alexcrichton/flate2-rs
// which is the top result for https://crates.io/search?q=flate&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust Deflate implementations. The equivalent
// Wuffs benchmarks (on the same test files) are run via:
//
// wuffs bench std/deflate
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).
extern crate flate2;
extern crate rustc_version_runtime;
use std::io::Read;
use std::time::Instant;
const ITERSCALE: u64 = 20;
const REPS: u64 = 5;
fn main() {
let version = rustc_version_runtime::version();
print!(
"# Rust {}.{}.{}\n",
version.major,
version.minor,
version.patch
);
print!("#\n");
print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
print!("# install Go, then run \"go install golang.org/x/perf/cmd/benchstat\".\n");
let mut dst = vec![0u8; 64 * 1024 * 1024];
// The various magic constants below are copied from test/c/std/deflate.c
for i in 0..(1 + REPS) {
bench(
"1k_full_init",
&mut dst[..],
&include_bytes!("../../../test/data/romeo.txt.gz")[20..550],
i == 0, // warm_up
942, // want_num_bytes
2000, // iters_unscaled
);
bench(
"10k_full_init",
&mut dst[..],
&include_bytes!("../../../test/data/midsummer.txt.gz")[24..5166],
i == 0, // warm_up
11065, // want_num_bytes
300, // iters_unscaled
);
bench(
"100k_just_one_read",
&mut dst[..],
&include_bytes!("../../../test/data/pi.txt.gz")[17..48335],
i == 0, // warm_up
100003, // want_num_bytes
30, // iters_unscaled
);
}
}
fn bench(
name: &str, // Benchmark name.
dst: &mut [u8], // Destination buffer.
src: &[u8], // Source data.
warm_up: bool, // Whether this is a warm up rep.
want_num_bytes: u64, // Expected num_bytes per iteration.
iters_unscaled: u64, // Base number of iterations.
) {
let iters = iters_unscaled * ITERSCALE;
let mut total_num_bytes = 0u64;
let start = Instant::now();
for _ in 0..iters {
let n = decode(&mut dst[..], src);
if n != want_num_bytes {
panic!("num_bytes: got {}, want {}", n, want_num_bytes);
}
total_num_bytes += n;
}
let elapsed = start.elapsed();
let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
let kb_per_s: u64 = total_num_bytes * 1_000_000 / elapsed_nanos;
if warm_up {
return;
}
print!(
"Benchmarkrust_deflate_decode_{:16} {:8} {:12} ns/op {:3}.{:03} MB/s\n",
name,
iters,
elapsed_nanos / iters,
kb_per_s / 1_000,
kb_per_s % 1_000
);
}
// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8]) -> u64 {
let mut num_bytes = 0u64;
let mut decoder = flate2::read::DeflateDecoder::new(src);
loop {
let n = decoder.read(dst).unwrap();
if n == 0 {
break;
}
num_bytes += n as u64;
}
num_bytes
}