Skip to content

Commit eb1b1f3

Browse files
committed
crc-fast-rust: added fuzzing; fix the software memory leak; benched the software impl to validate the cache perf win
1 parent c2d5bac commit eb1b1f3

File tree

11 files changed

+9253
-179
lines changed

11 files changed

+9253
-179
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
.DS_Store
66
.git
77
.vscode
8+
walkthrough.md

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,7 @@ rustdoc-args = ["--cfg", "docsrs"]
105105
name = "checksum_integration_tests"
106106
path = "tests/checksum_integration_tests.rs"
107107
required-features = ["cli"]
108+
109+
[[bench]]
110+
name = "software_bench"
111+
harness = false

benches/software_bench.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use crc_fast::{checksum_with_params, CrcAlgorithm, CrcKeysStorage, CrcParams};
2+
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
3+
use std::hint::black_box;
4+
5+
fn benchmark_custom_crc(c: &mut Criterion) {
6+
let params = CrcParams {
7+
algorithm: CrcAlgorithm::Crc32Custom,
8+
name: "Custom",
9+
width: 32,
10+
poly: 0x04c11db7,
11+
init: 0xffffffff,
12+
refin: true,
13+
refout: true,
14+
xorout: 0xffffffff,
15+
check: 0,
16+
keys: CrcKeysStorage::KeysFold256([0; 23]),
17+
};
18+
19+
let data = vec![0u8; 1024]; // 1KB
20+
21+
let mut group = c.benchmark_group("software_fallback");
22+
group.throughput(Throughput::Bytes(data.len() as u64));
23+
24+
group.bench_function("custom_crc32_1kb", |b| {
25+
b.iter(|| checksum_with_params(black_box(params), black_box(&data)))
26+
});
27+
28+
group.finish();
29+
}
30+
31+
criterion_group!(benches, benchmark_custom_crc);
32+
criterion_main!(benches);

fuzz/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
target
2+
corpus
3+
artifacts
4+
coverage

fuzz/Cargo.lock

Lines changed: 185 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fuzz/Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "crc-fast-fuzz"
3+
version = "0.0.0"
4+
publish = false
5+
edition = "2021"
6+
7+
[package.metadata]
8+
cargo-fuzz = true
9+
10+
[dependencies]
11+
libfuzzer-sys = "0.4"
12+
crc = "3"
13+
14+
[dependencies.crc-fast]
15+
path = ".."
16+
17+
[[bin]]
18+
name = "compare_vs_crc"
19+
path = "fuzz_targets/compare_vs_crc.rs"
20+
test = false
21+
doc = false
22+
bench = false
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#![no_main]
2+
use crc_fast::{CrcAlgorithm, Digest};
3+
use libfuzzer_sys::fuzz_target;
4+
5+
fuzz_target!(|data: (u8, Vec<u8>)| {
6+
let (algo_idx, bytes) = data;
7+
8+
// List of algorithms to test
9+
let algorithms = [
10+
CrcAlgorithm::Crc32Aixm,
11+
CrcAlgorithm::Crc32Autosar,
12+
CrcAlgorithm::Crc32Base91D,
13+
CrcAlgorithm::Crc32Bzip2,
14+
CrcAlgorithm::Crc32CdRomEdc,
15+
CrcAlgorithm::Crc32Cksum,
16+
CrcAlgorithm::Crc32Iscsi,
17+
CrcAlgorithm::Crc32IsoHdlc,
18+
CrcAlgorithm::Crc32Jamcrc,
19+
CrcAlgorithm::Crc32Mef,
20+
CrcAlgorithm::Crc32Mpeg2,
21+
CrcAlgorithm::Crc32Xfer,
22+
CrcAlgorithm::Crc64Ecma182,
23+
CrcAlgorithm::Crc64GoIso,
24+
CrcAlgorithm::Crc64Ms,
25+
// CrcAlgorithm::Crc64Nvme, // Not in crc crate
26+
CrcAlgorithm::Crc64Redis,
27+
CrcAlgorithm::Crc64We,
28+
CrcAlgorithm::Crc64Xz,
29+
];
30+
31+
if algorithms.is_empty() {
32+
return;
33+
}
34+
let algo = algorithms[algo_idx as usize % algorithms.len()];
35+
36+
// Compute expected value using crc crate
37+
let (expected, width) = match algo {
38+
CrcAlgorithm::Crc32Aixm => (
39+
crc::Crc::<u32>::new(&crc::CRC_32_AIXM).checksum(&bytes) as u64,
40+
32,
41+
),
42+
CrcAlgorithm::Crc32Autosar => (
43+
crc::Crc::<u32>::new(&crc::CRC_32_AUTOSAR).checksum(&bytes) as u64,
44+
32,
45+
),
46+
CrcAlgorithm::Crc32Base91D => (
47+
crc::Crc::<u32>::new(&crc::CRC_32_BASE91_D).checksum(&bytes) as u64,
48+
32,
49+
),
50+
CrcAlgorithm::Crc32Bzip2 => (
51+
crc::Crc::<u32>::new(&crc::CRC_32_BZIP2).checksum(&bytes) as u64,
52+
32,
53+
),
54+
CrcAlgorithm::Crc32CdRomEdc => (
55+
crc::Crc::<u32>::new(&crc::CRC_32_CD_ROM_EDC).checksum(&bytes) as u64,
56+
32,
57+
),
58+
CrcAlgorithm::Crc32Cksum => (
59+
crc::Crc::<u32>::new(&crc::CRC_32_CKSUM).checksum(&bytes) as u64,
60+
32,
61+
),
62+
CrcAlgorithm::Crc32Iscsi => (
63+
crc::Crc::<u32>::new(&crc::CRC_32_ISCSI).checksum(&bytes) as u64,
64+
32,
65+
),
66+
CrcAlgorithm::Crc32IsoHdlc => (
67+
crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC).checksum(&bytes) as u64,
68+
32,
69+
),
70+
CrcAlgorithm::Crc32Jamcrc => (
71+
crc::Crc::<u32>::new(&crc::CRC_32_JAMCRC).checksum(&bytes) as u64,
72+
32,
73+
),
74+
CrcAlgorithm::Crc32Mef => (
75+
crc::Crc::<u32>::new(&crc::CRC_32_MEF).checksum(&bytes) as u64,
76+
32,
77+
),
78+
CrcAlgorithm::Crc32Mpeg2 => (
79+
crc::Crc::<u32>::new(&crc::CRC_32_MPEG_2).checksum(&bytes) as u64,
80+
32,
81+
),
82+
CrcAlgorithm::Crc32Xfer => (
83+
crc::Crc::<u32>::new(&crc::CRC_32_XFER).checksum(&bytes) as u64,
84+
32,
85+
),
86+
87+
CrcAlgorithm::Crc64Ecma182 => (
88+
crc::Crc::<u64>::new(&crc::CRC_64_ECMA_182).checksum(&bytes),
89+
64,
90+
),
91+
CrcAlgorithm::Crc64GoIso => (
92+
crc::Crc::<u64>::new(&crc::CRC_64_GO_ISO).checksum(&bytes),
93+
64,
94+
),
95+
CrcAlgorithm::Crc64Ms => (crc::Crc::<u64>::new(&crc::CRC_64_MS).checksum(&bytes), 64),
96+
CrcAlgorithm::Crc64Redis => (
97+
crc::Crc::<u64>::new(&crc::CRC_64_REDIS).checksum(&bytes),
98+
64,
99+
),
100+
CrcAlgorithm::Crc64We => (crc::Crc::<u64>::new(&crc::CRC_64_WE).checksum(&bytes), 64),
101+
CrcAlgorithm::Crc64Xz => (crc::Crc::<u64>::new(&crc::CRC_64_XZ).checksum(&bytes), 64),
102+
103+
_ => return,
104+
};
105+
106+
// Compute actual value using crc-fast
107+
let mut digest = Digest::new(algo);
108+
digest.update(&bytes);
109+
let actual = digest.finalize();
110+
111+
assert_eq!(
112+
actual,
113+
expected,
114+
"Mismatch for algorithm {:?} with input len {}",
115+
algo,
116+
bytes.len()
117+
);
118+
});

0 commit comments

Comments
 (0)