Skip to content

Instantly share code, notes, and snippets.

@pietroalbini
Created July 18, 2019 13:49
Show Gist options
  • Save pietroalbini/d5ac409063626eb64edfd08f70fc4630 to your computer and use it in GitHub Desktop.
Save pietroalbini/d5ac409063626eb64edfd08f70fc4630 to your computer and use it in GitHub Desktop.
[package]
name = "benchmark"
version = "0.1.0"
authors = ["Pietro Albini <[email protected]>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
walkdir = "2.2.8"
flate2 = "1.0.9"
zstd = "0.4.24"
brotli2 = "0.3.2"
use std::error::Error;
use std::io::prelude::*;
use std::time::Instant;
use walkdir::WalkDir;
static PLAIN: &str = "plain";
static EXTENSIONS: &[&str] = &["html", "css", "js", "json"];
trait Algorithm {
fn name(&self) -> String;
fn compress(&self, input: &[u8]) -> Result<Vec<u8>, Box<Error>>;
fn decompress(&self, input: &[u8], original_len: usize) -> Result<(), Box<Error>>;
}
struct Gzip(u32);
impl Algorithm for Gzip {
fn name(&self) -> String {
format!("gzip | {}", self.0)
}
fn compress(&self, input: &[u8]) -> Result<Vec<u8>, Box<Error>> {
let mut e = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::new(self.0));
e.write_all(input)?;
Ok(e.finish()?)
}
fn decompress(&self, input: &[u8], _original_len: usize) -> Result<(), Box<Error>> {
let mut d = flate2::write::GzDecoder::new(Vec::new());
d.write_all(input)?;
d.finish()?;
Ok(())
}
}
struct Zstd(i32);
impl Algorithm for Zstd {
fn name(&self) -> String {
format!("zstd | {}", self.0)
}
fn compress(&self, input: &[u8]) -> Result<Vec<u8>, Box<Error>> {
Ok(zstd::block::compress(input, self.0)?)
}
fn decompress(&self, input: &[u8], original_len: usize) -> Result<(), Box<Error>> {
zstd::block::decompress(input, original_len)?;
Ok(())
}
}
struct Brotli(u32);
impl Algorithm for Brotli {
fn name(&self) -> String {
format!("brotli | {}", self.0)
}
fn compress(&self, input: &[u8]) -> Result<Vec<u8>, Box<Error>> {
let mut e = brotli2::write::BrotliEncoder::new(Vec::new(), self.0);
e.write_all(input)?;
Ok(e.finish()?)
}
fn decompress(&self, input: &[u8], _original_len: usize) -> Result<(), Box<Error>> {
let mut d = brotli2::write::BrotliDecoder::new(Vec::new());
d.write_all(input)?;
d.finish()?;
Ok(())
}
}
struct Benchmark {
files: Vec<Vec<u8>>,
}
impl Benchmark {
fn new() -> Self {
Benchmark { files: Vec::new() }
}
fn load_plain(&mut self) -> Result<(), Box<Error>> {
for entry in WalkDir::new(PLAIN) {
let entry = entry?;
if entry.file_type().is_file()
&& EXTENSIONS.contains(
&entry
.path()
.extension()
.and_then(|ext| ext.to_str())
.unwrap_or(""),
)
{
self.files.push(std::fs::read(entry.path())?);
}
}
let total_size = self
.files
.iter()
.map(|f| f.len())
.fold(0.0, |sum, entry| sum + entry as f32);
println!(
"| plain | - | {:.1} MB | - | - | - | - |",
total_size / 1024.0 / 1024.0
);
Ok(())
}
fn run(&self, algorithm: &dyn Algorithm) -> Result<(), Box<Error>> {
let now = Instant::now();
let mut compressed = Vec::new();
for file in &self.files {
compressed.push((algorithm.compress(&file)?, file.len()));
}
let compress = now.elapsed();
let now = Instant::now();
for (file, original_len) in &compressed {
algorithm.decompress(&file, *original_len)?;
}
let decompress = now.elapsed();
println!(
"| {} | {:.1} MB | {:.1?} | {:.1?} | {:.1?} | {:.1?} |",
algorithm.name(),
compressed
.iter()
.map(|(s, _)| s.len())
.fold(0.0, |sum, entry| sum + entry as f32)
/ 1024.0
/ 1024.0,
compress,
compress / self.files.len() as u32,
decompress,
decompress / self.files.len() as u32
);
Ok(())
}
}
fn main() -> Result<(), Box<Error>> {
println!("| Algorithm | Level | Size | Comp. | Comp. (one) | Dec. | Dec. (one) |");
println!("| --- | --- | --- | --- | --- | --- | --- |");
let mut benchmark = Benchmark::new();
benchmark.load_plain()?;
benchmark.run(&Gzip(9))?;
benchmark.run(&Gzip(5))?;
benchmark.run(&Gzip(1))?;
benchmark.run(&Zstd(9))?;
benchmark.run(&Zstd(5))?;
benchmark.run(&Zstd(1))?;
benchmark.run(&Brotli(9))?;
benchmark.run(&Brotli(5))?;
benchmark.run(&Brotli(1))?;
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment