• 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 { info } from '../../../log/Log';
19import { procedurePool } from '../../database/Procedure';
20import { type NativeEventHeap } from '../../bean/NativeHook';
21import { HeapRender, HeapStruct } from '../../database/ui-worker/ProcedureWorkerHeap';
22import { Utils } from '../trace/base/Utils';
23import { renders } from '../../database/ui-worker/ProcedureWorker';
24import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
25import { type BaseStruct } from '../../bean/BaseStruct';
26import {
27  nativeMemoryChartDataCacheSender,
28  nativeMemoryChartDataSender,
29} from '../../database/data-trafic/NativeMemoryDataSender';
30import { queryNativeHookProcess, queryNativeHookStatisticsCount } from '../../database/sql/NativeHook.sql';
31import { queryHeapGroupByEvent } from '../../database/sql/SqlLite.sql';
32import { queryNativeMemoryRealTime } from '../../database/sql/Memory.sql';
33import { queryBootTime } from '../../database/sql/Clock.sql';
34
35export class SpNativeMemoryChart {
36  static EVENT_HEAP: Array<NativeEventHeap> = [];
37  static REAL_TIME_DIF: number = 0;
38  private trace: SpSystemTrace;
39
40  constructor(trace: SpSystemTrace) {
41    this.trace = trace;
42  }
43
44  folderThreadHandler(row: TraceRow<BaseStruct>): void {
45    row.onThreadHandler = (useCache): void => {
46      row.canvasSave(this.trace.canvasPanelCtx!);
47      if (row.expansion) {
48        // @ts-ignore
49        this.trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
50      } else {
51        (renders.empty as EmptyRender).renderMainThread(
52          {
53            context: this.trace.canvasPanelCtx,
54            useCache: useCache,
55            type: '',
56          },
57          row
58        );
59      }
60      row.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
61    };
62  }
63
64  chartThreadHandler(row: TraceRow<HeapStruct>): void {
65    row.onThreadHandler = (useCache): void => {
66      let context: CanvasRenderingContext2D;
67      if (row.currentContext) {
68        context = row.currentContext;
69      } else {
70        context = row.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
71      }
72      row.canvasSave(context);
73      (renders.heap as HeapRender).renderMainThread(
74        {
75          context: context,
76          useCache: useCache,
77          type: 'heap',
78        },
79        row
80      );
81      row.canvasRestore(context, this.trace);
82    };
83  }
84
85  initNativeMemoryFolder(process: number, ipid: number): TraceRow<BaseStruct> {
86    const nativeRow = TraceRow.skeleton();
87    nativeRow.rowId = `native-memory ${process} ${ipid}`;
88    nativeRow.index = 0;
89    nativeRow.rowType = TraceRow.ROW_TYPE_NATIVE_MEMORY;
90    nativeRow.drawType = 0;
91    nativeRow.style.height = '40px';
92    nativeRow.rowParentId = '';
93    nativeRow.folder = true;
94    nativeRow.addTemplateTypes('NativeMemory', 'Memory');
95    nativeRow.name = `Native Memory (${process})`;
96    nativeRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
97    nativeRow.selectChangeHandler = this.trace.selectChangeHandler;
98    nativeRow.addRowSettingPop();
99    nativeRow.rowSetting = 'enable';
100    nativeRow.rowSettingPopoverDirection = 'bottomLeft';
101    nativeRow.rowSettingList = [
102      {
103        key: '0',
104        title: 'Current Bytes',
105        checked: true,
106      },
107      {
108        key: '1',
109        title: 'Native Memory Density',
110      },
111    ];
112    nativeRow.onRowSettingChangeHandler = (value): void => {
113      nativeRow.childrenList.forEach((row) => (row.drawType = parseInt(value[0])));
114      this.trace
115        .getCollectRows((row) => row.rowType === 'heap')
116        .forEach((it) => {
117          it.drawType = parseInt(value[0]);
118        });
119      this.trace.refreshCanvas(false);
120    };
121    nativeRow.supplier = (): Promise<BaseStruct[]> => new Promise<Array<BaseStruct>>((resolve) => resolve([]));
122    this.folderThreadHandler(nativeRow);
123    this.trace.rowsEL?.appendChild(nativeRow);
124    return nativeRow;
125  }
126
127  initAllocMapChart(folder: TraceRow<BaseStruct>, type: string, process: { pid: number; ipid: number }): void {
128    const chartList = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
129    for (let i = 0; i < chartList.length; i++) {
130      const nm = chartList[i];
131      const allHeapRow = TraceRow.skeleton<HeapStruct>();
132      allHeapRow.index = i;
133      allHeapRow.rowParentId = `native-memory ${process.pid} ${process.ipid}`;
134      allHeapRow.rowHidden = !folder.expansion;
135      allHeapRow.style.height = '40px';
136      allHeapRow.name = nm;
137      allHeapRow.rowId = nm;
138      allHeapRow.drawType = 0;
139      allHeapRow.isHover = true;
140      allHeapRow.folder = false;
141      allHeapRow.rowType = TraceRow.ROW_TYPE_HEAP;
142      allHeapRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
143      allHeapRow.selectChangeHandler = this.trace.selectChangeHandler;
144      allHeapRow.setAttribute('heap-type', type);
145      allHeapRow.setAttribute('children', '');
146      allHeapRow.focusHandler = (): void => {
147        let tip = '';
148        if (HeapStruct.hoverHeapStruct) {
149          if (allHeapRow.drawType === 1) {
150            tip = `<span>${HeapStruct.hoverHeapStruct.density}</span>`;
151          } else {
152            tip = `<span>${Utils.getByteWithUnit(HeapStruct.hoverHeapStruct.heapsize!)}</span>`;
153          }
154        }
155        this.trace?.displayTip(allHeapRow, HeapStruct.hoverHeapStruct, tip);
156      };
157      allHeapRow.findHoverStruct = (): void => {
158        HeapStruct.hoverHeapStruct = allHeapRow.getHoverStruct();
159      }; //@ts-ignore
160      allHeapRow.supplierFrame = (): Promise<unknown> =>
161        nativeMemoryChartDataSender(allHeapRow, {
162          eventType: i,
163          ipid: process.ipid,
164          model: type,
165          drawType: allHeapRow.drawType,
166        });
167      this.chartThreadHandler(allHeapRow);
168      folder.addChildTraceRow(allHeapRow);
169    }
170  }
171
172  initChart = async (): Promise<void> => {
173    let time = new Date().getTime();
174    let nativeMemoryType = 'native_hook';
175    let nmsCount = await queryNativeHookStatisticsCount();
176    if (nmsCount && nmsCount[0] && nmsCount[0].num > 0) {
177      nativeMemoryType = 'native_hook_statistic';
178    }
179    let nativeProcess = await queryNativeHookProcess(nativeMemoryType);
180    info('NativeHook Process data size is: ', nativeProcess!.length);
181    if (nativeProcess.length === 0) {
182      return;
183    }
184    await this.initNativeMemory();
185    await nativeMemoryChartDataCacheSender(
186      nativeProcess.map((it) => it.ipid),
187      nativeMemoryType
188    );
189    SpNativeMemoryChart.EVENT_HEAP = await queryHeapGroupByEvent(nativeMemoryType);
190    for (const process of nativeProcess) {
191      const nativeRow = this.initNativeMemoryFolder(process.pid, process.ipid);
192      this.initAllocMapChart(nativeRow, nativeMemoryType, process);
193    }
194    let durTime = new Date().getTime() - time;
195    info('The time to load the Native Memory data is: ', durTime);
196  };
197
198  initNativeMemory = async (): Promise<void> => {
199    let time = new Date().getTime();
200    let isRealtime = false;
201    let realTimeDif = 0;
202    SpNativeMemoryChart.REAL_TIME_DIF = 0;
203    let queryTime = await queryNativeMemoryRealTime();
204    let bootTime = await queryBootTime();
205    if (queryTime.length > 0) {
206      //@ts-ignore
207      isRealtime = queryTime[0].clock_name === 'realtime';
208    }
209    if (bootTime.length > 0 && isRealtime) {
210      //@ts-ignore
211      realTimeDif = queryTime[0].ts - bootTime[0].ts;
212      SpNativeMemoryChart.REAL_TIME_DIF = realTimeDif;
213    }
214    await new Promise<unknown>((resolve) => {
215      procedurePool.submitWithName(
216        'logic0',
217        'native-memory-init',
218        { isRealtime, realTimeDif },
219        undefined,
220        (res: unknown) => {
221          resolve(res);
222        }
223      );
224    });
225    let durTime = new Date().getTime() - time;
226    info('The time to init the native memory data is: ', durTime);
227  };
228}
229