-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbench_test.go
More file actions
122 lines (111 loc) · 3.34 KB
/
Copy pathbench_test.go
File metadata and controls
122 lines (111 loc) · 3.34 KB
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package consistenthash
import (
"strconv"
"strings"
"testing"
)
// BenchmarkNew measures constructing a Map and seeding it with nodes via
// WithNodes (the common entry point). Covers id-capture + slice growth.
func BenchmarkNew(b *testing.B) {
b.Run("10nodes", func(b *testing.B) {
nodes := makeNodes(10)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = New[string](strID, WithNodes(nodes...))
}
})
b.Run("100nodes", func(b *testing.B) {
nodes := makeNodes(100)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = New[string](strID, WithNodes(nodes...))
}
})
}
// BenchmarkAdd measures incremental membership growth. Each iteration adds one
// node to a live map, exercising the duplicate check (O(N) scan) + append.
func BenchmarkAdd(b *testing.B) {
m := New[string](strID, WithNodes(makeNodes(100)...))
add := "added-node"
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Add(add + strconv.Itoa(i)) // unique id each time to force the scan
}
}
// BenchmarkGet is the hot path: a single rendezvous lookup. Parameterized by
// node count since Get is O(N). 10/50/100 nodes cover the documented shard
// routing range; 500 shows the linear cost. The scratch buffer is pool-recycled,
// so steady-state allocs/op should be 0 regardless of node count.
func BenchmarkGet(b *testing.B) {
for _, n := range []int{10, 50, 100, 500} {
b.Run(strconv.Itoa(n)+"nodes", func(b *testing.B) {
m := New[string](strID, WithNodes(makeNodes(n)...))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = m.Get("auction-42")
}
})
}
}
// BenchmarkGetLongIDs exercises the oversized-input path: node IDs and key well
// beyond the initial scratch capacity force the buffer to grow once, then it is
// reused. Confirms the recycled scratch still yields 0 steady-state allocs even
// for large hash inputs.
func BenchmarkGetLongIDs(b *testing.B) {
const nNodes = 100
nodes := make([]string, nNodes)
pad := strings.Repeat("x", 256) // force scratch growth past initial cap
for i := range nNodes {
nodes[i] = "node-" + strconv.Itoa(i) + "-" + pad
}
longKey := "auction-" + strings.Repeat("k", 256)
m := New[string](strID, WithNodes(nodes...))
b.ReportAllocs()
for b.Loop() {
_, _ = m.Get(longKey)
}
}
// BenchmarkGetN measures replication-site selection (top-n by HRW score).
// GetN scores every node then partial-sorts, so it's heavier than Get.
func BenchmarkGetN(b *testing.B) {
for _, n := range []int{10, 100, 500} {
b.Run(strconv.Itoa(n)+"nodes", func(b *testing.B) {
m := New[string](strID, WithNodes(makeNodes(n)...))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = m.GetN("auction-42", 3)
}
})
}
}
// BenchmarkRemove measures node removal (O(N) id scan + in-place compaction).
func BenchmarkRemove(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
b.StopTimer()
m := New[string](strID, WithNodes(makeNodes(100)...))
b.StartTimer()
m.Remove("node-0050")
}
}
// BenchmarkDefaultHash isolates the FNV-1a 64 cost per Get iteration, since the
// hash dominates Get at large N.
func BenchmarkDefaultHash(b *testing.B) {
data := []byte("node-0042auction-42")
b.ReportAllocs()
for b.Loop() {
_ = DefaultHash(data)
}
}
func makeNodes(n int) []string {
out := make([]string, n)
for i := range n {
out[i] = "node-" + strconv.Itoa(i)
}
return out
}