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