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 { SpHiPerf } from './SpHiPerf';
18import { SpCpuChart } from './SpCpuChart';
19import { SpFreqChart } from './SpFreqChart';
20import { SpFpsChart } from './SpFpsChart';
21import { info } from '../../../log/Log';
22import { SpNativeMemoryChart } from './SpNativeMemoryChart';
23import { SpAbilityMonitorChart } from './SpAbilityMonitorChart';
24import { SpProcessChart } from './SpProcessChart';
25import { perfDataQuery } from './PerfDataQuery';
26import { SpVirtualMemChart } from './SpVirtualMemChart';
27import { SpEBPFChart } from './SpEBPFChart';
28import { SpSdkChart } from './SpSdkChart';
29import { SpHiSysEnergyChart } from './SpHiSysEnergyChart';
30import { VmTrackerChart } from './SpVmTrackerChart';
31import { SpClockChart } from './SpClockChart';
32import { SpXpowerChart } from './SpXpowerChart';
33import { SpIrqChart } from './SpIrqChart';
34import { renders } from '../../database/ui-worker/ProcedureWorker';
35import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
36import { TraceRow } from '../trace/base/TraceRow';
37import { SpFrameTimeChart } from './SpFrameTimeChart';
38import { Utils } from '../trace/base/Utils';
39import { SpArkTsChart } from './SpArkTsChart';
40import { MemoryConfig } from '../../bean/MemoryConfig';
41import { FlagsConfig } from '../SpFlags';
42import { SpLogChart } from './SpLogChart';
43import { SpHiSysEventChart } from './SpHiSysEventChart';
44import { SpAllAppStartupsChart } from './SpAllAppStartups';
45import { procedurePool } from '../../database/Procedure';
46import { SpSegmentationChart } from './SpSegmentationChart';
47import { SpHangChart } from './SpHangChart';
48import { SpPerfOutputDataChart } from './SpPerfOutputDataChart';
49import {
50  queryAppStartupProcessIds,
51  queryDataDICT,
52  queryThreadAndProcessName,
53} from '../../database/sql/ProcessThread.sql';
54import { queryTaskPoolCallStack, queryTotalTime } from '../../database/sql/SqlLite.sql';
55import { queryMemoryConfig } from '../../database/sql/Memory.sql';
56import { SpLtpoChart } from './SpLTPO';
57import { SpBpftraceChart } from './SpBpftraceChart';
58import { sliceSender } from '../../database/data-trafic/SliceSender';
59import { BaseStruct } from '../../bean/BaseStruct';
60import { SpGpuCounterChart } from './SpGpuCounterChart';
61import { SpUserFileChart } from './SpUserPluginChart';
62import { SpImportUserPluginsChart } from './SpImportUserPluginsChart';
63import { queryDmaFenceIdAndCat } from '../../database/sql/dmaFence.sql';
64import { queryAllFuncNames } from '../../database/sql/Func.sql';
65
66export class SpChartManager {
67  static APP_STARTUP_PID_ARR: Array<number> = [];
68
69  private trace: SpSystemTrace;
70  public perf: SpHiPerf;
71  private cpu: SpCpuChart;
72  private freq: SpFreqChart;
73  private virtualMemChart: SpVirtualMemChart;
74  private fps: SpFpsChart;
75  private nativeMemory: SpNativeMemoryChart;
76  private abilityMonitor: SpAbilityMonitorChart;
77  private process: SpProcessChart;
78  private process2?: SpProcessChart;
79  private fileSystem: SpEBPFChart;
80  private sdkChart: SpSdkChart;
81  private hiSyseventChart: SpHiSysEnergyChart;
82  private smapsChart: VmTrackerChart;
83  private clockChart: SpClockChart;
84  private xpowerChart: SpXpowerChart;
85  private irqChart: SpIrqChart;
86  private spAllAppStartupsChart!: SpAllAppStartupsChart;
87  private SpLtpoChart!: SpLtpoChart;
88  frameTimeChart: SpFrameTimeChart;
89  public arkTsChart: SpArkTsChart;
90  private logChart: SpLogChart;
91  private spHiSysEvent: SpHiSysEventChart;
92  private spSegmentationChart: SpSegmentationChart;
93  private hangChart: SpHangChart;
94  private spBpftraceChart: SpBpftraceChart;
95  private spPerfOutputDataChart: SpPerfOutputDataChart;
96  private spGpuCounterChart: SpGpuCounterChart;
97  private spUserFileChart: SpUserFileChart;
98  private spImportUserPluginsChart: SpImportUserPluginsChart;
99
100  constructor(trace: SpSystemTrace) {
101    this.trace = trace;
102    this.perf = new SpHiPerf(trace);
103    this.fileSystem = new SpEBPFChart(trace);
104    this.cpu = new SpCpuChart(trace);
105    this.freq = new SpFreqChart(trace);
106    this.virtualMemChart = new SpVirtualMemChart(trace);
107    this.fps = new SpFpsChart(trace);
108    this.nativeMemory = new SpNativeMemoryChart(trace);
109    this.abilityMonitor = new SpAbilityMonitorChart(trace);
110    this.process = new SpProcessChart(trace);
111    this.sdkChart = new SpSdkChart(trace);
112    this.hiSyseventChart = new SpHiSysEnergyChart(trace);
113    this.smapsChart = new VmTrackerChart(trace);
114    this.clockChart = new SpClockChart(trace);
115    this.irqChart = new SpIrqChart(trace);
116    this.frameTimeChart = new SpFrameTimeChart(trace);
117    this.arkTsChart = new SpArkTsChart(trace);
118    this.logChart = new SpLogChart(trace);
119    this.spHiSysEvent = new SpHiSysEventChart(trace);
120    this.spAllAppStartupsChart = new SpAllAppStartupsChart(trace);
121    this.SpLtpoChart = new SpLtpoChart(trace);
122    this.spSegmentationChart = new SpSegmentationChart(trace);
123    this.hangChart = new SpHangChart(trace);
124    this.spBpftraceChart = new SpBpftraceChart(trace);
125    this.spPerfOutputDataChart = new SpPerfOutputDataChart(trace);
126    this.spGpuCounterChart = new SpGpuCounterChart(trace);
127    this.spUserFileChart = new SpUserFileChart(trace);
128    this.spImportUserPluginsChart = new SpImportUserPluginsChart(trace);
129    this.xpowerChart = new SpXpowerChart(trace);
130  }
131  async initPreprocessData(progress: Function): Promise<void> {
132    progress('load data dict', 50);
133    this.process2 = undefined;
134    SpSystemTrace.DATA_DICT.clear();
135    SpChartManager.APP_STARTUP_PID_ARR = [];
136    let dict = await queryDataDICT();
137    if (FlagsConfig.getFlagsConfigEnableStatus('AppStartup')) {
138      let appStartUpPids = await queryAppStartupProcessIds();
139      appStartUpPids.forEach((it) => SpChartManager.APP_STARTUP_PID_ARR.push(it.pid));
140    }
141    await this.initTraceConfig(); //@ts-ignore
142    dict.map((d) => SpSystemTrace.DATA_DICT.set(d.id, d.data));
143    await this.cacheDataDictToWorker();
144    SpSystemTrace.DATA_TASK_POOL_CALLSTACK.clear();
145    let taskPoolCallStack = await queryTaskPoolCallStack();
146    taskPoolCallStack.map((d) => SpSystemTrace.DATA_TASK_POOL_CALLSTACK.set(d.id, d));
147    progress('time range', 65);
148    await this.initTotalTime();
149    let ptArr = await queryThreadAndProcessName(); //@ts-ignore
150    this.handleProcessThread(ptArr);
151    info('initData timerShaftEL Data initialized');
152    let funArr = await queryAllFuncNames();
153    this.handleFuncName(funArr);
154  }
155
156  async initCpu(progress: Function): Promise<void> {
157    progress('cpu', 70);
158    let result = await sliceSender();
159    // @ts-ignore
160    SpProcessChart.threadStateList = result.threadMap;
161    // @ts-ignore
162    SpProcessChart.processRowSortMap = result.processRowSortMap;
163    //@ts-ignore
164    await this.cpu.init(result.count.cpu);
165    info('initData cpu Data initialized');
166    if (FlagsConfig.getFlagsConfigEnableStatus('Bpftrace')) {
167      await this.spBpftraceChart.init(null);
168    }
169    if (FlagsConfig.getFlagsConfigEnableStatus('UserPluginsRow')) {
170      await this.spUserFileChart.init(null)
171      await this.spImportUserPluginsChart.init();
172    }
173    if (FlagsConfig.getFlagsConfigEnableStatus('GpuCounter')) {
174      await this.spGpuCounterChart.init([]);
175    }
176    if (FlagsConfig.getFlagsConfigEnableStatus('SchedulingAnalysis')) {
177      await this.cpu.initCpuIdle0Data(progress);
178      await this.cpu.initSchedulingPTData(progress);
179      await this.cpu.initSchedulingFreqData(progress);
180    }
181    info('initData ProcessThreadState Data initialized');
182    progress('cpu rate', 75);
183    //@ts-ignore
184    await this.initCpuRate(result.cpuUtiliRateArray);
185    info('initData Cpu Rate Data initialized');
186    progress('cpu freq', 80);
187    await this.freq.init();
188    info('initData Cpu Freq Data initialized');
189  }
190
191  async init(progress: Function): Promise<void> {
192    info('initData data parse end ');
193    await this.initPreprocessData(progress);
194    await this.initCpu(progress);
195    await this.logChart.init();
196    await this.spHiSysEvent.init();
197    let idAndNameArr = await queryDmaFenceIdAndCat();
198    this.handleDmaFenceName(idAndNameArr as { id: number; cat: string; seqno: number; driver: string; context: string }[]);
199    if (FlagsConfig.getFlagsConfigEnableStatus('Hangs Detection')) {
200      progress('Hang init', 80);
201      await this.hangChart.init();
202    }
203    progress('Clock init', 82);
204    await this.clockChart.init();
205    progress('Xpower init', 83);
206    await this.xpowerChart.init();
207    progress('Irq init', 84);
208    await this.irqChart.init();
209    progress('SpSegmentationChart inin', 84.5);
210    await this.spSegmentationChart.init();
211    await this.virtualMemChart.init();
212    progress('fps', 85);
213    await this.fps.init();
214    progress('native memory', 87);
215    await this.nativeMemory.initChart();
216    progress('ability monitor', 88);
217    await this.abilityMonitor.init();
218    progress('hiSysevent', 88.2);
219    await this.hiSyseventChart.init();
220    progress('vm tracker', 88.4);
221    await this.smapsChart.init();
222    progress('sdk', 88.6);
223    await this.sdkChart.init();
224    progress('perf', 88.8);
225    await this.perf!.init();
226    await perfDataQuery.initPerfCache();
227    progress('file system', 89);
228    await this.fileSystem!.init();
229    progress('ark ts', 90);
230    await this.arkTsChart.initFolder();
231    await this.spAllAppStartupsChart.init();
232    await this.SpLtpoChart.init();
233    await this.frameTimeChart.init();
234    await this.spPerfOutputDataChart.init();
235    progress('process', 92);
236    this.process.clearCache();
237    this.process2?.clearCache();
238    this.process2 = undefined;
239    await this.process.initAsyncFuncData({
240      startTs: Utils.getInstance().getRecordStartNS(),
241      endTs: Utils.getInstance().getRecordEndNS(),
242    });
243    await this.process.initDeliverInputEvent();
244    await this.process.initTouchEventDispatch();
245    await this.process.init(false);
246    progress('display', 95);
247  }
248
249  async initDistributedChart(progress: Function, file1: string, file2: string): Promise<void> {
250    let funArr1 = await queryAllFuncNames('1');
251    let funArr2 = await queryAllFuncNames('2');
252    this.handleFuncName(funArr1, '1');
253    this.handleFuncName(funArr2, '2');
254    progress('load data dict', 50);
255    SpSystemTrace.DATA_DICT.clear();
256    SpChartManager.APP_STARTUP_PID_ARR = [];
257    SpSystemTrace.DATA_TASK_POOL_CALLSTACK.clear();
258    this.process.clearCache();
259    this.process2?.clearCache();
260    let trace1Folder = this.createFolderRow('trace-1', 'trace-1', file1);
261    let trace2Folder = this.createFolderRow('trace-2', 'trace-2', file2);
262    this.trace.rowsEL!.appendChild(trace1Folder);
263    this.trace.rowsEL!.appendChild(trace2Folder);
264    await this.initTotalTime(true);
265    await this.initDistributedTraceRow('1', trace1Folder, progress);
266    info(`trace 1 load completed`);
267    await this.initDistributedTraceRow('2', trace2Folder, progress);
268    info(`trace 2 load completed`);
269  }
270
271  // @ts-ignore
272  async initDistributedTraceRow(traceId: string, traceFolder: TraceRow<unknown>, progress: Function): Promise<void> {
273    let ptArr = await queryThreadAndProcessName(traceId);
274    // @ts-ignore
275    this.handleProcessThread(ptArr, traceId);
276    info(`initData trace ${traceId} timerShaftEL Data initialized`);
277    progress(`trace ${traceId} cpu`, 70);
278    let count = await sliceSender(traceId);
279    // @ts-ignore
280    await this.cpu.init(count.count.cpu, traceFolder, traceId);
281    info(`initData trace ${traceId} cpu Data initialized`);
282    progress(`trace ${traceId} cpu freq`, 75);
283    // @ts-ignore
284    await this.freq.init(traceFolder, traceId);
285    info(`initData trace ${traceId} cpu freq Data initialized`);
286    progress(`trace ${traceId} clock`, 80);
287    // @ts-ignore
288    await this.clockChart.init(traceFolder, traceId);
289    info(`initData trace ${traceId} clock Data initialized`);
290    progress(`trace ${traceId} Irq`, 85);
291    // @ts-ignore
292    await this.irqChart.init(traceFolder, traceId);
293    info(`initData trace ${traceId} irq Data initialized`);
294    progress(`trace ${traceId} process`, 92);
295    if (traceId === '2') {
296      if (!this.process2) {
297        this.process2 = new SpProcessChart(this.trace);
298      }
299      await this.process2.initAsyncFuncData(
300        {
301          startTs: Utils.getInstance().getRecordStartNS('2'),
302          endTs: Utils.getInstance().getRecordEndNS('2'),
303        },
304        traceId
305      );
306      await this.process2.init(true, traceFolder, traceId);
307    } else {
308      await this.process.initAsyncFuncData(
309        {
310          startTs: Utils.getInstance().getRecordStartNS('1'),
311          endTs: Utils.getInstance().getRecordEndNS('1'),
312        },
313        traceId
314      );
315      await this.process.init(true, traceFolder, traceId);
316    }
317  }
318
319  async initSample(ev: File) {
320    await this.initSampleTime(ev, 'bpftrace');
321    await this.spBpftraceChart.init(ev);
322  }
323
324  async initGpuCounter(ev: File): Promise<void> {
325    const res = await this.initSampleTime(ev, 'gpucounter');
326    //@ts-ignore
327    await this.spGpuCounterChart.init(res);
328  }
329
330  async importSoFileUpdate(): Promise<void> {
331    SpSystemTrace.DATA_DICT.clear();
332    let dict = await queryDataDICT(); //@ts-ignore
333    dict.map((d) => SpSystemTrace.DATA_DICT.set(d.id, d.data));
334    await this.cacheDataDictToWorker();
335    await perfDataQuery.initPerfCache();
336    await this.nativeMemory.initNativeMemory();
337    await this.fileSystem.initFileCallchain();
338    this.perf.resetAllChartData();
339  }
340
341  handleProcessThread(arr: { id: number; name: string; type: string }[], traceId?: string): void {
342    Utils.getInstance().getProcessMap(traceId).clear();
343    Utils.getInstance().getThreadMap(traceId).clear();
344    for (let pt of arr) {
345      if (pt.type === 'p') {
346        Utils.getInstance().getProcessMap(traceId).set(pt.id, pt.name);
347      } else {
348        Utils.getInstance().getThreadMap(traceId).set(pt.id, pt.name);
349      }
350    }
351  }
352
353  // 将callstatck表信息转为map存入utils
354  handleFuncName(funcNameArray: Array<unknown>, traceId?: string): void {
355    if (traceId) {
356      funcNameArray.forEach((it) => {
357        //@ts-ignore
358        Utils.getInstance().getCallStatckMap().set(`${traceId}_${it.id!}`, it.name);
359        //@ts-ignore
360        Utils.getInstance().getCallStatckMap().set(it.name, it.colorIndex);
361      });
362    } else {
363      funcNameArray.forEach((it) => {
364        //@ts-ignore
365        Utils.getInstance().getCallStatckMap().set(it.id, it.name);
366        //@ts-ignore
367        Utils.getInstance().getCallStatckMap().set(it.name, it.colorIndex);
368      });
369    }
370  }
371
372  initTotalTime = async (isDistributed: boolean = false): Promise<void> => {
373    let res1 = await queryTotalTime('1');
374    let total = res1[0].total;
375    Utils.getInstance().trace1RecordStartNS = res1[0].recordStartNS;
376    Utils.getInstance().trace1RecordEndNS = Math.max(res1[0].recordEndNS, res1[0].recordStartNS + 1);
377    if (isDistributed) {
378      let res2 = await queryTotalTime('2');
379      total = Math.max(total, res2[0].total);
380      Utils.getInstance().trace2RecordStartNS = res2[0].recordStartNS;
381      Utils.getInstance().trace2RecordEndNS = Math.max(res2[0].recordEndNS, res2[0].recordStartNS + 1);
382    }
383    if (this.trace.timerShaftEL) {
384      if (total === 0) {
385        total = 1;
386      }
387      Utils.getInstance().totalNS = total;
388      this.trace.timerShaftEL.totalNS = total;
389      this.trace.timerShaftEL.getRangeRuler()!.drawMark = true;
390      this.trace.timerShaftEL.setRangeNS(0, total);
391      window.recordStartNS = Utils.getInstance().trace1RecordStartNS;
392      window.recordEndNS = Utils.getInstance().trace1RecordEndNS;
393      window.totalNS = total;
394      this.trace.timerShaftEL.loadComplete = true;
395    }
396  };
397
398  initSampleTime = async (ev: File, type: string): Promise<unknown> => {
399    let res;
400    let endNS = 30_000_000_000;
401    if (type === 'gpucounter') {
402      res = await this.spGpuCounterChart.getCsvData(ev);
403      // @ts-ignore
404      const endTime = Number(res[res.length - 1].split(',')[0]);
405      // @ts-ignore
406      const minIndex = this.spGpuCounterChart.getMinData(res) + 1;
407      // @ts-ignore
408      const startTime = Number(res[minIndex].split(',')[0]);
409      endNS = Number((endTime - startTime).toString().slice(0, 11));
410    }
411    if (this.trace.timerShaftEL) {
412      let total = endNS;
413      let startNS = 0;
414      this.trace.timerShaftEL.totalNS = total;
415      this.trace.timerShaftEL.getRangeRuler()!.drawMark = true;
416      this.trace.timerShaftEL.setRangeNS(0, total); // @ts-ignore
417      (window as unknown).recordStartNS = startNS; // @ts-ignore
418      (window as unknown).recordEndNS = endNS; // @ts-ignore
419      (window as unknown).totalNS = total;
420      this.trace.timerShaftEL.loadComplete = true;
421    }
422    return res;
423  };
424
425  initCpuRate = async (rates: Array<{ cpu: number; ro: number; rate: number; }>): Promise<void> => {
426    if (this.trace.timerShaftEL) {
427      this.trace.timerShaftEL.cpuUsage = rates;
428    }
429    info('Cpu UtilizationRate data size is: ', rates.length);
430  };
431
432  initTraceConfig = async (): Promise<void> => {
433    queryMemoryConfig().then((result) => {
434      if (result && result.length > 0) {
435        const config = result[0];
436        MemoryConfig.getInstance().updateConfig(config.pid, config.iPid, config.processName, config.interval);
437      }
438    });
439  };
440
441  async cacheDataDictToWorker(): Promise<void> {
442    return new Promise((resolve) => {
443      procedurePool.submitWithName(
444        'logic0',
445        'cache-data-dict',
446        { dataDict: SpSystemTrace.DATA_DICT },
447        undefined,
448        (res: unknown): void => {
449          resolve();
450        }
451      );
452    });
453  }
454
455  // @ts-ignore
456  createFolderRow(rowId: string, rowType: string, rowName: string, traceId?: string): TraceRow<unknown> {
457    let row = TraceRow.skeleton<BaseStruct>(traceId);
458    row.setAttribute('disabled-check', '');
459    row.rowId = rowId;
460    row.rowType = rowType;
461    row.rowParentId = '';
462    row.folder = true;
463    row.style.height = '40px';
464    row.name = rowName;
465    // @ts-ignore
466    row.supplier = folderSupplier();
467    row.onThreadHandler = folderThreadHandler(row, this.trace);
468    row.addEventListener('expansion-change', (evt) => {
469      if (!row.expansion) {
470        this.trace.clickEmptyArea();
471      }
472    });
473    return row;
474  }
475
476  //存名字
477  handleDmaFenceName<T extends { id: number; cat: string; seqno: number; driver: string; context: string }>(arr: T[]): void {
478    Utils.DMAFENCECAT_MAP.clear();
479    for (let item of arr) {
480      Utils.DMAFENCECAT_MAP.set(item.id, item);
481    }
482  }
483}
484
485export const folderSupplier = (): () => Promise<BaseStruct[]> => {
486  return () => new Promise<Array<BaseStruct>>((resolve) => resolve([]));
487};
488
489export const folderThreadHandler = (row: TraceRow<BaseStruct>, trace: SpSystemTrace) => {
490  return (useCache: boolean): void => {
491    row.canvasSave(trace.canvasPanelCtx!);
492    if (row.expansion) {
493      // @ts-ignore
494      trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
495    } else {
496      (renders.empty as EmptyRender).renderMainThread(
497        {
498          context: trace.canvasPanelCtx,
499          useCache: useCache,
500          type: '',
501        },
502        row
503      );
504    }
505    row.canvasRestore(trace.canvasPanelCtx!, trace);
506  };
507};
508
509export function rowThreadHandler<T>(
510  tag: string,
511  contextField: string,
512  arg: unknown, // @ts-ignore
513  row: TraceRow<unknown>,
514  trace: SpSystemTrace
515) {
516  return (useCache: boolean): void => {
517    let context: CanvasRenderingContext2D = getRowContext(row, trace);
518    row.canvasSave(context); // @ts-ignore
519    arg.useCache = useCache;
520    if (contextField) {
521      // @ts-ignore
522      arg[contextField] = context;
523    } // @ts-ignore
524    (renders[tag] as unknown).renderMainThread(arg, row);
525    row.canvasRestore(context, trace);
526  };
527}
528// @ts-ignore
529export const getRowContext = (row: TraceRow<unknown>, trace: SpSystemTrace): CanvasRenderingContext2D => {
530  if (row.currentContext) {
531    return row.currentContext;
532  } else {
533    return row.collect ? trace.canvasFavoritePanelCtx! : trace.canvasPanelCtx!;
534  }
535};
536