From d9c3aea9e949e2e18774d28e4cf8242007cfe30c Mon Sep 17 00:00:00 2001 From: Peter Rabbitson Date: Mon, 30 Jan 2023 11:52:56 +0100 Subject: [PATCH] Basic chore cleanups of tests and benchmarks (#66) * Upgrade cpuid, regen buildtags * Move all uses of cpuid to one place, adjust benchmarks * Rename SIMD functions to match instruction set * One more rename, align arch-specific files --- cpuid_other.go | 6 ++- go.mod | 2 +- go.sum | 6 ++- sha256.go | 51 ++++++++----------- sha256_test.go | 38 ++++++++------ sha256blockAvx512_amd64.go | 3 +- sha256blockAvx512_amd64_test.go | 19 +++---- sha256blockSha_amd64.go | 6 --- sha256block_amd64.go | 14 +++-- sha256blockSha_amd64.s => sha256block_amd64.s | 2 +- ...amd64_test.go => sha256block_amd64_test.go | 11 ++-- sha256block_arm64.go | 13 ++--- sha256block_arm64.s | 2 +- sha256block_other.go | 11 ++-- 14 files changed, 94 insertions(+), 90 deletions(-) delete mode 100644 sha256blockSha_amd64.go rename sha256blockSha_amd64.s => sha256block_amd64.s (99%) rename sha256blockSha_amd64_test.go => sha256block_amd64_test.go (88%) diff --git a/cpuid_other.go b/cpuid_other.go index cd9fbf2..97af6a1 100644 --- a/cpuid_other.go +++ b/cpuid_other.go @@ -23,6 +23,11 @@ import ( "github.com/klauspost/cpuid/v2" ) +var ( + hasIntelSha = runtime.GOARCH == "amd64" && cpuid.CPU.Supports(cpuid.SHA, cpuid.SSSE3, cpuid.SSE4) + hasAvx512 = cpuid.CPU.Supports(cpuid.AVX512F, cpuid.AVX512DQ, cpuid.AVX512BW, cpuid.AVX512VL) +) + func hasArmSha2() bool { if cpuid.CPU.Has(cpuid.SHA2) { return true @@ -42,5 +47,4 @@ func hasArmSha2() bool { return false } return bytes.Contains(cpuInfo, []byte(sha256Feature)) - } diff --git a/go.mod b/go.mod index b254fa3..cb03f65 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/minio/sha256-simd go 1.13 -require github.com/klauspost/cpuid/v2 v2.0.6 +require github.com/klauspost/cpuid/v2 v2.2.3 diff --git a/go.sum b/go.sum index 5b8b0f4..6e09442 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ -github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI= -github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e h1:CsOuNlbOuf0mzxJIefr6Q4uAUetRUwZE4qt7VfzP+xo= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/sha256.go b/sha256.go index b137ead..00dd797 100644 --- a/sha256.go +++ b/sha256.go @@ -20,9 +20,6 @@ import ( "crypto/sha256" "encoding/binary" "hash" - "runtime" - - "github.com/klauspost/cpuid/v2" ) // Size - The size of a SHA256 checksum in bytes. @@ -68,42 +65,34 @@ func (d *digest) Reset() { type blockfuncType int const ( - blockfuncGeneric blockfuncType = iota - blockfuncSha blockfuncType = iota - blockfuncArm blockfuncType = iota + blockfuncStdlib blockfuncType = iota + blockfuncIntelSha + blockfuncArmSha2 + blockfuncForceGeneric = -1 ) var blockfunc blockfuncType func init() { - blockfunc = blockfuncGeneric switch { - case hasSHAExtensions(): - blockfunc = blockfuncSha + case hasIntelSha: + blockfunc = blockfuncIntelSha case hasArmSha2(): - blockfunc = blockfuncArm - default: - blockfunc = blockfuncGeneric + blockfunc = blockfuncArmSha2 } } -var avx512 = cpuid.CPU.Supports(cpuid.AVX512F, cpuid.AVX512DQ, cpuid.AVX512BW, cpuid.AVX512VL) - -// hasSHAExtensions return whether the cpu supports SHA extensions. -func hasSHAExtensions() bool { - return cpuid.CPU.Supports(cpuid.SHA, cpuid.SSSE3, cpuid.SSE4) && runtime.GOARCH == "amd64" -} - // New returns a new hash.Hash computing the SHA256 checksum. func New() hash.Hash { - if blockfunc != blockfuncGeneric { - d := new(digest) - d.Reset() - return d + if blockfunc == blockfuncStdlib { + // Fallback to the standard golang implementation + // if no features were found. + return sha256.New() } - // Fallback to the standard golang implementation - // if no features were found. - return sha256.New() + + d := new(digest) + d.Reset() + return d } // Sum256 - single caller sha256 helper @@ -272,11 +261,11 @@ func (d *digest) checkSum() (digest [Size]byte) { } func block(dig *digest, p []byte) { - if blockfunc == blockfuncSha { - blockShaGo(dig, p) - } else if blockfunc == blockfuncArm { - blockArmGo(dig, p) - } else if blockfunc == blockfuncGeneric { + if blockfunc == blockfuncIntelSha { + blockIntelShaGo(dig, p) + } else if blockfunc == blockfuncArmSha2 { + blockArmSha2Go(dig, p) + } else { blockGeneric(dig, p) } } diff --git a/sha256_test.go b/sha256_test.go index 602a298..1a2fef8 100644 --- a/sha256_test.go +++ b/sha256_test.go @@ -54,8 +54,6 @@ import ( "fmt" "strings" "testing" - - "github.com/klauspost/cpuid/v2" ) type sha256Test struct { @@ -2217,7 +2215,7 @@ func TestGolden(t *testing.T) { }() if true { - blockfunc = blockfuncGeneric + blockfunc = blockfuncForceGeneric for _, g := range golden { s := fmt.Sprintf("%x", Sum256([]byte(g.in))) if Sum256([]byte(g.in)) != g.out { @@ -2226,8 +2224,8 @@ func TestGolden(t *testing.T) { } } - if cpuid.CPU.Supports(cpuid.SHA, cpuid.SSSE3, cpuid.SSE4) { - blockfunc = blockfuncSha + if hasIntelSha { + blockfunc = blockfuncIntelSha for _, g := range golden { s := fmt.Sprintf("%x", Sum256([]byte(g.in))) if Sum256([]byte(g.in)) != g.out { @@ -2237,7 +2235,7 @@ func TestGolden(t *testing.T) { } if hasArmSha2() { - blockfunc = blockfuncArm + blockfunc = blockfuncArmSha2 for _, g := range golden { s := fmt.Sprintf("%x", Sum256([]byte(g.in))) if Sum256([]byte(g.in)) != g.out { @@ -2269,20 +2267,26 @@ func benchmarkSize(b *testing.B, size int) { b.ResetTimer() for i := 0; i < b.N; i++ { bench.Reset() - bench.Write(buf[:size]) + bench.Write(buf) bench.Sum(sum[:0]) } } func BenchmarkHash(b *testing.B) { - algos := []struct { + type alg struct { n string t blockfuncType - f bool - }{ - {"SHA_", blockfuncSha, hasSHAExtensions()}, - {"GEN_", blockfuncGeneric, true}, } + algos := make([]alg, 0, 2) + + algos = append(algos, alg{"Generic", blockfuncForceGeneric}) + if hasIntelSha { + algos = append(algos, alg{"IntelSHA", blockfuncIntelSha}) + } + if hasArmSha2() { + algos = append(algos, alg{"ArmSha2", blockfuncArmSha2}) + } + algos = append(algos, alg{"GoStdlib", blockfuncStdlib}) sizes := []struct { n string @@ -2290,6 +2294,7 @@ func BenchmarkHash(b *testing.B) { s int }{ {"8Bytes", benchmarkSize, 1 << 3}, + {"64Bytes", benchmarkSize, 1 << 6}, {"1K", benchmarkSize, 1 << 10}, {"8K", benchmarkSize, 1 << 13}, {"1M", benchmarkSize, 1 << 20}, @@ -2298,14 +2303,15 @@ func BenchmarkHash(b *testing.B) { } for _, a := range algos { - if a.f { - blockfuncSaved := blockfunc + func() { + orig := blockfunc + defer func() { blockfunc = orig }() + blockfunc = a.t for _, y := range sizes { s := a.n + "/" + y.n b.Run(s, func(b *testing.B) { y.f(b, y.s) }) } - blockfunc = blockfuncSaved - } + }() } } diff --git a/sha256blockAvx512_amd64.go b/sha256blockAvx512_amd64.go index b7d7c16..4b9473a 100644 --- a/sha256blockAvx512_amd64.go +++ b/sha256blockAvx512_amd64.go @@ -1,4 +1,5 @@ -//+build !noasm,!appengine,gc +//go:build !noasm && !appengine && gc +// +build !noasm,!appengine,gc /* * Minio Cloud Storage, (C) 2017 Minio, Inc. diff --git a/sha256blockAvx512_amd64_test.go b/sha256blockAvx512_amd64_test.go index f4eab62..a8e6536 100644 --- a/sha256blockAvx512_amd64_test.go +++ b/sha256blockAvx512_amd64_test.go @@ -1,4 +1,5 @@ -//+build !noasm,!appengine,gc +//go:build !noasm && !appengine && gc +// +build !noasm,!appengine,gc /* * Minio Cloud Storage, (C) 2017 Minio, Inc. @@ -31,7 +32,7 @@ import ( func TestGoldenAVX512(t *testing.T) { - if !avx512 { + if !hasAvx512 { t.SkipNow() return } @@ -75,7 +76,7 @@ func initDigests() *[512]byte { func testSha256Avx512(t *testing.T, offset, padding int) [16][]byte { - if !avx512 { + if !hasAvx512 { t.SkipNow() return [16][]byte{} } @@ -118,7 +119,7 @@ func TestAvx512_3Blocks(t *testing.T) { testSha256Avx512(t, 47, 55) } func TestAvx512_MixedBlocks(t *testing.T) { - if !avx512 { + if !hasAvx512 { t.SkipNow() return } @@ -153,7 +154,7 @@ func TestAvx512_MixedBlocks(t *testing.T) { func TestAvx512_MixedWithNilBlocks(t *testing.T) { - if !avx512 { + if !hasAvx512 { t.SkipNow() return } @@ -200,7 +201,7 @@ func TestAvx512_MixedWithNilBlocks(t *testing.T) { func TestAvx512Server(t *testing.T) { - if !avx512 { + if !hasAvx512 { t.SkipNow() return } @@ -251,7 +252,7 @@ func TestAvx512Server(t *testing.T) { func TestAvx512Digest(t *testing.T) { - if !avx512 { + if !hasAvx512 { t.SkipNow() return } @@ -295,7 +296,7 @@ func benchmarkAvx512SingleCore(h512 []hash.Hash, body []byte) { func benchmarkAvx512(b *testing.B, size int) { - if !avx512 { + if !hasAvx512 { b.SkipNow() return } @@ -325,7 +326,7 @@ func BenchmarkAvx512_10M(b *testing.B) { benchmarkAvx512(b, 10*1024*1024) } func benchmarkAvx512MultiCore(b *testing.B, size, cores int) { - if !avx512 { + if !hasAvx512 { b.SkipNow() return } diff --git a/sha256blockSha_amd64.go b/sha256blockSha_amd64.go deleted file mode 100644 index bef9494..0000000 --- a/sha256blockSha_amd64.go +++ /dev/null @@ -1,6 +0,0 @@ -//+build !noasm,!appengine,gc - -package sha256 - -//go:noescape -func blockSha(h *[8]uint32, message []uint8) diff --git a/sha256block_amd64.go b/sha256block_amd64.go index 0c48d45..e536f54 100644 --- a/sha256block_amd64.go +++ b/sha256block_amd64.go @@ -1,4 +1,5 @@ -//+build !noasm,!appengine,gc +//go:build !noasm && !appengine && gc +// +build !noasm,!appengine,gc /* * Minio Cloud Storage, (C) 2016 Minio, Inc. @@ -18,10 +19,13 @@ package sha256 -func blockArmGo(dig *digest, p []byte) { - panic("blockArmGo called unexpectedly") +func blockArmSha2Go(dig *digest, p []byte) { + panic("blockArmSha2Go called unexpectedly") } -func blockShaGo(dig *digest, p []byte) { - blockSha(&dig.h, p) +//go:noescape +func blockIntelSha(h *[8]uint32, message []uint8) + +func blockIntelShaGo(dig *digest, p []byte) { + blockIntelSha(&dig.h, p) } diff --git a/sha256blockSha_amd64.s b/sha256block_amd64.s similarity index 99% rename from sha256blockSha_amd64.s rename to sha256block_amd64.s index 14cf2c6..c98a1d8 100644 --- a/sha256blockSha_amd64.s +++ b/sha256block_amd64.s @@ -106,7 +106,7 @@ GLOBL SHUF_MASK<>(SB), RODATA|NOPTR, $16 // X13 saved hash state // CDGH // X15 data shuffle mask (constant) -TEXT ·blockSha(SB), NOSPLIT, $0-32 +TEXT ·blockIntelSha(SB), NOSPLIT, $0-32 MOVQ h+0(FP), DX MOVQ message_base+8(FP), SI MOVQ message_len+16(FP), DI diff --git a/sha256blockSha_amd64_test.go b/sha256block_amd64_test.go similarity index 88% rename from sha256blockSha_amd64_test.go rename to sha256block_amd64_test.go index 1ca144f..da3d60c 100644 --- a/sha256blockSha_amd64_test.go +++ b/sha256block_amd64_test.go @@ -1,4 +1,5 @@ -//+build !noasm,!appengine,gc +//go:build !noasm && !appengine && gc +// +build !noasm,!appengine,gc package sha256 @@ -20,7 +21,7 @@ func sha256hash(m []byte) (r [32]byte) { h[6] = 0x1f83d9ab h[7] = 0x5be0cd19 - blockSha(&h, m) + blockIntelSha(&h, m) l0 := len(m) l := l0 & (BlockSize - 1) m = m[l0-l:] @@ -31,7 +32,7 @@ func sha256hash(m []byte) (r [32]byte) { k[l] = 0x80 if l >= 56 { - blockSha(&h, k[:]) + blockIntelSha(&h, k[:]) binary.LittleEndian.PutUint64(k[0:8], 0) binary.LittleEndian.PutUint64(k[8:16], 0) binary.LittleEndian.PutUint64(k[16:24], 0) @@ -41,7 +42,7 @@ func sha256hash(m []byte) (r [32]byte) { binary.LittleEndian.PutUint64(k[48:56], 0) } binary.BigEndian.PutUint64(k[56:64], uint64(l0)<<3) - blockSha(&h, k[:]) + blockIntelSha(&h, k[:]) binary.BigEndian.PutUint32(r[0:4], h[0]) binary.BigEndian.PutUint32(r[4:8], h[1]) @@ -71,7 +72,7 @@ func TestSha0(t *testing.T) { } func TestSha1(t *testing.T) { - if hasSHAExtensions() && !runTestSha(sha256hash) { + if hasIntelSha && !runTestSha(sha256hash) { t.Errorf("FAILED") } } diff --git a/sha256block_arm64.go b/sha256block_arm64.go index 58ccf6e..d4369e2 100644 --- a/sha256block_arm64.go +++ b/sha256block_arm64.go @@ -1,4 +1,5 @@ -//+build !noasm,!appengine,gc +//go:build !noasm && !appengine && gc +// +build !noasm,!appengine,gc /* * Minio Cloud Storage, (C) 2016 Minio, Inc. @@ -18,18 +19,18 @@ package sha256 -func blockShaGo(dig *digest, p []byte) { - panic("blockShaGoc called unexpectedly") +func blockIntelShaGo(dig *digest, p []byte) { + panic("blockIntelShaGo called unexpectedly") } //go:noescape -func blockArm(h []uint32, message []uint8) +func blockArmSha2(h []uint32, message []uint8) -func blockArmGo(dig *digest, p []byte) { +func blockArmSha2Go(dig *digest, p []byte) { h := []uint32{dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]} - blockArm(h[:], p[:]) + blockArmSha2(h[:], p[:]) dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7] diff --git a/sha256block_arm64.s b/sha256block_arm64.s index d85170d..7ab88b1 100644 --- a/sha256block_arm64.s +++ b/sha256block_arm64.s @@ -25,7 +25,7 @@ // their Plan9 equivalents // -TEXT ·blockArm(SB), 7, $0 +TEXT ·blockArmSha2(SB), 7, $0 MOVD h+0(FP), R0 MOVD message+24(FP), R1 MOVD message_len+32(FP), R2 // length of message diff --git a/sha256block_other.go b/sha256block_other.go index ec586c0..94d7eb0 100644 --- a/sha256block_other.go +++ b/sha256block_other.go @@ -1,4 +1,5 @@ -//+build appengine noasm !amd64,!arm64 !gc +//go:build appengine || noasm || (!amd64 && !arm64) || !gc +// +build appengine noasm !amd64,!arm64 !gc /* * Minio Cloud Storage, (C) 2019 Minio, Inc. @@ -18,11 +19,11 @@ package sha256 -func blockShaGo(dig *digest, p []byte) { - panic("blockShaGo called unexpectedly") +func blockIntelShaGo(dig *digest, p []byte) { + panic("blockIntelShaGo called unexpectedly") } -func blockArmGo(dig *digest, p []byte) { - panic("blockArmGo called unexpectedly") +func blockArmSha2Go(dig *digest, p []byte) { + panic("blockArmSha2Go called unexpectedly") }