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