Better "optimal selection

Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
Jakub Sztandera 2020-08-13 02:23:52 +02:00
parent d25f386bb5
commit f35555964d
No known key found for this signature in database
GPG Key ID: 9A9AF56F8B3879BA
3 changed files with 64 additions and 44 deletions

View File

@ -1,8 +1,15 @@
package messagepool
import "math"
import (
"math"
"sync"
)
var noWinnersProbCache []float64
var noWinnersProbOnce sync.Once
func noWinnersProb() []float64 {
noWinnersProbOnce.Do(func() {
poissPdf := func(x float64) float64 {
const Mu = 5
lg, _ := math.Lgamma(x + 1)
@ -14,7 +21,9 @@ func noWinnersProb() []float64 {
for i := 0; i < MaxBlocks; i++ {
out = append(out, poissPdf(float64(i)))
}
return out
noWinnersProbCache = out
})
return noWinnersProbCache
}
func binomialCoefficient(n, k float64) float64 {

View File

@ -28,6 +28,7 @@ type msgChain struct {
gasPerf float64
effPerf float64
bp float64
parentOffset float64
valid bool
merged bool
next *msgChain
@ -153,7 +154,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
last := len(chains)
for i, chain := range chains {
// did we run out of performing chains?
if chain.gasPerf < 0 {
if chain.effPerf < 0 {
break
}
@ -176,12 +177,22 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
for i := len(chainDeps) - 1; i >= 0; i-- {
curChain := chainDeps[i]
curChain.merged = true
if next := curChain.next; next != nil {
next.effPerf += next.parentOffset
}
result = append(result, curChain.msgs...)
}
chain.merged = true
if next := chain.next; next != nil {
next.effPerf += next.parentOffset
}
result = append(result, chain.msgs...)
gasLimit -= chainGasLimit
sort.Slice(chains[i+1:], func(i, j int) bool {
return chains[i].BeforeEffective(chains[j])
})
continue
}
@ -852,7 +863,9 @@ func (mc *msgChain) SetEffectivePerf(bp float64) {
func (mc *msgChain) setEffPerf() {
effPerf := mc.gasPerf * mc.bp
if mc.prev != nil {
effPerf = (effPerf*float64(mc.gasLimit) + mc.prev.effPerf*float64(mc.prev.gasLimit)) / float64(mc.gasLimit+mc.prev.gasLimit)
effPerfWithParent := (effPerf*float64(mc.gasLimit) + mc.prev.effPerf*float64(mc.prev.gasLimit)) / float64(mc.gasLimit+mc.prev.gasLimit)
mc.parentOffset = effPerf - effPerfWithParent
effPerf = effPerfWithParent
}
mc.effPerf = effPerf
@ -867,7 +880,8 @@ func (mc *msgChain) SetNullEffectivePerf() {
}
func (mc *msgChain) BeforeEffective(other *msgChain) bool {
return mc.effPerf > other.effPerf ||
// moved merged chains to the front so we can discard them earlier
return (mc.merged && !other.merged) || mc.effPerf > other.effPerf ||
(mc.effPerf == other.effPerf && mc.gasPerf > other.gasPerf) ||
(mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
}

View File

@ -919,6 +919,8 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) {
t.Fatal(err)
}
logging.SetLogLevel("messagepool", "error")
for i := 0; i < 50; i++ {
// 2. optimal selection
minersRand := rng.Float64()
winerProba := noWinnersProb()
@ -931,8 +933,6 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) {
nMiners = 1
}
logging.SetLogLevel("messagepool", "error")
for i := 0; i < 1; i++ {
optMsgs := make(map[cid.Cid]*types.SignedMessage)
for j := 0; j < nMiners; j++ {
tq := rng.Float64()
@ -946,7 +946,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) {
}
t.Logf("nMiners: %d", nMiners)
t.Logf("greedy capacity %d, optimal capacity %d (x%.1f)", len(greedyMsgs),
t.Logf("greedy capacity %d, optimal capacity %d (x %.1f )", len(greedyMsgs),
len(optMsgs), float64(len(optMsgs))/float64(len(greedyMsgs)))
if len(greedyMsgs) > len(optMsgs) {
t.Fatal("greedy capacity higher than optimal capacity; wtf")
@ -965,18 +965,15 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) {
nMinersBig := big.NewInt(int64(nMiners))
greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64()
optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, nMinersBig).Float64()
t.Logf("greedy reward: %.0f, optimal reward: %.0f (x%.1f)", greedyAvgReward,
t.Logf("greedy reward: %.0f, optimal reward: %.0f (x %.1f )", greedyAvgReward,
optimalAvgReward, optimalAvgReward/greedyAvgReward)
if greedyReward.Cmp(optReward) > 0 {
t.Fatal("greedy reward raw higher than optimal reward; booh")
}
}
logging.SetLogLevel("messagepool", "info")
}
func TestCompetitiveMessageSelection(t *testing.T) {
seeds := []int64{1947, 1976, 2020, 2100, 10000}
seeds := []int64{1947, 1976, 2020, 2100, 10000, 143324, 432432, 131, 32, 45}
for _, seed := range seeds {
t.Log("running competitve message selection with seed", seed)
testCompetitiveMessageSelection(t, rand.New(rand.NewSource(seed)))