"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"
type PieceRequestOrder struct {
tree *btree.BTree[pieceRequestOrderItem]
keys map[PieceRequestOrderKey]PieceRequestOrderState
- pathHint btree.PathHint
+ PathHint *btree.PathHint
}
type PieceRequestOrderKey struct {
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
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")
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
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)
--- /dev/null
+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)
+ })
+}