From 743ae102f1d1ba9eba3bdc94683db060c4882cf1 Mon Sep 17 00:00:00 2001 From: Paul Masurel Date: Tue, 10 Apr 2018 10:05:42 +0900 Subject: [PATCH] Using bitpacker@3 --- Cargo.toml | 5 ++- src/common/bitpacker.rs | 9 +++--- src/compression/mod.rs | 71 ++++++++--------------------------------- 3 files changed, 21 insertions(+), 64 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a73703209..7c29246b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ stable_deref_trait = "1.0.0" rust-stemmers = "0.1.0" downcast = { version="0.9", features = ["nightly"]} matches = "0.1" -bitpacking = {path="../bitpacking", default-features=false} +bitpacking = "0.3" [target.'cfg(windows)'.dependencies] winapi = "0.2" @@ -57,8 +57,7 @@ debug-assertions = false [features] -default = ["mmap", "simdcompression"] -simdcompression = ["bitpacking/sse3"] +default = ["mmap"] streamdict = [] mmap = ["fst/mmap", "atomicwrites"] diff --git a/src/common/bitpacker.rs b/src/common/bitpacker.rs index 04524013a..0d36e4d41 100644 --- a/src/common/bitpacker.rs +++ b/src/common/bitpacker.rs @@ -3,6 +3,7 @@ use std::io; use common::serialize::BinarySerializable; use std::mem; use std::ops::Deref; +use std::ptr; pub(crate) struct BitPacker { mini_buffer: u64, @@ -105,18 +106,18 @@ where addr + 8 <= data.len(), "The fast field field should have been padded with 7 bytes." ); - let val_unshifted_unmasked: u64 = unsafe { *(data[addr..].as_ptr() as *const u64) }; + let val_unshifted_unmasked: u64 = unsafe { ptr::read_unaligned(data[addr..].as_ptr() as *const u64) }; let val_shifted = (val_unshifted_unmasked >> bit_shift) as u64; val_shifted & mask } else { let val_unshifted_unmasked: u64 = if addr + 8 <= data.len() { - unsafe { *(data[addr..].as_ptr() as *const u64) } + unsafe { ptr::read_unaligned(data[addr..].as_ptr() as *const u64) } } else { let mut buffer = [0u8; 8]; for i in addr..data.len() { buffer[i - addr] += data[i]; } - unsafe { *(buffer[..].as_ptr() as *const u64) } + unsafe { ptr::read_unaligned(buffer[..].as_ptr() as *const u64) } }; let val_shifted = val_unshifted_unmasked >> (bit_shift as u64); val_shifted & mask @@ -140,7 +141,7 @@ where for output_val in output.iter_mut() { let addr = addr_in_bits >> 3; let bit_shift = addr_in_bits & 7; - let val_unshifted_unmasked: u64 = unsafe { *(data[addr..].as_ptr() as *const u64) }; + let val_unshifted_unmasked: u64 = unsafe { ptr::read_unaligned(data[addr..].as_ptr() as *const u64) }; let val_shifted = (val_unshifted_unmasked >> bit_shift) as u64; *output_val = val_shifted & mask; addr_in_bits += num_bits; diff --git a/src/compression/mod.rs b/src/compression/mod.rs index fea9587a1..c4f5294a9 100644 --- a/src/compression/mod.rs +++ b/src/compression/mod.rs @@ -7,20 +7,10 @@ pub const COMPRESSION_BLOCK_SIZE: usize = 128; const COMPRESSED_BLOCK_MAX_SIZE: usize = COMPRESSION_BLOCK_SIZE * 4 + 1; pub use self::stream::CompressedIntStream; -use std::cmp; -use bitpacking::BitPacker; +use bitpacking::{BitPacker, BitPacker4x}; -#[cfg(not(feature = "simdcompression"))] -pub use bitpacking::ScalarBitPacker as BitPackerImpl; -#[cfg(not(feature = "simdcompression"))] -const MINI_BLOCK: usize = 4; - -#[cfg(feature = "simdcompression")] -pub use bitpacking::SSE3BitPacker as BitPackerImpl; -#[cfg(feature = "simdcompression")] -const MINI_BLOCK: usize = 1; /// Returns the size in bytes of a compressed block, given `num_bits`. pub fn compressed_block_size(num_bits: u8) -> usize { @@ -28,6 +18,7 @@ pub fn compressed_block_size(num_bits: u8) -> usize { } pub struct BlockEncoder { + bitpacker: BitPacker4x, pub output: [u8; COMPRESSED_BLOCK_MAX_SIZE], pub output_len: usize, } @@ -35,52 +26,30 @@ pub struct BlockEncoder { impl BlockEncoder { pub fn new() -> BlockEncoder { BlockEncoder { + bitpacker: BitPacker4x::new(), output: [0u8; COMPRESSED_BLOCK_MAX_SIZE], output_len: 0, } } - pub fn compress_block_sorted(&mut self, vals: &[u32], offset: u32) -> &[u8] { - assert_eq!(vals.len(), COMPRESSION_BLOCK_SIZE); - let mut num_bits = 0; - let mut offsets = [offset; MINI_BLOCK]; - for i in 1..MINI_BLOCK { - offsets[i] = vals[(i * BitPackerImpl::BLOCK_LEN) - 1]; - } - for i in 0..MINI_BLOCK { - let block = &vals[i * BitPackerImpl::BLOCK_LEN.. (i + 1)*BitPackerImpl::BLOCK_LEN]; - num_bits = cmp::max(BitPackerImpl::num_bits_sorted(offsets[i], block), num_bits); - } + pub fn compress_block_sorted(&mut self, block: &[u32], offset: u32) -> &[u8] { + let num_bits = self.bitpacker.num_bits_sorted(offset, block); self.output[0] = num_bits; - let compressed_chunk_len = (num_bits as usize) * BitPackerImpl::BLOCK_LEN / 8; - let mut written_size = 1; - for i in 0..MINI_BLOCK { - let block = &vals[i * BitPackerImpl::BLOCK_LEN.. (i + 1)*BitPackerImpl::BLOCK_LEN]; - BitPackerImpl::compress_sorted(offsets[i], block, &mut self.output[written_size..], num_bits); - written_size += compressed_chunk_len; - } + let written_size = 1 + self.bitpacker.compress_sorted(offset, block, &mut self.output[1..], num_bits); &self.output[..written_size] } - pub fn compress_block_unsorted(&mut self, vals: &[u32]) -> &[u8] { - assert_eq!(vals.len(), COMPRESSION_BLOCK_SIZE); - let num_bits = vals.chunks(BitPackerImpl::BLOCK_LEN) - .map(|chunk| BitPackerImpl::num_bits(chunk)) - .max() - .unwrap_or(0u8); + pub fn compress_block_unsorted(&mut self, block: &[u32]) -> &[u8] { + let num_bits = self.bitpacker.num_bits(block); self.output[0] = num_bits; - let mut written_size = 1; - let compressed_chunk_len = (num_bits as usize) * BitPackerImpl::BLOCK_LEN / 8; - for chunk in vals.chunks(BitPackerImpl::BLOCK_LEN) { - BitPackerImpl::compress(chunk, &mut self.output[written_size..], num_bits); - written_size += compressed_chunk_len; - } + let written_size = 1 + self.bitpacker.compress(block, &mut self.output[1..], num_bits); &self.output[..written_size] } } pub struct BlockDecoder { + bitpacker: BitPacker4x, pub output: [u32; COMPRESSION_BLOCK_SIZE + 1], pub output_len: usize, } @@ -94,34 +63,22 @@ impl BlockDecoder { let mut output = [val; COMPRESSION_BLOCK_SIZE + 1]; output[COMPRESSION_BLOCK_SIZE] = 0u32; BlockDecoder { + bitpacker: BitPacker4x::new(), output, output_len: 0, } } - pub fn uncompress_block_sorted(&mut self, compressed_data: &[u8], mut offset: u32) -> usize { + pub fn uncompress_block_sorted(&mut self, compressed_data: &[u8], offset: u32) -> usize { let num_bits = compressed_data[0]; - let mut read_size: usize = 1; - let chunk_size: usize = (num_bits as usize) * BitPackerImpl::BLOCK_LEN / 8; - for i in 0..MINI_BLOCK { - BitPackerImpl::decompress_sorted(offset, &compressed_data[read_size..], &mut self.output[i*BitPackerImpl::BLOCK_LEN..], num_bits); - offset = self.output[(i + 1)*BitPackerImpl::BLOCK_LEN - 1]; - read_size += chunk_size; - } self.output_len = COMPRESSION_BLOCK_SIZE; - read_size + 1 + self.bitpacker.decompress_sorted(offset, &compressed_data[1..], &mut self.output, num_bits) } pub fn uncompress_block_unsorted<'a>(&mut self, compressed_data: &'a [u8]) -> usize { let num_bits = compressed_data[0]; - let mut read_size: usize = 1; - let chunk_size: usize = (num_bits as usize) * BitPackerImpl::BLOCK_LEN / 8; - for i in 0..MINI_BLOCK { - BitPackerImpl::decompress(&compressed_data[read_size..], &mut self.output[i*BitPackerImpl::BLOCK_LEN..], num_bits); - read_size += chunk_size; - } self.output_len = COMPRESSION_BLOCK_SIZE; - read_size + 1 + self.bitpacker.decompress(&compressed_data[1..], &mut self.output, num_bits) } #[inline]