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