Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update pgu #151

Merged
merged 4 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions app/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@ type OkbcConfig struct {
maxGasUsedPerBlock int64
// mempool.enable-pgu
enablePGU bool
// mempool.pgu-percentage-threshold
pguPercentageThreshold int64
// mempool.pgu-concurrency
pguConcurrency int
// mempool.pgu-adjustment
pguAdjustment float64
// mempool.pgu-persist
pguPersist bool
// mempool.node_key_whitelist
nodeKeyWhitelist []string
//mempool.check_tx_cost
Expand Down Expand Up @@ -135,7 +141,10 @@ const (
FlagMaxTxNumPerBlock = "mempool.max_tx_num_per_block"
FlagMaxGasUsedPerBlock = "mempool.max_gas_used_per_block"
FlagEnablePGU = "mempool.enable-pgu"
FlagPGUPercentageThreshold = "mempool.pgu-percentage-threshold"
FlagPGUConcurrency = "mempool.pgu-concurrency"
FlagPGUAdjustment = "mempool.pgu-adjustment"
FlagPGUPersist = "mempool.pgu-persist"
FlagNodeKeyWhitelist = "mempool.node_key_whitelist"
FlagMempoolCheckTxCost = "mempool.check_tx_cost"
FlagMempoolEnableDeleteMinGPTx = "mempool.enable_delete_min_gp_tx"
Expand Down Expand Up @@ -277,7 +286,10 @@ func (c *OkbcConfig) loadFromConfig() {
c.SetEnableDeleteMinGPTx(viper.GetBool(FlagMempoolEnableDeleteMinGPTx))
c.SetMaxGasUsedPerBlock(viper.GetInt64(FlagMaxGasUsedPerBlock))
c.SetEnablePGU(viper.GetBool(FlagEnablePGU))
c.SetPGUPercentageThreshold(viper.GetInt64(FlagPGUPercentageThreshold))
c.SetPGUConcurrency(viper.GetInt(FlagPGUConcurrency))
c.SetPGUAdjustment(viper.GetFloat64(FlagPGUAdjustment))
c.SetPGUPersist(viper.GetBool(FlagPGUPersist))
c.SetGasLimitBuffer(viper.GetUint64(FlagGasLimitBuffer))

c.SetEnableDynamicGp(viper.GetBool(FlagEnableDynamicGp))
Expand Down Expand Up @@ -484,12 +496,30 @@ func (c *OkbcConfig) updateFromKVStr(k, v string) {
return
}
c.SetEnablePGU(r)
case FlagPGUPercentageThreshold:
r, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return
}
c.SetPGUPercentageThreshold(r)
case FlagPGUConcurrency:
r, err := strconv.Atoi(v)
if err != nil {
return
}
c.SetPGUConcurrency(r)
case FlagPGUAdjustment:
r, err := strconv.ParseFloat(v, 64)
if err != nil {
return
}
c.SetPGUAdjustment(r)
case FlagPGUPersist:
r, err := strconv.ParseBool(v)
if err != nil {
return
}
c.SetPGUPersist(r)
case FlagGasLimitBuffer:
r, err := strconv.ParseUint(v, 10, 64)
if err != nil {
Expand Down Expand Up @@ -802,6 +832,22 @@ func (c *OkbcConfig) SetEnablePGU(value bool) {
c.enablePGU = value
}

func (c *OkbcConfig) GetPGUPercentageThreshold() int64 {
return c.pguPercentageThreshold
}

func (c *OkbcConfig) SetPGUPercentageThreshold(value int64) {
c.pguPercentageThreshold = value
}

func (c *OkbcConfig) GetPGUConcurrency() int {
return c.pguConcurrency
}

func (c *OkbcConfig) SetPGUConcurrency(value int) {
c.pguConcurrency = value
}

func (c *OkbcConfig) GetPGUAdjustment() float64 {
return c.pguAdjustment
}
Expand All @@ -810,6 +856,14 @@ func (c *OkbcConfig) SetPGUAdjustment(value float64) {
c.pguAdjustment = value
}

func (c *OkbcConfig) GetPGUPersist() bool {
return c.pguPersist
}

func (c *OkbcConfig) SetPGUPersist(value bool) {
c.pguPersist = value
}

func (c *OkbcConfig) GetGasLimitBuffer() uint64 {
return c.gasLimitBuffer
}
Expand Down
27 changes: 22 additions & 5 deletions libs/cosmos-sdk/baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -997,25 +997,42 @@ func (app *BaseApp) GetRealTxFromRawTx(rawTx tmtypes.Tx) abci.TxEssentials {
return nil
}

func (app *BaseApp) GetTxHistoryGasUsed(rawTx tmtypes.Tx) int64 {
func (app *BaseApp) GetTxHistoryGasUsed(rawTx tmtypes.Tx, gasLimit int64) (int64, bool) {
tx, err := app.txDecoder(rawTx)
if err != nil {
return -1
return -1, false
}

txFnSig, toDeployContractSize := tx.GetTxFnSignatureInfo()
if txFnSig == nil {
return -1
return -1, false
}

hgu := InstanceOfHistoryGasUsedRecordDB().GetHgu(txFnSig)
if hgu == nil {
return -1, false
}
precise := true
if hgu.BlockNum < preciseBlockNum ||
(hgu.MaxGas-hgu.MovingAverageGas)*100/hgu.MovingAverageGas > cfg.DynamicConfig.GetPGUPercentageThreshold() ||
(hgu.MovingAverageGas-hgu.MinGas)*100/hgu.MinGas > cfg.DynamicConfig.GetPGUPercentageThreshold() {
precise = false
}

var gasWanted int64
if toDeployContractSize > 0 {
// if deploy contract case, the history gas used value is unit gas used
return hgu*int64(toDeployContractSize) + int64(1000)
gasWanted = hgu.MovingAverageGas*int64(toDeployContractSize) + int64(1000)
} else {
gasWanted = hgu.MovingAverageGas
}

// hgu gas can not be greater than gasLimit
if gasWanted > gasLimit {
gasWanted = gasLimit
}

return hgu
return gasWanted, precise
}

func (app *BaseApp) MsgServiceRouter() *MsgServiceRouter { return app.msgServiceRouter }
Expand Down
99 changes: 64 additions & 35 deletions libs/cosmos-sdk/baseapp/gasuseddb.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package baseapp

import (
"encoding/binary"
"log"
"path/filepath"
"sync"

"github.com/gogo/protobuf/proto"
lru "github.com/hashicorp/golang-lru"
"github.com/okx/okbchain/libs/cosmos-sdk/client/flags"
sdk "github.com/okx/okbchain/libs/cosmos-sdk/types"
Expand All @@ -17,13 +18,15 @@ const (
HistoryGasUsedDBName = "hgu"

FlagGasUsedFactor = "gu_factor"
preciseBlockNum = 20
)

var (
once sync.Once
GasUsedFactor = 0.4
jobQueueLen = 10
cacheSize = 10000
once sync.Once
GasUsedFactor = 0.4
regressionFactor = 0.05
jobQueueLen = 10
cacheSize = 10000

historyGasUsedRecordDB HistoryGasUsedRecordDB
)
Expand All @@ -35,7 +38,7 @@ type gasKey struct {

type HistoryGasUsedRecordDB struct {
latestGuMtx sync.Mutex
latestGu map[string]int64
latestGu map[string][]int64
cache *lru.Cache
guDB db.DB

Expand All @@ -46,7 +49,7 @@ func InstanceOfHistoryGasUsedRecordDB() *HistoryGasUsedRecordDB {
once.Do(func() {
cache, _ := lru.New(cacheSize)
historyGasUsedRecordDB = HistoryGasUsedRecordDB{
latestGu: make(map[string]int64),
latestGu: make(map[string][]int64),
cache: cache,
guDB: initDb(),
jobQueue: make(chan func(), jobQueueLen),
Expand All @@ -58,13 +61,13 @@ func InstanceOfHistoryGasUsedRecordDB() *HistoryGasUsedRecordDB {

func (h *HistoryGasUsedRecordDB) UpdateGasUsed(key []byte, gasUsed int64) {
h.latestGuMtx.Lock()
h.latestGu[string(key)] = gasUsed
h.latestGu[string(key)] = append(h.latestGu[string(key)], gasUsed)
h.latestGuMtx.Unlock()
}

func (h *HistoryGasUsedRecordDB) GetHgu(key []byte) int64 {
func (h *HistoryGasUsedRecordDB) GetHgu(key []byte) *HguRecord {
hgu, cacheHit := h.getHgu(key)
if !cacheHit && hgu != -1 {
if hgu != nil && !cacheHit {
// add to cache before returning hgu
h.cache.Add(string(key), hgu)
}
Expand All @@ -75,43 +78,71 @@ func (h *HistoryGasUsedRecordDB) FlushHgu() {
if len(h.latestGu) == 0 {
return
}
latestGasKeys := make([]gasKey, len(h.latestGu))
index := 0
for key, gas := range h.latestGu {
latestGasKeys[index] = gasKey{
gas: gas,
latestGasKeys := make([]gasKey, 0, len(h.latestGu))
for key, allGas := range h.latestGu {
latestGasKeys = append(latestGasKeys, gasKey{
gas: meanGas(allGas),
key: key,
}
index++
})
delete(h.latestGu, key)
}
h.jobQueue <- func() { h.flushHgu(latestGasKeys...) } // closure
}

func (h *HistoryGasUsedRecordDB) getHgu(key []byte) (hgu int64, fromCache bool) {
func (h *HistoryGasUsedRecordDB) getHgu(key []byte) (hgu *HguRecord, fromCache bool) {
v, ok := h.cache.Get(string(key))
if ok {
return v.(int64), true
return v.(*HguRecord), true
}

data, err := h.guDB.Get(key)
if err != nil || len(data) == 0 {
return -1, false
return nil, false
}

return bytesToInt64(data), false
var r HguRecord
err = proto.Unmarshal(data, &r)
if err != nil {
return nil, false
}
return &r, false
}

func (h *HistoryGasUsedRecordDB) flushHgu(gks ...gasKey) {
for _, gk := range gks {
hgu, cacheHit := h.getHgu([]byte(gk.key))
// avgGas = 0.4 * newGas + 0.6 * oldGas.The value of wasm store contract is too small and need to be rounded up.
yann-sjtu marked this conversation as resolved.
Show resolved Hide resolved
avgGas := int64(GasUsedFactor*float64(gk.gas) + (1.0-GasUsedFactor)*float64(hgu) + 0.6)
// add to cache if hit
if cacheHit {
h.cache.Add(gk.key, avgGas)
if hgu == nil {
hgu = &HguRecord{
MaxGas: gk.gas,
MinGas: gk.gas,
MovingAverageGas: gk.gas,
}
} else {
// MovingAverageGas = 0.4 * newGas + 0.6 * oldMovingAverageGas
hgu.MovingAverageGas = int64(GasUsedFactor*float64(gk.gas) + (1.0-GasUsedFactor)*float64(hgu.MovingAverageGas))
// MaxGas = 0.05 * MovingAverageGas + 0.95 * oldMaxGas
hgu.MaxGas = int64(regressionFactor*float64(hgu.MovingAverageGas) + (1.0-regressionFactor)*float64(hgu.MaxGas))
// MinGas = 0.05 * MovingAverageGas + 0.95 * oldMinGas
hgu.MinGas = int64(regressionFactor*float64(hgu.MovingAverageGas) + (1.0-regressionFactor)*float64(hgu.MinGas))
hgu.BlockNum++
if gk.gas > hgu.MaxGas {
hgu.MaxGas = gk.gas
} else if gk.gas < hgu.MinGas {
hgu.MinGas = gk.gas
}
// add to cache if hit
if cacheHit {
h.cache.Add(gk.key, hgu)
}
}

data, err := proto.Marshal(hgu)
if err != nil {
log.Println("flushHgu marshal error:", err)
continue
}
h.guDB.Set([]byte(gk.key), int64ToBytes(avgGas))

h.guDB.Set([]byte(gk.key), data)
}
}

Expand All @@ -132,12 +163,10 @@ func initDb() db.DB {
return db
}

func int64ToBytes(i int64) []byte {
var buf = make([]byte, 8)
binary.BigEndian.PutUint64(buf, uint64(i))
return buf
}

func bytesToInt64(buf []byte) int64 {
return int64(binary.BigEndian.Uint64(buf))
func meanGas(allGas []int64) int64 {
var totalGas int64
for _, gas := range allGas {
totalGas += gas
}
return totalGas / int64(len(allGas))
}
Loading