Skip to content

Commit 8df0677

Browse files
committed
even faster combine
1 parent f8dd0a1 commit 8df0677

2 files changed

Lines changed: 68 additions & 64 deletions

File tree

benches/bench.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ fn bench_megabyte_specialized(b: &mut Bencher) {
3535
)
3636
}
3737

38-
fn bench_combine(b: &mut Bencher) {
39-
let (i1, l1, i2, l2) = rand::thread_rng().gen();
38+
fn bench_combine_inner(b: &mut Bencher, i1: u32, l1: u64, i2: u32, l2: u64) {
4039
let h1 = Hasher::new_with_initial_len(i1, l1);
4140
let h2 = Hasher::new_with_initial_len(i2, l2);
4241

@@ -47,6 +46,21 @@ fn bench_combine(b: &mut Bencher) {
4746
})
4847
}
4948

49+
fn bench_combine_16(b: &mut Bencher) {
50+
let (i1, l1, i2, l2): (u32, u64, u32, u16) = rand::thread_rng().gen();
51+
bench_combine_inner(b, i1, l1, i2, u64::from(l2))
52+
}
53+
54+
fn bench_combine_32(b: &mut Bencher) {
55+
let (i1, l1, i2, l2): (u32, u64, u32, u32) = rand::thread_rng().gen();
56+
bench_combine_inner(b, i1, l1, i2, u64::from(l2))
57+
}
58+
59+
fn bench_combine_64(b: &mut Bencher) {
60+
let (i1, l1, i2, l2): (u32, u64, u32, u64) = rand::thread_rng().gen();
61+
bench_combine_inner(b, i1, l1, i2, l2)
62+
}
63+
5064
bencher::benchmark_group!(
5165
bench_baseline,
5266
bench_kilobyte_baseline,
@@ -57,5 +71,10 @@ bencher::benchmark_group!(
5771
bench_kilobyte_specialized,
5872
bench_megabyte_specialized
5973
);
60-
bencher::benchmark_group!(bench_combine_group, bench_combine);
61-
bencher::benchmark_main!(bench_baseline, bench_specialized, bench_combine_group);
74+
bencher::benchmark_group!(
75+
bench_combine,
76+
bench_combine_16,
77+
bench_combine_32,
78+
bench_combine_64
79+
);
80+
bencher::benchmark_main!(bench_baseline, bench_specialized, bench_combine);

src/combine.rs

Lines changed: 45 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,57 @@
1-
const GF2_DIM: usize = 32;
1+
const POLY: u32 = 0xedb88320;
22

3-
fn gf2_matrix_times(mat: &[u32; GF2_DIM], vec: u32) -> u32 {
4-
let mut sum = 0;
3+
static X2N_TABLE: [u32; 32] = [
4+
0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, 0xed627dae, 0x88d14467, 0xd7bbfe6a,
5+
0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f, 0x83852d0f, 0x30362f1a, 0x7b5a9cc3,
6+
0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, 0xbad90e37, 0x2e4e5eef, 0x4eaba214,
7+
0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c, 0x40000000, 0x20000000, 0x08000000,
8+
];
59

6-
for (i, m) in mat.iter().enumerate() {
7-
if vec >> i & 1 == 1 {
8-
sum ^= *m;
9-
}
10-
}
11-
12-
sum
13-
}
10+
// Calculates a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
11+
// reflected. For speed, this requires that a not be zero.
12+
fn multiply(a: u32, mut b: u32) -> u32 {
13+
let mut m = 1u32 << 31;
14+
let mut p = 0u32;
1415

15-
fn gf2_matrix_square(square: &mut [u32; GF2_DIM], mat: &[u32; GF2_DIM]) {
16-
for n in 0..GF2_DIM {
17-
square[n] = gf2_matrix_times(mat, mat[n]);
18-
}
19-
}
20-
21-
pub(crate) fn combine(mut crc1: u32, crc2: u32, mut len2: u64) -> u32 {
22-
let mut even = [0u32; GF2_DIM]; // even-power-of-two zeros operator
23-
let mut odd = [0u32; GF2_DIM]; // odd-power-of-two zeros operator
24-
25-
// degenerate case (also disallow negative lengths)
26-
if len2 == 0 {
27-
return crc1;
28-
}
29-
30-
// put operator for one zero bit in odd
31-
odd[0] = 0xedb88320; // CRC-32 polynomial
32-
for (i, r) in odd[1..].iter_mut().enumerate() {
33-
*r = 1 << i;
34-
}
35-
36-
// put operator for two zero bits in even
37-
gf2_matrix_square(&mut even, &odd);
38-
39-
// put operator for four zero bits in odd
40-
gf2_matrix_square(&mut odd, &even);
41-
42-
// apply len2 zeros to crc1 (first square will put the operator for one
43-
// zero byte, eight zero bits, in even)
4416
loop {
45-
// apply zeros operator for this bit of len2
46-
gf2_matrix_square(&mut even, &odd);
47-
if len2 & 1 == 1 {
48-
crc1 = gf2_matrix_times(&even, crc1);
17+
if (a & m) != 0 {
18+
p ^= b;
19+
if (a & (m - 1)) == 0 {
20+
break;
21+
}
4922
}
50-
len2 >>= 1;
51-
52-
// if no more bits set, then done
53-
if len2 == 0 {
54-
break;
23+
m >>= 1;
24+
if b & 1 != 0 {
25+
b = (b >> 1) ^ POLY;
26+
} else {
27+
b >>= 1;
5528
}
29+
}
5630

57-
// another iteration of the loop with odd and even swapped
58-
gf2_matrix_square(&mut odd, &even);
59-
if len2 & 1 == 1 {
60-
crc1 = gf2_matrix_times(&odd, crc1);
61-
}
62-
len2 >>= 1;
31+
p
32+
}
33+
34+
pub(crate) fn combine(crc1: u32, crc2: u32, len2: u64) -> u32 {
35+
let mut p = 1u32 << 31; // x^0 == 1
36+
let n = 64 - len2.leading_zeros();
6337

64-
// if no more bits set, then done
65-
if len2 == 0 {
66-
break;
38+
for i in 0..n {
39+
if (len2 >> i & 1) != 0 {
40+
p = multiply(X2N_TABLE[(i & 0x1F) as usize], p);
6741
}
6842
}
6943

70-
// return combined crc
71-
crc1 ^ crc2
44+
multiply(p, crc1) ^ crc2
45+
}
46+
47+
#[test]
48+
fn golden() {
49+
assert_eq!(
50+
combine(0xB8AD0532, 0x804754D9, 0x19B77C403D9D90EE),
51+
940758956
52+
);
53+
assert_eq!(
54+
combine(0xF310DC54, 0x8B65DF79, 0x2F0327F1309076FF),
55+
3454617599
56+
);
7257
}

0 commit comments

Comments
 (0)