summaryrefslogtreecommitdiff
path: root/libgo/go/hash/crc32/crc32_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/hash/crc32/crc32_test.go')
-rw-r--r--libgo/go/hash/crc32/crc32_test.go252
1 files changed, 201 insertions, 51 deletions
diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go
index 1ca3ac2a27..1356734d50 100644
--- a/libgo/go/hash/crc32/crc32_test.go
+++ b/libgo/go/hash/crc32/crc32_test.go
@@ -5,7 +5,8 @@
package crc32
import (
- "io"
+ "hash"
+ "math/rand"
"testing"
)
@@ -48,82 +49,231 @@ var golden = []test{
{0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"},
}
-func TestGolden(t *testing.T) {
- castagnoliTab := MakeTable(Castagnoli)
+// testGoldenIEEE verifies that the given function returns
+// correct IEEE checksums.
+func testGoldenIEEE(t *testing.T, crcFunc func(b []byte) uint32) {
+ for _, g := range golden {
+ if crc := crcFunc([]byte(g.in)); crc != g.ieee {
+ t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, crc, g.ieee)
+ }
+ }
+}
+// testGoldenCastagnoli verifies that the given function returns
+// correct IEEE checksums.
+func testGoldenCastagnoli(t *testing.T, crcFunc func(b []byte) uint32) {
for _, g := range golden {
- ieee := NewIEEE()
- io.WriteString(ieee, g.in)
- s := ieee.Sum32()
- if s != g.ieee {
- t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee)
+ if crc := crcFunc([]byte(g.in)); crc != g.castagnoli {
+ t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, crc, g.castagnoli)
}
+ }
+}
- castagnoli := New(castagnoliTab)
- io.WriteString(castagnoli, g.in)
- s = castagnoli.Sum32()
- if s != g.castagnoli {
- t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+// testCrossCheck generates random buffers of various lengths and verifies that
+// the two "update" functions return the same result.
+func testCrossCheck(t *testing.T, crcFunc1, crcFunc2 func(crc uint32, b []byte) uint32) {
+ // The AMD64 implementation has some cutoffs at lengths 168*3=504 and
+ // 1344*3=4032. We should make sure lengths around these values are in the
+ // list.
+ lengths := []int{0, 1, 2, 3, 4, 5, 10, 16, 50, 100, 128,
+ 500, 501, 502, 503, 504, 505, 512, 1000, 1024, 2000,
+ 4030, 4031, 4032, 4033, 4036, 4040, 4048, 4096, 5000, 10000}
+ for _, length := range lengths {
+ p := make([]byte, length)
+ _, _ = rand.Read(p)
+ crcInit := uint32(rand.Int63())
+ crc1 := crcFunc1(crcInit, p)
+ crc2 := crcFunc2(crcInit, p)
+ if crc1 != crc2 {
+ t.Errorf("mismatch: 0x%x vs 0x%x (buffer length %d)", crc1, crc2, length)
}
+ }
+}
- if len(g.in) > 0 {
- // The SSE4.2 implementation of this has code to deal
- // with misaligned data so we ensure that we test that
- // too.
- castagnoli = New(castagnoliTab)
- io.WriteString(castagnoli, g.in[:1])
- io.WriteString(castagnoli, g.in[1:])
- s = castagnoli.Sum32()
- if s != g.castagnoli {
- t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
- }
+// TestSimple tests the simple generic algorithm.
+func TestSimple(t *testing.T) {
+ tab := simpleMakeTable(IEEE)
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ return simpleUpdate(0, tab, b)
+ })
+
+ tab = simpleMakeTable(Castagnoli)
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ return simpleUpdate(0, tab, b)
+ })
+}
+
+// TestSimple tests the slicing-by-8 algorithm.
+func TestSlicing(t *testing.T) {
+ tab := slicingMakeTable(IEEE)
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ return slicingUpdate(0, tab, b)
+ })
+
+ tab = slicingMakeTable(Castagnoli)
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ return slicingUpdate(0, tab, b)
+ })
+
+ // Cross-check various polys against the simple algorithm.
+ for _, poly := range []uint32{IEEE, Castagnoli, Koopman, 0xD5828281} {
+ t1 := simpleMakeTable(poly)
+ f1 := func(crc uint32, b []byte) uint32 {
+ return simpleUpdate(crc, t1, b)
+ }
+ t2 := slicingMakeTable(poly)
+ f2 := func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, t2, b)
}
+ testCrossCheck(t, f1, f2)
}
}
-func BenchmarkIEEECrc1KB(b *testing.B) {
- b.SetBytes(1024)
- data := make([]byte, 1024)
- for i := range data {
- data[i] = byte(i)
+func TestArchIEEE(t *testing.T) {
+ if !archAvailableIEEE() {
+ t.Skip("Arch-specific IEEE not available.")
}
- h := NewIEEE()
- in := make([]byte, 0, h.Size())
+ archInitIEEE()
+ slicingTable := slicingMakeTable(IEEE)
+ testCrossCheck(t, archUpdateIEEE, func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, slicingTable, b)
+ })
+}
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- h.Reset()
- h.Write(data)
- h.Sum(in)
+func TestArchCastagnoli(t *testing.T) {
+ if !archAvailableCastagnoli() {
+ t.Skip("Arch-specific Castagnoli not available.")
}
+ archInitCastagnoli()
+ slicingTable := slicingMakeTable(Castagnoli)
+ testCrossCheck(t, archUpdateCastagnoli, func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, slicingTable, b)
+ })
}
-func BenchmarkIEEECrc4KB(b *testing.B) {
- b.SetBytes(4096)
- data := make([]byte, 4096)
- for i := range data {
- data[i] = byte(i)
+func TestGolden(t *testing.T) {
+ testGoldenIEEE(t, ChecksumIEEE)
+
+ // Some implementations have special code to deal with misaligned
+ // data; test that as well.
+ for delta := 1; delta <= 7; delta++ {
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ ieee := NewIEEE()
+ d := delta
+ if d >= len(b) {
+ d = len(b)
+ }
+ ieee.Write(b[:d])
+ ieee.Write(b[d:])
+ return ieee.Sum32()
+ })
}
- 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)
+ castagnoliTab := MakeTable(Castagnoli)
+ if castagnoliTab == nil {
+ t.Errorf("nil Castagnoli Table")
}
+
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ castagnoli := New(castagnoliTab)
+ castagnoli.Write(b)
+ return castagnoli.Sum32()
+ })
+
+ // Some implementations have special code to deal with misaligned
+ // data; test that as well.
+ for delta := 1; delta <= 7; delta++ {
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ castagnoli := New(castagnoliTab)
+ d := delta
+ if d >= len(b) {
+ d = len(b)
+ }
+ castagnoli.Write(b[:d])
+ castagnoli.Write(b[d:])
+ return castagnoli.Sum32()
+ })
+ }
+}
+
+func BenchmarkIEEECrc40B(b *testing.B) {
+ benchmark(b, NewIEEE(), 40, 0)
+}
+
+func BenchmarkIEEECrc1KB(b *testing.B) {
+ benchmark(b, NewIEEE(), 1<<10, 0)
+}
+
+func BenchmarkIEEECrc4KB(b *testing.B) {
+ benchmark(b, NewIEEE(), 4<<10, 0)
+}
+
+func BenchmarkIEEECrc32KB(b *testing.B) {
+ benchmark(b, NewIEEE(), 32<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc15B(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 15, 0)
+}
+
+func BenchmarkCastagnoliCrc15BMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 15, 1)
+}
+
+func BenchmarkCastagnoliCrc40B(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 40, 0)
+}
+
+func BenchmarkCastagnoliCrc40BMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 40, 1)
+}
+
+func BenchmarkCastagnoliCrc512(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 512, 0)
+}
+
+func BenchmarkCastagnoliCrc512Misaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 512, 1)
}
func BenchmarkCastagnoliCrc1KB(b *testing.B) {
- b.SetBytes(1024)
- data := make([]byte, 1024)
+ benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc1KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 1<<10, 1)
+}
+
+func BenchmarkCastagnoliCrc4KB(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc4KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 4<<10, 1)
+}
+
+func BenchmarkCastagnoliCrc32KB(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc32KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 1)
+}
+
+func benchmark(b *testing.B, h hash.Hash32, n, alignment int64) {
+ b.SetBytes(n)
+ data := make([]byte, n+alignment)
+ data = data[alignment:]
for i := range data {
data[i] = byte(i)
}
- h := New(MakeTable(Castagnoli))
in := make([]byte, 0, h.Size())
+ // Warm up
+ h.Reset()
+ h.Write(data)
+ h.Sum(in)
+
b.ResetTimer()
for i := 0; i < b.N; i++ {
h.Reset()