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