consensus/ethash: reduce keccak hash allocations (#16857)

Use Read instead of Sum to avoid internal allocations and
copying the state.

name                      old time/op  new time/op  delta
CacheGeneration-8          764ms ± 1%   579ms ± 1%  -24.22%  (p=0.000 n=20+17)
SmallDatasetGeneration-8  75.2ms ±12%  60.6ms ±10%  -19.37%  (p=0.000 n=20+20)
HashimotoLight-8          1.58ms ±11%  1.55ms ± 8%     ~     (p=0.322 n=20+19)
HashimotoFullSmall-8      4.90µs ± 1%  4.88µs ± 1%   -0.31%  (p=0.013 n=19+18)
pull/16880/head
Felix Lange 7 years ago committed by Péter Szilágyi
parent c8dcb9584e
commit 3f33a7c8ce
  1. 23
      consensus/ethash/algorithm.go

@ -94,14 +94,25 @@ func calcDatasetSize(epoch int) uint64 {
// reused between hash runs instead of requiring new ones to be created. // reused between hash runs instead of requiring new ones to be created.
type hasher func(dest []byte, data []byte) type hasher func(dest []byte, data []byte)
// makeHasher creates a repetitive hasher, allowing the same hash data structures // makeHasher creates a repetitive hasher, allowing the same hash data structures to
// to be reused between hash runs instead of requiring new ones to be created. // be reused between hash runs instead of requiring new ones to be created. The returned
// The returned function is not thread safe! // function is not thread safe!
func makeHasher(h hash.Hash) hasher { func makeHasher(h hash.Hash) hasher {
// sha3.state supports Read to get the sum, use it to avoid the overhead of Sum.
// Read alters the state but we reset the hash before every operation.
type readerHash interface {
hash.Hash
Read([]byte) (int, error)
}
rh, ok := h.(readerHash)
if !ok {
panic("can't find Read method on hash")
}
outputLen := rh.Size()
return func(dest []byte, data []byte) { return func(dest []byte, data []byte) {
h.Write(data) rh.Reset()
h.Sum(dest[:0]) rh.Write(data)
h.Reset() rh.Read(dest[:outputLen])
} }
} }

Loading…
Cancel
Save