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