This repository was archived by the owner on Jun 19, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 30
test: add simple arc cache benchmarks #65
Closed
Closed
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
0c93e53
test: add simple arc cache benchmarks
frrist 2c26cc5
test: add concurrent benchmarks for arc cache
frrist 14b065f
test: add delay store to arc benchmarks
frrist 80e1a84
fixup: go mod tidy after master rebase
frrist 0838a9b
test: add store thrasher for more accurate benchmarks
frrist b75f631
gofmt
frrist 00b337f
polish: each thrasher routine own rand source
frrist e7eea83
fix(typo): in test trap
frrist File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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")) | ||
|
@@ -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) | ||
|
@@ -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) | ||
|
@@ -45,6 +63,81 @@ func untrap(cd *callbackDatastore) { | |
cd.SetFunc(func() {}) | ||
} | ||
|
||
type storeThrasher struct { | ||
store *arccache | ||
|
||
trace []blocks.Block | ||
|
||
numBlocks int | ||
numThreads int | ||
|
||
ctx context.Context | ||
cancel context.CancelFunc | ||
} | ||
|
||
func NewThrasher(store *arccache, numBlocks, numThreads int) (*storeThrasher, []blocks.Block) { | ||
t := &storeThrasher{ | ||
numBlocks: numBlocks, | ||
numThreads: numThreads, | ||
store: store, | ||
} | ||
trace := make([]blocks.Block, t.numBlocks) | ||
for i := 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 := 0; i < t.numThreads; i++ { | ||
go func() { | ||
for { | ||
select { | ||
case <-t.ctx.Done(): | ||
return | ||
default: | ||
idx := rand.Intn(t.numBlocks - 1) | ||
t.store.Put(t.trace[idx]) | ||
} | ||
} | ||
}() | ||
|
||
go func() { | ||
for { | ||
select { | ||
case <-t.ctx.Done(): | ||
return | ||
default: | ||
idx := rand.Intn(t.numBlocks - 1) | ||
t.store.Get(t.trace[idx].Cid()) | ||
} | ||
} | ||
}() | ||
|
||
go func() { | ||
for { | ||
select { | ||
case <-t.ctx.Done(): | ||
return | ||
default: | ||
idx := rand.Intn(t.numBlocks - 1) | ||
t.store.DeleteBlock(t.trace[idx].Cid()) | ||
} | ||
} | ||
}() | ||
} | ||
} | ||
|
||
func TestRemoveCacheEntryOnDelete(t *testing.T) { | ||
arc, _, cd := createStores(t) | ||
|
||
|
@@ -259,3 +352,187 @@ func TestPutManyCaches(t *testing.T) { | |
trap("PunMany has hit datastore", cd, t) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it's not actually in the diff, but I happen to see a typo here. (And it's the best typo.) |
||
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 int | ||
threads int | ||
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 int | ||
threads int | ||
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 int | ||
threads int | ||
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() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: give each goroutine it's own
rand.Source
. The package level functions likerand.Intn
use a shared source with a mutex.