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