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 */ 15import { BaseStruct, Rect, Render, drawLoadingFrame, isFrameContainPoint, ns2x } from './ProcedureWorkerCommon'; 16import { TraceRow } from '../../component/trace/base/TraceRow'; 17import { Utils } from '../../component/trace/base/Utils'; 18import { MemoryConfig } from '../../bean/MemoryConfig'; 19import { SpSystemTrace } from '../../component/SpSystemTrace'; 20 21export class SnapshotRender extends Render { 22 renderMainThread( 23 req: { 24 context: CanvasRenderingContext2D; 25 useCache: boolean; 26 type: string; 27 }, 28 row: TraceRow<SnapshotStruct> 29 ): void { 30 let filter = row.dataListCache; 31 let maxValue = 0; 32 for (let item of filter) { 33 maxValue = Math.max(maxValue, item.value || 0); 34 } 35 snapshot( 36 filter, 37 maxValue, 38 TraceRow.range?.startNS ?? 0, 39 (TraceRow.range?.endNS ?? 0) - (TraceRow.range?.startNS! ?? 0), 40 row.frame 41 ); 42 drawLoadingFrame(req.context, row.dataListCache, row); 43 req.context!.beginPath(); 44 let find = false; 45 for (let re of filter) { 46 SnapshotStruct.draw(req.context, re); 47 if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 48 SnapshotStruct.hoverSnapshotStruct = re; 49 find = true; 50 } 51 } 52 if (!find && row.isHover) { 53 SnapshotStruct.hoverSnapshotStruct = undefined; 54 } 55 req.context!.closePath(); 56 } 57} 58export function snapshot( 59 filter: Array<SnapshotStruct>, 60 maxValue: number, 61 startNs: number, 62 totalNs: number, 63 frame: Rect 64): void { 65 for (let file of filter) { 66 SnapshotStruct.setFrame(file, maxValue, startNs || 0, totalNs || 0, frame); 67 } 68} 69const padding = 2; 70export function SnapshotStructOnClick(clickRowType: string, sp: SpSystemTrace) { 71 return new Promise((resolve, reject) => { 72 if (SnapshotStruct.hoverSnapshotStruct) { 73 if (clickRowType === TraceRow.ROW_TYPE_SYS_MEMORY_GPU_TOTAL) { 74 displayGpuDumpTotalSheet(sp, reject); 75 } else if (clickRowType === TraceRow.ROW_TYPE_SYS_MEMORY_GPU_WINDOW) { 76 displayGpuDumpWindowSheet(sp, reject); 77 } else if (clickRowType === TraceRow.ROW_TYPE_VM_TRACKER_SMAPS) { 78 displaySmapsSheet(sp, reject); 79 } 80 if (clickRowType === TraceRow.ROW_TYPE_VMTRACKER_SHM) { 81 displayShmSheet(sp, reject); 82 } 83 if (clickRowType === TraceRow.ROW_TYPE_PURGEABLE_TOTAL_ABILITY) { 84 displayTotalAbilitySheet(sp, reject); 85 } 86 if (clickRowType === TraceRow.ROW_TYPE_PURGEABLE_PIN_ABILITY) { 87 displayPinAbilitySheet(sp, reject); 88 } 89 if (clickRowType === TraceRow.ROW_TYPE_PURGEABLE_TOTAL_VM) { 90 displayTotalVMSheet(sp, reject); 91 } 92 if (clickRowType === TraceRow.ROW_TYPE_PURGEABLE_PIN_VM) { 93 displayPinVMSheet(sp, reject); 94 } 95 if (clickRowType === TraceRow.ROW_TYPE_DMA_ABILITY) { 96 displayDmaAbilitySheet(sp, reject); 97 } 98 if (clickRowType === TraceRow.ROW_TYPE_DMA_VMTRACKER) { 99 displayDmaVmTrackerSheet(sp, reject); 100 } 101 if (clickRowType === TraceRow.ROW_TYPE_GPU_MEMORY_ABILITY) { 102 displayGpuMemoryAbilitySheet(sp, reject); 103 } 104 if (clickRowType === TraceRow.ROW_TYPE_GPU_MEMORY_VMTRACKER) { 105 displayGpuMemoryVmTrackerSheet(sp, reject); 106 } 107 if (clickRowType === TraceRow.ROW_TYPE_GPU_RESOURCE_VMTRACKER) { 108 displayGpuResourceSheet(sp); 109 } else { 110 resolve(null); 111 } 112 } 113 }); 114} 115 116function displayGpuDumpTotalSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 117 let gpuDumpTotalRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>( 118 `trace-row[row-id='Skia Gpu Dump Total']` 119 ); 120 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 121 sp.traceSheetEL?.displayGpuSelectedData( 122 'total', 123 SnapshotStruct.selectSnapshotStruct!.startNs, 124 gpuDumpTotalRow!.dataListCache 125 ); 126 sp.timerShaftEL?.modifyFlagList(undefined); 127 reject(); 128} 129 130function displayGpuDumpWindowSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 131 let gpuDumpWindowRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>( 132 `trace-row[row-id='Skia Gpu Dump Window']` 133 ); 134 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 135 sp.traceSheetEL?.displayGpuSelectedData( 136 'window', 137 SnapshotStruct.selectSnapshotStruct!.startNs, 138 gpuDumpWindowRow!.dataListCache 139 ); 140 sp.timerShaftEL?.modifyFlagList(undefined); 141 reject(); 142} 143 144function displaySmapsSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 145 let smapsRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>(`trace-row[row-id='Dirty']`); 146 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 147 sp.traceSheetEL?.displaySmapsData(SnapshotStruct.selectSnapshotStruct!, smapsRow!.dataListCache); 148 reject(); 149} 150 151function displayShmSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 152 let shmRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>(`trace-row[row-id='SHM']`); 153 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 154 sp.traceSheetEL?.displayShmData(SnapshotStruct.selectSnapshotStruct!, shmRow!.dataListCache); 155 reject(); 156} 157 158function displayTotalAbilitySheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 159 let totalAbilityRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>( 160 `trace-row[row-id='System Purgeable Total']` 161 ); 162 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 163 sp.traceSheetEL?.displayPurgTotalAbilityData(SnapshotStruct.hoverSnapshotStruct!, totalAbilityRow!.dataListCache); 164 reject(); 165} 166 167function displayPinAbilitySheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 168 let pinAbilityRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>( 169 `trace-row[row-id='System Purgeable Pin']` 170 ); 171 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 172 sp.traceSheetEL?.displayPurgPinAbilityData(SnapshotStruct.hoverSnapshotStruct!, pinAbilityRow!.dataListCache); 173 reject(); 174} 175 176function displayTotalVMSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 177 let totalVMRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>(`trace-row[row-id='Purgeable Total']`); 178 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 179 sp.traceSheetEL?.displayPurgTotalVMData(SnapshotStruct.hoverSnapshotStruct!, totalVMRow!.dataListCache); 180 reject(); 181} 182 183function displayPinVMSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 184 let pinVMRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>(`trace-row[row-id='Purgeable Pin']`); 185 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 186 sp.traceSheetEL?.displayPurgPinVMData(SnapshotStruct.hoverSnapshotStruct!, pinVMRow!.dataListCache); 187 reject(); 188} 189 190function displayDmaAbilitySheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 191 let dmaAbilityRow = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>(`trace-row[row-id='abilityMonitorDma']`); 192 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 193 sp.traceSheetEL?.displayDmaAbility(SnapshotStruct.selectSnapshotStruct!.startNs, dmaAbilityRow!.dataListCache); 194 reject(); 195} 196 197function displayDmaVmTrackerSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 198 let dmaVmTracker = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>(`trace-row[row-type='dma-vmTracker']`); 199 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 200 sp.traceSheetEL?.displayDmaVmTracker(SnapshotStruct.selectSnapshotStruct!.startNs, dmaVmTracker!.dataListCache); 201 reject(); 202} 203 204function displayGpuMemoryAbilitySheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 205 let gpuMemoryAbilityMonitor = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>( 206 `trace-row[row-id='abilityMonitorGpuMemory']` 207 ); 208 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 209 sp.traceSheetEL?.displayGpuMemoryAbility( 210 SnapshotStruct.selectSnapshotStruct!.startNs, 211 gpuMemoryAbilityMonitor!.dataListCache 212 ); 213 reject(); 214} 215 216function displayGpuMemoryVmTrackerSheet(sp: SpSystemTrace, reject: (reason?: any) => void) { 217 let gpuMemoryVmTracker = sp.shadowRoot?.querySelector<TraceRow<SnapshotStruct>>( 218 `trace-row[row-id='Skia Gpu Memory']` 219 ); 220 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 221 sp.traceSheetEL?.displayGpuMemoryVmTracker( 222 SnapshotStruct.selectSnapshotStruct!.startNs, 223 gpuMemoryVmTracker!.dataListCache 224 ); 225 reject(); 226} 227 228function displayGpuResourceSheet(sp: SpSystemTrace) { 229 SnapshotStruct.selectSnapshotStruct = SnapshotStruct.hoverSnapshotStruct; 230 sp.traceSheetEL?.displayGpuResourceVmTracker(SnapshotStruct.selectSnapshotStruct!.startNs); 231} 232 233export class SnapshotStruct extends BaseStruct { 234 startNs: number = 0; 235 endNs: number = 0; 236 dur: number = 0; 237 name: string = ''; 238 aSize: number = 0; 239 categoryNameId: number = 0; 240 textWidth: number = 0; 241 value: number = 0; 242 type: string = ''; 243 static hoverSnapshotStruct: SnapshotStruct | undefined; 244 static selectSnapshotStruct: SnapshotStruct | undefined; 245 static setFrame(node: SnapshotStruct, maxValue: number, startNs: number, totalNs: number, frame: Rect): void { 246 node.frame = undefined; 247 frame.height = 40 - padding * 2; 248 // sample_interval单位是ms,startNs和endNs单位是纳秒,每一次采样的时间按采样间隔的五分之一算 249 node.dur = MemoryConfig.getInstance().snapshotDur; 250 node.endNs = node.startNs + node.dur; 251 if ((node.startNs - startNs || node.startNs - startNs === 0) && node.endNs - node.startNs) { 252 let rectangle: Rect = new Rect( 253 Math.floor(((node.startNs - startNs) / totalNs) * frame.width), 254 Math.floor(((maxValue - node.value) / maxValue) * frame.height), 255 Math.ceil(((node.endNs - node.startNs) / totalNs) * frame.width), 256 Math.ceil((node.value / maxValue) * frame.height) 257 ); 258 node.frame = rectangle; 259 } 260 if (node.value === 0) { 261 let rectangle: Rect = new Rect( 262 Math.floor(((node.startNs - startNs) / totalNs) * frame.width), 263 30, 264 Math.ceil((node.dur / totalNs) * frame.width), 265 1 266 ); 267 node.frame = rectangle; 268 } 269 } 270 static draw(ctx: CanvasRenderingContext2D, data: SnapshotStruct): void { 271 if (data.frame) { 272 ctx.fillStyle = 'rgb(86,192,197)'; 273 ctx!.fillRect(data.frame!.x, data.frame!.y + padding, data.frame!.width, data.frame!.height); 274 if (data.frame!.width > 7) { 275 ctx.globalAlpha = 1.0; 276 ctx.lineWidth = 1; 277 ctx.fillStyle = '#fff'; 278 ctx.textBaseline = 'middle'; 279 if (data.frame!.height > 10 && data.frame!.height < 25) { 280 SnapshotStruct.drawString(ctx, data.name || '', 4, data.frame!, data, 4); 281 } else if (data.frame!.height >= 25) { 282 SnapshotStruct.drawString(ctx, data.name || '', 4, data.frame!, data, 4); 283 SnapshotStruct.drawString(ctx, Utils.getBinaryByteWithUnit(data.value || 0), 11, data.frame!, data, 2); 284 } 285 } 286 if (SnapshotStruct.selectSnapshotStruct && SnapshotStruct.equals(SnapshotStruct.selectSnapshotStruct, data)) { 287 ctx.strokeStyle = '#232c5d'; 288 ctx.lineWidth = 2; 289 ctx.strokeRect(data.frame!.x, data.frame!.y + padding, data.frame!.width - 2, data.frame!.height); 290 } 291 } 292 } 293 /** 294 * 295 * @param ctx current context 296 * @param str text 297 * @param textPadding padding 298 * @param frame rectangle 299 * @param data PurgeableStruct 300 * @param location the position of the string, the bigger the numerical value, the higher the position on the canvas 301 */ 302 static drawString( 303 ctx: CanvasRenderingContext2D, 304 str: string, 305 textPadding: number, 306 frame: Rect, 307 data: SnapshotStruct, 308 location: number 309 ): void { 310 if (data.textWidth === undefined) { 311 data.textWidth = ctx.measureText(str).width; 312 } 313 let textWidth = Math.round(data.textWidth / str.length); 314 let fillTextWidth = frame.width - textPadding * 2; 315 if (data.textWidth < fillTextWidth) { 316 let x = Math.floor(frame.width / 2 - data.textWidth / 2 + frame.x + textPadding); 317 ctx.fillText(str, x, Math.floor(frame.y + frame.height / location + textPadding), fillTextWidth); 318 } else { 319 if (fillTextWidth >= textWidth) { 320 let characterNum = fillTextWidth / textWidth; 321 let x = frame.x + textPadding; 322 if (characterNum < 2) { 323 ctx.fillText( 324 str.substring(0, 1), 325 x, 326 Math.floor(frame.y + frame.height / location + textPadding), 327 fillTextWidth 328 ); 329 } else { 330 ctx.fillText( 331 `${str.substring(0, characterNum - 1)}...`, 332 x, 333 Math.floor(frame.y + frame.height / location + textPadding), 334 fillTextWidth 335 ); 336 } 337 } 338 } 339 } 340 static equals(baseSnapshot: SnapshotStruct, targetSnapshot: SnapshotStruct): boolean { 341 return baseSnapshot === targetSnapshot; 342 } 343} 344