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 { type BaseStruct } from '../../bean/BaseStruct'; 19import { renders } from '../../database/ui-worker/ProcedureWorker'; 20import { Utils } from '../trace/base/Utils'; 21import { type EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU'; 22import { info } from '../../../log/Log'; 23import { type SnapshotRender, SnapshotStruct } from '../../database/ui-worker/ProcedureWorkerSnapshot'; 24import { type TreeItemData } from '../../../base-ui/tree/LitTree'; 25import { MemoryConfig } from '../../bean/MemoryConfig'; 26import { TabPaneSmapsRecord } from '../trace/sheet/smaps/TabPaneSmapsRecord'; 27import { 28 dmaDataSender, 29 gpuGpuDataSender, 30 gpuMemoryDataSender, 31 gpuResourceDataSender, 32 gpuTotalDataSender, 33 gpuWindowDataSender, 34 purgeableDataSender, 35 sMapsDataSender, 36 shmDataSender, 37} from '../../database/data-trafic/VmTrackerDataSender'; 38import { resetVmTracker } from '../../database/data-trafic/VmTrackerDataReceiver'; 39import { querySmapsExits } from '../../database/sql/Smaps.sql'; 40import { 41 queryisExistsGpuMemoryData, 42 queryisExistsPurgeableData, 43 queryisExistsShmData, 44} from '../../database/sql/Memory.sql'; 45import { queryisExistsDmaData } from '../../database/sql/Dma.sql'; 46import { 47 queryGpuTotalType, 48 queryGpuWindowType, 49 queryisExistsGpuData, 50 queryisExistsGpuResourceData, 51} from '../../database/sql/Gpu.sql'; 52 53export class VmTrackerChart { 54 private trace: SpSystemTrace; 55 private rowFolder!: TraceRow<BaseStruct>; 56 private sMapsFolder!: TraceRow<BaseStruct>; 57 private gpuFolder!: TraceRow<BaseStruct>; 58 private memoryConfig: MemoryConfig = MemoryConfig.getInstance(); 59 static gpuTotalModule: number | null = null; //ns 60 static gpuWindow: number | null = null; //ns 61 static gpuWindowModule: number | null = null; //ns 62 private smapsRecordTab: TabPaneSmapsRecord | undefined | null; 63 private scratchId = -1; 64 constructor(trace: SpSystemTrace) { 65 this.trace = trace; 66 } 67 68 async init(): Promise<void> { 69 this.smapsRecordTab = this.trace 70 .shadowRoot!.querySelector('div > trace-sheet')! 71 .shadowRoot!.querySelector<TabPaneSmapsRecord>('#box-smaps-record > tabpane-smaps-record'); 72 if (this.scratchId === -1) { 73 for (let [key, value] of SpSystemTrace.DATA_DICT) { 74 if (value === 'Scratch') { 75 this.scratchId = key; 76 break; 77 } 78 } 79 } 80 const result = await querySmapsExits(); 81 if (result.length <= 0) { 82 return; 83 } 84 await this.initVmTrackerFolder(); 85 await this.initSMapsFolder(); 86 const rowNameList: Array<string> = ['Dirty', 'Swapped', 'RSS', 'PSS', 'USS']; 87 for (const rowName of rowNameList) { 88 await this.initSmapsRows(rowName); 89 } 90 const isExistsShm = await queryisExistsShmData(this.memoryConfig.iPid); 91 const isExistsDma = await queryisExistsDmaData(this.memoryConfig.iPid); 92 //@ts-ignore 93 if (isExistsShm[0].data_exists) { 94 await this.initShmRows(); 95 } 96 await this.initPurgeableVM(); 97 // @ts-ignore 98 if (isExistsDma[0].data_exists) { 99 await this.initDmaRow(); 100 } 101 await this.initGpuData(); 102 } 103 104 private async initGpuData(): Promise<void> { 105 const isExistsGpuMemory = await queryisExistsGpuMemoryData(this.memoryConfig.iPid); 106 const isExistsGpuResource = await queryisExistsGpuResourceData(this.scratchId); 107 const isExistsGraph = await queryisExistsGpuData(MemoryConfig.getInstance().iPid, "'mem.graph_pss'"); 108 const isExistsGl = await queryisExistsGpuData(MemoryConfig.getInstance().iPid, "'mem.gl_pss'"); 109 if ( 110 // @ts-ignore 111 isExistsGpuMemory[0].data_exists || 112 // @ts-ignore 113 isExistsGpuResource[0].data_exists || 114 // @ts-ignore 115 isExistsGraph[0].data_exists || 116 // @ts-ignore 117 isExistsGl[0].data_exists 118 ) { 119 await this.initGpuFolder(); 120 // @ts-ignore 121 if (isExistsGpuMemory[0].data_exists) { 122 await this.initGpuMemoryRow(); 123 } 124 // @ts-ignore 125 if (isExistsGpuResource[0].data_exists) { 126 await this.initGpuResourceRow(this.scratchId); 127 } else { 128 this.smapsRecordTab!.GLESHostCache = []; 129 } 130 // @ts-ignore 131 if (isExistsGraph[0].data_exists) { 132 await this.addGpuGraphRow(); 133 } 134 // @ts-ignore 135 if (isExistsGl[0].data_exists) { 136 await this.addGpuGLRow(); 137 await this.addGpuTotalRow(); 138 await this.addGpuWindowRow(); 139 } 140 } 141 } 142 143 private initVmTrackerFolder = async (): Promise<void> => { 144 let VmTrackerRow = TraceRow.skeleton(); 145 VmTrackerRow.rowId = 'VmTrackerRow'; 146 VmTrackerRow.rowType = TraceRow.ROW_TYPE_VM_TRACKER; 147 VmTrackerRow.addTemplateTypes('ProcessMemory'); 148 VmTrackerRow.addTemplateTypes('Memory'); 149 VmTrackerRow.rowParentId = ''; 150 VmTrackerRow.style.height = '40px'; 151 VmTrackerRow.index = 0; 152 VmTrackerRow.folder = true; 153 VmTrackerRow.name = `VM Tracker (${this.memoryConfig.processName} ${this.memoryConfig.pid})`; 154 VmTrackerRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 155 VmTrackerRow.selectChangeHandler = this.trace.selectChangeHandler; 156 VmTrackerRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => 157 new Promise<Array<SnapshotStruct>>((resolve) => resolve([])); 158 VmTrackerRow.onThreadHandler = (useCache): void => { 159 let context: CanvasRenderingContext2D; 160 if (VmTrackerRow.currentContext) { 161 context = VmTrackerRow.currentContext; 162 } else { 163 context = VmTrackerRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 164 } 165 VmTrackerRow.canvasSave(context); 166 if (VmTrackerRow.expansion) { 167 // @ts-ignore 168 context?.clearRect(0, 0, VmTrackerRow.frame.width, VmTrackerRow.frame.height); 169 } else { 170 (renders.empty as EmptyRender).renderMainThread( 171 { 172 context: context, 173 useCache: useCache, 174 type: '', 175 }, 176 VmTrackerRow 177 ); 178 } 179 VmTrackerRow.canvasRestore(context, this.trace); 180 }; 181 this.rowFolder = VmTrackerRow; 182 this.trace.rowsEL?.appendChild(VmTrackerRow); 183 }; 184 185 private initSMapsFolder = async (): Promise<void> => { 186 let sMapsRow = TraceRow.skeleton<SnapshotStruct>(); 187 sMapsRow.rowId = 'smapsRow'; 188 sMapsRow.rowParentId = 'VmTrackerRow'; 189 sMapsRow.rowHidden = !this.rowFolder.expansion; 190 sMapsRow.rowType = TraceRow.ROW_TYPE_VM_TRACKER_SMAPS; 191 sMapsRow.folder = true; 192 sMapsRow.name = 'Smaps'; 193 sMapsRow.folderPaddingLeft = 20; 194 sMapsRow.style.height = '40px'; 195 sMapsRow.style.width = '100%'; 196 sMapsRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 197 sMapsRow.selectChangeHandler = this.trace.selectChangeHandler; 198 sMapsRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => 199 new Promise<Array<SnapshotStruct>>((resolve) => resolve([])); 200 sMapsRow.onThreadHandler = (useCache): void => { 201 let context: CanvasRenderingContext2D; 202 if (sMapsRow.currentContext) { 203 context = sMapsRow.currentContext; 204 } else { 205 context = sMapsRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 206 } 207 sMapsRow.canvasSave(context); 208 if (sMapsRow.expansion) { 209 // @ts-ignore 210 context?.clearRect(0, 0, sMapsRow.frame.width, sMapsRow.frame.height); 211 } else { 212 (renders.empty as EmptyRender).renderMainThread( 213 { 214 context: context, 215 useCache: useCache, 216 type: '', 217 }, 218 sMapsRow 219 ); 220 } 221 sMapsRow.canvasRestore(context, this.trace); 222 }; 223 this.sMapsFolder = sMapsRow; 224 this.rowFolder?.addChildTraceRow(sMapsRow); 225 }; 226 227 private initGpuFolder = async (): Promise<TraceRow<SnapshotStruct>> => { 228 let gpuTraceRow = TraceRow.skeleton<SnapshotStruct>(); 229 gpuTraceRow.rowId = 'skiaGpuTraceRow'; 230 gpuTraceRow.rowType = TraceRow.ROW_TYPE_SYS_MEMORY_GPU; 231 gpuTraceRow.rowParentId = 'VmTrackerRow'; 232 gpuTraceRow.style.height = '40px'; 233 gpuTraceRow.folder = true; 234 gpuTraceRow.folderPaddingLeft = 20; 235 gpuTraceRow.rowHidden = !this.rowFolder.expansion; 236 gpuTraceRow.name = 'GPU'; 237 gpuTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 238 gpuTraceRow.selectChangeHandler = this.trace.selectChangeHandler; 239 gpuTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => 240 new Promise<Array<SnapshotStruct>>((resolve) => resolve([])); 241 gpuTraceRow.onThreadHandler = (useCache): void => { 242 let context: CanvasRenderingContext2D; 243 if (gpuTraceRow.currentContext) { 244 context = gpuTraceRow.currentContext; 245 } else { 246 context = gpuTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 247 } 248 gpuTraceRow.canvasSave(context); 249 if (gpuTraceRow.expansion) { 250 // @ts-ignore 251 context?.clearRect(0, 0, gpuTraceRow.frame.width, gpuTraceRow.frame.height); 252 } else { 253 (renders.empty as EmptyRender).renderMainThread( 254 { 255 context: context, 256 useCache: useCache, 257 type: '', 258 }, 259 gpuTraceRow 260 ); 261 } 262 gpuTraceRow.canvasRestore(context, this.trace); 263 }; 264 this.gpuFolder = gpuTraceRow; 265 this.rowFolder.addChildTraceRow(gpuTraceRow); 266 return gpuTraceRow; 267 }; 268 269 private getSmapsKeyName(rowName: string): string { 270 let columnName = rowName.toLowerCase(); 271 let keyName = ''; 272 switch (rowName) { 273 case 'USS': 274 keyName = 'private_clean + private_dirty'; 275 break; 276 case 'RSS': 277 keyName = 'resident_size'; 278 break; 279 case 'Swapped': 280 keyName = 'swap + swap_pss'; 281 break; 282 default: 283 keyName = columnName; 284 } 285 return keyName; 286 } 287 288 private initSmapsRows = async (rowName: string): Promise<void> => { 289 let sMapsTraceRow = this.initTraceRow(rowName, TraceRow.ROW_TYPE_VM_TRACKER_SMAPS, 'smapsRow'); 290 sMapsTraceRow.rowHidden = !this.sMapsFolder.expansion; 291 sMapsTraceRow.folderTextLeft = 40; 292 sMapsTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 293 //@ts-ignore 294 return sMapsDataSender(this.getSmapsKeyName(rowName), sMapsTraceRow).then((sMaps: unknown[]) => { 295 this.setName(sMaps); 296 return sMaps; 297 }); 298 }; 299 this.sMapsFolder.addChildTraceRow(sMapsTraceRow); 300 }; 301 302 private initShmRows = async (): Promise<void> => { 303 let shmTraceRow = this.initTraceRow('SHM', TraceRow.ROW_TYPE_VMTRACKER_SHM, 'VmTrackerRow'); 304 shmTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 305 //@ts-ignore 306 return shmDataSender(this.memoryConfig.iPid, shmTraceRow).then((shmData: unknown[]) => { 307 this.setName(shmData); 308 return shmData; 309 }); 310 }; 311 this.rowFolder.addChildTraceRow(shmTraceRow); 312 }; 313 314 private async initPurgeableTotal(): Promise<void> { 315 let totalTraceRow = this.initTraceRow('Purgeable Total', TraceRow.ROW_TYPE_PURGEABLE_TOTAL_VM, 'VmTrackerRow'); 316 totalTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 317 //@ts-ignore 318 return purgeableDataSender(this.memoryConfig.iPid, totalTraceRow, false).then((purgeableTotalData: unknown[]) => { 319 this.setName(purgeableTotalData); 320 return purgeableTotalData; 321 }); 322 }; 323 this.rowFolder.addChildTraceRow(totalTraceRow); 324 } 325 326 private async initPurgeablePin(): Promise<void> { 327 let pinTraceRow = this.initTraceRow('Purgeable Pin', TraceRow.ROW_TYPE_PURGEABLE_PIN_VM, 'VmTrackerRow'); 328 pinTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 329 //@ts-ignore 330 return purgeableDataSender(this.memoryConfig.iPid, pinTraceRow, true).then((purgeablePinData: unknown[]) => { 331 this.setName(purgeablePinData); 332 return purgeablePinData; 333 }); 334 }; 335 this.rowFolder.addChildTraceRow(pinTraceRow); 336 } 337 338 private initPurgeableVM = async (): Promise<void> => { 339 let time = new Date().getTime(); 340 const isExistsPurgeableTotal = await queryisExistsPurgeableData(this.memoryConfig.iPid, false); 341 const isExistsPurgeablePin = await queryisExistsPurgeableData(this.memoryConfig.iPid, true); //@ts-ignore 342 if (isExistsPurgeableTotal[0].data_exists) { 343 await this.initPurgeableTotal(); 344 } //@ts-ignore 345 if (isExistsPurgeablePin[0].data_exists) { 346 await this.initPurgeablePin(); 347 } 348 let durTime = new Date().getTime() - time; 349 info('The time to load the VM Purgeable is: ', durTime); 350 }; 351 352 private initDmaRow = async (): Promise<void> => { 353 let dmaTraceRow = this.initTraceRow('DMA', TraceRow.ROW_TYPE_DMA_VMTRACKER, 'VmTrackerRow'); 354 dmaTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 355 //@ts-ignore 356 return dmaDataSender(this.memoryConfig.iPid, dmaTraceRow).then((dmaData: unknown[]) => { 357 this.setName(dmaData); 358 return dmaData; 359 }); 360 }; 361 this.rowFolder.addChildTraceRow(dmaTraceRow); 362 }; 363 364 private initGpuMemoryRow = async (): Promise<void> => { 365 let gpuMemoryTraceRow = this.initTraceRow( 366 'Skia Gpu Memory', 367 TraceRow.ROW_TYPE_GPU_MEMORY_VMTRACKER, 368 'skiaGpuTraceRow' 369 ); 370 gpuMemoryTraceRow.rowHidden = !this.gpuFolder.expansion; 371 gpuMemoryTraceRow.folderTextLeft = 40; 372 gpuMemoryTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 373 //@ts-ignore 374 return gpuMemoryDataSender(this.memoryConfig.iPid, gpuMemoryTraceRow).then((gpuMemoryData: unknown[]) => { 375 this.setName(gpuMemoryData); 376 return gpuMemoryData; 377 }); 378 }; 379 this.gpuFolder.addChildTraceRow(gpuMemoryTraceRow); 380 }; 381 382 private initGpuResourceRow = async (scratchId: number): Promise<void> => { 383 let gpuMemoryTraceRow = this.initTraceRow( 384 'Gpu Resource', 385 TraceRow.ROW_TYPE_GPU_RESOURCE_VMTRACKER, 386 this.gpuFolder.rowId! 387 ); 388 gpuMemoryTraceRow.rowHidden = !this.gpuFolder.expansion; 389 gpuMemoryTraceRow.folderTextLeft = 40; 390 gpuMemoryTraceRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 391 //@ts-ignore 392 return gpuResourceDataSender(scratchId, gpuMemoryTraceRow).then((gpuResourceData: unknown[]) => { 393 this.setName(gpuResourceData); 394 // 将泳道图数据传递给Native Heap Tab页 395 //@ts-ignore 396 this.smapsRecordTab!.GLESHostCache = gpuResourceData; 397 return gpuResourceData; 398 }); 399 }; 400 this.gpuFolder.addChildTraceRow(gpuMemoryTraceRow); 401 }; 402 403 private async addGpuGraphRow(): Promise<void> { 404 let graphRow = this.initTraceRow('Graph', TraceRow.ROW_TYPE_SYS_MEMORY_GPU_GRAPH, this.gpuFolder.rowId!); 405 graphRow.addTemplateTypes('sys-memory'); 406 graphRow.folderTextLeft = 40; 407 graphRow.supplierFrame = (): Promise<SnapshotStruct[]> => { 408 //@ts-ignore 409 return gpuGpuDataSender(this.memoryConfig.iPid, "'mem.graph_pss'", graphRow).then((graphData: unknown[]) => { 410 this.setName(graphData); 411 return graphData; 412 }); 413 }; 414 this.gpuFolder.addChildTraceRow(graphRow); 415 } 416 417 private async addGpuGLRow(): Promise<void> { 418 let glRow = this.initTraceRow('GL', TraceRow.ROW_TYPE_SYS_MEMORY_GPU_GL, this.gpuFolder.rowId!); 419 glRow.addTemplateTypes('sys-memory'); 420 glRow.folderTextLeft = 40; 421 glRow.supplierFrame = (): Promise<SnapshotStruct[]> => { 422 //@ts-ignore 423 return gpuGpuDataSender(this.memoryConfig.iPid, "'mem.gl_pss'", glRow).then((glData: unknown[]) => { 424 this.setName(glData); 425 return glData; 426 }); 427 }; 428 this.gpuFolder.addChildTraceRow(glRow); 429 } 430 431 private async addGpuTotalRow(): Promise<void> { 432 let types = await queryGpuTotalType(); 433 if (!types || types.length === 0) { 434 return; 435 } 436 let gpuTotalRow = this.initTraceRow( 437 'Skia Gpu Dump Total', 438 TraceRow.ROW_TYPE_SYS_MEMORY_GPU_TOTAL, 439 this.gpuFolder.rowId! 440 ); 441 gpuTotalRow.folderTextLeft = 40; 442 gpuTotalRow.addTemplateTypes('sys-memory'); 443 gpuTotalRow.addRowSettingPop(); 444 gpuTotalRow.rowSetting = 'enable'; 445 gpuTotalRow.rowSettingList = [ 446 { 447 key: 'total', 448 title: 'Total', 449 checked: true, 450 }, 451 ...types.map( 452 ( 453 it 454 ): { 455 key: string; 456 title: string; 457 } => { 458 return { 459 key: `${it.id}`, 460 title: it.data, 461 }; 462 } 463 ), 464 ]; 465 this.addHandleEventByGpuTotalRow(gpuTotalRow); 466 this.gpuFolder.addChildTraceRow(gpuTotalRow); 467 } 468 469 private addHandleEventByGpuTotalRow(gpuTotalRow: TraceRow<SnapshotStruct>): void { 470 gpuTotalRow.onRowSettingChangeHandler = (setting): void => { 471 if (setting && setting.length > 0) { 472 gpuTotalRow.dataListCache = []; 473 gpuTotalRow.dataList = []; 474 gpuTotalRow.isComplete = false; 475 VmTrackerChart.gpuTotalModule = setting[0] === 'total' ? null : parseInt(setting[0]); 476 gpuTotalRow.needRefresh = true; 477 gpuTotalRow.drawFrame(); 478 } 479 }; 480 gpuTotalRow.supplierFrame = (): Promise<Array<SnapshotStruct>> => { 481 //@ts-ignore 482 return gpuTotalDataSender(VmTrackerChart.gpuTotalModule, gpuTotalRow).then((gpuTotalData: unknown[]) => { 483 this.setName(gpuTotalData); 484 return gpuTotalData; 485 }); 486 }; 487 } 488 489 private async addGpuWindowRow(): Promise<void> { 490 let types = await queryGpuWindowType(); 491 if (!types || types.length === 0) { 492 return; 493 } 494 let settings: TreeItemData[] = types 495 .filter((it) => it.pid === null) 496 .map((it) => { 497 return { 498 key: `${it.id}`, 499 title: it.data, 500 children: [], 501 }; 502 }); 503 settings.forEach((it) => { 504 it.children = types 505 .filter((child) => `${child.pid}` === it.key) 506 .map((item) => { 507 return { 508 key: `${it.key}-${item.id}`, 509 title: item.data, 510 }; 511 }); 512 }); 513 settings[0].checked = true; 514 VmTrackerChart.gpuWindow = parseInt(settings[0].key); 515 VmTrackerChart.gpuWindowModule = null; 516 let gpuWindowRow = this.initTraceRow( 517 'Skia Gpu Dump Window', 518 TraceRow.ROW_TYPE_SYS_MEMORY_GPU_WINDOW, 519 this.gpuFolder.rowId! 520 ); 521 gpuWindowRow.folderTextLeft = 40; 522 gpuWindowRow.addRowSettingPop(); 523 gpuWindowRow.rowSetting = 'enable'; 524 gpuWindowRow.rowSettingList = settings; 525 gpuWindowRow.addTemplateTypes('sys-memory'); 526 this.addHandleEventByGpuWindowRow(gpuWindowRow); 527 this.gpuFolder.addChildTraceRow(gpuWindowRow); 528 } 529 530 private addHandleEventByGpuWindowRow(gpuWindowRow: TraceRow<SnapshotStruct>): void { 531 gpuWindowRow.onRowSettingChangeHandler = (setting): void => { 532 if (setting && setting.length > 0) { 533 let split = setting[0].split('-'); 534 VmTrackerChart.gpuWindow = parseInt(split[0]); 535 VmTrackerChart.gpuWindowModule = split.length > 1 ? parseInt(split[1]) : null; 536 gpuWindowRow.dataListCache = []; 537 gpuWindowRow.dataList = []; 538 gpuWindowRow.isComplete = false; 539 gpuWindowRow.needRefresh = true; 540 gpuWindowRow.drawFrame(); 541 } 542 }; 543 gpuWindowRow.supplierFrame = (): Promise<SnapshotStruct[]> => { 544 //@ts-ignore 545 return gpuWindowDataSender(VmTrackerChart.gpuWindow!, VmTrackerChart.gpuWindowModule, gpuWindowRow).then( 546 (gpuWindowData: unknown[]) => { 547 this.setName(gpuWindowData); 548 return gpuWindowData; 549 } 550 ); 551 }; 552 } 553 554 private initTraceRow(rowName: string, type: string, rowParentId: string): TraceRow<SnapshotStruct> { 555 let vmTrackerTraceRow = TraceRow.skeleton<SnapshotStruct>(); 556 vmTrackerTraceRow.rowParentId = rowParentId; 557 vmTrackerTraceRow.rowId = rowName; 558 vmTrackerTraceRow.rowType = type; 559 vmTrackerTraceRow.folderTextLeft = 20; 560 vmTrackerTraceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler; 561 vmTrackerTraceRow.selectChangeHandler = this.trace.selectChangeHandler; 562 vmTrackerTraceRow.style.height = '40px'; 563 vmTrackerTraceRow.style.width = '100%'; 564 vmTrackerTraceRow.setAttribute('children', ''); 565 vmTrackerTraceRow.name = rowName; 566 vmTrackerTraceRow.focusHandler = (): void => { 567 this.showTip(vmTrackerTraceRow); 568 }; 569 vmTrackerTraceRow.findHoverStruct = (): void => { 570 SnapshotStruct.hoverSnapshotStruct = vmTrackerTraceRow.getHoverStruct(); 571 }; 572 vmTrackerTraceRow.onThreadHandler = (useCache): void => { 573 let context: CanvasRenderingContext2D; 574 if (vmTrackerTraceRow.currentContext) { 575 context = vmTrackerTraceRow.currentContext; 576 } else { 577 context = vmTrackerTraceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!; 578 } 579 vmTrackerTraceRow.canvasSave(context); 580 (renders.snapshot as SnapshotRender).renderMainThread( 581 { 582 context: context, 583 useCache: useCache, 584 type: 'snapshot', 585 }, 586 vmTrackerTraceRow 587 ); 588 vmTrackerTraceRow.canvasRestore(context, this.trace); 589 }; 590 return vmTrackerTraceRow; 591 } 592 593 private showTip(traceRow: TraceRow<SnapshotStruct>): void { 594 this.trace?.displayTip( 595 traceRow, 596 SnapshotStruct.hoverSnapshotStruct, 597 `<span>Name: ${SnapshotStruct.hoverSnapshotStruct?.name || ''}</span> 598 <span>Size: ${Utils.getBinaryByteWithUnit(SnapshotStruct.hoverSnapshotStruct?.value || 0)}</span>` 599 ); 600 } 601 602 private setName(data: Array<unknown>): void { 603 if (data.length > 0) { 604 data.forEach((item, index) => { 605 //@ts-ignore 606 item.name = `SnapShot ${index}`; 607 }); 608 } 609 } 610} 611