Better "optimal selection
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
d25f386bb5
commit
f35555964d
@ -1,20 +1,29 @@
|
|||||||
package messagepool
|
package messagepool
|
||||||
|
|
||||||
import "math"
|
import (
|
||||||
|
"math"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var noWinnersProbCache []float64
|
||||||
|
var noWinnersProbOnce sync.Once
|
||||||
|
|
||||||
func noWinnersProb() []float64 {
|
func noWinnersProb() []float64 {
|
||||||
poissPdf := func(x float64) float64 {
|
noWinnersProbOnce.Do(func() {
|
||||||
const Mu = 5
|
poissPdf := func(x float64) float64 {
|
||||||
lg, _ := math.Lgamma(x + 1)
|
const Mu = 5
|
||||||
result := math.Exp((math.Log(Mu) * x) - lg - Mu)
|
lg, _ := math.Lgamma(x + 1)
|
||||||
return result
|
result := math.Exp((math.Log(Mu) * x) - lg - Mu)
|
||||||
}
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
out := make([]float64, 0, MaxBlocks)
|
out := make([]float64, 0, MaxBlocks)
|
||||||
for i := 0; i < MaxBlocks; i++ {
|
for i := 0; i < MaxBlocks; i++ {
|
||||||
out = append(out, poissPdf(float64(i)))
|
out = append(out, poissPdf(float64(i)))
|
||||||
}
|
}
|
||||||
return out
|
noWinnersProbCache = out
|
||||||
|
})
|
||||||
|
return noWinnersProbCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func binomialCoefficient(n, k float64) float64 {
|
func binomialCoefficient(n, k float64) float64 {
|
||||||
|
@ -22,16 +22,17 @@ var bigBlockGasLimit = big.NewInt(build.BlockGasLimit)
|
|||||||
const MaxBlocks = 15
|
const MaxBlocks = 15
|
||||||
|
|
||||||
type msgChain struct {
|
type msgChain struct {
|
||||||
msgs []*types.SignedMessage
|
msgs []*types.SignedMessage
|
||||||
gasReward *big.Int
|
gasReward *big.Int
|
||||||
gasLimit int64
|
gasLimit int64
|
||||||
gasPerf float64
|
gasPerf float64
|
||||||
effPerf float64
|
effPerf float64
|
||||||
bp float64
|
bp float64
|
||||||
valid bool
|
parentOffset float64
|
||||||
merged bool
|
valid bool
|
||||||
next *msgChain
|
merged bool
|
||||||
prev *msgChain
|
next *msgChain
|
||||||
|
prev *msgChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mp *MessagePool) SelectMessages(ts *types.TipSet, tq float64) ([]*types.SignedMessage, error) {
|
func (mp *MessagePool) SelectMessages(ts *types.TipSet, tq float64) ([]*types.SignedMessage, error) {
|
||||||
@ -153,7 +154,7 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
|
|||||||
last := len(chains)
|
last := len(chains)
|
||||||
for i, chain := range chains {
|
for i, chain := range chains {
|
||||||
// did we run out of performing chains?
|
// did we run out of performing chains?
|
||||||
if chain.gasPerf < 0 {
|
if chain.effPerf < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,12 +177,22 @@ func (mp *MessagePool) selectMessagesOptimal(curTs, ts *types.TipSet, tq float64
|
|||||||
for i := len(chainDeps) - 1; i >= 0; i-- {
|
for i := len(chainDeps) - 1; i >= 0; i-- {
|
||||||
curChain := chainDeps[i]
|
curChain := chainDeps[i]
|
||||||
curChain.merged = true
|
curChain.merged = true
|
||||||
|
if next := curChain.next; next != nil {
|
||||||
|
next.effPerf += next.parentOffset
|
||||||
|
}
|
||||||
result = append(result, curChain.msgs...)
|
result = append(result, curChain.msgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.merged = true
|
chain.merged = true
|
||||||
|
if next := chain.next; next != nil {
|
||||||
|
next.effPerf += next.parentOffset
|
||||||
|
}
|
||||||
result = append(result, chain.msgs...)
|
result = append(result, chain.msgs...)
|
||||||
gasLimit -= chainGasLimit
|
gasLimit -= chainGasLimit
|
||||||
|
|
||||||
|
sort.Slice(chains[i+1:], func(i, j int) bool {
|
||||||
|
return chains[i].BeforeEffective(chains[j])
|
||||||
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +863,9 @@ func (mc *msgChain) SetEffectivePerf(bp float64) {
|
|||||||
func (mc *msgChain) setEffPerf() {
|
func (mc *msgChain) setEffPerf() {
|
||||||
effPerf := mc.gasPerf * mc.bp
|
effPerf := mc.gasPerf * mc.bp
|
||||||
if mc.prev != nil {
|
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
|
mc.effPerf = effPerf
|
||||||
|
|
||||||
@ -867,7 +880,8 @@ func (mc *msgChain) SetNullEffectivePerf() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (mc *msgChain) BeforeEffective(other *msgChain) bool {
|
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.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
|
(mc.effPerf == other.effPerf && mc.gasPerf == other.gasPerf && mc.gasReward.Cmp(other.gasReward) > 0)
|
||||||
}
|
}
|
||||||
|
@ -919,20 +919,20 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. optimal selection
|
|
||||||
minersRand := rng.Float64()
|
|
||||||
winerProba := noWinnersProb()
|
|
||||||
i := 0
|
|
||||||
for ; i < MaxBlocks && minersRand > 0; i++ {
|
|
||||||
minersRand -= winerProba[i]
|
|
||||||
}
|
|
||||||
nMiners := i
|
|
||||||
if nMiners == 0 {
|
|
||||||
nMiners = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
logging.SetLogLevel("messagepool", "error")
|
logging.SetLogLevel("messagepool", "error")
|
||||||
for i := 0; i < 1; i++ {
|
for i := 0; i < 50; i++ {
|
||||||
|
// 2. optimal selection
|
||||||
|
minersRand := rng.Float64()
|
||||||
|
winerProba := noWinnersProb()
|
||||||
|
i := 0
|
||||||
|
for ; i < MaxBlocks && minersRand > 0; i++ {
|
||||||
|
minersRand -= winerProba[i]
|
||||||
|
}
|
||||||
|
nMiners := i
|
||||||
|
if nMiners == 0 {
|
||||||
|
nMiners = 1
|
||||||
|
}
|
||||||
|
|
||||||
optMsgs := make(map[cid.Cid]*types.SignedMessage)
|
optMsgs := make(map[cid.Cid]*types.SignedMessage)
|
||||||
for j := 0; j < nMiners; j++ {
|
for j := 0; j < nMiners; j++ {
|
||||||
tq := rng.Float64()
|
tq := rng.Float64()
|
||||||
@ -946,7 +946,7 @@ func testCompetitiveMessageSelection(t *testing.T, rng *rand.Rand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("nMiners: %d", nMiners)
|
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)))
|
len(optMsgs), float64(len(optMsgs))/float64(len(greedyMsgs)))
|
||||||
if len(greedyMsgs) > len(optMsgs) {
|
if len(greedyMsgs) > len(optMsgs) {
|
||||||
t.Fatal("greedy capacity higher than optimal capacity; wtf")
|
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))
|
nMinersBig := big.NewInt(int64(nMiners))
|
||||||
greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64()
|
greedyAvgReward, _ := new(big.Rat).SetFrac(greedyReward, nMinersBig).Float64()
|
||||||
optimalAvgReward, _ := new(big.Rat).SetFrac(optReward, 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)
|
optimalAvgReward, optimalAvgReward/greedyAvgReward)
|
||||||
|
|
||||||
if greedyReward.Cmp(optReward) > 0 {
|
|
||||||
t.Fatal("greedy reward raw higher than optimal reward; booh")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
logging.SetLogLevel("messagepool", "info")
|
logging.SetLogLevel("messagepool", "info")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompetitiveMessageSelection(t *testing.T) {
|
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 {
|
for _, seed := range seeds {
|
||||||
t.Log("running competitve message selection with seed", seed)
|
t.Log("running competitve message selection with seed", seed)
|
||||||
testCompetitiveMessageSelection(t, rand.New(rand.NewSource(seed)))
|
testCompetitiveMessageSelection(t, rand.New(rand.NewSource(seed)))
|
||||||
|
Loading…
Reference in New Issue
Block a user