1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { SpSystemTrace } from '../SpSystemTrace'; 17import { TraceRow } from '../trace/base/TraceRow'; 18import { Utils } from '../trace/base/Utils'; 19import { PerfThread } from '../../bean/PerfProfile'; 20import { HiPerfCpuStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfCPU2'; 21import { 22 HiPerfCallChartRender, 23 HiPerfCallChartStruct, 24} from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfCallChart'; 25import { HiPerfThreadStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfThread2'; 26import { HiPerfProcessStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfProcess2'; 27import { info } from '../../../log/Log'; 28import { HiPerfEventStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfEvent'; 29import { perfDataQuery } from './PerfDataQuery'; 30import { type HiPerfReportStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfReport'; 31import { folderThreadHandler, getRowContext, rowThreadHandler, SpChartManager } from './SpChartManager'; 32import { HiperfCpuRender2 } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfCPU2'; 33import { hiperfCpuDataSender } from '../../database/data-trafic/hiperf/HiperfCpuDataSender'; 34import { hiperfProcessDataSender } from '../../database/data-trafic/hiperf/HiperfProcessDataSender'; 35import { HiperfProcessRender2 } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfProcess2'; 36import { hiperfThreadDataSender } from '../../database/data-trafic/hiperf/HiperfThreadDataSender'; 37import { HiperfThreadRender2 } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfThread2'; 38import { 39 hiperfCallChartDataCacheSender, 40 hiperfCallChartDataSender, 41 hiperfCallStackCacheSender, 42} from '../../database/data-trafic/hiperf/HiperfCallChartSender'; 43import { 44 queryHiPerfCpuMergeData2, 45 queryPerfCmdline, 46 queryPerfEventType, 47 queryPerfThread, 48} from '../../database/sql/Perf.sql'; 49import { renders } from '../../database/ui-worker/ProcedureWorker'; 50import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil'; 51 52export interface ResultData { 53 existA: boolean | null | undefined; 54 existF: boolean | null | undefined; 55 fValue: number; 56} 57const FOLD_HEIGHT = 20; 58export class SpHiPerf { 59 static selectCpuStruct: HiPerfCpuStruct | undefined; 60 static stringResult: ResultData | undefined; 61 62 private cpuData: Array<unknown> | undefined; 63 public maxCpuId: number = 0; //@ts-ignore 64 private rowFolder!: TraceRow<unknown>; 65 private perfThreads: Array<PerfThread> | undefined; 66 private trace: SpSystemTrace; 67 private group: unknown; //@ts-ignore 68 private rowList: TraceRow<unknown>[] | undefined; 69 private eventTypeList: Array<{ id: number; report: string }> = []; 70 private callChartType: number = 0; 71 private callChartId: number = 0; 72 private eventTypeId: number = -2; 73 74 constructor(trace: SpSystemTrace) { 75 this.trace = trace; 76 } 77 78 async init(): Promise<void> { 79 await this.initCmdLine(); 80 this.eventTypeList = await queryPerfEventType(); 81 this.rowList = []; 82 this.perfThreads = await queryPerfThread(); 83 info('PerfThread Data size is: ', this.perfThreads!.length); 84 this.group = Utils.groupBy(this.perfThreads || [], 'pid'); 85 this.cpuData = await queryHiPerfCpuMergeData2(); 86 this.callChartType = 0; 87 this.callChartId = 0; 88 this.eventTypeId = -2; //@ts-ignore 89 this.maxCpuId = this.cpuData.length > 0 ? this.cpuData[0].cpu_id : -Infinity; 90 if (this.cpuData.length > 0) { 91 await this.initFolder(); 92 await this.initCallChart(); 93 await this.initCpuMerge(); 94 await this.initCpu(); 95 await this.initProcess(); 96 } 97 info('HiPerf Data initialized'); 98 } 99 100 getStringResult(s: string = ''): void { 101 let list = s.split(' '); 102 let sA = list.findIndex((item) => item === '-a'); 103 let sF = list.findIndex((item) => item === '-f'); 104 SpHiPerf.stringResult = { 105 existA: sA !== -1, 106 existF: sF !== -1, 107 fValue: Number((1000 / (sF !== -1 ? parseInt(list[sF + 1]) : 1000)).toFixed(2)), 108 }; 109 } 110 111 async initCmdLine(): Promise<void> { 112 let perfCmdLines = await queryPerfCmdline(); 113 if (perfCmdLines.length > 0) { 114 this.getStringResult(perfCmdLines[0].report_value); 115 } else { 116 SpHiPerf.stringResult = { 117 existA: true, 118 existF: false, 119 fValue: 1, 120 }; 121 } 122 } 123 124 async initFolder(): Promise<void> { 125 let row = TraceRow.skeleton(); 126 row.rowId = 'HiPerf'; 127 row.index = 0; 128 row.rowType = TraceRow.ROW_TYPE_HIPERF; 129 row.rowParentId = ''; 130 row.folder = true; 131 row.drawType = -2; 132 row.addRowSettingPop(); 133 row.rowSetting = 'enable'; 134 row.rowSettingPopoverDirection = 'bottomLeft'; 135 row.style.height = '40px'; 136 this.folderRowSettingConfig(row); 137 if (SpHiPerf.stringResult?.existA === true) { 138 row.name = 'HiPerf (All)'; 139 } else { 140 //@ts-ignore 141 let names = Reflect.ownKeys(this.group) 142 .map((pid: unknown) => { 143 //@ts-ignore 144 let array = this.group[pid] as Array<PerfThread>; 145 let process = array.filter((th) => th.pid === th.tid)[0]; 146 return process.processName; 147 }) 148 .join(','); 149 row.name = `HiPerf (${names})`; 150 } //@ts-ignore 151 row.supplier = (): Promise<Array<unknown>> => new Promise<Array<unknown>>((resolve) => resolve([])); 152 row.onThreadHandler = folderThreadHandler(row, this.trace); 153 this.rowFolder = row; 154 this.trace.rowsEL?.appendChild(row); 155 } 156 157 //@ts-ignore 158 folderRowSettingConfig(row: TraceRow<unknown>): void { 159 row.rowSettingList = [ 160 { 161 key: '-2', 162 title: 'Cpu Usage', 163 checked: true, 164 }, 165 ...this.eventTypeList.map((et) => { 166 return { 167 key: `${et.id}`, 168 title: et.report, 169 }; 170 }), 171 ]; 172 row.onRowSettingChangeHandler = (value): void => { 173 let drawType = parseInt(value[0]); 174 if (this.eventTypeId !== drawType) { 175 this.eventTypeId = drawType; 176 row.drawType = drawType; 177 row.childrenList.forEach((child): void => { 178 if (child.drawType !== drawType) { 179 child.drawType = drawType; 180 child.needRefresh = true; 181 child.isComplete = false; 182 child.childrenList.forEach((sz) => { 183 sz.drawType = drawType; 184 sz.isComplete = false; 185 sz.needRefresh = true; 186 }); 187 } 188 }); 189 TraceRow.range!.refresh = true; 190 this.trace.refreshCanvas(false); 191 } 192 }; 193 } 194 195 async initCallChart(): Promise<void> { 196 await hiperfCallStackCacheSender(); 197 await hiperfCallChartDataCacheSender(); 198 let perfCallCutRow = TraceRow.skeleton<HiPerfCallChartStruct>(); 199 perfCallCutRow.rowId = 'HiPerf-callchart'; 200 perfCallCutRow.index = 0; 201 perfCallCutRow.rowType = TraceRow.ROW_TYPE_PERF_CALLCHART; 202 perfCallCutRow.enableCollapseChart(FOLD_HEIGHT, this.trace); 203 perfCallCutRow.rowParentId = 'HiPerf'; 204 perfCallCutRow.rowHidden = !this.rowFolder.expansion; 205 perfCallCutRow.folder = false; 206 perfCallCutRow.drawType = -2; 207 perfCallCutRow.name = 'CallChart [cpu0]'; 208 perfCallCutRow.funcExpand = false; 209 perfCallCutRow.setAttribute('children', ''); 210 perfCallCutRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 211 perfCallCutRow.selectChangeHandler = this.trace.selectChangeHandler; 212 this.rowFolder.addChildTraceRow(perfCallCutRow); 213 perfCallCutRow.focusHandler = (): void => { 214 this.callChartRowFocusHandler(perfCallCutRow); 215 }; 216 // @ts-ignore 217 perfCallCutRow.supplierFrame = async (): Promise<unknown> => { 218 const res = await hiperfCallChartDataSender(perfCallCutRow, { 219 startTime: window.recordStartNS, 220 eventTypeId: this.eventTypeId, 221 type: this.callChartType, 222 id: this.callChartId, 223 }); 224 // @ts-ignore 225 let maxHeight = res.maxDepth * FOLD_HEIGHT; 226 perfCallCutRow.funcMaxHeight = maxHeight; 227 if (perfCallCutRow.funcExpand) { 228 perfCallCutRow!.style.height = `${maxHeight}px`; 229 if (perfCallCutRow.collect) { 230 window.publish(window.SmartEvent.UI.RowHeightChange, { 231 expand: true, 232 value: perfCallCutRow.funcMaxHeight - FOLD_HEIGHT, 233 }); 234 } 235 } 236 // @ts-ignore 237 return res.dataList; 238 }; 239 perfCallCutRow.findHoverStruct = (): void => { 240 HiPerfCallChartStruct.hoverPerfCallCutStruct = perfCallCutRow.getHoverStruct(); 241 }; 242 await this.setCallTotalRow(perfCallCutRow, this.cpuData, this.perfThreads); 243 } 244 245 callChartRowFocusHandler(perfCallCutRow: TraceRow<HiPerfCallChartStruct>): void { 246 let hoverStruct = HiPerfCallChartStruct.hoverPerfCallCutStruct; 247 if (hoverStruct) { 248 let callName = hoverStruct.name; 249 callName = callName.replace(/</g, '<').replace(/>/g, '>'); 250 this.trace?.displayTip( 251 perfCallCutRow!, 252 hoverStruct, 253 `<span style="font-weight: bold;color:'#000'">Name: </span> 254 <span>${callName}</span><br> 255 <span style='font-weight: bold;'>Lib: </span> 256 <span>${perfDataQuery.getLibName(hoverStruct!.fileId, hoverStruct!.symbolId)}</span><br> 257 <span style='font-weight: bold;'>Self Time: </span> 258 <span>${Utils.getProbablyTime(hoverStruct.selfDur || 0)}</span><br> 259 <span style='font-weight: bold;'>Duration: </span> 260 <span>${Utils.getProbablyTime(hoverStruct.totalTime)}</span><br> 261 <span style='font-weight: bold;'>Event Count: </span> 262 <span>${hoverStruct.eventCount || ''}</span><br>` 263 ); 264 } 265 } 266 267 //@ts-ignore 268 async setCallTotalRow(row: TraceRow<unknown>, cpuData: unknown = Array, threadData: unknown = Array): Promise<void> { 269 //@ts-ignore 270 let pt: Map<string, unknown> = threadData.reduce((map: Map<string, unknown>, current: unknown) => { 271 //@ts-ignore 272 const key = `${current.processName || 'Process'}(${current.pid})`; 273 const thread = { 274 //@ts-ignore 275 key: `${current.tid}-t`, //@ts-ignore 276 title: `${current.threadName || 'Thread'}(${current.tid})`, 277 }; 278 if (map.has(key)) { 279 //@ts-ignore 280 if (map.get(key).children) { 281 //@ts-ignore 282 map.get(key).children.push(thread); 283 } else { 284 //@ts-ignore 285 map.get(key).children = [thread]; 286 } 287 } else { 288 map.set(key, { 289 //@ts-ignore 290 key: `${current.pid}-p`, 291 title: key, 292 children: [thread], 293 disable: true, 294 }); 295 } 296 return map; 297 }, new Map<string, unknown>()); 298 row.addTemplateTypes('hiperf-callchart'); 299 row.addRowSettingPop(); 300 row.rowSetting = 'enable'; //@ts-ignore 301 this.setCallChartRowSetting(row, cpuData, pt); 302 row.onThreadHandler = rowThreadHandler<HiPerfCallChartRender>( 303 'HiPerf-callchart', 304 'context', 305 { 306 type: 'HiPerf-callchart', 307 }, 308 row, 309 this.trace 310 ); 311 } 312 313 setCallChartRowSetting( 314 row: TraceRow<HiPerfCallChartStruct>, 315 cpuData: Array<unknown>, 316 pt: Map<string, unknown> 317 ): void { 318 //@ts-ignore 319 row.rowSettingList = [ 320 ...cpuData.reverse().map( 321 ( 322 it: unknown 323 ): { 324 key: string; 325 title: string; 326 checked?: boolean; 327 } => { 328 return { 329 //@ts-ignore 330 key: `${it.cpu_id}-c`, 331 //@ts-ignore 332 checked: it.cpu_id === 0, 333 //@ts-ignore 334 title: `cpu${it.cpu_id}`, 335 }; 336 } 337 ), 338 ...Array.from(pt.values()), 339 ]; 340 row.onRowSettingChangeHandler = (setting: unknown, nodes): void => { 341 //@ts-ignore 342 if (setting && setting.length > 0) { 343 //type 0:cpu,1:process,2:thread 344 //@ts-ignore 345 let key: string = setting[0]; 346 let type = this.callChartType; 347 if (key.includes('p')) { 348 type = 1; 349 } else if (key.includes('t')) { 350 type = 2; 351 } else { 352 type = 0; 353 } 354 let id = Number(key.split('-')[0]); 355 if (this.callChartType === type && this.callChartId === id) { 356 return; 357 } 358 this.callChartType = type; 359 this.callChartId = id; // @ts-ignore 360 row.name = `CallChart [${nodes[0].title}]`; 361 row.isComplete = false; 362 row.needRefresh = true; 363 row.drawFrame(); 364 } 365 }; 366 } 367 368 async initCpuMerge(): Promise<void> { 369 let cpuMergeRow = TraceRow.skeleton<HiPerfCpuStruct>(); 370 cpuMergeRow.rowId = 'HiPerf-cpu-merge'; 371 cpuMergeRow.index = 0; 372 cpuMergeRow.rowType = TraceRow.ROW_TYPE_HIPERF_CPU; 373 cpuMergeRow.rowParentId = 'HiPerf'; 374 cpuMergeRow.rowHidden = !this.rowFolder.expansion; 375 cpuMergeRow.folder = false; 376 cpuMergeRow.drawType = -2; 377 cpuMergeRow.name = 'HiPerf'; 378 cpuMergeRow.style.height = '40px'; 379 cpuMergeRow.setAttribute('children', ''); 380 cpuMergeRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 381 cpuMergeRow.selectChangeHandler = this.trace.selectChangeHandler; //@ts-ignore 382 cpuMergeRow.supplierFrame = (): Promise<unknown> => { 383 return hiperfCpuDataSender( 384 -1, 385 cpuMergeRow.drawType, 386 this.maxCpuId + 1, 387 SpHiPerf.stringResult?.fValue || 1, 388 TraceRow.range?.scale || 50, 389 cpuMergeRow 390 ); 391 }; 392 cpuMergeRow.focusHandler = (): void => this.hoverTip(cpuMergeRow, HiPerfCpuStruct.hoverStruct); 393 cpuMergeRow.findHoverStruct = (): void => { 394 HiPerfCpuStruct.hoverStruct = cpuMergeRow.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000); 395 }; 396 cpuMergeRow.onThreadHandler = this.rowThreadHandler<HiperfCpuRender2>( 397 'HiPerf-Cpu-2', 398 'context', 399 { 400 type: 'HiPerf-Cpu-Merge', 401 maxCpu: this.maxCpuId + 1, 402 intervalPerf: SpHiPerf.stringResult?.fValue || 1, 403 }, 404 cpuMergeRow, 405 this.trace 406 ); 407 this.rowFolder.addChildTraceRow(cpuMergeRow); 408 this.rowList?.push(cpuMergeRow); 409 } 410 411 //@ts-ignore 412 rowThreadHandler<T>(tag: string, contextField: string, arg: unknown, row: TraceRow<unknown>, trace: SpSystemTrace) { 413 return (useCache: boolean): void => { 414 let context: CanvasRenderingContext2D = getRowContext(row, trace); 415 row.canvasSave(context); //@ts-ignore 416 arg.useCache = useCache; //@ts-ignore 417 arg.scale = TraceRow.range?.scale || 50; //@ts-ignore 418 arg.range = TraceRow.range; 419 if (contextField) { 420 //@ts-ignore 421 arg[contextField] = context; 422 } //@ts-ignore 423 (renders[tag] as unknown).renderMainThread(arg, row); 424 row.canvasRestore(context, trace); 425 }; 426 } 427 428 async initCpu(): Promise<void> { 429 for (let i = 0; i <= this.maxCpuId; i++) { 430 let perfCpuRow = TraceRow.skeleton<HiPerfCpuStruct>(); 431 perfCpuRow.rowId = `HiPerf-cpu-${i}`; 432 perfCpuRow.index = i; 433 perfCpuRow.rowType = TraceRow.ROW_TYPE_HIPERF_CPU; 434 perfCpuRow.rowParentId = 'HiPerf'; 435 perfCpuRow.rowHidden = !this.rowFolder.expansion; 436 perfCpuRow.folder = false; 437 perfCpuRow.drawType = -2; 438 perfCpuRow.name = `Cpu ${i}`; 439 perfCpuRow.setAttribute('children', ''); 440 perfCpuRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 441 perfCpuRow.selectChangeHandler = this.trace.selectChangeHandler; 442 perfCpuRow.style.height = '40px'; //@ts-ignore 443 perfCpuRow.supplierFrame = (): Promise<unknown> => { 444 return hiperfCpuDataSender( 445 i, 446 perfCpuRow.drawType, 447 this.maxCpuId + 1, 448 SpHiPerf.stringResult?.fValue || 1, 449 TraceRow.range?.scale || 50, 450 perfCpuRow 451 ); 452 }; 453 perfCpuRow.focusHandler = (): void => this.hoverTip(perfCpuRow, HiPerfCpuStruct.hoverStruct); 454 perfCpuRow.findHoverStruct = (): void => { 455 HiPerfCpuStruct.hoverStruct = perfCpuRow.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000); 456 }; 457 perfCpuRow.onThreadHandler = this.rowThreadHandler<HiperfCpuRender2>( 458 'HiPerf-Cpu-2', 459 'context', 460 { 461 type: `HiPerf-Cpu-${i}`, 462 maxCpu: this.maxCpuId + 1, 463 intervalPerf: SpHiPerf.stringResult?.fValue || 1, 464 }, 465 perfCpuRow, 466 this.trace 467 ); 468 this.rowFolder.addChildTraceRow(perfCpuRow); 469 this.rowList?.push(perfCpuRow); 470 } 471 } 472 473 async initProcess(): Promise<void> { 474 //@ts-ignore 475 Reflect.ownKeys(this.group).forEach((key, index): void => { 476 //@ts-ignore 477 let array = this.group[key] as Array<PerfThread>; 478 let process = array.filter((th): boolean => th.pid === th.tid)[0]; 479 let row = TraceRow.skeleton<HiPerfProcessStruct>(); 480 row.rowId = `${process.pid}-Perf-Process`; 481 row.index = index; 482 row.rowType = TraceRow.ROW_TYPE_HIPERF_PROCESS; 483 row.rowParentId = 'HiPerf'; 484 row.rowHidden = !this.rowFolder.expansion; 485 row.folder = true; 486 row.drawType = -2; 487 if (SpChartManager.APP_STARTUP_PID_ARR.find((pid) => pid === process.pid) !== undefined) { 488 row.addTemplateTypes('AppStartup'); 489 } 490 row.addTemplateTypes('HiPerf'); 491 row.name = `${process.processName || 'Process'} [${process.pid}]`; 492 row.folderPaddingLeft = 6; 493 row.style.height = '40px'; 494 row.favoriteChangeHandler = this.trace.favoriteChangeHandler; 495 row.selectChangeHandler = this.trace.selectChangeHandler; //@ts-ignore 496 row.supplierFrame = (): Promise<unknown> => { 497 return hiperfProcessDataSender( 498 process.pid, 499 row.drawType, 500 this.maxCpuId + 1, 501 SpHiPerf.stringResult?.fValue || 1, 502 TraceRow.range?.scale || 50, 503 row 504 ); 505 }; 506 row.focusHandler = (): void => this.hoverTip(row, HiPerfProcessStruct.hoverStruct); 507 row.findHoverStruct = (): void => { 508 HiPerfProcessStruct.hoverStruct = row.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000); 509 }; 510 row.onThreadHandler = this.rowThreadHandler<HiperfProcessRender2>( 511 'HiPerf-Process-2', 512 'context', 513 { 514 type: `HiPerf-Process-${row.index}`, 515 intervalPerf: SpHiPerf.stringResult?.fValue || 1, 516 }, 517 row, 518 this.trace 519 ); 520 this.rowFolder.addChildTraceRow(row); 521 this.rowList?.push(row); 522 this.addHiPerfThreadRow(array, row); 523 }); 524 } 525 526 addHiPerfThreadRow(array: PerfThread[], row: TraceRow<HiPerfProcessStruct>): void { 527 array.forEach((thObj, thIdx): void => { 528 let thread = TraceRow.skeleton<HiPerfThreadStruct>(); 529 thread.rowId = `${thObj.tid}-Perf-Thread`; 530 thread.index = thIdx; 531 thread.rowType = TraceRow.ROW_TYPE_HIPERF_THREAD; 532 thread.rowParentId = row.rowId; 533 thread.rowHidden = !row.expansion; 534 thread.folder = false; 535 thread.drawType = -2; 536 thread.name = `${thObj.threadName || 'Thread'} [${thObj.tid}]`; 537 thread.setAttribute('children', ''); 538 thread.folderPaddingLeft = 0; 539 thread.style.height = '40px'; 540 thread.favoriteChangeHandler = this.trace.favoriteChangeHandler; 541 thread.selectChangeHandler = this.trace.selectChangeHandler; //@ts-ignore 542 thread.supplierFrame = (): Promise<unknown> => { 543 return hiperfThreadDataSender( 544 thObj.tid, 545 thread.drawType, 546 this.maxCpuId + 1, 547 SpHiPerf.stringResult?.fValue || 1, 548 TraceRow.range?.scale || 50, 549 thread 550 ); 551 }; 552 thread.focusHandler = (): void => this.hoverTip(thread, HiPerfThreadStruct.hoverStruct); 553 thread.findHoverStruct = (): void => { 554 HiPerfThreadStruct.hoverStruct = thread.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000); 555 }; 556 thread.onThreadHandler = this.rowThreadHandler<HiperfThreadRender2>( 557 'HiPerf-Thread-2', 558 'context', 559 { 560 type: `HiPerf-Thread-${row.index}-${thread.index}`, 561 intervalPerf: SpHiPerf.stringResult?.fValue || 1, 562 }, 563 thread, 564 this.trace 565 ); 566 row.addChildTraceRow(thread); 567 this.rowList?.push(thread); 568 }); 569 } 570 571 //@ts-ignore 572 resetChartData(row: TraceRow<unknown>): void { 573 row.dataList = []; 574 row.dataList2 = []; 575 row.dataListCache = []; 576 row.isComplete = false; 577 } 578 579 resetAllChartData(): void { 580 const callChartRow = this.rowList?.find(row => row.rowId === 'HiPerf-callchart'); 581 if (callChartRow) { 582 this.resetChartData(callChartRow); 583 } 584 } 585 586 hoverTip( 587 //@ts-ignore 588 row: TraceRow<unknown>, 589 struct: 590 | HiPerfThreadStruct 591 | HiPerfProcessStruct 592 | HiPerfEventStruct 593 | HiPerfReportStruct 594 | HiPerfCpuStruct 595 | undefined 596 ): void { 597 let tip = ''; 598 let groupBy10MS = (TraceRow.range?.scale || 50) > 30_000_000; 599 if (struct) { 600 if (groupBy10MS) { 601 if (row.drawType === -2) { 602 let num: number | string = 0; 603 if (struct instanceof HiPerfEventStruct) { 604 num = Math.trunc(((struct.sum || 0) / (struct.max || 0)) * 100); 605 } else { 606 let interval = SpHiPerf.stringResult?.fValue || 1; 607 num = ((struct.sampleCount! / (10 / interval)) * 100).toFixed(2); 608 } 609 tip = `<span>${num}% (10.00ms)</span>`; 610 } else { 611 tip = `<span>${struct.event_count || struct.eventCount} (10.00ms)</span>`; 612 } 613 } else { 614 let perfCall = perfDataQuery.callChainMap.get(struct.callchain_id || 0); 615 if (perfCall) { 616 let perfName; 617 typeof perfCall.name === 'number' 618 ? (perfName = SpSystemTrace.DATA_DICT.get(parseInt(perfCall.name))) 619 : (perfName = perfCall.name); 620 tip = `<span>${perfCall ? perfName : ''} (${perfCall ? perfCall.depth : '0'} other frames)</span>`; 621 } 622 } 623 } 624 this.trace?.displayTip(row, struct, tip); 625 } 626} 627