@@ -15,14 +15,14 @@ type rander struct {
1515 r * rand.Rand
1616}
1717
18- func (r * rander ) randString () string {
19- buf := make ([]byte , 18 )
18+ func (r * rander ) randString (stringSize int ) string {
19+ buf := make ([]byte , stringSize )
2020 rand .Read (buf )
2121 return hex .EncodeToString (buf )
2222}
2323
24- func (r * rander ) randValue () []byte {
25- buf := make ([]byte , 30 )
24+ func (r * rander ) randValue (datasize int ) []byte {
25+ buf := make ([]byte , datasize )
2626 rand .Read (buf )
2727 return buf
2828}
@@ -34,7 +34,7 @@ func BenchmarkSerializeNode(b *testing.B) {
3434 n := NewNode (cs )
3535
3636 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 {
3838 b .Fatal (err )
3939 }
4040 }
@@ -50,83 +50,92 @@ func BenchmarkSerializeNode(b *testing.B) {
5050 }
5151}
5252
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
6558}
6659
67- type benchFindCase struct {
68- kcount int
60+ type benchCase struct {
61+ id string
62+ count int
6963 bitwidth int
7064 datasize int
65+ keysize int
7166}
7267
73- var benchSetCaseTable []benchSetCase
74- var benchFillCaseTable []benchFillCase
75- var benchFindCaseTable []benchFindCase
68+ var caseTable []benchCase
7669
7770func 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+
8872 bitwidths := []int {
73+ 1 ,
74+ 2 ,
8975 3 ,
9076 4 ,
9177 5 ,
9278 6 ,
9379 7 ,
9480 8 ,
9581 }
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+ },
102126 }
127+
103128 // 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+ })
130139 }
131140 }
132141}
@@ -157,15 +166,15 @@ func init() {
157166// See "BenchmarkSet*" for a probe of how long it takes to set additional entries in an already-large hamt
158167// (this gives a more interesting and useful nanoseconds-per-op indicators).
159168func 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 ) {
162171 for i := 0 ; i < b .N ; i ++ {
163172 r := rander {rand .New (rand .NewSource (int64 (i )))}
164173 blockstore := newMockBlocks ()
165174 n := NewNode (cbor .NewCborStore (blockstore ), UseTreeBitWidth (t .bitwidth ))
166175 //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 {
169178 b .Fatal (err )
170179 }
171180 }
@@ -179,56 +188,61 @@ func BenchmarkFill(b *testing.B) {
179188 if blockstore .stats .evtcntPutDup > 0 {
180189 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.
181190 }
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" )
185194 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" )
188197 b .StartTimer ()
189198 }
190199 })
191200 }
192201}
193202
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,
195204// measuring the time taken for this second batch of inserts.
196- // Flushing rate is parameterized .
205+ // Flushing happens once after all 1000 inserts .
197206//
198207// The number of *additional* blocks per entry is reported.
199208// 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 )
205220}
206221
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 ) {
210225 for i := 0 ; i < b .N ; i ++ {
211226 b .StopTimer ()
212227 r := rander {rand .New (rand .NewSource (int64 (i )))}
213228 blockstore := newMockBlocks ()
214229 n := NewNode (cbor .NewCborStore (blockstore ), UseTreeBitWidth (t .bitwidth ))
215230 // 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 {
218233 b .Fatal (err )
219234 }
220235 }
221236 if err := n .Flush (context .Background ()); err != nil {
222237 b .Fatal (err )
223238 }
224- initalBlockstoreSize := len (blockstore .data )
225239 // b.ResetTimer()
226240 blockstore .stats = blockstoreStats {}
227241 // Additional inserts:
228242 b .ReportAllocs ()
229243 b .StartTimer ()
230244 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 {
232246 b .Fatal (err )
233247 }
234248 if flushPer {
@@ -249,23 +263,23 @@ func doBenchmarkSetSuite(b *testing.B) {
249263 if blockstore .stats .evtcntPutDup > 0 {
250264 b .Logf ("on round N=%d: blockstore stats: %#v\n " , b .N , blockstore .stats )
251265 }
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 " )
255269 b .StartTimer ()
256270 }
257271 })
258272 }
259273}
260274
261275func 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 ))
265279 }
266280}
267281
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 ) {
269283 r := rander {rand .New (rand .NewSource (int64 (num )))}
270284 return func (b * testing.B ) {
271285 blockstore := newMockBlocks ()
@@ -274,8 +288,8 @@ func doBenchmarkEntriesCount(num int, bitWidth int) func(b *testing.B) {
274288
275289 var keys []string
276290 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 {
279293 b .Fatal (err )
280294 }
281295 keys = append (keys , k )
0 commit comments