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