Skip to content

Commit 1bcd218

Browse files
committed
feat: add basic sp selection score modelling
1 parent fe9e760 commit 1bcd218

File tree

5 files changed

+627
-2
lines changed

5 files changed

+627
-2
lines changed

pkg/session/model/cmd/main.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math/rand"
6+
"os"
7+
"strconv"
8+
"time"
9+
10+
"github.com/dustin/go-humanize"
11+
"github.com/filecoin-project/lassie/pkg/session"
12+
"github.com/filecoin-project/lassie/pkg/session/model"
13+
"github.com/multiformats/go-multicodec"
14+
)
15+
16+
var (
17+
GRAPHSYNC_FAST_RELIABLE_LOTS_OF_POPULAR_DATA = model.Provider{
18+
Name: "graphsync fast, semi-reliable, lots of popular data",
19+
Probabilities: map[multicodec.Code]model.Probabilities{
20+
multicodec.TransportGraphsyncFilecoinv1: {
21+
Candidate: model.Chance(0.5),
22+
Success: model.Chance(0.6),
23+
ConnectTimeMs: model.ProbDist{StdDev: 6, Mean: 10},
24+
TimeToFirstByteMs: model.ProbDist{StdDev: 6, Mean: 10},
25+
BandwidthBps: model.ProbDist{StdDev: 1e6, Mean: 1e8}, // Mean of 100Mb/s +/- 1MB/s
26+
LatencyMs: model.ProbDist{StdDev: 1, Mean: 20},
27+
FastRetrieval: model.Chance(0.9),
28+
Verified: model.Chance(0.9),
29+
},
30+
},
31+
}
32+
33+
GRAPHSYNC_MEDIUM_RELIABLE_SOME_POPULAR_DATA = model.Provider{
34+
Name: "graphsync medium, semi-reliable, some popular data",
35+
Probabilities: map[multicodec.Code]model.Probabilities{
36+
multicodec.TransportGraphsyncFilecoinv1: {
37+
Candidate: model.Chance(0.3),
38+
Success: model.Chance(0.5),
39+
ConnectTimeMs: model.ProbDist{StdDev: 6, Mean: 50},
40+
TimeToFirstByteMs: model.ProbDist{StdDev: 10, Mean: 25},
41+
BandwidthBps: model.ProbDist{StdDev: 1e6, Mean: 1e7}, // Mean of 10MB/s +/- 1MB/s
42+
LatencyMs: model.ProbDist{StdDev: 10, Mean: 40},
43+
FastRetrieval: model.Chance(0.9),
44+
Verified: model.Chance(0.9),
45+
},
46+
},
47+
}
48+
49+
GRAPHSYNC_MEDIUM_RELIABLE_MINIMAL_POPULAR_DATA = model.Provider{
50+
Name: "graphsync medium, semi-reliable, minimal popular data",
51+
Probabilities: map[multicodec.Code]model.Probabilities{
52+
multicodec.TransportGraphsyncFilecoinv1: {
53+
Candidate: model.Chance(0.1),
54+
Success: model.Chance(0.5),
55+
ConnectTimeMs: model.ProbDist{StdDev: 6, Mean: 50},
56+
TimeToFirstByteMs: model.ProbDist{StdDev: 10, Mean: 25},
57+
BandwidthBps: model.ProbDist{StdDev: 1e6, Mean: 1e7}, // Mean of 10MB/s +/- 1MB/s
58+
LatencyMs: model.ProbDist{StdDev: 10, Mean: 40},
59+
FastRetrieval: model.Chance(0.9),
60+
Verified: model.Chance(0.9),
61+
},
62+
},
63+
}
64+
65+
GRAPHSYNC_MEDIUM_UNRELIABLE_SOME_POPULAR_DATA = model.Provider{
66+
Name: "graphsync medium, unreliable, some popular data",
67+
Probabilities: map[multicodec.Code]model.Probabilities{
68+
multicodec.TransportGraphsyncFilecoinv1: {
69+
Candidate: model.Chance(0.3),
70+
Success: model.Chance(0.3),
71+
ConnectTimeMs: model.ProbDist{StdDev: 6, Mean: 50},
72+
TimeToFirstByteMs: model.ProbDist{StdDev: 20, Mean: 50},
73+
BandwidthBps: model.ProbDist{StdDev: 1e5, Mean: 1e6}, // Mean of 1MB/s +/- 100KB/s
74+
LatencyMs: model.ProbDist{StdDev: 10, Mean: 40},
75+
FastRetrieval: model.Chance(0.5),
76+
Verified: model.Chance(0.5),
77+
},
78+
},
79+
}
80+
81+
GRAPHSYNC_MEDIUM_VERY_UNRELIABLE_SOME_POPULAR_DATA = model.Provider{
82+
Name: "graphsync medium, very unreliable, some popular data",
83+
Probabilities: map[multicodec.Code]model.Probabilities{
84+
multicodec.TransportGraphsyncFilecoinv1: {
85+
Candidate: model.Chance(0.3),
86+
Success: model.Chance(0.1),
87+
ConnectTimeMs: model.ProbDist{StdDev: 100, Mean: 200},
88+
TimeToFirstByteMs: model.ProbDist{StdDev: 6, Mean: 100},
89+
BandwidthBps: model.ProbDist{StdDev: 1e5, Mean: 1e6}, // Mean of 1MB/s +/- 100KB/s
90+
LatencyMs: model.ProbDist{StdDev: 10, Mean: 100},
91+
FastRetrieval: model.Chance(0.2),
92+
Verified: model.Chance(0.2),
93+
},
94+
},
95+
}
96+
97+
HTTP_FAST_SEMIRELIABLE_LOTS_OF_POPULAR_DATA = model.Provider{
98+
Name: "http fast, semi-reliable, lots of popular data", // e-ipfs?
99+
Probabilities: map[multicodec.Code]model.Probabilities{
100+
multicodec.TransportIpfsGatewayHttp: {
101+
Candidate: model.Chance(0.5),
102+
Success: model.Chance(0.5),
103+
ConnectTimeMs: model.ProbDist{StdDev: 0, Mean: 0},
104+
TimeToFirstByteMs: model.ProbDist{StdDev: 6, Mean: 10},
105+
BandwidthBps: model.ProbDist{StdDev: 1e6, Mean: 1e8}, // Mean of 100Mb/s +/- 1MB/s
106+
LatencyMs: model.ProbDist{StdDev: 1, Mean: 20},
107+
},
108+
},
109+
}
110+
111+
HTTP_MEDIUM_FLAKY_SOME_POPULAR_DATA = model.Provider{
112+
Name: "http medium, semi-reliable, lots of popular data", // e-ipfs?
113+
Probabilities: map[multicodec.Code]model.Probabilities{
114+
multicodec.TransportIpfsGatewayHttp: {
115+
Candidate: model.Chance(0.7),
116+
Success: model.Chance(0.6),
117+
ConnectTimeMs: model.ProbDist{StdDev: 0, Mean: 0},
118+
TimeToFirstByteMs: model.ProbDist{StdDev: 6, Mean: 10},
119+
BandwidthBps: model.ProbDist{StdDev: 1e6, Mean: 1e7}, // Mean of 10MB/s +/- 1MB/s
120+
LatencyMs: model.ProbDist{StdDev: 10, Mean: 40},
121+
},
122+
},
123+
}
124+
)
125+
126+
func main() {
127+
seed := time.Now().UnixNano()
128+
switch len(os.Args) {
129+
case 1:
130+
case 2:
131+
// first arg is a seed if it's a number
132+
if s, err := strconv.ParseInt(os.Args[1], 10, 64); err == nil {
133+
seed = s
134+
} else {
135+
fmt.Println("Usage: go run main.go [seed]")
136+
os.Exit(1)
137+
}
138+
default:
139+
fmt.Println("Usage: go run main.go [seed]")
140+
os.Exit(1)
141+
}
142+
143+
simRand := rand.New(rand.NewSource(seed))
144+
145+
// TODO: generate static population up-front with fixed characteristics
146+
pop := &model.Population{}
147+
pop.Add(GRAPHSYNC_FAST_RELIABLE_LOTS_OF_POPULAR_DATA, 4)
148+
pop.Add(GRAPHSYNC_MEDIUM_RELIABLE_SOME_POPULAR_DATA, 20)
149+
pop.Add(GRAPHSYNC_MEDIUM_UNRELIABLE_SOME_POPULAR_DATA, 20)
150+
pop.Add(GRAPHSYNC_MEDIUM_RELIABLE_MINIMAL_POPULAR_DATA, 50)
151+
pop.Add(HTTP_FAST_SEMIRELIABLE_LOTS_OF_POPULAR_DATA, 1)
152+
153+
sim := model.Simulation{
154+
Population: pop,
155+
Retrievals: 50000,
156+
RetrievalSize: model.ProbDist{StdDev: 2e7, Mean: 1e7}, // Mean of 20MB +/- 10MB
157+
HttpChance: model.Chance(0.5),
158+
GraphsyncChance: model.Chance(0.5),
159+
}
160+
161+
ret := sim.Run(simRand)
162+
cfg := session.DefaultConfig()
163+
cfg.Random = simRand
164+
ses := session.NewSession(cfg, true)
165+
res := ret.RunWith(simRand, ses)
166+
167+
fmt.Println("---------------------------------------------------------------")
168+
fmt.Println("Simulation of of", len(ret), "retrievals, seed:", seed)
169+
fmt.Println()
170+
fmt.Printf("\t Size per retrieval: %s < %s < %s\n", humanize.IBytes(uint64(ret.MinSize())), humanize.IBytes(uint64(ret.AvgSize())), humanize.IBytes(uint64(ret.MaxSize())))
171+
fmt.Printf("\tCandidate per retrieval: %s < %s < %s\n", humanize.Comma(int64(ret.MinCandidateCount())), humanize.Comma(int64(ret.AvgCandidateCount())), humanize.Comma(int64(ret.MaxCandidateCount())))
172+
fmt.Println("---------------------------------------------------------------")
173+
fmt.Printf("\t Runs: %d\n", res.Runs)
174+
fmt.Printf("\t Successes: %d\n", res.Successes)
175+
fmt.Printf("\t Retrieval failures: %d\n", res.RetrievalFailures)
176+
fmt.Printf("\t Size: %s\n", humanize.IBytes(uint64(res.Size)))
177+
fmt.Printf("\t Total time: %v\n", time.Duration(res.TotalTimeMs)*time.Millisecond)
178+
fmt.Printf("\t Average TTFB: %s\n", time.Duration(res.AverageTimeToFirstByteMs)*time.Millisecond)
179+
fmt.Printf("\t Average bandwidth: %s/s\n", humanize.IBytes(uint64(res.AverageBandwidth)))
180+
fmt.Printf("\t Total bandwidth: %s/s\n", humanize.IBytes(uint64(res.Size)/uint64(res.TotalTimeMs/1000)))
181+
fmt.Println("---------------------------------------------------------------")
182+
}

pkg/session/model/pop.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package model
2+
3+
import "github.com/multiformats/go-multicodec"
4+
5+
type Provider struct {
6+
Name string
7+
Probabilities map[multicodec.Code]Probabilities
8+
}
9+
10+
type Population struct {
11+
Providers []PC
12+
}
13+
14+
type PC struct {
15+
Provider Provider
16+
Count int
17+
}
18+
19+
func (p *Population) Add(provider Provider, count int) {
20+
if p.Providers == nil {
21+
p.Providers = make([]PC, 0)
22+
}
23+
p.Providers = append(p.Providers, PC{Provider: provider, Count: count})
24+
}

pkg/session/model/prob.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package model
2+
3+
import "math/rand"
4+
5+
// Probabilities defines the probabilistic behaviour of a provider for a
6+
// particular protocol
7+
type Probabilities struct {
8+
// Probability of being a candidate for any given retrieval [0,1]
9+
Candidate Chance
10+
// Probability of a successful retrieval [0,1]
11+
Success Chance
12+
// Distribution for connect time in milliseconds
13+
ConnectTimeMs ProbDist
14+
// Distribution for time to first byte in milliseconds
15+
TimeToFirstByteMs ProbDist
16+
// Distribution in bandwidth in bytes per second, this has to account for
17+
// block fetching speed on the remote, not just the pipe
18+
BandwidthBps ProbDist
19+
// Distribution for latency in milliseconds, this will be multiplied to
20+
// simulate connection initialisation round-trips
21+
LatencyMs ProbDist
22+
// Probability of having FastRetrieval for a graphsync retrieval [0,1]
23+
FastRetrieval Chance
24+
// Probability of having Verified for a graphsync retrieval [0,1]
25+
Verified Chance
26+
}
27+
28+
type ProbDist struct {
29+
StdDev float64
30+
Mean float64
31+
}
32+
33+
func (pd ProbDist) Sample(rand *rand.Rand) float64 {
34+
return rand.NormFloat64()*pd.StdDev + pd.Mean
35+
}
36+
37+
// Chance is the probability of a Roll() being true, the higher the value in the
38+
// range [0,1] the more likely it is to be true.
39+
type Chance float64
40+
41+
func (c Chance) Roll(rand *rand.Rand) bool {
42+
return rand.Float64() < float64(c)
43+
}
44+
45+
const FIFTY_FIFTY = Chance(0.5)

0 commit comments

Comments
 (0)