| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 | 
							- // Copyright (C) 2016 The Syncthing Authors.
 
- //
 
- // This Source Code Form is subject to the terms of the Mozilla Public
 
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 
- // You can obtain one at https://mozilla.org/MPL/2.0/.
 
- package sha256
 
- import (
 
- 	"crypto/rand"
 
- 	cryptoSha256 "crypto/sha256"
 
- 	"encoding/hex"
 
- 	"fmt"
 
- 	"hash"
 
- 	"os"
 
- 	"time"
 
- 	minioSha256 "github.com/minio/sha256-simd"
 
- 	"github.com/syncthing/syncthing/lib/logger"
 
- )
 
- var l = logger.DefaultLogger.NewFacility("sha256", "SHA256 hashing package")
 
- const (
 
- 	benchmarkingIterations = 3
 
- 	benchmarkingDuration   = 150 * time.Millisecond
 
- 	defaultImpl            = "crypto/sha256"
 
- 	minioImpl              = "minio/sha256-simd"
 
- )
 
- const (
 
- 	BlockSize = cryptoSha256.BlockSize
 
- 	Size      = cryptoSha256.Size
 
- )
 
- // May be switched out for another implementation
 
- var (
 
- 	New    = cryptoSha256.New
 
- 	Sum256 = cryptoSha256.Sum256
 
- )
 
- var (
 
- 	selectedImpl = defaultImpl
 
- 	cryptoPerf   float64
 
- 	minioPerf    float64
 
- )
 
- func SelectAlgo() {
 
- 	switch os.Getenv("STHASHING") {
 
- 	case "":
 
- 		// When unset, probe for the fastest implementation.
 
- 		benchmark()
 
- 		if minioPerf > cryptoPerf {
 
- 			selectMinio()
 
- 		}
 
- 	case "minio":
 
- 		// When set to "minio", use that.
 
- 		selectMinio()
 
- 	default:
 
- 		// When set to anything else, such as "standard", use the default Go
 
- 		// implementation. Make sure not to touch the minio
 
- 		// implementation as it may be disabled for incompatibility reasons.
 
- 	}
 
- 	verifyCorrectness()
 
- }
 
- // Report prints a line with the measured hash performance rates for the
 
- // selected and alternate implementation.
 
- func Report() {
 
- 	var otherImpl string
 
- 	var selectedRate, otherRate float64
 
- 	switch selectedImpl {
 
- 	case defaultImpl:
 
- 		selectedRate = cryptoPerf
 
- 		otherRate = minioPerf
 
- 		otherImpl = minioImpl
 
- 	case minioImpl:
 
- 		selectedRate = minioPerf
 
- 		otherRate = cryptoPerf
 
- 		otherImpl = defaultImpl
 
- 	}
 
- 	if selectedRate == 0 {
 
- 		return
 
- 	}
 
- 	l.Infof("Single thread SHA256 performance is %s using %s (%s using %s).", formatRate(selectedRate), selectedImpl, formatRate(otherRate), otherImpl)
 
- }
 
- func selectMinio() {
 
- 	New = minioSha256.New
 
- 	Sum256 = minioSha256.Sum256
 
- 	selectedImpl = minioImpl
 
- }
 
- func benchmark() {
 
- 	// Interleave the tests to achieve some sort of fairness if the CPU is
 
- 	// just in the process of spinning up to full speed.
 
- 	for i := 0; i < benchmarkingIterations; i++ {
 
- 		if perf := cpuBenchOnce(benchmarkingDuration, cryptoSha256.New); perf > cryptoPerf {
 
- 			cryptoPerf = perf
 
- 		}
 
- 		if perf := cpuBenchOnce(benchmarkingDuration, minioSha256.New); perf > minioPerf {
 
- 			minioPerf = perf
 
- 		}
 
- 	}
 
- }
 
- func cpuBenchOnce(duration time.Duration, newFn func() hash.Hash) float64 {
 
- 	chunkSize := 100 * 1 << 10
 
- 	h := newFn()
 
- 	bs := make([]byte, chunkSize)
 
- 	rand.Reader.Read(bs)
 
- 	t0 := time.Now()
 
- 	b := 0
 
- 	for time.Since(t0) < duration {
 
- 		h.Write(bs)
 
- 		b += chunkSize
 
- 	}
 
- 	h.Sum(nil)
 
- 	d := time.Since(t0)
 
- 	return float64(int(float64(b)/d.Seconds()/(1<<20)*100)) / 100
 
- }
 
- func formatRate(rate float64) string {
 
- 	decimals := 0
 
- 	if rate < 1 {
 
- 		decimals = 2
 
- 	} else if rate < 10 {
 
- 		decimals = 1
 
- 	}
 
- 	return fmt.Sprintf("%.*f MB/s", decimals, rate)
 
- }
 
- func verifyCorrectness() {
 
- 	// The currently selected algo should in fact perform a SHA256 calculation.
 
- 	// $ echo "Syncthing Magic Testing Value" | openssl dgst -sha256 -hex
 
- 	correct := "87f6cfd24131724c6ec43495594c5c22abc7d2b86bcc134bc6f10b7ec3dda4ee"
 
- 	input := "Syncthing Magic Testing Value\n"
 
- 	h := New()
 
- 	h.Write([]byte(input))
 
- 	sum := hex.EncodeToString(h.Sum(nil))
 
- 	if sum != correct {
 
- 		panic("sha256 is broken")
 
- 	}
 
- 	arr := Sum256([]byte(input))
 
- 	sum = hex.EncodeToString(arr[:])
 
- 	if sum != correct {
 
- 		panic("sha256 is broken")
 
- 	}
 
- }
 
 
  |