Switch to sync.Pool.
sync.Pool is after all faster than the home-made free list. Especially under contention. To prove that, this commit also adds a benchmark for concurrent fingerprint calculation. Benchmark results: (Run with -cpu=1,2,4. x-y -> x goroutines with GOMAXPROCS=y.) benchmark old ns/op new ns/op delta BenchmarkMetricToFingerprintTripleConc4-4 320 138 -56.88% BenchmarkMetricToFingerprintTripleConc8-4 314 141 -55.10% BenchmarkMetricToFingerprintTripleConc4-2 344 264 -23.26% BenchmarkMetricToFingerprintTripleConc2-4 331 256 -22.66% BenchmarkMetricToFingerprintTripleConc8-2 338 263 -22.19% BenchmarkMetricToFingerprintTripleConc1-4 599 505 -15.69% BenchmarkMetricToFingerprintTripleConc4 553 493 -10.85% BenchmarkMetricToFingerprintTripleConc2-2 327 292 -10.70% BenchmarkMetricToFingerprintTripleConc8 554 496 -10.47% BenchmarkMetricToFingerprintTripleConc2 555 501 -9.73% BenchmarkMetricToFingerprintTripleConc1 554 509 -8.12% BenchmarkMetricToFingerprintTripleConc1-2 551 513 -6.90%
This commit is contained in:
parent
1002745d7b
commit
cbe221c969
|
@ -17,6 +17,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"hash"
|
"hash"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
|
// SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
|
||||||
|
@ -28,7 +29,7 @@ var (
|
||||||
// cache the signature of an empty label set.
|
// cache the signature of an empty label set.
|
||||||
emptyLabelSignature = fnv.New64a().Sum64()
|
emptyLabelSignature = fnv.New64a().Sum64()
|
||||||
|
|
||||||
hashAndBufPool = make(chan *hashAndBuf, 1024)
|
hashAndBufPool sync.Pool
|
||||||
)
|
)
|
||||||
|
|
||||||
type hashAndBuf struct {
|
type hashAndBuf struct {
|
||||||
|
@ -37,19 +38,15 @@ type hashAndBuf struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHashAndBuf() *hashAndBuf {
|
func getHashAndBuf() *hashAndBuf {
|
||||||
select {
|
hb := hashAndBufPool.Get()
|
||||||
case hb := <-hashAndBufPool:
|
if hb == nil {
|
||||||
return hb
|
|
||||||
default:
|
|
||||||
return &hashAndBuf{h: fnv.New64a()}
|
return &hashAndBuf{h: fnv.New64a()}
|
||||||
}
|
}
|
||||||
|
return hb.(*hashAndBuf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func putHashAndBuf(hb *hashAndBuf) {
|
func putHashAndBuf(hb *hashAndBuf) {
|
||||||
select {
|
hashAndBufPool.Put(hb)
|
||||||
case hashAndBufPool <- hb:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LabelsToSignature returns a unique signature (i.e., fingerprint) for a given
|
// LabelsToSignature returns a unique signature (i.e., fingerprint) for a given
|
||||||
|
|
|
@ -15,6 +15,7 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -216,3 +217,40 @@ func TestEmptyLabelSignature(t *testing.T) {
|
||||||
t.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
|
t.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func benchmarkMetricToFingerprintConc(b *testing.B, m Metric, e Fingerprint, concLevel int) {
|
||||||
|
var start, end sync.WaitGroup
|
||||||
|
start.Add(1)
|
||||||
|
end.Add(concLevel)
|
||||||
|
|
||||||
|
for i := 0; i < concLevel; i++ {
|
||||||
|
go func() {
|
||||||
|
start.Wait()
|
||||||
|
for j := b.N / concLevel; j >= 0; j-- {
|
||||||
|
if a := metricToFingerprint(m); a != e {
|
||||||
|
b.Fatalf("expected signature of %d for %s, got %d", e, m, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
b.ResetTimer()
|
||||||
|
start.Done()
|
||||||
|
end.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintTripleConc1(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintTripleConc2(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintTripleConc4(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkMetricToFingerprintTripleConc8(b *testing.B) {
|
||||||
|
benchmarkMetricToFingerprintConc(b, Metric{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue