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 Cargo.lock
*.bk *.bk
.DS_Store .DS_Store
*.out.png

View file

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

View file

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

View file

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

View file

@ -371,7 +371,7 @@ fn palette_should_be_grayscale() {
#[test] #[test]
fn strip_headers() { 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); let mut opts = get_opts(&input);
opts.strip = true; opts.strip = true;
let output = opts.out_file.clone(); let output = opts.out_file.clone();