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 }