• 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 */
15import { SpSystemTrace } from '../SpSystemTrace';
16import { TraceRow } from '../trace/base/TraceRow';
17import { info } from '../../../log/Log';
18import { renders } from '../../database/ui-worker/ProcedureWorker';
19import { type EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
20import { type HeapTimelineRender, HeapTimelineStruct } from '../../database/ui-worker/ProcedureWorkerHeapTimeline';
21import { HeapDataInterface, type ParseListener } from '../../../js-heap/HeapDataInterface';
22import { LoadDatabase } from '../../../js-heap/LoadDatabase';
23import { type FileInfo } from '../../../js-heap/model/UiStruct';
24import { type HeapSnapshotRender, HeapSnapshotStruct } from '../../database/ui-worker/ProcedureWorkerHeapSnapshot';
25import { procedurePool } from '../../database/Procedure';
26import { Utils } from '../trace/base/Utils';
27import { type JsCpuProfilerChartFrame } from '../../bean/JsStruct';
28import { type JsCpuProfilerRender, JsCpuProfilerStruct } from '../../database/ui-worker/ProcedureWorkerCpuProfiler';
29import { ns2s } from '../../database/ui-worker/ProcedureWorkerCommon';
30import {
31  cpuProfilerDataSender
32} from '../../database/data-trafic/ArkTsSender';
33import {queryJsCpuProfilerConfig, queryJsCpuProfilerData} from "../../database/sql/Cpu.sql";
34import {queryJsMemoryData} from "../../database/sql/Memory.sql";
35
36const TYPE_SNAPSHOT = 0;
37const TYPE_TIMELINE = 1;
38const LAMBDA_FUNCTION_NAME = '(anonymous)';
39export class SpArkTsChart implements ParseListener {
40  private trace: SpSystemTrace;
41  private folderRow: TraceRow<any> | undefined;
42  private jsCpuProfilerRow: TraceRow<JsCpuProfilerStruct> | undefined;
43  private heapTimelineRow: TraceRow<HeapTimelineStruct> | undefined;
44  private heapSnapshotRow: TraceRow<HeapSnapshotStruct> | undefined;
45  private loadJsDatabase: LoadDatabase;
46  private allCombineDataMap = new Map<number, JsCpuProfilerChartFrame>();
47  private process: string = '';
48
49  constructor(trace: SpSystemTrace) {
50    this.trace = trace;
51    this.loadJsDatabase = LoadDatabase.getInstance();
52  }
53
54  public get chartFrameMap(): Map<number, JsCpuProfilerChartFrame> {
55    return this.allCombineDataMap;
56  }
57
58  public async initFolder(): Promise<void> {
59    let jsConfig = await queryJsCpuProfilerConfig();
60
61    let jsCpu = await queryJsCpuProfilerData();
62    let jsMemory = await queryJsMemoryData();
63    if (jsMemory.length > 0 || jsCpu.length > 0) {
64      this.folderRow = TraceRow.skeleton();
65      this.process = jsConfig[0].pid;
66      this.folderRow.rowId = this.process;
67      this.folderRow.rowType = TraceRow.ROW_TYPE_ARK_TS;
68      this.folderRow.style.height = '40px';
69      this.folderRow.rowParentId = '';
70      this.folderRow.folder = true;
71      this.folderRow.name = `Ark Ts ` + this.process;
72      this.folderRow.addTemplateTypes('ArkTs');
73      this.folderRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
74      this.folderRow.selectChangeHandler = this.trace.selectChangeHandler;
75      this.folderRow.supplierFrame = (): Promise<Array<unknown>> =>
76        new Promise<Array<unknown>>((resolve) => resolve([]));
77      this.folderRow.onThreadHandler = (useCache): void => {
78        this.folderRow!.canvasSave(this.trace.canvasPanelCtx!);
79        if (this.folderRow!.expansion) {
80          this.trace.canvasPanelCtx?.clearRect(0, 0, this.folderRow!.frame.width, this.folderRow!.frame.height);
81        } else {
82          (renders.empty as EmptyRender).renderMainThread(
83            {
84              context: this.trace.canvasPanelCtx,
85              useCache: useCache,
86              type: ``,
87            },
88            this.folderRow!
89          );
90        }
91        this.folderRow!.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
92      };
93      this.trace.rowsEL?.appendChild(this.folderRow);
94      if (this.folderRow && jsConfig[0].type !== -1 && jsMemory.length > 0) {
95        this.folderRow.addTemplateTypes('Memory');
96        if (jsConfig[0].type === TYPE_SNAPSHOT) {
97          // snapshot
98          await this.initSnapshotChart();
99        } else if (jsConfig[0].type === TYPE_TIMELINE) {
100          // timeline
101          await this.initTimelineChart();
102        }
103      }
104      if (this.folderRow && jsConfig[0].enableCpuProfiler === 1 && jsCpu.length > 0) {
105        await this.initJsCpuChart();
106      }
107      if ((this.heapSnapshotRow || this.heapTimelineRow) && jsMemory.length > 0) {
108        await this.loadJsDatabase.loadDatabase(this);
109      }
110      if (this.jsCpuProfilerRow && jsCpu.length > 0) {
111        this.jsCpuProfilerRow!.supplierFrame = (): Promise<Array<any>> => {
112          return cpuProfilerDataSender(this.jsCpuProfilerRow!).then((res: any) => {
113            let maxHeight = res.maxDepth * 20;
114            this.jsCpuProfilerRow!.style.height = `${maxHeight}px`;
115            if (res.dataList.length > 0) {
116              this.allCombineDataMap = new Map<number, JsCpuProfilerChartFrame>();
117              for (let data of res.dataList) {
118                this.allCombineDataMap.set(data.id, data);
119                SpSystemTrace.jsProfilerMap.set(data.id, data);
120              }
121              res.dataList.forEach((data: any) => {
122                data.children = [];
123                if (data.childrenIds.length > 0) {
124                  for (let id of data.childrenIds) {
125                    let child = SpSystemTrace.jsProfilerMap.get(Number(id));
126                    data.children.push(child);
127                  }
128                }
129                data.name = SpSystemTrace.DATA_DICT.get(data.nameId) || LAMBDA_FUNCTION_NAME;
130                data.url = SpSystemTrace.DATA_DICT.get(data.urlId) || 'unknown';
131                if (data.url && data.url !== 'unknown') {
132                  let dirs = data.url.split('/');
133                  data.scriptName = dirs.pop() || '';
134                }
135              });
136            }
137            return res.dataList;
138          });
139        };
140      }
141    }
142  }
143
144  private async initTimelineChart(): Promise<void> {
145    this.heapTimelineRow = TraceRow.skeleton<HeapTimelineStruct>();
146    this.heapTimelineRow.rowParentId = this.process;
147    this.heapTimelineRow.rowHidden = !this.folderRow!.expansion;
148    this.heapTimelineRow.style.height = '40px';
149    this.heapTimelineRow.name = `Heaptimeline`;
150    this.heapTimelineRow.folder = false;
151    this.heapTimelineRow.rowType = TraceRow.ROW_TYPE_HEAP_TIMELINE;
152    this.heapTimelineRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
153    this.heapTimelineRow.selectChangeHandler = this.trace.selectChangeHandler;
154    this.heapTimelineRow.setAttribute('children', '');
155    this.heapTimelineRow!.focusHandler = (): void => {
156      this.trace?.displayTip(
157        this.heapTimelineRow!,
158        HeapTimelineStruct.hoverHeapTimelineStruct,
159        `<span>Size: ${Utils.getBinaryByteWithUnit(HeapTimelineStruct.hoverHeapTimelineStruct?.size || 0)}</span>`
160      );
161    };
162    this.heapTimelineRow!.findHoverStruct = () => {
163      HeapTimelineStruct.hoverHeapTimelineStruct = this.heapTimelineRow!.getHoverStruct();
164    };
165    this.folderRow!.addChildTraceRow(this.heapTimelineRow!);
166  }
167
168  private async initSnapshotChart(): Promise<void> {
169    this.heapSnapshotRow = TraceRow.skeleton<HeapSnapshotStruct>();
170    this.heapSnapshotRow.rowParentId = this.process;
171    this.heapSnapshotRow.rowHidden = !this.folderRow!.expansion;
172    this.heapSnapshotRow.style.height = '40px';
173    this.heapSnapshotRow.name = `Heapsnapshot`;
174    this.heapSnapshotRow.rowId = `heapsnapshot`;
175    this.heapSnapshotRow.folder = false;
176    this.heapSnapshotRow.rowType = TraceRow.ROW_TYPE_HEAP_SNAPSHOT;
177    this.heapSnapshotRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
178    this.heapSnapshotRow.selectChangeHandler = this.trace.selectChangeHandler;
179    this.heapSnapshotRow.setAttribute('children', '');
180    this.heapSnapshotRow!.focusHandler = (): void => {
181      this.trace?.displayTip(
182        this.heapSnapshotRow!,
183        HeapSnapshotStruct.hoverSnapshotStruct,
184        `<span>Name: ${HeapSnapshotStruct.hoverSnapshotStruct?.name || ''}</span>
185            <span>Size: ${Utils.getBinaryByteWithUnit(HeapSnapshotStruct.hoverSnapshotStruct?.size || 0)}</span>`
186      );
187    };
188    this.heapSnapshotRow!.findHoverStruct = () => {
189      HeapSnapshotStruct.hoverSnapshotStruct = this.heapSnapshotRow!.getHoverStruct();
190    };
191    this.folderRow!.addChildTraceRow(this.heapSnapshotRow);
192  }
193
194  public async parseDone(fileModule: Array<FileInfo>): Promise<void> {
195    if (fileModule.length > 0) {
196      let heapFile = HeapDataInterface.getInstance().getFileStructs();
197      let file = heapFile[0];
198      this.trace.snapshotFile = file;
199      if (file.type === TYPE_TIMELINE) {
200        let samples = HeapDataInterface.getInstance().getSamples(file.id);
201        this.heapTimelineRow!.rowId = `heaptimeline` + file.id;
202        this.heapTimelineRow!.supplierFrame = (): Promise<any> => new Promise<any>((resolve) => resolve(samples));
203        this.heapTimelineRow!.onThreadHandler = (useCache): void => {
204          let context: CanvasRenderingContext2D;
205          if (this.heapTimelineRow?.currentContext) {
206            context = this.heapTimelineRow!.currentContext;
207          } else {
208            context = this.heapTimelineRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
209          }
210          this.heapTimelineRow!.canvasSave(context);
211          (renders['heap-timeline'] as HeapTimelineRender).renderMainThread(
212            {
213              context: context,
214              useCache: useCache,
215              type: `heap-timeline`,
216              samples: samples,
217            },
218            this.heapTimelineRow!
219          );
220          this.heapTimelineRow!.canvasRestore(context, this.trace);
221        };
222      } else if (file.type === TYPE_SNAPSHOT) {
223        this.heapSnapshotRow!.supplierFrame = (): Promise<Array<any>> =>
224          new Promise<Array<any>>((resolve) => resolve(heapFile));
225        this.heapSnapshotRow!.onThreadHandler = (useCache): void => {
226          let context: CanvasRenderingContext2D;
227          if (this.heapSnapshotRow?.currentContext) {
228            context = this.heapSnapshotRow!.currentContext;
229          } else {
230            context = this.heapSnapshotRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
231          }
232          this.heapSnapshotRow!.canvasSave(context);
233          (renders['heap-snapshot'] as HeapSnapshotRender).renderMainThread(
234            {
235              context: context,
236              useCache: useCache,
237              type: `heap-snapshot`,
238            },
239            this.heapSnapshotRow!
240          );
241          this.heapSnapshotRow!.canvasRestore(context, this.trace);
242        };
243      }
244    }
245  }
246
247  private initJsCpuChart = async (): Promise<void> => {
248    this.jsCpuProfilerRow = TraceRow.skeleton<JsCpuProfilerStruct>();
249    this.jsCpuProfilerRow.rowParentId = this.process;
250    this.jsCpuProfilerRow.rowHidden = !this.folderRow!.expansion;
251    this.jsCpuProfilerRow.name = 'CpuProfiler';
252    this.jsCpuProfilerRow.rowId = 'JsCpuProfiler';
253    this.jsCpuProfilerRow.folder = false;
254    this.jsCpuProfilerRow.rowType = TraceRow.ROW_TYPE_JS_CPU_PROFILER;
255    this.jsCpuProfilerRow!.style.height = '40px';
256    this.jsCpuProfilerRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
257    this.jsCpuProfilerRow.selectChangeHandler = this.trace.selectChangeHandler;
258    this.jsCpuProfilerRow.setAttribute('children', '');
259    this.jsCpuProfilerRow.focusHandler = (): void => {
260      this.trace?.displayTip(
261        this.jsCpuProfilerRow!,
262        JsCpuProfilerStruct.hoverJsCpuProfilerStruct,
263        `<span style='font-weight: bold;'>Name: </span>
264        <span>${JsCpuProfilerStruct.hoverJsCpuProfilerStruct?.name || ''}</span><br>
265        <span style='font-weight: bold;'>Self Time: </span>
266        <span>${ns2s(JsCpuProfilerStruct.hoverJsCpuProfilerStruct?.selfTime || 0)}</span><br>
267        <span style='font-weight: bold;'>Total Time: </span>
268        <span>${ns2s(JsCpuProfilerStruct.hoverJsCpuProfilerStruct?.totalTime || 0)}</span><br>
269        <span style='font-weight: bold;'>Url: </span>
270        <span>${JsCpuProfilerStruct.hoverJsCpuProfilerStruct?.url || 0}</span>`
271      );
272    };
273    this.jsCpuProfilerRow!.findHoverStruct = () => {
274      JsCpuProfilerStruct.hoverJsCpuProfilerStruct = this.jsCpuProfilerRow!.getHoverStruct();
275    };
276    this.jsCpuProfilerRow.onThreadHandler = (useCache): void => {
277      let context: CanvasRenderingContext2D;
278      if (this.jsCpuProfilerRow?.currentContext) {
279        context = this.jsCpuProfilerRow!.currentContext;
280      } else {
281        context = this.jsCpuProfilerRow!.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
282      }
283      this.jsCpuProfilerRow!.canvasSave(context);
284      (renders['js-cpu-profiler'] as JsCpuProfilerRender).renderMainThread(
285        {
286          context: context,
287          useCache: useCache,
288          type: `js-cpu-profiler`,
289        },
290        this.jsCpuProfilerRow!
291      );
292      this.jsCpuProfilerRow!.canvasRestore(context, this.trace);
293    };
294    this.folderRow!.addChildTraceRow(this.jsCpuProfilerRow);
295  };
296}
297