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