diff --git a/go.mod b/go.mod index 1cf7aa0..58bb25f 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,22 @@ module github.com/filecoin-project/go-hamt-ipld/v3 require ( + github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect github.com/ipfs/go-block-format v0.0.2 - github.com/ipfs/go-cid v0.0.6 + github.com/ipfs/go-cid v0.0.7 github.com/ipfs/go-ipld-cbor v0.0.4 + github.com/ipfs/go-ipld-format v0.0.2 // indirect + github.com/minio/sha256-simd v0.1.1 // indirect + github.com/multiformats/go-multihash v0.0.14 // indirect + github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a // indirect + github.com/smartystreets/assertions v1.0.1 // indirect + github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect github.com/spaolacci/murmur3 v1.1.0 github.com/stretchr/testify v1.6.1 - github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488 - golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 + github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 // indirect + github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c + golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 ) go 1.13 diff --git a/go.sum b/go.sum index 4132630..4e16286 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk= +github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gxed/hashland/keccakpg v0.0.1 h1:wrk3uMNaMxbXiHibbPO4S0ymqJMm41WiudyFSs7UnsU= github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= github.com/gxed/hashland/murmur3 v0.0.1 h1:SheiaIt0sda5K+8FLz952/1iWS9zrnKsEJaOJu4ZbSc= @@ -10,24 +12,33 @@ github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmv github.com/ipfs/go-block-format v0.0.2 h1:qPDvcP19izTjU8rgo6p7gTXZlkMkF5bz5G3fqIsSCPE= github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= +github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms= github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.6 h1:go0y+GcDOGeJIV01FeBsta4FHngoA4Wz7KMeLkXAhMs= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= +github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY= +github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50= github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= github.com/ipfs/go-ipld-cbor v0.0.4 h1:Aw3KPOKXjvrm6VjwJvFf1F1ekR/BH3jdof3Bk7OTiSA= github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= github.com/ipfs/go-ipld-format v0.0.1 h1:HCu4eB/Gh+KD/Q0M8u888RFkorTWNIL3da4oc5dwc80= github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= +github.com/ipfs/go-ipld-format v0.0.2 h1:OVAGlyYT6JPZ0pEfGntFPS40lfrDmaDbQwNHEY2G9Zs= +github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16 h1:5W7KhL8HVF3XCFOweFD3BNESdnO8ewyYTFT2R+/b8FQ= github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo= github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= +github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ= github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78= @@ -48,16 +59,24 @@ github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6w github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= github.com/multiformats/go-multihash v0.0.13 h1:06x+mk/zj1FoMsgNejLpy6QTvJqlSt/BhLEy87zidlc= github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= +github.com/multiformats/go-multihash v0.0.14 h1:QoBceQYQQtNUuf6s7wHxnE2c8bhbMqhfGzNI032se/I= +github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= github.com/multiformats/go-varint v0.0.5 h1:XVZwSo04Cs3j/jS0uAEPpT3JY6DzMcVLLoWOSnCxOjg= github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE= github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a h1:hjZfReYVLbqFkAtr2us7vdy04YWz3LVAirzP7reh8+M= +github.com/polydawn/refmt v0.0.0-20190809202753-05966cbd336a/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHeiJApdr3r4w= +github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa h1:E+gaaifzi2xF65PbDmuKI3PhLWY6G5opMLniFq8vmXA= github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8= +github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= @@ -66,15 +85,18 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436 h1:qOpVTI+BrstcjTZLm2Yz/3sOnqkzj3FQoh0g+E5s3Gc= github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830 h1:8kxMKmKzXXL4Ru1nyhvdms/JjWt+3YLpvRb/bAjO/y0= +github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 h1:WXhVOwj2USAXB5oMDwRl3piOux2XMV9TANaYxXHdkoE= github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488 h1:P/Q9QT99FpyHtFke7ERUqX7yYtZ/KigO880L+TKFyTQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20200806213330-63aa96ca5488/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c h1:otRnI08JoahNBxUFqX3372Ab9GnTj8L5J9iP5ImyxGU= +github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67 h1:ng3VDlRp5/DHpSWl02R4rM9I+8M2rhmsuLwAMmkLQWE= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -82,9 +104,14 @@ golang.org/x/sys v0.0.0-20190219092855-153ac476189d h1:Z0Ahzd7HltpJtjAHHxX8QFP3j golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/hamt_bench_test.go b/hamt_bench_test.go index deab914..7ef4d17 100644 --- a/hamt_bench_test.go +++ b/hamt_bench_test.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "math/rand" + "os" "runtime" "testing" @@ -15,26 +16,44 @@ type rander struct { r *rand.Rand } -func (r *rander) randString() string { - buf := make([]byte, 18) - rand.Read(buf) +func (r *rander) randString(stringSize int) string { + buf := make([]byte, stringSize) + r.r.Read(buf) return hex.EncodeToString(buf) } -func (r *rander) randValue() []byte { - buf := make([]byte, 30) - rand.Read(buf) +func (r *rander) randValue(datasize int) []byte { + buf := make([]byte, datasize) + r.r.Read(buf) return buf } +func (r *rander) selectKey(keys []string) string { + i := r.r.Int() % len(keys) + return keys[i] +} + +var benchSeed = int64(42) + +func TestMain(m *testing.M) { + // Hack to run multiple different benchmark seed values + for benchMarkIter := int64(0); benchMarkIter < 3; benchMarkIter++ { + benchSeed = 42 + (100_000_000_000 * benchMarkIter) // We resample on every b.N so choose step size bigger than b.N values + if code := m.Run(); code != 0 { + os.Exit(code) + } + } + os.Exit(0) +} + func BenchmarkSerializeNode(b *testing.B) { - r := rander{rand.New(rand.NewSource(1234))} + r := rander{rand.New(rand.NewSource(benchSeed + 1234))} cs := cbor.NewCborStore(newMockBlocks()) n := NewNode(cs) for i := 0; i < 50; i++ { - if err := n.Set(context.TODO(), r.randString(), r.randValue()); err != nil { + if err := n.Set(context.TODO(), r.randString(18), r.randValue(30)); err != nil { b.Fatal(err) } } @@ -50,25 +69,28 @@ func BenchmarkSerializeNode(b *testing.B) { } } -type benchSetCase struct { - kcount int +type hamtParams struct { + id string + count int + datasize int + keysize int +} + +type benchCase struct { + id string + count int bitwidth int + datasize int + keysize int } -var benchSetCaseTable []benchSetCase +var caseTable []benchCase func init() { - kCounts := []int{ - 1, - 5, - 10, - 50, - 100, - 500, - 1000, // aka 1M - //10000, // aka 10M -- you'll need a lot of RAM for this. Also, some patience. - } + bitwidths := []int{ + 1, + 2, 3, 4, 5, @@ -76,10 +98,39 @@ func init() { 7, 8, } + + hamts := []hamtParams{ + hamtParams{ + id: "init.AddressMap.Now", + count: 100000, + datasize: 3, + keysize: 26, + }, + hamtParams{ + id: "init.AddressMap.ThreeMonths", + count: 167000, + datasize: 3, + keysize: 26, + }, + hamtParams{ + id: "init.AddressMap.SixMonths", + count: 240000, + datasize: 3, + keysize: 26, + }, + } + // bucketsize-aka-arraywidth? maybe someday. - for _, c := range kCounts { + for _, h := range hamts { for _, bw := range bitwidths { - benchSetCaseTable = append(benchSetCaseTable, benchSetCase{kcount: c, bitwidth: bw}) + caseTable = append(caseTable, + benchCase{ + id: fmt.Sprintf("%s -- bw=%d", h.id, bw), + count: h.count, + bitwidth: bw, + datasize: h.datasize, + keysize: h.keysize, + }) } } } @@ -110,15 +161,15 @@ func init() { // See "BenchmarkSet*" for a probe of how long it takes to set additional entries in an already-large hamt // (this gives a more interesting and useful nanoseconds-per-op indicators). func BenchmarkFill(b *testing.B) { - for _, t := range benchSetCaseTable { - b.Run(fmt.Sprintf("n=%dk/bitwidth=%d", t.kcount, t.bitwidth), func(b *testing.B) { + for _, t := range caseTable { + b.Run(fmt.Sprintf("%s", t.id), func(b *testing.B) { for i := 0; i < b.N; i++ { - r := rander{rand.New(rand.NewSource(int64(i)))} + r := rander{rand.New(rand.NewSource(benchSeed + int64(i)))} blockstore := newMockBlocks() n := NewNode(cbor.NewCborStore(blockstore), UseTreeBitWidth(t.bitwidth)) //b.ResetTimer() - for j := 0; j < t.kcount*1000; j++ { - if err := n.Set(context.Background(), r.randString(), r.randValue()); err != nil { + for j := 0; j < t.count; j++ { + if err := n.Set(context.Background(), r.randString(t.keysize), r.randValue(t.datasize)); err != nil { b.Fatal(err) } } @@ -132,24 +183,24 @@ func BenchmarkFill(b *testing.B) { if blockstore.stats.evtcntPutDup > 0 { 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. } - b.ReportMetric(float64(blockstore.stats.evtcntGet)/float64(t.kcount*1000), "getEvts/entry") - b.ReportMetric(float64(blockstore.stats.evtcntPut)/float64(t.kcount*1000), "putEvts/entry") - b.ReportMetric(float64(len(blockstore.data))/float64(t.kcount*1000), "blocks/entry") + b.ReportMetric(float64(blockstore.stats.evtcntGet)/float64(t.count), "getEvts") + b.ReportMetric(float64(blockstore.stats.evtcntPut)/float64(t.count), "putEvts") + b.ReportMetric(float64(len(blockstore.data))/float64(t.count), "blocks") binarySize, _ := n.checkSize(context.Background()) - b.ReportMetric(float64(binarySize)/float64(t.kcount*1000), "bytes(hamtAccnt)/entry") - b.ReportMetric(float64(blockstore.totalBlockSizes())/float64(t.kcount*1000), "bytes(blockstoreAccnt)/entry") + b.ReportMetric(float64(binarySize)/float64(t.count), "bytes(hamtAccnt)/entry") + b.ReportMetric(float64(blockstore.totalBlockSizes())/float64(t.count), "bytes(blockstoreAccnt)/entry") b.StartTimer() } }) } } -// BenchmarkSetBulk creates a large HAMT, then resets the timer, and does another 1000 inserts, +// BenchmarkSetBulk creates a large HAMT, then starts the timer, and does another 1000 inserts, // measuring the time taken for this second batch of inserts. // Flushing happens once after all 1000 inserts. // // The number of *additional* blocks per entry is reported. -// This number is usually less than one, because the bulk flush means changes might be amortized. +// This number is usually less than one with high flush interval means changes might be amortized. func BenchmarkSetBulk(b *testing.B) { doBenchmarkSetSuite(b, false) } @@ -158,36 +209,35 @@ func BenchmarkSetBulk(b *testing.B) { // Flush happens per insert. // // The number of *additional* blocks per entry is reported. -// Since we flush each insert individually, this number should be at least 1 -- -// however, since we choose random keys, it can still turn out lower if keys happen to collide. -// (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.) +// Since we flush each insert individually, this number should be at least 1. func BenchmarkSetIndividual(b *testing.B) { doBenchmarkSetSuite(b, true) } func doBenchmarkSetSuite(b *testing.B, flushPer bool) { - for _, t := range benchSetCaseTable { - b.Run(fmt.Sprintf("n=%dk/bitwidth=%d", t.kcount, t.bitwidth), func(b *testing.B) { + for _, t := range caseTable { + b.Run(fmt.Sprintf("%s", t.id), func(b *testing.B) { for i := 0; i < b.N; i++ { - r := rander{rand.New(rand.NewSource(int64(i)))} + b.StopTimer() + r := rander{rand.New(rand.NewSource(benchSeed + int64(i)))} blockstore := newMockBlocks() n := NewNode(cbor.NewCborStore(blockstore), UseTreeBitWidth(t.bitwidth)) // Initial fill: - for j := 0; j < t.kcount*1000; j++ { - if err := n.Set(context.Background(), r.randString(), r.randValue()); err != nil { + for j := 0; j < t.count; j++ { + if err := n.Set(context.Background(), r.randString(t.keysize), r.randValue(t.datasize)); err != nil { b.Fatal(err) } } if err := n.Flush(context.Background()); err != nil { b.Fatal(err) } - initalBlockstoreSize := len(blockstore.data) - b.ResetTimer() + // b.ResetTimer() blockstore.stats = blockstoreStats{} // Additional inserts: b.ReportAllocs() + b.StartTimer() for j := 0; j < 1000; j++ { - if err := n.Set(context.Background(), r.randString(), r.randValue()); err != nil { + if err := n.Set(context.Background(), r.randString(t.keysize), r.randValue(t.datasize)); err != nil { b.Fatal(err) } if flushPer { @@ -208,9 +258,9 @@ func doBenchmarkSetSuite(b *testing.B, flushPer bool) { if blockstore.stats.evtcntPutDup > 0 { b.Logf("on round N=%d: blockstore stats: %#v\n", b.N, blockstore.stats) } - b.ReportMetric(float64(blockstore.stats.evtcntGet)/float64(t.kcount*1000), "getEvts/entry") - b.ReportMetric(float64(blockstore.stats.evtcntPut)/float64(t.kcount*1000), "putEvts/entry") - b.ReportMetric(float64(len(blockstore.data)-initalBlockstoreSize)/float64(1000), "addntlBlocks/addntlEntry") + b.ReportMetric(float64(blockstore.stats.evtcntGet)/1000, "getEvts") + b.ReportMetric(float64(blockstore.stats.evtcntPut)/1000, "putEvts") + b.ReportMetric(float64(blockstore.stats.bytesPut)/1000, "bytesPut") b.StartTimer() } }) @@ -218,14 +268,14 @@ func doBenchmarkSetSuite(b *testing.B, flushPer bool) { } func BenchmarkFind(b *testing.B) { - for _, t := range benchSetCaseTable { - b.Run(fmt.Sprintf("n=%dk/bitwidth=%d", t.kcount, t.bitwidth), - doBenchmarkEntriesCount(t.kcount*1000, t.bitwidth)) + for _, t := range caseTable { + b.Run(fmt.Sprintf("%s", t.id), + doBenchmarkEntriesCount(t.count, t.bitwidth, t.datasize, t.keysize)) } } -func doBenchmarkEntriesCount(num int, bitWidth int) func(b *testing.B) { - r := rander{rand.New(rand.NewSource(int64(num)))} +func doBenchmarkEntriesCount(num int, bitWidth int, datasize int, keysize int) func(b *testing.B) { + r := rander{rand.New(rand.NewSource(benchSeed + int64(num)))} return func(b *testing.B) { blockstore := newMockBlocks() cs := cbor.NewCborStore(blockstore) @@ -233,8 +283,8 @@ func doBenchmarkEntriesCount(num int, bitWidth int) func(b *testing.B) { var keys []string for i := 0; i < num; i++ { - k := r.randString() - if err := n.Set(context.TODO(), k, r.randValue()); err != nil { + k := r.randString(keysize) + if err := n.Set(context.TODO(), k, r.randValue(datasize)); err != nil { b.Fatal(err) } keys = append(keys, k) @@ -250,21 +300,83 @@ func doBenchmarkEntriesCount(num int, bitWidth int) func(b *testing.B) { } runtime.GC() - blockstore.stats = blockstoreStats{} b.ResetTimer() b.ReportAllocs() for i := 0; i < b.N; i++ { - nd, err := LoadNode(context.TODO(), cs, c, UseTreeBitWidth(bitWidth)) - if err != nil { - b.Fatal(err) + blockstore.stats = blockstoreStats{} + for j := 0; j < 1000; j++ { + nd, err := LoadNode(context.TODO(), cs, c, UseTreeBitWidth(bitWidth)) + if err != nil { + b.Fatal(err) + } + if err = nd.Find(context.TODO(), r.selectKey(keys), nil); err != nil { + b.Fatal(err) + } } + b.StopTimer() + b.ReportMetric(float64(blockstore.stats.evtcntGet)/float64(1000), "getEvts") + b.ReportMetric(float64(blockstore.stats.evtcntPut)/float64(1000), "putEvts") // surely this is zero, but for completeness. + b.StartTimer() + } + } +} - if err = nd.Find(context.TODO(), keys[i%num], nil); err != nil { +func BenchmarkReset(b *testing.B) { + for _, t := range caseTable { + b.Run(fmt.Sprintf("%s", t.id), + doBenchmarkResetSuite(t.count, t.bitwidth, t.datasize, t.keysize)) + } +} + +func doBenchmarkResetSuite(num int, bitWidth int, datasize int, keysize int) func(b *testing.B) { + r := rander{rand.New(rand.NewSource(benchSeed + int64(num)))} + return func(b *testing.B) { + blockstore := newMockBlocks() + cs := cbor.NewCborStore(blockstore) + n := NewNode(cs, UseTreeBitWidth(bitWidth)) + + var keys []string + for i := 0; i < num; i++ { + k := r.randString(keysize) + if err := n.Set(context.TODO(), k, r.randValue(datasize)); err != nil { b.Fatal(err) } + keys = append(keys, k) + } + + if err := n.Flush(context.TODO()); err != nil { + b.Fatal(err) + } + + c, err := cs.Put(context.TODO(), n) + if err != nil { + b.Fatal(err) + } + + runtime.GC() + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + blockstore.stats = blockstoreStats{} + for j := 0; j < 1000; j++ { + nd, err := LoadNode(context.TODO(), cs, c, UseTreeBitWidth(bitWidth)) + if err != nil { + b.Fatal(err) + } + if err := nd.Set(context.Background(), r.selectKey(keys), r.randValue(datasize)); err != nil { + b.Fatal(err) + } + if err := nd.Flush(context.Background()); err != nil { + b.Fatal(err) + } + } + b.StopTimer() + b.ReportMetric(float64(blockstore.stats.evtcntGet)/1000, "getEvts") + b.ReportMetric(float64(blockstore.stats.evtcntPut)/1000, "putEvts") + b.ReportMetric(float64(blockstore.stats.bytesPut)/1000, "bytesPut") + b.StartTimer() } - b.ReportMetric(float64(blockstore.stats.evtcntGet)/float64(b.N), "getEvts/find") - b.ReportMetric(float64(blockstore.stats.evtcntPut)/float64(b.N), "putEvts/find") // surely this is zero, but for completeness. } } diff --git a/hamt_test.go b/hamt_test.go index c67288d..18765be 100644 --- a/hamt_test.go +++ b/hamt_test.go @@ -41,6 +41,7 @@ func (mb *mockBlocks) Get(c cid.Cid) (block.Block, error) { func (mb *mockBlocks) Put(b block.Block) error { mb.stats.evtcntPut++ + mb.stats.bytesPut += len(b.RawData()) if _, exists := mb.data[b.Cid()]; exists { mb.stats.evtcntPutDup++ } @@ -51,6 +52,7 @@ func (mb *mockBlocks) Put(b block.Block) error { type blockstoreStats struct { evtcntGet int evtcntPut int + bytesPut int evtcntPutDup int }