• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
27  HiPerfProcessStruct,
28} from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfProcess2';
29import { info } from '../../../log/Log';
30import { HiPerfEventStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfEvent';
31import { perfDataQuery } from './PerfDataQuery';
32import { renders } from '../../database/ui-worker/ProcedureWorker';
33import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
34import { type HiPerfReportStruct } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfReport';
35import { SpChartManager } from './SpChartManager';
36import { procedurePool } from '../../database/Procedure';
37import { HiPerfChartFrame } from '../../bean/PerfStruct';
38import { HiperfCpuRender2 } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfCPU2';
39import { hiperfCpuDataSender } from '../../database/data-trafic/hiperf/HiperfCpuDataSender';
40import { hiperfProcessDataSender } from '../../database/data-trafic/hiperf/HiperfProcessDataSender';
41import { HiperfProcessRender2 } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfProcess2';
42import { hiperfThreadDataSender } from '../../database/data-trafic/hiperf/HiperfThreadDataSender';
43import { HiperfThreadRender2 } from '../../database/ui-worker/hiperf/ProcedureWorkerHiPerfThread2';
44import {
45  hiperfCallChartDataCacheSender,
46  hiperfCallChartDataSender,
47  hiperfCallStackCacheSender,
48} from '../../database/data-trafic/hiperf/HiperfCallChartSender';
49import {
50  queryHiPerfCpuMergeData2,
51  queryPerfCmdline,
52  queryPerfEventType,
53  queryPerfThread,
54} from '../../database/sql/Perf.sql';
55
56export interface ResultData {
57  existA: boolean | null | undefined;
58  existF: boolean | null | undefined;
59  fValue: number;
60}
61
62export class SpHiPerf {
63  static selectCpuStruct: HiPerfCpuStruct | undefined;
64  static selectProcessStruct: HiPerfProcessStruct | undefined;
65  static selectThreadStruct: HiPerfThreadStruct | undefined;
66  static stringResult: ResultData | undefined;
67
68  private cpuData: Array<any> | undefined;
69  public maxCpuId: number = 0;
70  private rowFolder!: TraceRow<any>;
71  private perfThreads: Array<PerfThread> | undefined;
72  private trace: SpSystemTrace;
73  private group: any;
74  private rowList: TraceRow<any>[] | undefined;
75  private eventTypeList: Array<{ id: number; report: string }> = [];
76  private callChartType: number = 0;
77  private callChartId: number = 0;
78  private eventTypeId: number = -2;
79  private stackChartMaxDepth: number = 1;
80
81  constructor(trace: SpSystemTrace) {
82    this.trace = trace;
83  }
84
85  async init() {
86    await this.initCmdLine();
87    this.eventTypeList = await queryPerfEventType();
88    this.rowList = [];
89    this.perfThreads = await queryPerfThread();
90    info('PerfThread Data size is: ', this.perfThreads!.length);
91    this.group = Utils.groupBy(this.perfThreads || [], 'pid');
92    this.cpuData = await queryHiPerfCpuMergeData2();
93    this.callChartType = 0;
94    this.callChartId = 0;
95    this.eventTypeId = -2;
96    this.maxCpuId = this.cpuData.length > 0 ? this.cpuData[0].cpu_id : -Infinity;
97    if (this.cpuData.length > 0) {
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 = '') {
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() {
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() {
132    let row = TraceRow.skeleton();
133    row.setAttribute('disabled-check', '');
134    row.rowId = `HiPerf`;
135    row.index = 0;
136    row.rowType = TraceRow.ROW_TYPE_HIPERF;
137    row.rowParentId = '';
138    row.folder = true;
139    row.drawType = -2;
140    row.addRowSettingPop();
141    row.rowSetting = 'enable';
142    row.rowSettingPopoverDirection = 'bottomLeft';
143    row.rowSettingList = [
144      {
145        key: '-2',
146        title: 'Cpu Usage',
147        checked: true,
148      },
149      ...this.eventTypeList.map((et) => {
150        return {
151          key: `${et.id}`,
152          title: et.report,
153        };
154      }),
155    ];
156    row.onRowSettingChangeHandler = (value) => {
157      let drawType = parseInt(value[0]);
158      if (this.eventTypeId !== drawType) {
159        this.eventTypeId = drawType;
160        row.drawType = drawType;
161        row.childrenList.forEach((child) => {
162          if (child.drawType !== drawType) {
163            child.drawType = drawType;
164            child.needRefresh = true;
165            child.isComplete = false;
166            child.childrenList.forEach((sz) => {
167              sz.drawType = drawType;
168              sz.isComplete = false;
169              sz.needRefresh = true;
170            });
171          }
172        });
173        TraceRow.range!.refresh = true;
174        this.trace.refreshCanvas(false);
175      }
176    };
177    row.style.height = '40px';
178    if (SpHiPerf.stringResult?.existA === true) {
179      row.name = `HiPerf (All)`;
180    } else {
181      let names = Reflect.ownKeys(this.group)
182        .map((pid: any) => {
183          let array = this.group[pid] as Array<PerfThread>;
184          let process = array.filter((th) => th.pid === th.tid)[0];
185          return process.processName;
186        })
187        .join(',');
188      row.name = `HiPerf (${names})`;
189    }
190    row.supplier = () => new Promise<Array<any>>((resolve) => resolve([]));
191    row.onThreadHandler = (useCache) => {
192      row.canvasSave(this.trace.canvasPanelCtx!);
193      if (row.expansion) {
194        this.trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
195      } else {
196        (renders['empty'] as EmptyRender).renderMainThread(
197          {
198            context: this.trace.canvasPanelCtx,
199            useCache: useCache,
200            type: ``,
201          },
202          row
203        );
204      }
205      row.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
206    };
207    this.rowFolder = row;
208    this.trace.rowsEL?.appendChild(row);
209  }
210
211  async initCallChart() {
212    await hiperfCallStackCacheSender();
213    await hiperfCallChartDataCacheSender();
214    let perfCallCutRow = TraceRow.skeleton<HiPerfCallChartStruct>();
215    perfCallCutRow.rowId = `HiPerf-callchart`;
216    perfCallCutRow.index = 0;
217    perfCallCutRow.rowType = TraceRow.ROW_TYPE_PERF_CALLCHART;
218    perfCallCutRow.enableCollapseChart();
219    perfCallCutRow.rowParentId = 'HiPerf';
220    perfCallCutRow.rowHidden = !this.rowFolder.expansion;
221    perfCallCutRow.folder = false;
222    perfCallCutRow.drawType = -2;
223    perfCallCutRow.name = 'CallChart [cpu0]';
224    perfCallCutRow.funcExpand = false;
225    perfCallCutRow.setAttribute('children', '');
226    perfCallCutRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
227    perfCallCutRow.selectChangeHandler = this.trace.selectChangeHandler;
228    this.rowFolder.addChildTraceRow(perfCallCutRow);
229    perfCallCutRow.focusHandler = (): void => {
230      let hoverStruct = HiPerfCallChartStruct.hoverPerfCallCutStruct;
231      if (hoverStruct) {
232        let callName = hoverStruct.name;
233        callName = callName.replace(/</g, '&lt;').replace(/>/g, '&gt;');
234        this.trace?.displayTip(
235          perfCallCutRow!,
236          hoverStruct,
237          `<span style="font-weight: bold;color:'#000'">Name: </span>
238        <span>${callName}</span><br>
239        <span style='font-weight: bold;'>Lib: </span>
240        <span>${perfDataQuery.getLibName(hoverStruct!.fileId, hoverStruct!.symbolId)}</span><br>
241        <span style='font-weight: bold;'>Self Time: </span>
242        <span>${Utils.getProbablyTime(hoverStruct.selfDur || 0)}</span><br>
243        <span style='font-weight: bold;'>Duration: </span>
244        <span>${Utils.getProbablyTime(hoverStruct.totalTime)}</span><br>
245        <span style='font-weight: bold;'>Event Count: </span>
246        <span>${hoverStruct.eventCount || ''}</span><br>`
247        );
248      }
249    };
250    perfCallCutRow.supplierFrame = () => {
251      return hiperfCallChartDataSender(perfCallCutRow, {
252        startTime: window.recordStartNS,
253        eventTypeId: this.eventTypeId,
254        type: this.callChartType,
255        id: this.callChartId,
256      }).then((res) => {
257        let maxHeight = res.maxDepth * 20;
258        perfCallCutRow.funcMaxHeight = maxHeight;
259        if (perfCallCutRow.funcExpand) {
260          perfCallCutRow!.style.height = `${maxHeight}px`;
261          if (perfCallCutRow.collect) {
262            window.publish(window.SmartEvent.UI.RowHeightChange, {
263              expand: true,
264              value: perfCallCutRow.funcMaxHeight - 20,
265            });
266          }
267        }
268        return res.dataList;
269      });
270    };
271    perfCallCutRow.findHoverStruct = () => {
272      HiPerfCallChartStruct.hoverPerfCallCutStruct = perfCallCutRow.getHoverStruct();
273    };
274    await this.setCallTotalRow(perfCallCutRow, this.cpuData, this.perfThreads);
275  }
276
277  async setCallTotalRow(row: TraceRow<any>, cpuData: any = Array, threadData: any = Array) {
278    let pt: Map<string, any> = threadData.reduce((map: Map<string, any>, current: any) => {
279      const key = `${current.processName || 'Process'}(${current.pid})`;
280      const thread = {
281        key: `${current.tid}-t`,
282        title: `${current.threadName || 'Thread'}(${current.tid})`,
283      };
284      if (map.has(key)) {
285        if (map.get(key).children) {
286          map.get(key).children.push(thread);
287        } else {
288          map.get(key).children = [thread];
289        }
290      } else {
291        map.set(key, {
292          key: `${current.pid}-p`,
293          title: key,
294          children: [thread],
295          disable: true,
296        });
297      }
298      return map;
299    }, new Map<string, any>());
300    row.addTemplateTypes('hiperf-callchart');
301    row.addRowSettingPop();
302    row.rowSetting = 'enable';
303    row.rowSettingList = [
304      ...cpuData.reverse().map(
305        (
306          it: any
307        ): {
308          key: string;
309          title: string;
310          checked?: boolean;
311        } => {
312          return {
313            key: `${it.cpu_id}-c`,
314            checked: it.cpu_id === 0,
315            title: `cpu${it.cpu_id}`,
316          };
317        }
318      ),
319      ...Array.from(pt.values()),
320    ];
321    row.onRowSettingChangeHandler = (setting: any, nodes): void => {
322      if (setting && setting.length > 0) {
323        //type 0:cpu,1:process,2:thread
324        let key: string = setting[0];
325        let type = this.callChartType;
326        if (key.includes('p')) {
327          type = 1;
328        } else if (key.includes('t')) {
329          type = 2;
330        } else {
331          type = 0;
332        }
333        let id = Number(key.split('-')[0]);
334        if (this.callChartType === type && this.callChartId === id) {
335          return;
336        }
337        this.callChartType = type;
338        this.callChartId = id;
339        row.name = `CallChart [${nodes[0].title}]`;
340        row.isComplete = false;
341        row.needRefresh = true;
342        row.drawFrame();
343      }
344    };
345    row.onThreadHandler = (useCache: any) => {
346      let context: CanvasRenderingContext2D;
347      if (row.currentContext) {
348        context = row.currentContext;
349      } else {
350        context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
351      }
352      row.canvasSave(context);
353      (renders['HiPerf-callchart'] as HiPerfCallChartRender).renderMainThread(
354        {
355          context: context,
356          useCache: useCache,
357          type: `HiPerf-callchart`,
358        },
359        row
360      );
361      row.canvasRestore(context, this.trace);
362    };
363  }
364
365  async initCpuMerge() {
366    let cpuMergeRow = TraceRow.skeleton<HiPerfCpuStruct>();
367    cpuMergeRow.rowId = `HiPerf-cpu-merge`;
368    cpuMergeRow.index = 0;
369    cpuMergeRow.rowType = TraceRow.ROW_TYPE_HIPERF_CPU;
370    cpuMergeRow.rowParentId = 'HiPerf';
371    cpuMergeRow.rowHidden = !this.rowFolder.expansion;
372    cpuMergeRow.folder = false;
373    cpuMergeRow.drawType = -2;
374    cpuMergeRow.name = `HiPerf`;
375    cpuMergeRow.style.height = '40px';
376    cpuMergeRow.setAttribute('children', '');
377    cpuMergeRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
378    cpuMergeRow.selectChangeHandler = this.trace.selectChangeHandler;
379    cpuMergeRow.supplierFrame = () => {
380      return hiperfCpuDataSender(
381        -1,
382        cpuMergeRow.drawType,
383        this.maxCpuId + 1,
384        SpHiPerf.stringResult?.fValue || 1,
385        TraceRow.range?.scale || 50,
386        cpuMergeRow
387      );
388    };
389    cpuMergeRow.focusHandler = () => this.hoverTip(cpuMergeRow, HiPerfCpuStruct.hoverStruct);
390    cpuMergeRow.findHoverStruct = () => {
391      HiPerfCpuStruct.hoverStruct = cpuMergeRow.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000);
392    };
393    cpuMergeRow.onThreadHandler = (useCache) => {
394      let context: CanvasRenderingContext2D;
395      if (cpuMergeRow.currentContext) {
396        context = cpuMergeRow.currentContext;
397      } else {
398        context = cpuMergeRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
399      }
400      cpuMergeRow.canvasSave(context);
401      (renders['HiPerf-Cpu-2'] as HiperfCpuRender2).renderMainThread(
402        {
403          context: context,
404          useCache: useCache,
405          scale: TraceRow.range?.scale || 50,
406          type: `HiPerf-Cpu-Merge`,
407          maxCpu: this.maxCpuId + 1,
408          intervalPerf: SpHiPerf.stringResult?.fValue || 1,
409          range: TraceRow.range,
410        },
411        cpuMergeRow
412      );
413      cpuMergeRow.canvasRestore(context, this.trace);
414    };
415    this.rowFolder.addChildTraceRow(cpuMergeRow);
416    this.rowList?.push(cpuMergeRow);
417  }
418
419  async initCpu() {
420    for (let i = 0; i <= this.maxCpuId; i++) {
421      let perfCpuRow = TraceRow.skeleton<HiPerfCpuStruct>();
422      perfCpuRow.rowId = `HiPerf-cpu-${i}`;
423      perfCpuRow.index = i;
424      perfCpuRow.rowType = TraceRow.ROW_TYPE_HIPERF_CPU;
425      perfCpuRow.rowParentId = 'HiPerf';
426      perfCpuRow.rowHidden = !this.rowFolder.expansion;
427      perfCpuRow.folder = false;
428      perfCpuRow.drawType = -2;
429      perfCpuRow.name = `Cpu ${i}`;
430      perfCpuRow.setAttribute('children', '');
431      perfCpuRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
432      perfCpuRow.selectChangeHandler = this.trace.selectChangeHandler;
433      perfCpuRow.style.height = '40px';
434      perfCpuRow.supplierFrame = () => {
435        return hiperfCpuDataSender(
436          i,
437          perfCpuRow.drawType,
438          this.maxCpuId + 1,
439          SpHiPerf.stringResult?.fValue || 1,
440          TraceRow.range?.scale || 50,
441          perfCpuRow
442        );
443      };
444      perfCpuRow.focusHandler = () => this.hoverTip(perfCpuRow, HiPerfCpuStruct.hoverStruct);
445      perfCpuRow.findHoverStruct = () => {
446        HiPerfCpuStruct.hoverStruct = perfCpuRow.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000);
447      };
448      perfCpuRow.onThreadHandler = (useCache) => {
449        let context: CanvasRenderingContext2D;
450        if (perfCpuRow.currentContext) {
451          context = perfCpuRow.currentContext;
452        } else {
453          context = perfCpuRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
454        }
455        perfCpuRow.canvasSave(context);
456        (renders['HiPerf-Cpu-2'] as HiperfCpuRender2).renderMainThread(
457          {
458            context: context,
459            useCache: useCache,
460            scale: TraceRow.range?.scale || 50,
461            type: `HiPerf-Cpu-${i}`,
462            maxCpu: this.maxCpuId + 1,
463            intervalPerf: SpHiPerf.stringResult?.fValue || 1,
464            range: TraceRow.range,
465          },
466          perfCpuRow
467        );
468        perfCpuRow.canvasRestore(context, this.trace);
469      };
470      this.rowFolder.addChildTraceRow(perfCpuRow);
471      this.rowList?.push(perfCpuRow);
472    }
473  }
474
475  async initProcess() {
476    Reflect.ownKeys(this.group)
477      .filter((it) => {
478        return true;
479      })
480      .forEach((key, index) => {
481        let array = this.group[key] as Array<PerfThread>;
482        let process = array.filter((th) => th.pid === th.tid)[0];
483        let row = TraceRow.skeleton<HiPerfProcessStruct>();
484        row.rowId = `${process.pid}-Perf-Process`;
485        row.index = index;
486        row.rowType = TraceRow.ROW_TYPE_HIPERF_PROCESS;
487        row.rowParentId = 'HiPerf';
488        row.rowHidden = !this.rowFolder.expansion;
489        row.folder = true;
490        row.drawType = -2;
491        if (SpChartManager.APP_STARTUP_PID_ARR.find((pid) => pid === process.pid) !== undefined) {
492          row.addTemplateTypes('AppStartup');
493        }
494        row.addTemplateTypes('HiPerf');
495        row.name = `${process.processName || 'Process'} [${process.pid}]`;
496        row.folderPaddingLeft = 6;
497        row.style.height = '40px';
498        row.favoriteChangeHandler = this.trace.favoriteChangeHandler;
499        row.selectChangeHandler = this.trace.selectChangeHandler;
500        row.supplierFrame = () => {
501          return hiperfProcessDataSender(
502            process.pid,
503            row.drawType,
504            SpHiPerf.stringResult?.fValue || 1,
505            TraceRow.range?.scale || 50,
506            row
507          );
508        };
509        row.focusHandler = () => this.hoverTip(row, HiPerfProcessStruct.hoverStruct);
510        row.findHoverStruct = () => {
511          HiPerfProcessStruct.hoverStruct = row.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000);
512        };
513        row.onThreadHandler = (useCache) => {
514          let context: CanvasRenderingContext2D;
515          if (row.currentContext) {
516            context = row.currentContext;
517          } else {
518            context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
519          }
520          row.canvasSave(context);
521          if (row.expansion) {
522            this.trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
523          } else {
524            (renders['HiPerf-Process-2'] as HiperfProcessRender2).renderMainThread(
525              {
526                context: context,
527                useCache: useCache,
528                scale: TraceRow.range?.scale || 50,
529                type: `HiPerf-Process-${row.index}`,
530                intervalPerf: SpHiPerf.stringResult?.fValue || 1,
531                range: TraceRow.range,
532              },
533              row
534            );
535          }
536          row.canvasRestore(context, this.trace);
537        };
538        this.rowFolder.addChildTraceRow(row);
539        this.rowList?.push(row);
540        array.forEach((thObj, thIdx) => {
541          let thread = TraceRow.skeleton<HiPerfThreadStruct>();
542          thread.rowId = `${thObj.tid}-Perf-Thread`;
543          thread.index = thIdx;
544          thread.rowType = TraceRow.ROW_TYPE_HIPERF_THREAD;
545          thread.rowParentId = row.rowId;
546          thread.rowHidden = !row.expansion;
547          thread.folder = false;
548          thread.drawType = -2;
549          thread.name = `${thObj.threadName || 'Thread'} [${thObj.tid}]`;
550          thread.setAttribute('children', '');
551          thread.folderPaddingLeft = 0;
552          thread.style.height = '40px';
553          thread.favoriteChangeHandler = this.trace.favoriteChangeHandler;
554          thread.selectChangeHandler = this.trace.selectChangeHandler;
555          thread.supplierFrame = () => {
556            return hiperfThreadDataSender(
557              thObj.tid,
558              thread.drawType,
559              SpHiPerf.stringResult?.fValue || 1,
560              TraceRow.range?.scale || 50,
561              thread
562            );
563          };
564          thread.focusHandler = () => this.hoverTip(thread, HiPerfThreadStruct.hoverStruct);
565          thread.findHoverStruct = () => {
566            HiPerfThreadStruct.hoverStruct = thread.getHoverStruct(false, (TraceRow.range?.scale || 50) <= 30_000_000);
567          };
568          thread.onThreadHandler = (useCache) => {
569            let context: CanvasRenderingContext2D;
570            if (thread.currentContext) {
571              context = thread.currentContext;
572            } else {
573              context = thread.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
574            }
575            thread.canvasSave(context);
576            (renders['HiPerf-Thread-2'] as HiperfThreadRender2).renderMainThread(
577              {
578                context: context,
579                useCache: useCache,
580                scale: TraceRow.range?.scale || 50,
581                type: `HiPerf-Thread-${row.index}-${thread.index}`,
582                intervalPerf: SpHiPerf.stringResult?.fValue || 1,
583                range: TraceRow.range,
584              },
585              thread
586            );
587            thread.canvasRestore(context, this.trace);
588          };
589          row.addChildTraceRow(thread);
590          this.rowList?.push(thread);
591        });
592      });
593  }
594
595  async getHiPerfChartData(type: number, id: number, eventTypeId: number, row: TraceRow<any>) {
596    let source: Array<HiPerfChartFrame> = [];
597    this.stackChartMaxDepth = 1;
598    await new Promise((resolve) => {
599      procedurePool.submitWithName(
600        'logic0',
601        'perf-callstack-chart',
602        [type, id, eventTypeId, (window as any).totalNS],
603        undefined,
604        (res: any) => {
605          this.getAllCombineData(res, source);
606          let maxHeight = this.stackChartMaxDepth * 20;
607          row.funcMaxHeight = maxHeight;
608          if (row.funcExpand) {
609            row!.style.height = `${maxHeight}px`;
610            if (row.collect) {
611              window.publish(window.SmartEvent.UI.RowHeightChange, {
612                expand: true,
613                value: row.funcMaxHeight - 20,
614              });
615            }
616          }
617          resolve(source);
618        }
619      );
620    });
621    return source;
622  }
623
624  getAllCombineData(combineData: Array<HiPerfChartFrame>, allCombineData: Array<HiPerfChartFrame>): void {
625    for (let data of combineData) {
626      if (data.name != 'name') {
627        allCombineData.push(data);
628      }
629      if (data.depth + 1 > this.stackChartMaxDepth) {
630        this.stackChartMaxDepth = data.depth + 1;
631      }
632      if (data.children && data.children.length > 0) {
633        this.getAllCombineData(data.children, allCombineData);
634      }
635    }
636  }
637
638  resetChartData(row: TraceRow<any>) {
639    row.dataList = [];
640    row.dataList2 = [];
641    row.dataListCache = [];
642    row.isComplete = false;
643  }
644
645  resetAllChartData(): void {
646    this.rowList?.forEach((row) => this.resetChartData(row));
647  }
648
649  hoverTip(
650    row: TraceRow<any>,
651    struct:
652      | HiPerfThreadStruct
653      | HiPerfProcessStruct
654      | HiPerfEventStruct
655      | HiPerfReportStruct
656      | HiPerfCpuStruct
657      | undefined
658  ) {
659    let tip = '';
660    let groupBy10MS = (TraceRow.range?.scale || 50) > 30_000_000;
661    if (struct) {
662      if (groupBy10MS) {
663        if (row.drawType === -2) {
664          let num = 0;
665          if (struct instanceof HiPerfEventStruct) {
666            num = Math.trunc(((struct.sum || 0) / (struct.max || 0)) * 100);
667          } else {
668            num = Math.trunc(((struct.height || 0) / 40) * 100);
669          }
670          if (num > 0) {
671            tip = `<span>${num * (this.maxCpuId + 1)}% (10.00ms)</span>`;
672          }
673        } else {
674          tip = `<span>${struct.event_count || struct.eventCount} (10.00ms)</span>`;
675        }
676      } else {
677        let perfCall = perfDataQuery.callChainMap.get(struct.callchain_id || 0);
678        if (perfCall) {
679          let perfName = SpSystemTrace.DATA_DICT.get(parseInt(perfCall.name));
680          tip = `<span>${perfCall ? perfName : ''} (${perfCall ? perfCall.depth : '0'} other frames)</span>`;
681        }
682      }
683    }
684    this.trace?.displayTip(row, struct, tip);
685  }
686}
687