From a586f0761ae10a6fe5a401284f99098b47aedaf8 Mon Sep 17 00:00:00 2001 From: Moritz Borcherding Date: Tue, 14 Feb 2023 07:29:52 +0100 Subject: [PATCH] Use slice16 as default impl on all widths but u128 Also, document the trade-offs in the README. --- README.md | 86 +++++++++++++++++++++++++++++++++++++++----- src/crc16/default.rs | 10 +++--- src/crc32/default.rs | 8 ++--- src/crc64/default.rs | 8 ++--- src/crc8/default.rs | 10 +++--- src/lib.rs | 28 ++++++++++++--- 6 files changed, 122 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index f877a09..47fc464 100644 --- a/README.md +++ b/README.md @@ -40,20 +40,90 @@ let crc = Crc::::new(&CUSTOM_ALG); let mut digest = crc.digest(); digest.update(b"123456789"); assert_eq!(digest.finalize(), 0xaee7); -``` +``` + +### Lookup table flavors + +This crate offers three flavors of lookup tables providing a tradeoff between computation speed and used memory. +See the benchmark section for hints, but do benchmarks on your target hardware to decide if the tradeoff is worth it to you. + +1. `NoTable` provides an implementation that uses no additional memory +2. `Bytewise` provides an implementation that uses a lookup table that uses 256 entries of the used width (e.g. for u32 thats 256 * 4 bytes) +3. `Slice16` provides an implementation that uses a lookup table that uses 16 * 256 entries of the used width (e.g. for u32 thats 16 * 256 * 4 bytes) + +These can be used by substituting `Crc` with e.g. `Crc>`. If you use `Crc` the default implementation is used which are as follows: + +* u8 -> Slice16 +* u16 -> Slice16 +* u32 -> Slice16 +* u64 -> Slice16 +* u128 -> Bytewise + +Note that these tables can bloat your binary size if you precalculate them at compiletime (this happens in `Crc::new`). +Choosing a crate like oncecell or lazystatic to compute them once at runtime may be preferable where binary size is a concern. ## Benchmark -`cargo bench` with 2.6 GHz Intel Core i7. [Comparison](http://create.stephan-brumme.com/crc32/) +`cargo bench` with AMD Ryzen 7 3800X. [Comparison](http://create.stephan-brumme.com/crc32/) + +### With no lookup table + +``` +crc8/nolookup time: [138.00 µs 138.17 µs 138.35 µs] + thrpt: [112.93 MiB/s 113.08 MiB/s 113.22 MiB/s] + +crc16/nolookup time: [147.89 µs 148.00 µs 148.12 µs] + thrpt: [105.49 MiB/s 105.57 MiB/s 105.65 MiB/s] + + +crc32/nolookup time: [140.10 µs 140.37 µs 140.62 µs] + thrpt: [111.11 MiB/s 111.31 MiB/s 111.52 MiB/s] + +crc64/nolookup time: [112.02 µs 112.06 µs 112.10 µs] + thrpt: [139.39 MiB/s 139.44 MiB/s 139.49 MiB/s] + +crc82/nolookup time: [171.19 µs 171.50 µs 171.84 µs] + thrpt: [90.929 MiB/s 91.109 MiB/s 91.270 MiB/s] + + +``` + +### With 256 entry lookup table + ``` -crc16 time: [2.0082 ms 2.0206 ms 2.0367 ms] - thrpt: [468.25 MiB/s 471.96 MiB/s 474.89 MiB/s] +crc8/bytewise time: [26.670 µs 26.699 µs 26.732 µs] + thrpt: [584.51 MiB/s 585.22 MiB/s 585.87 MiB/s] + +crc16/bytewise time: [32.303 µs 32.320 µs 32.338 µs] + thrpt: [483.17 MiB/s 483.45 MiB/s 483.70 MiB/s] + +crc32/bytewise time: [30.284 µs 30.309 µs 30.339 µs] + thrpt: [515.02 MiB/s 515.52 MiB/s 515.95 MiB/s] + +crc64/bytewise time: [30.218 µs 30.223 µs 30.227 µs] + thrpt: [516.92 MiB/s 517.00 MiB/s 517.07 MiB/s] + +crc82/bytewise time: [35.603 µs 35.670 µs 35.724 µs] + thrpt: [437.39 MiB/s 438.05 MiB/s 438.87 MiB/s] +``` + +## With 16 x 256 entry lookup table + +``` +crc8/slice16 time: [4.8891 µs 4.9057 µs 4.9250 µs] + thrpt: [3.0982 GiB/s 3.1104 GiB/s 3.1210 GiB/s] + +crc16/slice16 time: [4.7201 µs 4.7235 µs 4.7277 µs] + thrpt: [3.2276 GiB/s 3.2304 GiB/s 3.2327 GiB/s] + +crc32/slice16 time: [4.6134 µs 4.6217 µs 4.6302 µs] + thrpt: [3.2955 GiB/s 3.3015 GiB/s 3.3075 GiB/s] -crc32 time: [1.7659 ms 1.7793 ms 1.7952 ms] - thrpt: [531.25 MiB/s 535.98 MiB/s 540.05 MiB/s] +crc64/slice16 time: [5.2283 µs 5.2303 µs 5.2324 µs] + thrpt: [2.9162 GiB/s 2.9174 GiB/s 2.9185 GiB/s] -crc64 time: [2.0655 ms 2.0803 ms 2.0973 ms] - thrpt: [454.71 MiB/s 458.43 MiB/s 461.72 MiB/s] +crc82/slice16 time: [25.055 µs 25.061 µs 25.067 µs] + thrpt: [623.32 MiB/s 623.47 MiB/s 623.64 MiB/s] ``` ## License diff --git a/src/crc16/default.rs b/src/crc16/default.rs index a44f800..75123d1 100644 --- a/src/crc16/default.rs +++ b/src/crc16/default.rs @@ -1,10 +1,12 @@ -use crate::crc16::{finalize, init, update_bytewise}; -use crate::table::crc16_table; +use crate::crc16::{finalize, init}; +use crate::table::crc16_table_slice_16; use crate::{Algorithm, Crc, Digest}; +use super::update_slice16; + impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc16_table(algorithm.width, algorithm.poly, algorithm.refin); + let table = crc16_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); Self { algorithm, table } } @@ -15,7 +17,7 @@ impl Crc { } const fn update(&self, crc: u16, bytes: &[u8]) -> u16 { - update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + update_slice16(crc, self.algorithm.refin, &self.table, bytes) } pub const fn digest(&self) -> Digest { diff --git a/src/crc32/default.rs b/src/crc32/default.rs index 0a188b8..c35e3be 100644 --- a/src/crc32/default.rs +++ b/src/crc32/default.rs @@ -1,11 +1,11 @@ -use crate::table::crc32_table; +use crate::table::crc32_table_slice_16; use crate::{Algorithm, Crc, Digest}; -use super::{finalize, init, update_bytewise}; +use super::{finalize, init, update_slice16}; impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc32_table(algorithm.width, algorithm.poly, algorithm.refin); + let table = crc32_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); Self { algorithm, table } } @@ -16,7 +16,7 @@ impl Crc { } const fn update(&self, crc: u32, bytes: &[u8]) -> u32 { - update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + update_slice16(crc, self.algorithm.refin, &self.table, bytes) } pub const fn digest(&self) -> Digest { diff --git a/src/crc64/default.rs b/src/crc64/default.rs index d1093b1..73628ef 100644 --- a/src/crc64/default.rs +++ b/src/crc64/default.rs @@ -1,11 +1,11 @@ -use crate::table::crc64_table; +use crate::table::crc64_table_slice_16; use crate::{Algorithm, Crc, Digest}; -use super::{finalize, init, update_bytewise}; +use super::{finalize, init, update_slice16}; impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc64_table(algorithm.width, algorithm.poly, algorithm.refin); + let table = crc64_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); Self { algorithm, table } } @@ -16,7 +16,7 @@ impl Crc { } const fn update(&self, crc: u64, bytes: &[u8]) -> u64 { - update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + update_slice16(crc, self.algorithm.refin, &self.table, bytes) } pub const fn digest(&self) -> Digest { diff --git a/src/crc8/default.rs b/src/crc8/default.rs index 8fe599f..2dfec0d 100644 --- a/src/crc8/default.rs +++ b/src/crc8/default.rs @@ -1,10 +1,12 @@ -use crate::crc8::{finalize, init, update_bytewise}; -use crate::table::crc8_table; +use crate::crc8::{finalize, init}; +use crate::table::crc8_table_slice_16; use crate::{Algorithm, Crc, Digest}; +use super::update_slice16; + impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc8_table(algorithm.width, algorithm.poly, algorithm.refin); + let table = crc8_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); Self { algorithm, table } } @@ -15,7 +17,7 @@ impl Crc { } const fn update(&self, crc: u8, bytes: &[u8]) -> u8 { - update_bytewise(crc, &self.table, bytes) + update_slice16(crc, &self.table, bytes) } pub const fn digest(&self) -> Digest { diff --git a/src/lib.rs b/src/lib.rs index f56bf8f..79b7723 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ //! digest.update(b"123456789"); //! assert_eq!(digest.finalize(), 0xaee7); //! ``` -//#![no_std] +#![no_std] #![forbid(unsafe_code)] pub use crc_catalog::*; @@ -79,9 +79,29 @@ pub trait Implementation: private::Sealed { type Table; } -impl Implementation for W { - type Width = W; - type Table = [W; 256]; +impl Implementation for u8 { + type Width = u8; + type Table = [[u8; 256]; 16]; +} + +impl Implementation for u16 { + type Width = u16; + type Table = [[u16; 256]; 16]; +} + +impl Implementation for u32 { + type Width = u32; + type Table = [[u32; 256]; 16]; +} + +impl Implementation for u64 { + type Width = u64; + type Table = [[u64; 256]; 16]; +} + +impl Implementation for u128 { + type Width = u128; + type Table = [u128; 256]; } /// Crc with pluggable implementations ([Nolookup], [Bytewise], [Slice16]).