Less allocations on SplitReward by default, small speedup changes

This commit is contained in:
DataHoarder 2023-07-12 12:32:02 +02:00
parent 894ebbba1b
commit c3cf2161bd
Signed by: DataHoarder
SSH key fingerprint: SHA256:OLTRf6Fl87G52SiR7sWLGNzlJt4WOX+tfI2yxo0z7xk
6 changed files with 45 additions and 18 deletions

View file

@ -589,7 +589,7 @@ func (b *PoolBlock) PreProcessBlock(consensus *Consensus, derivationCache Deriva
}
if len(b.Main.Coinbase.Outputs) == 0 {
if outputs, _ := CalculateOutputs(b, consensus, difficultyByHeight, getTemplateById, derivationCache, preAllocatedShares); outputs == nil {
if outputs, _ := CalculateOutputs(b, consensus, difficultyByHeight, getTemplateById, derivationCache, preAllocatedShares, nil); outputs == nil {
return nil, errors.New("error filling outputs for block: nil outputs")
} else {
b.Main.Coinbase.Outputs = outputs

View file

@ -45,14 +45,16 @@ func (s Shares) Clone() (o Shares) {
// Compact Merges duplicate Share entries based on Address
// len(s) must be greater than 0
func (s Shares) Compact() Shares {
if len(s) == 0 {
return s
}
// Sort shares based on address
s.Sort()
index := 0
for i, share := range s {
if i == 0 {
continue
}
for _, share := range s[1:] {
if s[index].Address == share.Address {
s[index].Weight = s[index].Weight.Add(share.Weight)
} else {

View file

@ -85,6 +85,7 @@ type SideChain struct {
precalcFinished atomic.Bool
preAllocatedShares Shares
preAllocatedRewards []uint64
preAllocatedSharesPool *PreAllocatedSharesPool
preAllocatedDifficultyData []DifficultyData
preAllocatedDifficultyDifferences []uint32
@ -98,6 +99,7 @@ func NewSideChain(server P2PoolInterface) *SideChain {
blocksByTemplateId: swiss.NewMap[types.Hash, *PoolBlock](uint32(server.Consensus().ChainWindowSize*2 + 300)),
blocksByHeight: swiss.NewMap[uint64, []*PoolBlock](uint32(server.Consensus().ChainWindowSize*2 + 300)),
preAllocatedShares: PreAllocateShares(server.Consensus().ChainWindowSize * 2),
preAllocatedRewards: make([]uint64, 0, server.Consensus().ChainWindowSize*2),
preAllocatedDifficultyData: make([]DifficultyData, 0, server.Consensus().ChainWindowSize*2),
preAllocatedDifficultyDifferences: make([]uint32, 0, server.Consensus().ChainWindowSize*2),
preAllocatedSharesPool: NewPreAllocatedSharesPool(server.Consensus().ChainWindowSize * 2),
@ -736,7 +738,7 @@ func (c *SideChain) verifyBlock(block *PoolBlock) (verification error, invalid e
return
}(); totalReward != block.Main.Coinbase.TotalReward {
return nil, fmt.Errorf("invalid total reward, got %d, expected %d", block.Main.Coinbase.TotalReward, totalReward)
} else if rewards := SplitReward(totalReward, shares); len(rewards) != len(block.Main.Coinbase.Outputs) {
} else if rewards := SplitReward(c.preAllocatedRewards, totalReward, shares); len(rewards) != len(block.Main.Coinbase.Outputs) {
return nil, fmt.Errorf("invalid number of outputs, got %d, expected %d", len(block.Main.Coinbase.Outputs), len(rewards))
} else {
@ -1016,10 +1018,12 @@ func (c *SideChain) GetMissingBlocks() []types.Hash {
return missingBlocks
}
// calculateOutputs
// Deprecated
func (c *SideChain) calculateOutputs(block *PoolBlock) (outputs transaction.Outputs, bottomHeight uint64) {
preAllocatedShares := c.preAllocatedSharesPool.Get()
defer c.preAllocatedSharesPool.Put(preAllocatedShares)
return CalculateOutputs(block, c.Consensus(), c.server.GetDifficultyByHeight, c.getPoolBlockByTemplateId, c.derivationCache, preAllocatedShares)
return CalculateOutputs(block, c.Consensus(), c.server.GetDifficultyByHeight, c.getPoolBlockByTemplateId, c.derivationCache, preAllocatedShares, c.preAllocatedRewards)
}
func (c *SideChain) Server() P2PoolInterface {

View file

@ -268,7 +268,7 @@ func BenchmarkSideChainDefault_CalculateOutputs(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
outputs, _ := benchLoadedSideChain.calculateOutputs(tip)
outputs, _ := CalculateOutputs(tip, benchLoadedSideChain.Consensus(), benchLoadedSideChain.server.GetDifficultyByHeight, benchLoadedSideChain.getPoolBlockByTemplateId, benchLoadedSideChain.derivationCache, benchLoadedSideChain.preAllocatedShares, benchLoadedSideChain.preAllocatedRewards)
if outputs == nil {
b.Error("nil outputs")
return
@ -291,6 +291,24 @@ func BenchmarkSideChainDefault_GetShares(b *testing.B) {
}
}
func BenchmarkSideChainDefault_SplitReward(b *testing.B) {
b.ReportAllocs()
tip := benchLoadedSideChain.GetChainTip()
shares, _ := benchLoadedSideChain.getShares(tip, benchLoadedSideChain.preAllocatedShares)
preAllocatedRewards := make([]uint64, 0, len(shares))
b.ResetTimer()
for i := 0; i < b.N; i++ {
rewards := SplitReward(preAllocatedRewards, tip.Main.Coinbase.TotalReward, shares)
if rewards == nil {
b.Error("nil rewards")
return
}
}
}
func BenchmarkSideChainDefault_BlocksInPPLNSWindow(b *testing.B) {
b.ReportAllocs()
tip := benchLoadedSideChain.GetChainTip()

View file

@ -24,7 +24,7 @@ type SideData struct {
Difficulty types.Difficulty
CumulativeDifficulty types.Difficulty
// ExtraBuffer available in ShareVersion ShareVersion_2 and above
// ExtraBuffer available in ShareVersion ShareVersion_V2 and above
ExtraBuffer struct {
SoftwareId p2pooltypes.SoftwareId
SoftwareVersion p2pooltypes.SoftwareVersion

View file

@ -25,9 +25,12 @@ type GetBySideHeightFunc func(height uint64) UniquePoolBlockSlice
// GetChainMainByHashFunc if h = types.ZeroHash, return tip
type GetChainMainByHashFunc func(h types.Hash) *ChainMain
func CalculateOutputs(block *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, derivationCache DerivationCacheInterface, preAllocatedShares Shares) (outputs transaction.Outputs, bottomHeight uint64) {
func CalculateOutputs(block *PoolBlock, consensus *Consensus, difficultyByHeight block.GetDifficultyByHeightFunc, getByTemplateId GetByTemplateIdFunc, derivationCache DerivationCacheInterface, preAllocatedShares Shares, preAllocatedRewards []uint64) (outputs transaction.Outputs, bottomHeight uint64) {
tmpShares, bottomHeight := GetShares(block, consensus, difficultyByHeight, getByTemplateId, preAllocatedShares)
tmpRewards := SplitReward(block.Main.Coinbase.TotalReward, tmpShares)
if preAllocatedRewards == nil {
preAllocatedRewards = make([]uint64, 0, len(tmpShares))
}
tmpRewards := SplitReward(preAllocatedRewards, block.Main.Coinbase.TotalReward, tmpShares)
if tmpShares == nil || tmpRewards == nil || len(tmpRewards) != len(tmpShares) {
return nil, 0
@ -442,7 +445,11 @@ func GetDifficulty(tip *PoolBlock, consensus *Consensus, getByTemplateId GetByTe
return curDifficulty, nil, nil
}
func SplitRewardNoAllocate(preAllocatedRewards []uint64, reward uint64, shares Shares) (rewards []uint64) {
func SplitRewardAllocate(reward uint64, shares Shares) (rewards []uint64) {
return SplitReward(make([]uint64, 0, len(shares)), reward, shares)
}
func SplitReward(preAllocatedRewards []uint64, reward uint64, shares Shares) (rewards []uint64) {
var totalWeight types.Difficulty
for i := range shares {
totalWeight = totalWeight.Add(shares[i].Weight)
@ -458,8 +465,8 @@ func SplitRewardNoAllocate(preAllocatedRewards []uint64, reward uint64, shares S
var w types.Difficulty
var rewardGiven uint64
for i := range shares {
w = w.Add(shares[i].Weight)
for _, share := range shares {
w = w.Add(share.Weight)
nextValue := w.Mul64(reward).Div(totalWeight)
rewards = append(rewards, nextValue.Lo-rewardGiven)
rewardGiven = nextValue.Lo
@ -477,10 +484,6 @@ func SplitRewardNoAllocate(preAllocatedRewards []uint64, reward uint64, shares S
return rewards
}
func SplitReward(reward uint64, shares Shares) (rewards []uint64) {
return SplitRewardNoAllocate(make([]uint64, 0, len(shares)), reward, shares)
}
func IsLongerChain(block, candidate *PoolBlock, consensus *Consensus, getByTemplateId GetByTemplateIdFunc, getChainMainByHash GetChainMainByHashFunc) (isLonger, isAlternative bool) {
if candidate == nil || !candidate.Verified.Load() || candidate.Invalid.Load() {
return false, false