github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/common/perf/performance.go (about)

     1  package perf
     2  
     3  import (
     4  	"fmt"
     5  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     6  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
     7  	"github.com/fibonacci-chain/fbc/x/common/monitor"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  var (
    13  	lastHeightTimestamp int64
    14  	_                   Perf = &performance{}
    15  	_                        = info{txNum: 0, beginBlockElapse: 0,
    16  		endBlockElapse: 0, blockheight: 0, deliverTxElapse: 0, txElapseBySum: 0}
    17  )
    18  
    19  func init() {
    20  	lastHeightTimestamp = time.Now().UnixNano()
    21  }
    22  
    23  const (
    24  	orderModule        = "order"
    25  	dexModule          = "dex"
    26  	swapModule         = "ammswap"
    27  	tokenModule        = "token"
    28  	stakingModule      = "staking"
    29  	govModule          = "gov"
    30  	distributionModule = "distribution"
    31  	farmModule         = "farm"
    32  	evmModule          = "evm"
    33  	summaryFormat      = "Summary: Height<%d>, Interval<%ds>, " +
    34  		"Abci<%dms>, " +
    35  		"Tx<%d>, " +
    36  		"%s %s"
    37  
    38  	appFormat = "App: Height<%d>, " +
    39  		"BeginBlock<%dms>, " +
    40  		"DeliverTx<%dms>, " +
    41  		"txElapseBySum<%dms>, " +
    42  		"EndBlock<%dms>, " +
    43  		"Commit<%dms>, " +
    44  		"Tx<%d>" +
    45  		"%s"
    46  	moduleFormat = "Module: Height<%d>, " +
    47  		"module<%s>, " +
    48  		"BeginBlock<%dms>, " +
    49  		"DeliverTx<%dms>, " +
    50  		"TxNum<%d>, " +
    51  		"EndBlock<%dms>,"
    52  	handlerFormat = "Handler: Height<%d>, " +
    53  		"module<%s>, " +
    54  		"DeliverTx<%s>, " +
    55  		"elapsed<%dms>, " +
    56  		"invoked<%d>,"
    57  )
    58  
    59  var perf *performance
    60  var once sync.Once
    61  
    62  // GetPerf gets the single instance of performance
    63  func GetPerf() Perf {
    64  	once.Do(func() {
    65  		perf = newPerf()
    66  	})
    67  	return perf
    68  }
    69  
    70  // Perf shows the expected behaviour
    71  type Perf interface {
    72  	InitChainer(logger log.Logger)
    73  
    74  	OnAppBeginBlockEnter(height int64) uint64
    75  	OnAppBeginBlockExit(height int64, seq uint64)
    76  
    77  	OnAppEndBlockEnter(height int64) uint64
    78  	OnAppEndBlockExit(height int64, seq uint64)
    79  
    80  	OnAppDeliverTxEnter(height int64) uint64
    81  	OnAppDeliverTxExit(height int64, seq uint64)
    82  
    83  	OnCommitEnter(height int64) uint64
    84  	OnCommitExit(height int64, seq uint64, logger log.Logger)
    85  
    86  	OnBeginBlockEnter(ctx sdk.Context, moduleName string) uint64
    87  	OnBeginBlockExit(ctx sdk.Context, moduleName string, seq uint64)
    88  
    89  	OnDeliverTxEnter(ctx sdk.Context, moduleName, handlerName string) uint64
    90  	OnDeliverTxExit(ctx sdk.Context, moduleName, handlerName string, seq uint64)
    91  
    92  	OnEndBlockEnter(ctx sdk.Context, moduleName string) uint64
    93  	OnEndBlockExit(ctx sdk.Context, moduleName string, seq uint64)
    94  
    95  	EnqueueMsg(msg string)
    96  	EnableCheck()
    97  }
    98  
    99  type hanlderInfo struct {
   100  	invoke          uint64
   101  	deliverTxElapse int64
   102  }
   103  
   104  type info struct {
   105  	blockheight      int64
   106  	beginBlockElapse int64
   107  	endBlockElapse   int64
   108  	txElapseBySum    int64
   109  	deliverTxElapse  int64
   110  	txNum            uint64
   111  }
   112  
   113  type moduleInfo struct {
   114  	info
   115  	data handlerInfoMapType
   116  }
   117  
   118  type appInfo struct {
   119  	info
   120  	commitElapse  int64
   121  	lastTimestamp int64
   122  	seqNum        uint64
   123  }
   124  
   125  func (app *appInfo) abciElapse() int64 {
   126  	return app.beginBlockElapse + app.endBlockElapse +
   127  		app.deliverTxElapse + app.commitElapse
   128  }
   129  
   130  type handlerInfoMapType map[string]*hanlderInfo
   131  
   132  func newHanlderMetrics() *moduleInfo {
   133  	m := &moduleInfo{
   134  		info: info{},
   135  		data: make(handlerInfoMapType),
   136  	}
   137  	return m
   138  }
   139  
   140  type performance struct {
   141  	lastTimestamp int64
   142  	seqNum        uint64
   143  
   144  	app           *appInfo
   145  	moduleInfoMap map[string]*moduleInfo
   146  	check         bool
   147  	msgQueue      []string
   148  	logger        log.Logger
   149  }
   150  
   151  func newPerf() *performance {
   152  	p := &performance{
   153  		moduleInfoMap: make(map[string]*moduleInfo),
   154  	}
   155  
   156  	p.app = &appInfo{
   157  		info: info{},
   158  	}
   159  	p.moduleInfoMap[orderModule] = newHanlderMetrics()
   160  	p.moduleInfoMap[dexModule] = newHanlderMetrics()
   161  	p.moduleInfoMap[swapModule] = newHanlderMetrics()
   162  	p.moduleInfoMap[tokenModule] = newHanlderMetrics()
   163  	p.moduleInfoMap[govModule] = newHanlderMetrics()
   164  	p.moduleInfoMap[distributionModule] = newHanlderMetrics()
   165  	p.moduleInfoMap[stakingModule] = newHanlderMetrics()
   166  	p.moduleInfoMap[farmModule] = newHanlderMetrics()
   167  	p.moduleInfoMap[evmModule] = newHanlderMetrics()
   168  
   169  	p.check = false
   170  
   171  	return p
   172  }
   173  
   174  ////////////////////////////////////////////////////////////////////////////////////
   175  
   176  func (p *performance) InitChainer(logger log.Logger) {
   177  	//p.logger = logger.With("module", "perf")
   178  }
   179  
   180  func (p *performance) EnableCheck() {
   181  	p.check = true
   182  }
   183  
   184  func (p *performance) EnqueueMsg(msg string) {
   185  	p.msgQueue = append(p.msgQueue, msg)
   186  }
   187  
   188  func (p *performance) OnAppBeginBlockEnter(height int64) uint64 {
   189  	p.msgQueue = nil
   190  	p.app.blockheight = height
   191  	p.app.seqNum++
   192  	p.app.lastTimestamp = time.Now().UnixNano()
   193  
   194  	return p.app.seqNum
   195  }
   196  
   197  func (p *performance) OnAppBeginBlockExit(height int64, seq uint64) {
   198  	p.sanityCheckApp(height, seq)
   199  	p.app.beginBlockElapse = time.Now().UnixNano() - p.app.lastTimestamp
   200  }
   201  
   202  ////////////////////////////////////////////////////////////////////////////////////
   203  
   204  func (p *performance) OnAppEndBlockEnter(height int64) uint64 {
   205  	p.sanityCheckApp(height, p.app.seqNum)
   206  
   207  	p.app.seqNum++
   208  	p.app.lastTimestamp = time.Now().UnixNano()
   209  
   210  	return p.app.seqNum
   211  }
   212  
   213  func (p *performance) OnAppEndBlockExit(height int64, seq uint64) {
   214  	p.sanityCheckApp(height, seq)
   215  	p.app.endBlockElapse = time.Now().UnixNano() - p.app.lastTimestamp
   216  }
   217  
   218  // ////////////////////////////////////////////////////////////////
   219  func (p *performance) OnAppDeliverTxEnter(height int64) uint64 {
   220  	p.sanityCheckApp(height, p.app.seqNum)
   221  
   222  	p.app.seqNum++
   223  	p.app.lastTimestamp = time.Now().UnixNano()
   224  
   225  	return p.app.seqNum
   226  }
   227  
   228  func (p *performance) OnAppDeliverTxExit(height int64, seq uint64) {
   229  	p.sanityCheckApp(height, seq)
   230  	p.app.deliverTxElapse += time.Now().UnixNano() - p.app.lastTimestamp
   231  }
   232  
   233  ////////////////////////////////////////////////////////////////////////////////////
   234  
   235  func (p *performance) OnBeginBlockEnter(ctx sdk.Context, moduleName string) uint64 {
   236  	p.lastTimestamp = time.Now().UnixNano()
   237  	p.seqNum++
   238  
   239  	m := p.getModule(moduleName)
   240  	if m == nil {
   241  		return 0
   242  	}
   243  	m.blockheight = ctx.BlockHeight()
   244  
   245  	return p.seqNum
   246  }
   247  
   248  func (p *performance) OnBeginBlockExit(ctx sdk.Context, moduleName string, seq uint64) {
   249  	p.sanityCheck(ctx, seq)
   250  	m := p.getModule(moduleName)
   251  	if m == nil {
   252  		return
   253  	}
   254  	m.beginBlockElapse = time.Now().UnixNano() - p.lastTimestamp
   255  }
   256  
   257  // //////////////////////////////////////////////////////////////////////////////////
   258  func (p *performance) OnEndBlockEnter(ctx sdk.Context, moduleName string) uint64 {
   259  	p.lastTimestamp = time.Now().UnixNano()
   260  	p.seqNum++
   261  
   262  	m := p.getModule(moduleName)
   263  	if m == nil {
   264  		return 0
   265  	}
   266  	m.blockheight = ctx.BlockHeight()
   267  
   268  	return p.seqNum
   269  }
   270  
   271  func (p *performance) OnEndBlockExit(ctx sdk.Context, moduleName string, seq uint64) {
   272  	p.sanityCheck(ctx, seq)
   273  	m := p.getModule(moduleName)
   274  	if m == nil {
   275  		return
   276  	}
   277  	m.endBlockElapse = time.Now().UnixNano() - p.lastTimestamp
   278  }
   279  
   280  ////////////////////////////////////////////////////////////////////////////////////
   281  
   282  func (p *performance) OnDeliverTxEnter(ctx sdk.Context, moduleName, handlerName string) uint64 {
   283  	if ctx.IsCheckTx() {
   284  		return 0
   285  	}
   286  
   287  	m := p.getModule(moduleName)
   288  	if m == nil {
   289  		return 0
   290  	}
   291  	m.blockheight = ctx.BlockHeight()
   292  
   293  	_, ok := m.data[handlerName]
   294  	if !ok {
   295  		m.data[handlerName] = &hanlderInfo{}
   296  	}
   297  
   298  	p.lastTimestamp = time.Now().UnixNano()
   299  	p.seqNum++
   300  	return p.seqNum
   301  }
   302  
   303  func (p *performance) OnDeliverTxExit(ctx sdk.Context, moduleName, handlerName string, seq uint64) {
   304  	if ctx.IsCheckTx() {
   305  		return
   306  	}
   307  	p.sanityCheck(ctx, seq)
   308  
   309  	m := p.getModule(moduleName)
   310  	if m == nil {
   311  		return
   312  	}
   313  	info, ok := m.data[handlerName]
   314  	if !ok {
   315  		//should never panic in performance monitoring
   316  		return
   317  	}
   318  	info.invoke++
   319  
   320  	elapse := time.Now().UnixNano() - p.lastTimestamp
   321  
   322  	info.deliverTxElapse += elapse
   323  
   324  	m.txNum++
   325  	m.deliverTxElapse += elapse
   326  
   327  	p.app.txNum++
   328  	p.app.txElapseBySum += elapse
   329  }
   330  
   331  ////////////////////////////////////////////////////////////////////////////////////
   332  
   333  func (p *performance) OnCommitEnter(height int64) uint64 {
   334  	p.sanityCheckApp(height, p.app.seqNum)
   335  
   336  	p.app.lastTimestamp = time.Now().UnixNano()
   337  	p.app.seqNum++
   338  	return p.app.seqNum
   339  }
   340  
   341  func (p *performance) OnCommitExit(height int64, seq uint64, l log.Logger) {
   342  
   343  	logger := p.logger
   344  	if logger == nil {
   345  		return
   346  	}
   347  
   348  	p.sanityCheckApp(height, seq)
   349  	// by millisecond
   350  	unit := int64(1e6)
   351  	p.app.commitElapse = time.Now().UnixNano() - p.app.lastTimestamp
   352  
   353  	var moduleInfo string
   354  	for moduleName, m := range p.moduleInfoMap {
   355  		handlerElapse := m.deliverTxElapse / unit
   356  		blockElapse := (m.beginBlockElapse + m.endBlockElapse) / unit
   357  		if blockElapse == 0 && m.txNum == 0 {
   358  			continue
   359  		}
   360  		moduleInfo += fmt.Sprintf(", %s[handler<%dms>, (begin+end)block<%dms>, tx<%d>]", moduleName, handlerElapse, blockElapse,
   361  			m.txNum)
   362  
   363  		logger.Info(fmt.Sprintf(moduleFormat, m.blockheight, moduleName, m.beginBlockElapse/unit, m.deliverTxElapse/unit,
   364  			m.txNum, m.endBlockElapse/unit))
   365  
   366  		for hanlderName, info := range m.data {
   367  			logger.Info(fmt.Sprintf(handlerFormat, m.blockheight, moduleName, hanlderName, info.deliverTxElapse/unit, info.invoke))
   368  		}
   369  	}
   370  
   371  	logger.Info(fmt.Sprintf(appFormat, p.app.blockheight,
   372  		p.app.beginBlockElapse/unit,
   373  		p.app.deliverTxElapse/unit,
   374  		p.app.txElapseBySum/unit,
   375  		p.app.endBlockElapse/unit,
   376  		p.app.commitElapse/unit,
   377  		p.app.txNum,
   378  		moduleInfo))
   379  
   380  	interval := (time.Now().UnixNano() - lastHeightTimestamp) / unit / 1e3
   381  	lastHeightTimestamp = time.Now().UnixNano()
   382  
   383  	// tendermint monitor
   384  	tendermintMonitor := monitor.GetTendermintMonitor()
   385  	if err := tendermintMonitor.Run(height); err != nil {
   386  		logger.Error("fail to get tendermint monitoring info: %s", err.Error())
   387  	}
   388  
   389  	// port monitor
   390  	portMonitor := monitor.GetPortMonitor()
   391  	if err := portMonitor.Run(); err != nil {
   392  		logger.Error("fail to get port monitoring info: %s", err.Error())
   393  	}
   394  
   395  	//set portMetrics by portMonitor
   396  	monitor.GetPortMetrics().SetConnectingNums(portMonitor.GetConnectingMap())
   397  
   398  	// format monitor result
   399  	monitorsRes := monitor.CombineMonitorsRes(tendermintMonitor.GetResultString(), portMonitor.GetResultString())
   400  
   401  	if len(p.msgQueue) == 0 {
   402  		p.EnqueueMsg("")
   403  	}
   404  
   405  	for _, e := range p.msgQueue {
   406  		logger.Info(fmt.Sprintf(summaryFormat,
   407  			p.app.blockheight,
   408  			interval,
   409  			p.app.abciElapse()/unit,
   410  			p.app.txNum,
   411  			monitorsRes,
   412  			e,
   413  		))
   414  	}
   415  
   416  	p.msgQueue = nil
   417  
   418  	p.app = &appInfo{seqNum: p.app.seqNum}
   419  	p.moduleInfoMap[orderModule] = newHanlderMetrics()
   420  	p.moduleInfoMap[dexModule] = newHanlderMetrics()
   421  	p.moduleInfoMap[swapModule] = newHanlderMetrics()
   422  	p.moduleInfoMap[tokenModule] = newHanlderMetrics()
   423  	p.moduleInfoMap[govModule] = newHanlderMetrics()
   424  	p.moduleInfoMap[distributionModule] = newHanlderMetrics()
   425  	p.moduleInfoMap[stakingModule] = newHanlderMetrics()
   426  	p.moduleInfoMap[farmModule] = newHanlderMetrics()
   427  	p.moduleInfoMap[evmModule] = newHanlderMetrics()
   428  }
   429  
   430  ////////////////////////////////////////////////////////////////////////////////////
   431  
   432  func (p *performance) sanityCheck(ctx sdk.Context, seq uint64) {
   433  	if !p.check {
   434  		return
   435  	}
   436  	if seq != p.seqNum {
   437  		panic("Invalid seq")
   438  	}
   439  
   440  	if ctx.BlockHeight() != p.app.blockheight {
   441  		panic("Invalid block height")
   442  	}
   443  }
   444  
   445  func (p *performance) sanityCheckApp(height int64, seq uint64) {
   446  	if !p.check {
   447  		return
   448  	}
   449  
   450  	if seq != p.app.seqNum {
   451  		panic("Invalid seq")
   452  	}
   453  
   454  	if height != p.app.blockheight {
   455  		panic("Invalid block height")
   456  	}
   457  }
   458  
   459  func (p *performance) getModule(moduleName string) *moduleInfo {
   460  
   461  	v, ok := p.moduleInfoMap[moduleName]
   462  	if !ok {
   463  		//should never panic in performance monitoring
   464  		return nil
   465  	}
   466  
   467  	return v
   468  }