• 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 { BaseElement, element } from '../../../../../base-ui/BaseElement';
17import { LitTable } from '../../../../../base-ui/table/lit-table';
18import { SelectionParam } from '../../../../bean/BoxSelection';
19import { NativeHookMalloc, NativeHookStatisticsTableData } from '../../../../bean/NativeHook';
20import { Utils } from '../../base/Utils';
21import { SpSystemTrace } from '../../../SpSystemTrace';
22import '../TabProgressBar';
23import { SpNativeMemoryChart } from '../../../chart/SpNativeMemoryChart';
24import { resizeObserver } from '../SheetUtils';
25import { TabPaneNMSampleList } from './TabPaneNMSampleList';
26import {
27  queryNativeHookStatistics,
28  queryNativeHookStatisticsMalloc,
29  queryNativeHookStatisticsSubType,
30} from '../../../../database/sql/NativeHook.sql';
31import { queryHeapSizeByIpid } from '../../../../database/sql/SqlLite.sql';
32
33
34@element('tabpane-native-statistics')
35export class TabPaneNMStatstics extends BaseElement {
36  private nativeStatisticsTbl: LitTable | null | undefined;
37  private nativeStatisticsSource: Array<NativeHookStatisticsTableData> = [];
38  private nativeType: Array<string> = ['All Heap & Anonymous VM', 'All Heap', 'All Anonymous VM'];
39  private allMax: number = 0;
40  private sortColumn: string = '';
41  private sortType: number = 0;
42  private currentSelection: SelectionParam | undefined;
43  private currentSelectIPid = 1;
44
45  set data(nativeStatisticsParam: SelectionParam) {
46    if (nativeStatisticsParam === this.currentSelection) {
47      return;
48    }
49    this.currentSelectIPid = nativeStatisticsParam.nativeMemoryCurrentIPid;
50    this.currentSelection = nativeStatisticsParam;
51    this.allMax = 0;
52    TabPaneNMSampleList.clearData();
53    this.recordEventHeap(nativeStatisticsParam.nativeMemoryCurrentIPid);
54    if (nativeStatisticsParam.nativeMemory.length > 0) {
55      Utils.getInstance().setCurrentSelectIPid(this.currentSelectIPid);
56      Utils.getInstance().initResponseTypeList(nativeStatisticsParam);
57    }
58    if (this.nativeStatisticsTbl) {
59      // @ts-ignore
60      this.nativeStatisticsTbl.shadowRoot.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 25
61        }px`;
62      // @ts-ignore
63      this.nativeStatisticsTbl.recycleDataSource = [];
64    }
65    this.nativeStatisticsTbl!.loading = true;
66    this.queryData(nativeStatisticsParam);
67  }
68
69  async recordEventHeap(ipid: number): Promise<void> {
70    SpNativeMemoryChart.EVENT_HEAP = await queryHeapSizeByIpid(ipid);
71    SpNativeMemoryChart.EVENT_HEAP.map((heap) => {
72      this.allMax += heap.sumHeapSize;
73    });
74  }
75
76  queryData(nativeStatisticsParam: SelectionParam): void {
77    Promise.all([
78      queryNativeHookStatistics(nativeStatisticsParam.leftNs, nativeStatisticsParam.rightNs, this.currentSelectIPid),
79      queryNativeHookStatisticsSubType(
80        nativeStatisticsParam.leftNs,
81        nativeStatisticsParam.rightNs,
82        this.currentSelectIPid
83      ),
84      queryNativeHookStatisticsMalloc(
85        nativeStatisticsParam.leftNs,
86        nativeStatisticsParam.rightNs,
87        this.currentSelectIPid
88      ),
89    ]).then((values) => {
90      this.nativeStatisticsTbl!.loading = false;
91      let arr: Array<NativeHookStatisticsTableData> = [];
92      let index1 = nativeStatisticsParam.nativeMemory.indexOf(this.nativeType[0]);
93      let index2 = nativeStatisticsParam.nativeMemory.indexOf(this.nativeType[1]);
94      let index3 = nativeStatisticsParam.nativeMemory.indexOf(this.nativeType[2]);
95      this.setMemoryTypeData(nativeStatisticsParam, values[0], arr);
96      if (index1 !== -1 || index3 !== -1) {
97        this.setSubTypeTableData(values[1], arr);
98      }
99      let type = 0;
100      if (index1 !== -1 || (index2 !== -1 && index3 !== -1)) {
101        type = 0;
102      } else {
103        type = index2 !== -1 ? 1 : 2;
104      }
105      this.setMallocTableData(values[2], arr, type);
106      this.nativeStatisticsSource = arr;
107      this.sortByColumn(this.sortColumn, this.sortType);
108    });
109  }
110
111  setMallocTableData(result: Array<NativeHookMalloc>, arr: Array<NativeHookStatisticsTableData>, type: number): void {
112    result.map((malloc) => {
113      let data = new NativeHookStatisticsTableData();
114      if (malloc.eventType === 'AllocEvent') {
115        data.memoryTap = `Malloc ${Utils.getByteWithUnit(malloc.heapSize)}`;
116      } else {
117        data.memoryTap = `Mmap ${Utils.getByteWithUnit(malloc.heapSize)}`;
118      }
119      data.existing = malloc.allocByte - malloc.freeByte;
120      data.allocCount = malloc.allocCount - malloc.freeCount;
121      data.freeCount = malloc.freeCount;
122      data.freeByte = malloc.freeByte;
123      data.totalBytes = malloc.allocByte;
124      data.totalCount = malloc.allocCount;
125      data.max = malloc.heapSize;
126      data.existingString = Utils.getByteWithUnit(data.existing);
127      data.freeByteString = Utils.getByteWithUnit(malloc.freeByte);
128      data.totalBytesString = Utils.getByteWithUnit(data.totalBytes);
129      data.maxStr = Utils.getByteWithUnit(malloc.heapSize);
130      data.existingValue = [data.existing, data.totalBytes, this.allMax];
131      if (type === 0) {
132        arr.push(data);
133      } else if (type === 1 && malloc.eventType === 'AllocEvent') {
134        arr.push(data);
135      } else if (type === 2 && malloc.eventType === 'MmapEvent') {
136        arr.push(data);
137      } else {
138      }
139    });
140  }
141
142  setSubTypeTableData(result: Array<NativeHookMalloc>, arr: Array<NativeHookStatisticsTableData>): void {
143    result.map((sub) => {
144      let subType = SpSystemTrace.DATA_DICT.get(sub.subTypeId);
145      if (subType !== null && subType !== undefined) {
146        let data = new NativeHookStatisticsTableData();
147        data.memoryTap = subType;
148        data.existing = sub.allocByte - sub.freeByte;
149        data.allocCount = sub.allocCount - sub.freeCount;
150        data.freeCount = sub.freeCount;
151        data.freeByte = sub.freeByte;
152        data.totalBytes = sub.allocByte;
153        data.totalCount = sub.allocCount;
154        data.max = sub.max;
155        data.freeByteString = Utils.getByteWithUnit(sub.freeByte);
156        data.existingString = Utils.getByteWithUnit(data.existing);
157        data.totalBytesString = Utils.getByteWithUnit(data.totalBytes);
158        data.maxStr = Utils.getByteWithUnit(sub.max);
159        data.existingValue = [data.existing, data.totalBytes, this.allMax];
160        arr.push(data);
161      }
162    });
163  }
164
165  setMemoryTypeData(
166    val: SelectionParam,
167    result: Array<NativeHookMalloc>,
168    arr: Array<NativeHookStatisticsTableData>
169  ): void {
170    let all: NativeHookStatisticsTableData | null = null;
171    let heap: NativeHookStatisticsTableData | null = null;
172    let anonymous: NativeHookStatisticsTableData | null = null;
173    if (val.nativeMemory.indexOf(this.nativeType[0]) !== -1) {
174      all = new NativeHookStatisticsTableData();
175      all.memoryTap = this.nativeType[0];
176    }
177    if (val.nativeMemory.indexOf(this.nativeType[1]) !== -1) {
178      heap = new NativeHookStatisticsTableData();
179      heap.memoryTap = this.nativeType[1];
180    }
181    if (val.nativeMemory.indexOf(this.nativeType[2]) !== -1) {
182      anonymous = new NativeHookStatisticsTableData();
183      anonymous.memoryTap = this.nativeType[2];
184    }
185    for (let hook of result) {
186      if (all !== null) {
187        this.processHookData(hook, all);
188      }
189      if (heap !== null && hook.eventType === 'AllocEvent') {
190        this.processHookData(hook, heap);
191      }
192      if (anonymous !== null && hook.eventType === 'MmapEvent') {
193        this.processHookData(hook, anonymous);
194      }
195    }
196    if (all?.maxStr === '' && all?.max === 0) {
197      all.maxStr = Utils.getByteWithUnit(all?.max);
198    }
199    if (heap?.maxStr === '' && heap?.max === 0) {
200      heap.maxStr = Utils.getByteWithUnit(heap?.max);
201    }
202    if (anonymous?.maxStr === '' && anonymous?.max === 0) {
203      anonymous.maxStr = Utils.getByteWithUnit(anonymous?.max);
204    }
205    if (all !== null) {
206      this.updateHookData(all, arr);
207    }
208    if (heap !== null) {
209      this.updateHookData(heap, arr);
210    }
211    if (anonymous !== null) {
212      this.updateHookData(anonymous, arr);
213    }
214  }
215
216  private processHookData(hook: unknown, data: NativeHookStatisticsTableData): void {
217    // @ts-ignore
218    data.totalBytes += hook.allocByte;
219    // @ts-ignore
220    data.totalCount += hook.allocCount;
221    // @ts-ignore
222    data.freeByte += hook.freeByte;
223    // @ts-ignore
224    data.freeCount += hook.freeCount; // @ts-ignore
225    if (hook.max > data.max) {
226      // @ts-ignore
227      data.max = hook.max;
228      data.maxStr = Utils.getByteWithUnit(data.max);
229    }
230  }
231
232  private updateHookData(data: NativeHookStatisticsTableData, arr: Array<NativeHookStatisticsTableData>): void {
233    data.existing = data.totalBytes - data.freeByte;
234    data.allocCount = data.totalCount - data.freeCount;
235    data.existingString = Utils.getByteWithUnit(data.existing);
236    data.totalBytesString = Utils.getByteWithUnit(data.totalBytes);
237    data.freeByteString = Utils.getByteWithUnit(data.freeByte);
238    data.existingValue = [data.existing, data.totalBytes, this.allMax];
239    arr.push(data);
240  }
241
242  initElements(): void {
243    this.nativeStatisticsTbl = this.shadowRoot?.querySelector<LitTable>('#tb-native-statstics');
244    this.nativeStatisticsTbl!.addEventListener('column-click', (evt) => {
245      // @ts-ignore
246      this.sortByColumn(evt.detail.key, evt.detail.sort);
247    });
248    this.nativeStatisticsTbl!.exportTextHandleMap.set('existingString', (value) => {
249      // @ts-ignore
250      return `${value.existing}`;
251    });
252    this.nativeStatisticsTbl!.exportTextHandleMap.set('freeByteString', (value) => {
253      // @ts-ignore
254      return `${value.totalBytes - value.existing}`;
255    });
256    this.nativeStatisticsTbl!.exportTextHandleMap.set('totalBytesString', (value) => {
257      // @ts-ignore
258      return `${value.totalBytes}`;
259    });
260    this.nativeStatisticsTbl!.exportTextHandleMap.set('maxStr', (value) => {
261      // @ts-ignore
262      return `${value.max}`;
263    });
264  }
265
266  connectedCallback(): void {
267    super.connectedCallback();
268    resizeObserver(this.parentElement!, this.nativeStatisticsTbl!, 25);
269  }
270
271  sortByColumn(nmStatColumn: string, nmStatSort: number): void {
272    this.sortColumn = nmStatColumn;
273    this.sortType = nmStatSort;
274    if (nmStatSort === 0) {
275      this.nativeStatisticsTbl!.recycleDataSource = this.nativeStatisticsSource;
276    } else {
277      let arr = [...this.nativeStatisticsSource];
278      let compareFunction = (
279        nativeStatisticsLeftData: unknown,
280        nativeStatisticsRightData: unknown,
281        column: string,
282        sortType: number
283      ): number => {
284        if (sortType === 1) {
285          // @ts-ignore
286          return nativeStatisticsLeftData[column] - nativeStatisticsRightData[column];
287        } else {
288          // @ts-ignore
289          return nativeStatisticsRightData[column] - nativeStatisticsLeftData[column];
290        }
291      };
292
293      let columnMap: { [key: string]: string } = {
294        existingString: 'existing',
295        allocCount: 'allocCount',
296        freeByteString: 'totalBytes',
297        freeCount: 'freeCount',
298        totalBytesString: 'totalBytes',
299        maxStr: 'max',
300        totalCount: 'totalCount',
301      };
302      let sortColumnKey = columnMap[nmStatColumn];
303      this.nativeStatisticsTbl!.recycleDataSource = arr.sort((leftData, rightData) =>
304        compareFunction(leftData, rightData, sortColumnKey, nmStatSort)
305      );
306    }
307  }
308
309  initHtml(): string {
310    return `
311<style>
312.nm-stat-tbl {
313    height: auto
314}
315:host{
316    display: flex;
317    flex-direction: column;
318    padding: 10px 10px;
319}
320</style>
321<lit-table id="tb-native-statstics" class="nm-stat-tbl">
322    <lit-table-column class="nm-stat-column" width="25%" title="Memory Type"
323    data-index="memoryTap" key="memoryTap"  align="flex-start"></lit-table-column>
324    <lit-table-column class="nm-stat-column" width="1fr" title="Existing"
325    data-index="existingString" key="existingString"  align="flex-start" order></lit-table-column>
326    <lit-table-column class="nm-stat-column" width="1fr" title="# Existing"
327    data-index="allocCount" key="allocCount"  align="flex-start" order></lit-table-column>
328    <lit-table-column class="nm-stat-column" width="1fr" title="Transient"
329    data-index="freeByteString" key="freeByteString"  align="flex-start" order></lit-table-column>
330    <lit-table-column class="nm-stat-column" width="1fr" title="# Transient"
331    data-index="freeCount" key="freeCount"  align="flex-start" order></lit-table-column>
332    <lit-table-column class="nm-stat-column" width="1fr" title="Total Bytes"
333    data-index="totalBytesString" key="totalBytesString"  align="flex-start" order></lit-table-column>
334    <lit-table-column class="nm-stat-column" width="1fr" title="# Total"
335    data-index="totalCount" key="totalCount"  align="flex-start" order></lit-table-column>
336    <lit-table-column class="nm-stat-column" width="1fr" title="Peak Value"
337    data-index="maxStr" key="maxStr"  align="flex-start" order></lit-table-column>
338    <lit-table-column class="nm-stat-column" width="160px" title="Existing / Total"
339    data-index="existingValue" key="existingValue"  align="flex-start" >
340    <template><tab-progress-bar data="{{existingValue}}"></tab-progress-bar></template>
341    </lit-table-column>
342</lit-table>
343        `;
344  }
345}
346