]> Cypherpunks repositories - gostls13.git/commitdiff
hash/crc32: speedup crc32 of IEEE using slicingBy8
authorDavies Liu <davies.liu@gmail.com>
Fri, 19 Dec 2014 06:45:55 +0000 (22:45 -0800)
committerRuss Cox <rsc@golang.org>
Thu, 18 Jun 2015 18:14:24 +0000 (18:14 +0000)
The Slicing-By-8 [1] algorithm has much performance improvements than
current approach. This patch only uses it for IEEE, which is the most
common case in practice.

There is the benchmark on Mac OS X 10.9:

benchmark                     old MB/s     new MB/s     speedup
BenchmarkIEEECrc1KB           349.40       353.03       1.01x
BenchmarkIEEECrc4KB           351.55       934.35       2.66x
BenchmarkCastagnoliCrc1KB     7037.58      7392.63      1.05x

This algorithm need 8K lookup table, so it's enabled only for block
larger than 4K.

We can see about 2.6x improvement for IEEE.

Change-Id: I7f786d20f0949245e4aa101d7921669f496ed0f7
Reviewed-on: https://go-review.googlesource.com/1863
Reviewed-by: Russ Cox <rsc@golang.org>
src/hash/crc32/crc32.go
src/hash/crc32/crc32_test.go

index 10867a79a85369e263ed3700e6ddd0893ad783a7..234d92968902d9003fdad3db899c3f3b35c8e367 100644 (file)
@@ -54,6 +54,13 @@ func castagnoliInit() {
 // IEEETable is the table for the IEEE polynomial.
 var IEEETable = makeTable(IEEE)
 
+// slicing8Table is array of 8 Tables
+type slicing8Table [8]Table
+
+// iEEETable8 is the slicing8Table for IEEE
+var iEEETable8 *slicing8Table
+var iEEETable8Once sync.Once
+
 // MakeTable returns the Table constructed from the specified polynomial.
 func MakeTable(poly uint32) *Table {
        switch poly {
@@ -83,6 +90,20 @@ func makeTable(poly uint32) *Table {
        return t
 }
 
+// makeTable8 returns slicing8Table constructed from the specified polynomial.
+func makeTable8(poly uint32) *slicing8Table {
+       t := new(slicing8Table)
+       t[0] = *makeTable(poly)
+       for i := 0; i < 256; i++ {
+               crc := t[0][i]
+               for j := 1; j < 8; j++ {
+                       crc = t[0][crc&0xFF] ^ (crc >> 8)
+                       t[j][i] = crc
+               }
+       }
+       return t
+}
+
 // digest represents the partial evaluation of a checksum.
 type digest struct {
        crc uint32
@@ -111,11 +132,32 @@ func update(crc uint32, tab *Table, p []byte) uint32 {
        return ^crc
 }
 
+// updateSlicingBy8 updates CRC using Slicing-by-8
+func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
+       crc = ^crc
+       for len(p) > 8 {
+               crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+               crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
+                       tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
+                       tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
+               p = p[8:]
+       }
+       crc = ^crc
+       return update(crc, &tab[0], p)
+}
+
 // Update returns the result of adding the bytes in p to the crc.
 func Update(crc uint32, tab *Table, p []byte) uint32 {
        if tab == castagnoliTable {
                return updateCastagnoli(crc, p)
        }
+       // only use slicing-by-8 when input is larger than 4KB
+       if tab == IEEETable && len(p) >= 4096 {
+               iEEETable8Once.Do(func() {
+                       iEEETable8 = makeTable8(IEEE)
+               })
+               return updateSlicingBy8(crc, iEEETable8, p)
+       }
        return update(crc, tab, p)
 }
 
@@ -137,4 +179,4 @@ func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
 
 // ChecksumIEEE returns the CRC-32 checksum of data
 // using the IEEE polynomial.
-func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) }
+func ChecksumIEEE(data []byte) uint32 { return Update(0, IEEETable, data) }
index 75dc26e7cc249aab1ed80b7b1c9184a2308cfb16..1ca3ac2a270471889455801e6922cfbfac10e985 100644 (file)
@@ -81,7 +81,7 @@ func TestGolden(t *testing.T) {
        }
 }
 
-func BenchmarkCrc32KB(b *testing.B) {
+func BenchmarkIEEECrc1KB(b *testing.B) {
        b.SetBytes(1024)
        data := make([]byte, 1024)
        for i := range data {
@@ -97,3 +97,37 @@ func BenchmarkCrc32KB(b *testing.B) {
                h.Sum(in)
        }
 }
+
+func BenchmarkIEEECrc4KB(b *testing.B) {
+       b.SetBytes(4096)
+       data := make([]byte, 4096)
+       for i := range data {
+               data[i] = byte(i)
+       }
+       h := NewIEEE()
+       in := make([]byte, 0, h.Size())
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               h.Reset()
+               h.Write(data)
+               h.Sum(in)
+       }
+}
+
+func BenchmarkCastagnoliCrc1KB(b *testing.B) {
+       b.SetBytes(1024)
+       data := make([]byte, 1024)
+       for i := range data {
+               data[i] = byte(i)
+       }
+       h := New(MakeTable(Castagnoli))
+       in := make([]byte, 0, h.Size())
+
+       b.ResetTimer()
+       for i := 0; i < b.N; i++ {
+               h.Reset()
+               h.Write(data)
+               h.Sum(in)
+       }
+}