Benchmark PieceRequestOrder with varying styles of path hint usage

Add per-piece piece request order path hints
This commit is contained in:
Matt Joiner 2021-12-17 21:25:38 +11:00
parent 62060fb897
commit c54dc22592
3 changed files with 83 additions and 7 deletions

View File

@ -8,7 +8,6 @@ import (
"github.com/RoaringBitmap/roaring"
"github.com/anacrolix/chansync"
"github.com/anacrolix/missinggo/v2/bitmap"
"github.com/anacrolix/torrent/metainfo"
pp "github.com/anacrolix/torrent/peer_protocol"
"github.com/anacrolix/torrent/storage"

View File

@ -21,7 +21,7 @@ func NewPieceOrder() *PieceRequestOrder {
type PieceRequestOrder struct {
tree *btree.BTree[pieceRequestOrderItem]
keys map[PieceRequestOrderKey]PieceRequestOrderState
pathHint btree.PathHint
PathHint *btree.PathHint
}
type PieceRequestOrderKey struct {
@ -51,7 +51,7 @@ func (me *PieceRequestOrder) Add(key PieceRequestOrderKey, state PieceRequestOrd
if _, ok := me.tree.SetHint(pieceRequestOrderItem{
key: key,
state: state,
}, &me.pathHint); ok {
}, me.PathHint); ok {
panic("shouldn't already have this")
}
me.keys[key] = state
@ -59,7 +59,10 @@ func (me *PieceRequestOrder) Add(key PieceRequestOrderKey, state PieceRequestOrd
type PieceRequestOrderPathHint = btree.PathHint
func (me *PieceRequestOrder) Update(key PieceRequestOrderKey, state PieceRequestOrderState) {
func (me *PieceRequestOrder) Update(
key PieceRequestOrderKey,
state PieceRequestOrderState,
) {
oldState, ok := me.keys[key]
if !ok {
panic("key should have been added already")
@ -71,11 +74,11 @@ func (me *PieceRequestOrder) Update(key PieceRequestOrderKey, state PieceRequest
key: key,
state: oldState,
}
if _, ok := me.tree.DeleteHint(item, &me.pathHint); !ok {
if _, ok := me.tree.DeleteHint(item, me.PathHint); !ok {
panic(fmt.Sprintf("%#v", key))
}
item.state = state
if _, ok := me.tree.SetHint(item, &me.pathHint); ok {
if _, ok := me.tree.SetHint(item, me.PathHint); ok {
panic(key)
}
me.keys[key] = state
@ -90,7 +93,7 @@ func (me *PieceRequestOrder) existingItemForKey(key PieceRequestOrderKey) pieceR
func (me *PieceRequestOrder) Delete(key PieceRequestOrderKey) {
item := me.existingItemForKey(key)
if _, ok := me.tree.DeleteHint(item, &me.pathHint); !ok {
if _, ok := me.tree.DeleteHint(item, me.PathHint); !ok {
panic(key)
}
delete(me.keys, key)

View File

@ -0,0 +1,74 @@
package request_strategy
import (
"testing"
"github.com/bradfitz/iter"
)
func benchmarkPieceRequestOrder(
b *testing.B,
hintForPiece func(index int) *PieceRequestOrderPathHint,
numPieces int,
) {
b.ResetTimer()
b.ReportAllocs()
for range iter.N(b.N) {
pro := NewPieceOrder()
state := PieceRequestOrderState{}
doPieces := func(m func(PieceRequestOrderKey)) {
for i := range iter.N(numPieces) {
key := PieceRequestOrderKey{
Index: i,
}
pro.PathHint = hintForPiece(i)
m(key)
}
}
doPieces(func(key PieceRequestOrderKey) {
pro.Add(key, state)
})
state.Availability++
doPieces(func(key PieceRequestOrderKey) {
pro.Update(key, state)
})
doPieces(func(key PieceRequestOrderKey) {
state.Priority = piecePriority(key.Index / 4)
pro.Update(key, state)
})
// state.Priority = 0
state.Availability++
doPieces(func(key PieceRequestOrderKey) {
pro.Update(key, state)
})
state.Availability--
doPieces(func(key PieceRequestOrderKey) {
pro.Update(key, state)
})
doPieces(pro.Delete)
if pro.Len() != 0 {
b.FailNow()
}
}
}
func BenchmarkPieceRequestOrder(b *testing.B) {
const numPieces = 2000
b.Run("NoPathHints", func(b *testing.B) {
benchmarkPieceRequestOrder(b, func(int) *PieceRequestOrderPathHint {
return nil
}, numPieces)
})
b.Run("SharedPathHint", func(b *testing.B) {
var pathHint PieceRequestOrderPathHint
benchmarkPieceRequestOrder(b, func(int) *PieceRequestOrderPathHint {
return &pathHint
}, numPieces)
})
b.Run("PathHintPerPiece", func(b *testing.B) {
pathHints := make([]PieceRequestOrderPathHint, numPieces)
benchmarkPieceRequestOrder(b, func(index int) *PieceRequestOrderPathHint {
return &pathHints[index]
}, numPieces)
})
}