Implement multithreading for deflate passes

Closes #6
This commit is contained in:
Joshua Holmer 2016-02-04 10:32:20 -05:00
parent 391c04ea62
commit 08e6d42021
5 changed files with 43 additions and 30 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@ target
Cargo.lock
*.bk
.DS_Store
*.out.png

View file

@ -8,6 +8,7 @@ bit-vec = "^0.4.2"
byteorder = "^0.4.0"
clap = "^1.5.4"
crc = "^1.0.0"
crossbeam = "^0.2.1"
libc = "^0.2.4"
libz-sys = "^1.0.0"
regex = "^0.1.8"

View file

@ -1,6 +1,7 @@
extern crate bit_vec;
extern crate byteorder;
extern crate crc;
extern crate crossbeam;
extern crate libc;
extern crate libz_sys;
@ -13,6 +14,7 @@ use std::io::BufWriter;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
pub mod deflate {
pub mod deflate;
@ -118,42 +120,51 @@ pub fn optimize(filepath: &Path, opts: &Options) -> Result<(), String> {
if opts.idat_recoding || something_changed {
// Go through selected permutations and determine the best
let mut best: Option<(u8, u8, u8, u8)> = None;
let scoped_idat = Arc::new(png.idat_data.clone());
let combinations = opts.filter.len() * opts.compression.len() * opts.memory.len() *
opts.strategies.len();
println!("Trying: {} combinations", combinations);
// TODO: Multithreading
for f in &opts.filter {
let filtered = png.filter_image(*f);
for zc in &opts.compression {
for zm in &opts.memory {
for zs in &opts.strategies {
let new_idat = match deflate::deflate::deflate(&filtered,
*zc,
*zm,
*zs,
opts.window) {
Ok(x) => x,
Err(x) => return Err(x),
};
if new_idat.len() < png.idat_data.len() ||
(best.is_none() && something_changed) {
best = Some((*f, *zc, *zm, *zs));
png.idat_data = new_idat.clone();
}
if opts.verbosity == Some(1) {
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
*zc,
*zm,
*zs,
*f,
new_idat.len());
crossbeam::scope(|scope| {
for f in &opts.filter {
let filtered = png.filter_image(*f);
for zc in &opts.compression {
for zm in &opts.memory {
for zs in &opts.strategies {
let moved_png = png.clone();
let mut moved_idat = scoped_idat.clone();
let moved_filtered = filtered.clone();
scope.spawn(move || {
let new_idat = match deflate::deflate::deflate(&moved_filtered,
*zc,
*zm,
*zs,
opts.window) {
Ok(x) => x,
Err(x) => return Err(x),
};
if new_idat.len() < moved_png.idat_data.len() ||
(best.is_none() && something_changed) {
best = Some((*f, *zc, *zm, *zs));
*Arc::make_mut(&mut moved_idat) = new_idat.clone();
}
if opts.verbosity == Some(1) {
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
*zc,
*zm,
*zs,
*f,
new_idat.len());
}
Ok(())
});
}
}
}
}
}
});
if let Some(better) = best {
png.idat_data = Arc::try_unwrap(scoped_idat).unwrap().clone();
println!("Found better combination:");
println!(" zc = {} zm = {} zs = {} f = {} {} bytes",
better.1,

View file

@ -123,7 +123,7 @@ struct ScanLine {
data: Vec<u8>,
}
#[derive(Debug)]
#[derive(Debug,Clone)]
pub struct PngData {
pub idat_data: Vec<u8>,
pub ihdr_data: IhdrData,
@ -134,7 +134,7 @@ pub struct PngData {
pub aux_headers: HashMap<String, Vec<u8>>,
}
#[derive(Debug)]
#[derive(Debug,Clone)]
pub struct IhdrData {
pub width: u32,
pub height: u32,

View file

@ -371,7 +371,7 @@ fn palette_should_be_grayscale() {
#[test]
fn strip_headers() {
let input = PathBuf::from("tests/files/rgb_should_be_palette.png");
let input = PathBuf::from("tests/files/rgb_should_be_rgb.png");
let mut opts = get_opts(&input);
opts.strip = true;
let output = opts.out_file.clone();