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