@@ -15,14 +15,14 @@ type rander struct {
15
15
r * rand.Rand
16
16
}
17
17
18
- func (r * rander ) randString () string {
19
- buf := make ([]byte , 18 )
18
+ func (r * rander ) randString (stringSize int ) string {
19
+ buf := make ([]byte , stringSize )
20
20
rand .Read (buf )
21
21
return hex .EncodeToString (buf )
22
22
}
23
23
24
- func (r * rander ) randValue () []byte {
25
- buf := make ([]byte , 30 )
24
+ func (r * rander ) randValue (datasize int ) []byte {
25
+ buf := make ([]byte , datasize )
26
26
rand .Read (buf )
27
27
return buf
28
28
}
@@ -34,7 +34,7 @@ func BenchmarkSerializeNode(b *testing.B) {
34
34
n := NewNode (cs )
35
35
36
36
for i := 0 ; i < 50 ; i ++ {
37
- if err := n .Set (context .TODO (), r .randString (), r .randValue ()); err != nil {
37
+ if err := n .Set (context .TODO (), r .randString (18 ), r .randValue (30 )); err != nil {
38
38
b .Fatal (err )
39
39
}
40
40
}
@@ -50,83 +50,92 @@ func BenchmarkSerializeNode(b *testing.B) {
50
50
}
51
51
}
52
52
53
- type benchSetCase struct {
54
- kcount int
55
- bitwidth int
56
- datasize int
57
- flushInterval int
58
- }
59
-
60
- type benchFillCase struct {
61
- kcount int
62
- bitwidth int
63
- datasize int
64
- flushInterval int
53
+ type hamtParams struct {
54
+ id string
55
+ count int
56
+ datasize int
57
+ keysize int
65
58
}
66
59
67
- type benchFindCase struct {
68
- kcount int
60
+ type benchCase struct {
61
+ id string
62
+ count int
69
63
bitwidth int
70
64
datasize int
65
+ keysize int
71
66
}
72
67
73
- var benchSetCaseTable []benchSetCase
74
- var benchFillCaseTable []benchFillCase
75
- var benchFindCaseTable []benchFindCase
68
+ var caseTable []benchCase
76
69
77
70
func init () {
78
- kCounts := []int {
79
- 1 ,
80
- 5 ,
81
- 10 ,
82
- 50 ,
83
- 100 ,
84
- 500 ,
85
- 1000 , // aka 1M
86
- //10000, // aka 10M -- you'll need a lot of RAM for this. Also, some patience.
87
- }
71
+
88
72
bitwidths := []int {
73
+ 1 ,
74
+ 2 ,
89
75
3 ,
90
76
4 ,
91
77
5 ,
92
78
6 ,
93
79
7 ,
94
80
8 ,
95
81
}
96
- flushIntervals := []int {
97
- 1 ,
98
- 1000 ,
99
- }
100
- dataSize := []int {
101
- 1 ,
82
+
83
+ hamts := []hamtParams {
84
+ hamtParams {
85
+ id : "init.AddressMap" ,
86
+ count : 55649 ,
87
+ datasize : 3 ,
88
+ keysize : 26 ,
89
+ },
90
+ hamtParams {
91
+ id : "market.PendingProposals" ,
92
+ count : 40713 ,
93
+ datasize : 151 ,
94
+ keysize : 38 ,
95
+ },
96
+ hamtParams {
97
+ id : "market.EscrowWTable" ,
98
+ count : 2113 ,
99
+ datasize : 7 ,
100
+ keysize : 4 ,
101
+ },
102
+ hamtParams {
103
+ id : "market.LockedTable" ,
104
+ count : 2098 ,
105
+ datasize : 4 ,
106
+ keysize : 4 ,
107
+ },
108
+ hamtParams {
109
+ id : "market.DealOpsByEpoch" ,
110
+ count : 16558 ,
111
+ datasize : 43 ,
112
+ keysize : 3 ,
113
+ },
114
+ hamtParams {
115
+ id : "power.CronEventQueue" ,
116
+ count : 60 ,
117
+ datasize : 43 ,
118
+ keysize : 3 ,
119
+ },
120
+ hamtParams {
121
+ id : "power.CLaims" ,
122
+ count : 15610 ,
123
+ datasize : 5 ,
124
+ keysize : 3 ,
125
+ },
102
126
}
127
+
103
128
// bucketsize-aka-arraywidth? maybe someday.
104
- for _ , c := range kCounts {
105
- for _ , d := range dataSize {
106
- for _ , bw := range bitwidths {
107
- benchFindCaseTable = append (benchFindCaseTable ,
108
- benchFindCase {
109
- kcount : c ,
110
- bitwidth : bw ,
111
- datasize : d ,
112
- })
113
- for _ , f := range flushIntervals {
114
- benchFillCaseTable = append (benchFillCaseTable ,
115
- benchFillCase {
116
- kcount : c ,
117
- bitwidth : bw ,
118
- datasize : d ,
119
- flushInterval : f ,
120
- })
121
- benchSetCaseTable = append (benchSetCaseTable ,
122
- benchSetCase {
123
- kcount : c ,
124
- bitwidth : bw ,
125
- datasize : d ,
126
- flushInterval : f ,
127
- })
128
- }
129
- }
129
+ for _ , h := range hamts {
130
+ for _ , bw := range bitwidths {
131
+ caseTable = append (caseTable ,
132
+ benchCase {
133
+ id : fmt .Sprintf ("%s -- bw=%d" , h .id , bw ),
134
+ count : h .count ,
135
+ bitwidth : bw ,
136
+ datasize : h .datasize ,
137
+ keysize : h .keysize ,
138
+ })
130
139
}
131
140
}
132
141
}
@@ -157,15 +166,15 @@ func init() {
157
166
// See "BenchmarkSet*" for a probe of how long it takes to set additional entries in an already-large hamt
158
167
// (this gives a more interesting and useful nanoseconds-per-op indicators).
159
168
func BenchmarkFill (b * testing.B ) {
160
- for _ , t := range benchFillCaseTable {
161
- b .Run (fmt .Sprintf ("n=%dk/bitwidth=%d " , t .kcount , t . bitwidth ), func (b * testing.B ) {
169
+ for _ , t := range caseTable {
170
+ b .Run (fmt .Sprintf ("%s " , t .id ), func (b * testing.B ) {
162
171
for i := 0 ; i < b .N ; i ++ {
163
172
r := rander {rand .New (rand .NewSource (int64 (i )))}
164
173
blockstore := newMockBlocks ()
165
174
n := NewNode (cbor .NewCborStore (blockstore ), UseTreeBitWidth (t .bitwidth ))
166
175
//b.ResetTimer()
167
- for j := 0 ; j < t .kcount * 1000 ; j ++ {
168
- if err := n .Set (context .Background (), r .randString (), r .randValue ()); err != nil {
176
+ for j := 0 ; j < t .count ; j ++ {
177
+ if err := n .Set (context .Background (), r .randString (t . keysize ), r .randValue (t . datasize )); err != nil {
169
178
b .Fatal (err )
170
179
}
171
180
}
@@ -179,56 +188,61 @@ func BenchmarkFill(b *testing.B) {
179
188
if blockstore .stats .evtcntPutDup > 0 {
180
189
b .Logf ("on round N=%d: blockstore stats: %#v\n " , b .N , blockstore .stats ) // note: must refer to this before doing `n.checkSize`; that function has many effects.
181
190
}
182
- b .ReportMetric (float64 (blockstore .stats .evtcntGet )/ float64 (t .kcount * 1000 ), "getEvts/entry" )
183
- b .ReportMetric (float64 (blockstore .stats .evtcntPut )/ float64 (t .kcount * 1000 ), "putEvts/entry" )
184
- b .ReportMetric (float64 (len (blockstore .data ))/ float64 (t .kcount * 1000 ), "blocks/entry" )
191
+ b .ReportMetric (float64 (blockstore .stats .evtcntGet )/ float64 (t .count ), "getEvts/entry" )
192
+ b .ReportMetric (float64 (blockstore .stats .evtcntPut )/ float64 (t .count ), "putEvts/entry" )
193
+ b .ReportMetric (float64 (len (blockstore .data ))/ float64 (t .count ), "blocks/entry" )
185
194
binarySize , _ := n .checkSize (context .Background ())
186
- b .ReportMetric (float64 (binarySize )/ float64 (t .kcount * 1000 ), "bytes(hamtAccnt)/entry" )
187
- b .ReportMetric (float64 (blockstore .totalBlockSizes ())/ float64 (t .kcount * 1000 ), "bytes(blockstoreAccnt)/entry" )
195
+ b .ReportMetric (float64 (binarySize )/ float64 (t .count ), "bytes(hamtAccnt)/entry" )
196
+ b .ReportMetric (float64 (blockstore .totalBlockSizes ())/ float64 (t .count ), "bytes(blockstoreAccnt)/entry" )
188
197
b .StartTimer ()
189
198
}
190
199
})
191
200
}
192
201
}
193
202
194
- // BenchmarkSet creates a large HAMT, then starts the timer, and does another 1000 inserts,
203
+ // BenchmarkSetBulk creates a large HAMT, then starts the timer, and does another 1000 inserts,
195
204
// measuring the time taken for this second batch of inserts.
196
- // Flushing rate is parameterized .
205
+ // Flushing happens once after all 1000 inserts .
197
206
//
198
207
// The number of *additional* blocks per entry is reported.
199
208
// This number is usually less than one with high flush interval means changes might be amortized.
200
- // For flush interval one this number should be at least 1 --
201
- // however, since we choose random keys, it can still turn out lower if keys happen to collide.
202
- // (The Set method does not make it possible to adjust our denominator to compensate for this: it does not yield previous values nor indicators of prior presense.)
203
- func BenchmarkSet (b * testing.B ) {
204
- doBenchmarkSetSuite (b )
209
+ func BenchmarkSetBulk (b * testing.B ) {
210
+ doBenchmarkSetSuite (b , false )
211
+ }
212
+
213
+ // BenchmarkSetIndividual is the same as BenchmarkSetBulk, but flushes more.
214
+ // Flush happens per insert.
215
+ //
216
+ // The number of *additional* blocks per entry is reported.
217
+ // Since we flush each insert individually, this number should be at least 1.
218
+ func BenchmarkSetIndividual (b * testing.B ) {
219
+ doBenchmarkSetSuite (b , true )
205
220
}
206
221
207
- func doBenchmarkSetSuite (b * testing.B ) {
208
- for j , t := range benchSetCaseTable {
209
- b .Run (fmt .Sprintf ("n=%dk/bitwidth=%d " , t .kcount , t . bitwidth ), func (b * testing.B ) {
222
+ func doBenchmarkSetSuite (b * testing.B , flushPer bool ) {
223
+ for _ , t := range caseTable {
224
+ b .Run (fmt .Sprintf ("%s " , t .id ), func (b * testing.B ) {
210
225
for i := 0 ; i < b .N ; i ++ {
211
226
b .StopTimer ()
212
227
r := rander {rand .New (rand .NewSource (int64 (i )))}
213
228
blockstore := newMockBlocks ()
214
229
n := NewNode (cbor .NewCborStore (blockstore ), UseTreeBitWidth (t .bitwidth ))
215
230
// Initial fill:
216
- for j := 0 ; j < t .kcount * 1000 ; j ++ {
217
- if err := n .Set (context .Background (), r .randString (), r .randValue ()); err != nil {
231
+ for j := 0 ; j < t .count ; j ++ {
232
+ if err := n .Set (context .Background (), r .randString (t . keysize ), r .randValue (t . datasize )); err != nil {
218
233
b .Fatal (err )
219
234
}
220
235
}
221
236
if err := n .Flush (context .Background ()); err != nil {
222
237
b .Fatal (err )
223
238
}
224
- initalBlockstoreSize := len (blockstore .data )
225
239
// b.ResetTimer()
226
240
blockstore .stats = blockstoreStats {}
227
241
// Additional inserts:
228
242
b .ReportAllocs ()
229
243
b .StartTimer ()
230
244
for j := 0 ; j < 1000 ; j ++ {
231
- if err := n .Set (context .Background (), r .randString (), r .randValue ()); err != nil {
245
+ if err := n .Set (context .Background (), r .randString (t . keysize ), r .randValue (t . datasize )); err != nil {
232
246
b .Fatal (err )
233
247
}
234
248
if flushPer {
@@ -249,23 +263,23 @@ func doBenchmarkSetSuite(b *testing.B) {
249
263
if blockstore .stats .evtcntPutDup > 0 {
250
264
b .Logf ("on round N=%d: blockstore stats: %#v\n " , b .N , blockstore .stats )
251
265
}
252
- b .ReportMetric (float64 (blockstore .stats .evtcntGet )/ float64 ( t . kcount * 1000 ) , "getEvts/entry " )
253
- b .ReportMetric (float64 (blockstore .stats .evtcntPut )/ float64 ( t . kcount * 1000 ) , "putEvts/entry " )
254
- b .ReportMetric (float64 (len ( blockstore .data ) - initalBlockstoreSize ) / float64 ( 1000 ) , "addntlBlocks/addntlEntry " )
266
+ b .ReportMetric (float64 (blockstore .stats .evtcntGet )/ 1000 , "getEvts/set " )
267
+ b .ReportMetric (float64 (blockstore .stats .evtcntPut )/ 1000 , "putEvts/set " )
268
+ b .ReportMetric (float64 (blockstore .stats . bytesPut ) / 1000 , "bytesPut/set " )
255
269
b .StartTimer ()
256
270
}
257
271
})
258
272
}
259
273
}
260
274
261
275
func BenchmarkFind (b * testing.B ) {
262
- for _ , t := range benchSetCaseTable {
263
- b .Run (fmt .Sprintf ("n=%dk/bitwidth=%d " , t .kcount , t . bitwidth ),
264
- doBenchmarkEntriesCount (t .kcount * 1000 , t .bitwidth ))
276
+ for _ , t := range caseTable {
277
+ b .Run (fmt .Sprintf ("%s " , t .id ),
278
+ doBenchmarkEntriesCount (t .count , t .bitwidth , t . datasize , t . keysize ))
265
279
}
266
280
}
267
281
268
- func doBenchmarkEntriesCount (num int , bitWidth int ) func (b * testing.B ) {
282
+ func doBenchmarkEntriesCount (num int , bitWidth int , datasize int , keysize int ) func (b * testing.B ) {
269
283
r := rander {rand .New (rand .NewSource (int64 (num )))}
270
284
return func (b * testing.B ) {
271
285
blockstore := newMockBlocks ()
@@ -274,8 +288,8 @@ func doBenchmarkEntriesCount(num int, bitWidth int) func(b *testing.B) {
274
288
275
289
var keys []string
276
290
for i := 0 ; i < num ; i ++ {
277
- k := r .randString ()
278
- if err := n .Set (context .TODO (), k , r .randValue ()); err != nil {
291
+ k := r .randString (keysize )
292
+ if err := n .Set (context .TODO (), k , r .randValue (datasize )); err != nil {
279
293
b .Fatal (err )
280
294
}
281
295
keys = append (keys , k )
0 commit comments