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