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