Skip to content

Instantly share code, notes, and snippets.

@samcday
Created March 9, 2019 11:27
Show Gist options
  • Save samcday/97ae61d66fc37b7374c4d96850ff3fde to your computer and use it in GitHub Desktop.
Save samcday/97ae61d66fc37b7374c4d96850ff3fde to your computer and use it in GitHub Desktop.
#[macro_use]
extern crate bencher;
use bencher::Bencher;
use lazy_static::lazy_static;
use oxideboy::{interrupt, ppu, simple_diff, Gameboy, Model};
use snap;
lazy_static! {
static ref DIFF_STATES: (Vec<u8>, Vec<u8>) = {
let rom = include_bytes!("../tests/blargg/mem_timing.gb").to_vec();
let mut gb = Gameboy::new(Model::DMG, rom);
let mut base_state = Vec::new();
let mut new_state = Vec::new();
for _ in 0..60 {
while !gb.new_frame {
gb.run_instruction();
}
gb.run_instruction();
gb.save_state(&mut base_state);
}
for _ in 0..60 {
while !gb.new_frame {
gb.run_instruction();
}
gb.run_instruction();
gb.save_state(&mut new_state);
}
(base_state, new_state)
};
}
fn diff_small(bench: &mut Bencher) {
let mut diff_out = Vec::new();
let base_state = &DIFF_STATES.0;
let new_state = &DIFF_STATES.1;
simple_diff::generate(&base_state, &new_state, &mut diff_out);
let cap = diff_out.capacity();
let size = diff_out.len();
bench.iter(|| {
diff_out.clear();
simple_diff::generate(&base_state, &new_state, &mut diff_out);
assert_eq!(diff_out.capacity(), cap);
assert_eq!(diff_out.len(), size);
});
}
benchmark_group!(
diff_small,
);
benchmark_main!(benches);
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::prelude::*;
/// The number of bytes that must be identical before a chunk is finished off.
pub const CHUNK_END_WINDOW: usize = 16;
/// Generates a diff between the base data and the new data. Results are written into the diff Vec.
pub fn generate(base: &[u8], new: &[u8], diff: &mut Vec<u8>) {
// This whole deal only works if our two blobs are the same size.
// assert_eq!(base.len(), new.len());
let mut chunk_start: usize = 0;
let mut chunk_end: usize = 0;
let mut in_chunk = false;
let mut chunk_count = 0;
// This will be the chunk count, we'll fill it in at the end.
diff.write_u32::<LittleEndian>(0).unwrap();
for (i, (l, r)) in base.iter().zip(new.iter()).enumerate() {
let eq = l == r;
if !eq {
if !in_chunk {
in_chunk = true;
chunk_start = i;
}
chunk_end = i;
}
if eq && in_chunk {
if i - chunk_end > CHUNK_END_WINDOW {
chunk_count += 1;
diff.write_u32::<LittleEndian>(chunk_start as u32).unwrap();
diff.write_u32::<LittleEndian>((chunk_end - chunk_start + 1) as u32)
.unwrap();
diff.write(&new[chunk_start..chunk_end + 1]).unwrap();
in_chunk = false;
}
}
}
if in_chunk {
chunk_count += 1;
diff.write_u32::<LittleEndian>(chunk_start as u32).unwrap();
diff.write_u32::<LittleEndian>((chunk_end - chunk_start + 1) as u32)
.unwrap();
diff.write(&new[chunk_start..chunk_end + 1]).unwrap();
}
LittleEndian::write_u32(&mut diff[0..4], chunk_count);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment