aboutsummaryrefslogtreecommitdiff
path: root/internal/cryptocore/randprefetch.go
blob: 8825a053d563383541388609e65a696019553a89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package cryptocore

import (
	"bytes"
	"log"
	"sync"
)

/*
Number of bytes to prefetch.

512 looks like a good compromise between throughput and latency:
Benchmark16-2      	 3000000	       567 ns/op	  28.18 MB/s
Benchmark64-2      	 5000000	       293 ns/op	  54.51 MB/s
Benchmark128-2     	10000000	       220 ns/op	  72.48 MB/s
Benchmark256-2     	10000000	       210 ns/op	  76.17 MB/s
Benchmark512-2     	10000000	       191 ns/op	  83.75 MB/s
Benchmark1024-2    	10000000	       171 ns/op	  93.48 MB/s
Benchmark2048-2    	10000000	       165 ns/op	  96.45 MB/s
Benchmark4096-2    	10000000	       165 ns/op	  96.58 MB/s
Benchmark40960-2   	10000000	       147 ns/op	 108.82 MB/s
*/
const prefetchN = 512

type randPrefetcherT struct {
	sync.Mutex
	buf bytes.Buffer
}

func (r *randPrefetcherT) read(want int) (out []byte) {
	out = make([]byte, want)
	r.Lock()
	// Note: don't use defer, it slows us down!
	have, err := r.buf.Read(out)
	if have == want && err == nil {
		r.Unlock()
		return out
	}
	// Buffer was empty -> re-fill
	r.buf.Reset()
	r.buf.Write(RandBytes(prefetchN))
	have, err = r.buf.Read(out)
	if have != want || err != nil {
		log.Panicf("randPrefetcher could not satisfy read: have=%d want=%d err=%v", have, want, err)
	}
	r.Unlock()
	return out
}

var randPrefetcher randPrefetcherT