Skip to content
This repository has been archived by the owner on Jun 19, 2023. It is now read-only.

test: add simple arc cache benchmarks #65

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 282 additions & 2 deletions arc_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ package blockstore

import (
"context"
"fmt"
"math/rand"
"testing"
"time"

blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
delaystore "github.com/ipfs/go-datastore/delayed"
syncds "github.com/ipfs/go-datastore/sync"
delay "github.com/ipfs/go-ipfs-delay"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

var exampleBlock = blocks.NewBlock([]byte("foo"))
Expand All @@ -26,7 +33,7 @@ func testArcCached(ctx context.Context, bs Blockstore) (*arccache, error) {
return nil, err
}

func createStores(t *testing.T) (*arccache, Blockstore, *callbackDatastore) {
func createStores(t testing.TB) (*arccache, Blockstore, *callbackDatastore) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
bs := NewBlockstore(syncds.MutexWrap(cd))
arc, err := testArcCached(context.TODO(), bs)
Expand All @@ -36,6 +43,17 @@ func createStores(t *testing.T) (*arccache, Blockstore, *callbackDatastore) {
return arc, bs, cd
}

func createStoresWithDelay(t testing.TB, delayed delay.D) (*arccache, Blockstore, *callbackDatastore) {
cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
slowStore := delaystore.New(cd, delayed)
bs := NewBlockstore(syncds.MutexWrap(slowStore))
arc, err := testArcCached(context.TODO(), bs)
if err != nil {
t.Fatal(err)
}
return arc, bs, cd
}

func trap(message string, cd *callbackDatastore, t *testing.T) {
cd.SetFunc(func() {
t.Fatal(message)
Expand All @@ -45,6 +63,84 @@ func untrap(cd *callbackDatastore) {
cd.SetFunc(func() {})
}

type storeThrasher struct {
store *arccache

trace []blocks.Block

numBlocks int64
numThreads int64

ctx context.Context
cancel context.CancelFunc
}

func NewThrasher(store *arccache, numBlocks, numThreads int64) (*storeThrasher, []blocks.Block) {
t := &storeThrasher{
numBlocks: numBlocks,
numThreads: numThreads,
store: store,
}
trace := make([]blocks.Block, t.numBlocks)
for i := int64(0); i < t.numBlocks; i++ {
token := make([]byte, 4)
rand.Read(token)
trace[i] = blocks.NewBlock(token)
}
t.trace = trace
t.ctx, t.cancel = context.WithCancel(context.Background())

return t, trace
}

func (t *storeThrasher) Destroy() {
t.cancel()
t.store = nil
}

func (t *storeThrasher) Start() {
for i := int64(0); i < t.numThreads; i++ {
go func() {
rs := rand.NewSource(time.Now().UnixNano())
for {
select {
case <-t.ctx.Done():
return
default:
idx := rs.Int63() % t.numBlocks
t.store.Put(t.trace[idx])
}
}
}()

go func() {
rs := rand.NewSource(time.Now().UnixNano())
for {
select {
case <-t.ctx.Done():
return
default:
idx := rs.Int63() % t.numBlocks
t.store.Get(t.trace[idx].Cid())
}
}
}()

go func() {
rs := rand.NewSource(time.Now().UnixNano())
for {
select {
case <-t.ctx.Done():
return
default:
idx := rs.Int63() % t.numBlocks
t.store.DeleteBlock(t.trace[idx].Cid())
}
}
}()
}
}

func TestRemoveCacheEntryOnDelete(t *testing.T) {
arc, _, cd := createStores(t)

Expand Down Expand Up @@ -256,6 +352,190 @@ func TestPutManyCaches(t *testing.T) {
arc.DeleteBlock(exampleBlock.Cid())

arc.Put(exampleBlock)
trap("PunMany has hit datastore", cd, t)
trap("PutMany has hit datastore", cd, t)
arc.PutMany([]blocks.Block{exampleBlock})
}

func init() {
rand.Seed(time.Now().UnixNano())
}

func Benchmark_SimplePutGet(b *testing.B) {
arc, _, _ := createStores(b)

trace := make([]blocks.Block, b.N)
for i := 0; i < b.N; i++ {
token := make([]byte, 4)
rand.Read(token)
trace[i] = blocks.NewBlock(token)
}
b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
if i%2 == 0 {
require.NoError(b, arc.Put(trace[i]))
}
}

for i := 0; i < b.N; i++ {
_, err := arc.Get(trace[i].Cid())
if i%2 == 0 {
assert.NoError(b, err)
}
}
}

func Benchmark_SimplePutDelete(b *testing.B) {
arc, _, _ := createStores(b)

trace := make([]blocks.Block, b.N)
for i := 0; i < b.N; i++ {
token := make([]byte, 4)
rand.Read(token)
trace[i] = blocks.NewBlock(token)
}
b.ResetTimer()
b.ReportAllocs()

for i := 0; i < b.N; i++ {
require.NoError(b, arc.Put(trace[i]))
}

for i := 0; i < b.N; i++ {
err := arc.DeleteBlock(trace[i].Cid())
require.NoError(b, err)
}
}

func Benchmark_ThrashPut(b *testing.B) {
table := []struct {
numBlocks int64
threads int64
delay time.Duration
}{
{
numBlocks: 1_000_000,
threads: 1,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 32,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 64,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 500,
delay: time.Millisecond * 1,
},
}

for _, test := range table {
arc, _, _ := createStoresWithDelay(b, delay.Fixed(test.delay))
thrasher, trace := NewThrasher(arc, test.numBlocks, test.threads)
thrasher.Start()

b.Run(fmt.Sprintf("%d_threads-%d_blocks", test.threads, test.numBlocks), func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
require.NoError(b, arc.Put(trace[i]))
}
})
thrasher.Destroy()
}
}

func Benchmark_ThrashGet(b *testing.B) {
table := []struct {
numBlocks int64
threads int64
delay time.Duration
}{
{
numBlocks: 1_000_000,
threads: 1,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 32,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 64,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 500,
delay: time.Millisecond * 1,
},
}

for _, test := range table {
arc, _, _ := createStoresWithDelay(b, delay.Fixed(test.delay))
thrasher, trace := NewThrasher(arc, test.numBlocks, test.threads)
thrasher.Start()

b.Run(fmt.Sprintf("%d_threads-%d_blocks", test.threads, test.numBlocks), func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
arc.Get(trace[i].Cid())
}
})
thrasher.Destroy()
}
}

func Benchmark_ThrashDelete(b *testing.B) {
table := []struct {
numBlocks int64
threads int64
delay time.Duration
}{
{
numBlocks: 1_000_000,
threads: 1,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 32,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 64,
delay: time.Millisecond * 1,
},
{
numBlocks: 1_000_000,
threads: 500,
delay: time.Millisecond * 1,
},
}

for _, test := range table {
arc, _, _ := createStoresWithDelay(b, delay.Fixed(test.delay))
thrasher, trace := NewThrasher(arc, test.numBlocks, test.threads)
thrasher.Start()

b.Run(fmt.Sprintf("%d_threads-%d_blocks", test.threads, test.numBlocks), func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
arc.DeleteBlock(trace[i].Cid())
}
})
thrasher.Destroy()
}
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
module github.com/ipfs/go-ipfs-blockstore

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/hashicorp/golang-lru v0.5.4
github.com/ipfs/bbloom v0.0.4
github.com/ipfs/go-block-format v0.0.2
github.com/ipfs/go-cid v0.0.5
github.com/ipfs/go-datastore v0.4.1
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8
github.com/ipfs/go-ipfs-ds-help v1.0.0
github.com/ipfs/go-ipfs-util v0.0.1
github.com/ipfs/go-log v0.0.1
github.com/ipfs/go-metrics-interface v0.0.1
github.com/multiformats/go-multihash v0.0.13
github.com/stretchr/testify v1.3.0
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
)

go 1.13
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
Expand All @@ -20,6 +22,7 @@ github.com/ipfs/go-cid v0.0.5 h1:o0Ix8e/ql7Zb5UVUJEUfjsWCIY8t48++9lR8qi6oiJU=
github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
github.com/ipfs/go-datastore v0.4.1 h1:W4ZfzyhNi3xmuU5dQhjfuRn/wFuqEE1KnOmmQiOevEY=
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8 h1:NAviDvJ0WXgD+yiL2Rj35AmnfgI11+pHXbdciD917U0=
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
github.com/ipfs/go-ipfs-ds-help v1.0.0 h1:bEQ8hMGs80h0sR8O4tfDgV6B01aaF9qeTrujrTLYV3g=
github.com/ipfs/go-ipfs-ds-help v1.0.0/go.mod h1:ujAbkeIgkKAWtxxNkoZHWLCyk5JpPoKnGyCcsoF6ueE=
Expand Down Expand Up @@ -82,6 +85,8 @@ golang.org/x/net v0.0.0-20190227160552-c95aed5357e7 h1:C2F/nMkR/9sfUTpvR3QrjBuTd
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
Expand Down