• 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 { BaseElement, element } from '../../../../../base-ui/BaseElement.js';
17import { LitTable } from '../../../../../base-ui/table/lit-table.js';
18import { HeapDataInterface } from '../../../../../js-heap/HeapDataInterface.js';
19import { ConstructorComparison, ConstructorItem, ConstructorType } from '../../../../../js-heap/model/UiStruct.js';
20import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column.js';
21import '../../../../../base-ui/table/lit-table-column.js';
22import { TabPaneJsMemoryFilter } from '../TabPaneJsMemoryFilter.js';
23import '../TabPaneJsMemoryFilter.js';
24import { HeapSnapshotStruct } from '../../../../database/ui-worker/ProcedureWorkerHeapSnapshot.js';
25import { LitSelectOption } from '../../../../../base-ui/select/LitSelectOption.js';
26import { LitSelect } from '../../../../../base-ui/select/LitSelect.js';
27
28@element('tabpane-comparison')
29export class TabPaneComparison extends BaseElement {
30  private comparisonTableEl: LitTable | undefined | null;
31  private retainerTableEl: LitTable | undefined | null;
32  private comparisonsData: Array<ConstructorComparison> = [];
33  private retainsData: Array<ConstructorItem> = [];
34  private baseFileId: number | undefined | null;
35  private targetFileId: number | undefined | null;
36  private filterEl: TabPaneJsMemoryFilter | undefined | null;
37  private selectEl: LitSelect | undefined | null;
38  private search: HTMLInputElement | undefined | null;
39  private comparisonData: Array<ConstructorItem> = [];
40  private comparisonFilter: Array<ConstructorComparison> = [];
41  private leftArray: Array<ConstructorComparison> = [];
42  private rightArray: Array<ConstructorItem> = [];
43  private rightTheadTable: HTMLDivElement | undefined | null;
44  private leftTheadTable: HTMLDivElement | undefined | null;
45  private comparisonTable: HTMLDivElement | undefined | null;
46  private fileSize: number = 0;
47
48  initElements(): void {
49    this.comparisonTableEl = this.shadowRoot!.querySelector<LitTable>('#tb-comparison') as LitTable;
50    this.retainerTableEl = this.shadowRoot!.querySelector<LitTable>('#tb-retainer') as LitTable;
51    this.filterEl = this.shadowRoot!.querySelector<TabPaneJsMemoryFilter>('#filter');
52    this.selectEl = this.filterEl?.shadowRoot?.querySelector<LitSelect>('lit-select');
53    this.search = this.filterEl?.shadowRoot?.querySelector('#js-memory-filter-input') as HTMLInputElement;
54    this.rightTheadTable = this.retainerTableEl!.shadowRoot?.querySelector('.thead') as HTMLDivElement;
55    this.leftTheadTable = this.comparisonTableEl!.shadowRoot?.querySelector('.thead') as HTMLDivElement;
56    this.comparisonTable = this.comparisonTableEl.shadowRoot?.querySelector('.table') as HTMLDivElement;
57    this.comparisonTableEl!.addEventListener('icon-click', (e) => {
58      // @ts-ignore
59      let clickRow = e.detail.data;
60      if (clickRow.status) {
61        clickRow.targetFileId = this.targetFileId;
62        let next = HeapDataInterface.getInstance().getNextForComparison(clickRow);
63        clickRow.children = next;
64        if (clickRow.children.length > 0) {
65          for (let item of clickRow.children) {
66            let nodeName = item.nodeName + ` @${item.id}`;
67            item.nodeId = ` @${item.id}`;
68            if (item.isString()) {
69              item.objectName = '"' + item.nodeName + '"' + ` @${item.id}`;
70            } else {
71              item.objectName = nodeName;
72            }
73            item.deltaCount = '-';
74            item.deltaSize = '-';
75            if (item.edgeName != '') {
76              item.objectName = item.edgeName + '\xa0' + '::' + '\xa0' + nodeName;
77            } else {
78              if (item.fileId == this.baseFileId) {
79                item.addedCount = '•';
80                item.addedSize = item.shallowSize;
81                item.removedCount = '-';
82                item.removedSize = '-';
83              } else if (item.fileId) {
84                item.removedCount = '•';
85                item.removedSize = item.shallowSize;
86                item.addedCount = '-';
87                item.addedSize = '-';
88              }
89            }
90            if (item.type == ConstructorType.FiledType) {
91              item.removedCount = '-';
92              item.removedSize = '-';
93              item.addedCount = '-';
94              item.addedSize = '-';
95            }
96          }
97        } else {
98          this.comparisonTableEl!.snapshotDataSource = [];
99        }
100      } else {
101        clickRow.status = true;
102      }
103      if (this.search!.value != '') {
104        if (this.leftTheadTable!.hasAttribute('sort')) {
105          this.comparisonTableEl!.snapshotDataSource = this.leftArray;
106        } else {
107          this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter;
108        }
109      } else {
110        if (this.leftTheadTable!.hasAttribute('sort')) {
111          this.comparisonTableEl!.snapshotDataSource = this.leftArray;
112        } else {
113          this.comparisonTableEl!.snapshotDataSource = this.comparisonsData;
114        }
115      }
116      new ResizeObserver(() => {
117        this.comparisonTableEl!.style.height = '100%';
118        this.comparisonTableEl!.reMeauseHeight();
119      }).observe(this.parentElement!);
120    });
121    this.retainerTableEl!.addEventListener('icon-click', (e) => {
122      // @ts-ignore
123      let retainerNext = e.detail.data as ConstructorItem;
124      if (retainerNext) {
125        if (this.retainsData.length > 0) {
126          if (retainerNext.status) {
127            retainerNext.getChildren();
128            let i = 0;
129            let that = this;
130            let retainsTable = () => {
131              const getList = (comList: Array<ConstructorItem>) => {
132                comList.forEach((row) => {
133                  let shallow = Math.round((row.shallowSize / this.fileSize) * 100) + '%';
134                  let retained = Math.round((row.retainedSize / this.fileSize) * 100) + '%';
135                  row.shallowPercent = shallow;
136                  row.retainedPercent = retained;
137                  let nodeId = row.nodeName + ` @${row.id}`;
138                  row.objectName = row.edgeName + '\xa0' + 'in' + '\xa0' + nodeId;
139                  if (row.distance >= 100000000 || row.distance == -5) {
140                    // @ts-ignore
141                    row.distance = '-';
142                  }
143                  i++;
144                  // @ts-ignore
145                  if (i < that.retainsData[0].distance - 1 && comList[0].distance != '-') {
146                    comList[0].getChildren();
147                    comList[0].expanded = false;
148                    if (row.hasNext) {
149                      getList(row.children);
150                    }
151                  } else {
152                    return;
153                  }
154                });
155              };
156              getList(retainerNext.children);
157            };
158            retainsTable();
159          } else {
160            retainerNext.status = true;
161          }
162          if (this.rightTheadTable!.hasAttribute('sort')) {
163            this.retainerTableEl!.snapshotDataSource = this.rightArray;
164          } else {
165            this.retainerTableEl!.snapshotDataSource = this.retainsData;
166          }
167        } else {
168          this.retainerTableEl!.snapshotDataSource = [];
169        }
170        new ResizeObserver(() => {
171          this.retainerTableEl!.style.height = 'calc(100% - 21px)';
172          this.retainerTableEl!.reMeauseHeight();
173        }).observe(this.parentElement!);
174      }
175    });
176    this.comparisonTableEl!.addEventListener('column-click', (e) => {
177      // @ts-ignore
178      this.sortComprisonByColumn(e.detail.key, e.detail.sort);
179      this.comparisonTableEl!.reMeauseHeight();
180    });
181    this.retainerTableEl!.addEventListener('column-click', (e) => {
182      // @ts-ignore
183      this.sortRetainerByColumn(e.detail.key, e.detail.sort);
184      this.retainerTableEl!.reMeauseHeight();
185    });
186    this.comparisonTableEl!.addEventListener('row-click', (e) => {
187      this.rightTheadTable!.removeAttribute('sort');
188      // @ts-ignore
189      let item = e.detail.data as ConstructorItem;
190      (item as any).isSelected = true;
191      this.retainsData = HeapDataInterface.getInstance().getRetains(item);
192      if (this.retainsData && this.retainsData.length > 0) {
193        this.retainsData.forEach((comparisonRetainEl) => {
194          let shallow = Math.round((comparisonRetainEl.shallowSize / this.fileSize) * 100) + '%';
195          let retained = Math.round((comparisonRetainEl.retainedSize / this.fileSize) * 100) + '%';
196          comparisonRetainEl.shallowPercent = shallow;
197          comparisonRetainEl.retainedPercent = retained;
198          if (comparisonRetainEl.distance >= 100000000 || comparisonRetainEl.distance === -5) {
199            // @ts-ignore
200            comparisonRetainEl.distance = '-';
201          }
202          let nodeId = comparisonRetainEl.nodeName + ` @${comparisonRetainEl.id}`;
203          comparisonRetainEl.objectName = comparisonRetainEl.edgeName + '\xa0' + 'in' + '\xa0' + nodeId;
204        });
205        let i = 0;
206        let that = this;
207        if (this.retainsData[0].distance > 1) {
208          this.retainsData[0].getChildren();
209          this.retainsData[0].expanded = false;
210        }
211        let retainsTable = () => {
212          const getList = (list: Array<ConstructorItem>) => {
213            list.forEach((structRow) => {
214              let shallow = Math.round((structRow.shallowSize / this.fileSize) * 100) + '%';
215              let retained = Math.round((structRow.retainedSize / this.fileSize) * 100) + '%';
216              structRow.shallowPercent = shallow;
217              structRow.retainedPercent = retained;
218              let nodeId = structRow.nodeName + ` @${structRow.id}`;
219              structRow.objectName = structRow.edgeName + '\xa0' + 'in' + '\xa0' + nodeId;
220              if (structRow.distance >= 100000000 || structRow.distance === -5) {
221                // @ts-ignore
222                structRow.distance = '-';
223              }
224              i++;
225              // @ts-ignore
226              if (i < that.retainsData[0].distance - 1 && list[0].distance != '-') {
227                list[0].getChildren();
228                list[0].expanded = false;
229                if (structRow.hasNext) {
230                  getList(structRow.children);
231                }
232              } else {
233                return;
234              }
235            });
236          };
237          getList(that.retainsData[0].children);
238        };
239        retainsTable();
240        this.retainerTableEl!.snapshotDataSource = this.retainsData;
241      } else {
242        this.retainerTableEl!.snapshotDataSource = [];
243      }
244      new ResizeObserver(() => {
245        this.retainerTableEl!.style.height = 'calc(100% - 21px)';
246        this.retainerTableEl!.reMeauseHeight();
247      }).observe(this.parentElement!);
248      // @ts-ignore
249      if ((e.detail as any).callBack) {
250        // @ts-ignore
251        (e.detail as any).callBack(true);
252      }
253    });
254    this.retainerTableEl!.addEventListener('row-click', (evt: any) => {
255      let data = evt.detail.data as ConstructorItem;
256      (data as any).isSelected = true;
257      if ((evt.detail as any).callBack) {
258        (evt.detail as any).callBack(true);
259      }
260    });
261    this.classFilter();
262  }
263
264  initComparison(data: HeapSnapshotStruct, dataList: Array<HeapSnapshotStruct>) {
265    this.clear();
266    this.retainerTableEl!.snapshotDataSource = [];
267    let fileArr: HeapSnapshotStruct[] = [];
268    let that = this;
269    for (let file of dataList) {
270      if (file.id !== data.id) {
271        fileArr.push(file);
272      }
273    }
274    fileArr = fileArr.sort();
275    this.fileSize = data.size;
276    this.initSelect(data.id, fileArr);
277    this.baseFileId = data.id;
278    this.targetFileId = fileArr[0].id;
279    that.updateComparisonData(data.id, fileArr[0].id);
280    new ResizeObserver(() => {
281      this.comparisonTableEl!.style.height = '100%';
282      this.comparisonTableEl!.reMeauseHeight();
283    }).observe(this.parentElement!);
284  }
285
286  updateComparisonData(baseFileId: number, targetFileId: number) {
287    this.comparisonsData = HeapDataInterface.getInstance().getClassListForComparison(baseFileId, targetFileId);
288    this.comparisonsData.forEach((dataList) => {
289      dataList.objectName = dataList.nodeName;
290    });
291    if (this.comparisonsData.length > 0) {
292      this.comparisonData = this.comparisonsData;
293      this.comparisonTableEl!.snapshotDataSource = this.comparisonsData;
294    } else {
295      this.comparisonTableEl!.snapshotDataSource = [];
296    }
297    this.comparisonTableEl!.reMeauseHeight();
298  }
299
300  initSelect(fileId: number, comFileArr: Array<HeapSnapshotStruct>) {
301    let that = this;
302    let input = this.selectEl!.shadowRoot?.querySelector('input') as HTMLInputElement;
303    this.selectEl!.innerHTML = '';
304    let option = new LitSelectOption();
305    option.innerHTML = 'File Name';
306    option.setAttribute('disabled', 'disabled');
307    this.selectEl?.appendChild(option);
308    if (comFileArr[0].name) {
309      option.setAttribute('value', comFileArr[0].name);
310    }
311    this.selectEl!.defaultValue = comFileArr[0].name || '';
312    this.selectEl!.placeholder = comFileArr[0].name || '';
313    this.selectEl!.dataSource = comFileArr;
314    this.selectEl!.querySelectorAll('lit-select-option').forEach((a) => {
315      a.addEventListener('onSelected', (e) => {
316        this.comparisonTable!.scrollTop = 0;
317        this.retainerTableEl!.snapshotDataSource = [];
318        for (let f of comFileArr) {
319          if (input.value == f.name) {
320            that.updateComparisonData(fileId, f.id);
321          }
322        }
323        e.stopPropagation();
324      });
325    });
326  }
327
328  sortComprisonByColumn(column: string, sort: number) {
329    switch (sort) {
330      case 0:
331        if (this.search!.value === '') {
332          this.comparisonTableEl!.snapshotDataSource = this.comparisonsData;
333        } else {
334          this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter;
335        }
336        break;
337      default:
338        if (this.search!.value === '') {
339          this.leftArray = [...this.comparisonsData];
340        } else {
341          this.leftArray = [...this.comparisonFilter];
342        }
343        switch (column) {
344          case 'addedCount':
345            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
346              return sort === 1 ? a.addedCount - b.addedCount : b.addedCount - a.addedCount;
347            });
348            break;
349          case 'removedCount':
350            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
351              return sort === 1 ? a.removedCount - b.removedCount : b.removedCount - a.removedCount;
352            });
353            break;
354          case 'deltaCount':
355            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
356              return sort === 1 ? a.deltaCount - b.deltaCount : b.deltaCount - a.deltaCount;
357            });
358            break;
359          case 'objectName':
360            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
361              return sort === 1
362                ? (a.objectName + '').localeCompare(b.objectName + '')
363                : (b.objectName + '').localeCompare(a.objectName + '');
364            });
365            break;
366          case 'addedSize':
367            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
368              return sort === 1 ? a.addedSize - b.addedSize : b.addedSize - a.addedSize;
369            });
370            break;
371          case 'removedSize':
372            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
373              return sort === 1 ? a.removedSize - b.removedSize : b.removedSize - a.removedSize;
374            });
375            break;
376          case 'deltaSize':
377            this.comparisonTableEl!.snapshotDataSource = this.leftArray.sort((a, b) => {
378              return sort === 1 ? a.deltaSize - b.deltaSize : b.deltaSize - a.deltaSize;
379            });
380            break;
381        }
382        break;
383    }
384  }
385
386  sortRetainerByColumn(column: string, sort: number) {
387    switch (sort) {
388      case 0:
389        this.retainerTableEl!.snapshotDataSource = this.retainsData;
390        break;
391      default:
392        this.rightArray = [...this.retainsData];
393        switch (column) {
394          case 'distance':
395            this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((a, b) => {
396              return sort === 1 ? a.distance - b.distance : b.distance - a.distance;
397            });
398            this.rightArray.forEach((list) => {
399              let retainsTable = function () {
400                const getList = function (currentList: Array<ConstructorItem>) {
401                  currentList.sort((a, b) => {
402                    return sort === 1 ? a.distance - b.distance : b.distance - a.distance;
403                  });
404                  currentList.forEach(function (currentRow) {
405                    if (currentRow.children.length > 0) {
406                      getList(currentRow.children);
407                    }
408                  });
409                };
410                getList(list.children);
411              };
412              retainsTable();
413            });
414            this.retainerTableEl!.snapshotDataSource = this.rightArray;
415            break;
416          case 'shallowSize':
417            this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((rightArrA, rightArrB) => {
418              return sort === 1
419                ? rightArrA.shallowSize - rightArrB.shallowSize
420                : rightArrB.shallowSize - rightArrA.shallowSize;
421            });
422            this.rightArray.forEach((list) => {
423              let retainsTable = function () {
424                const getList = function (listArr: Array<ConstructorItem>) {
425                  listArr.sort((listArrA, listArrB) => {
426                    return sort === 1
427                      ? listArrA.shallowSize - listArrB.shallowSize
428                      : listArrB.shallowSize - listArrA.shallowSize;
429                  });
430                  listArr.forEach(function (rowEl) {
431                    if (rowEl.children.length > 0) {
432                      getList(rowEl.children);
433                    }
434                  });
435                };
436                getList(list.children);
437              };
438              retainsTable();
439            });
440            this.retainerTableEl!.snapshotDataSource = this.rightArray;
441            break;
442          case 'retainedSize':
443            this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((rightArrA, rightArrB) => {
444              return sort === 1
445                ? rightArrA.retainedSize - rightArrB.retainedSize
446                : rightArrB.retainedSize - rightArrA.retainedSize;
447            });
448            this.rightArray.forEach((list) => {
449              let retainsTable = function () {
450                const getList = function (listArr: Array<ConstructorItem>) {
451                  listArr.sort((listArrA, listArrB) => {
452                    return sort === 1
453                      ? listArrA.retainedSize - listArrB.retainedSize
454                      : listArrB.retainedSize - listArrA.retainedSize;
455                  });
456                  listArr.forEach(function (row) {
457                    if (row.children.length > 0) {
458                      getList(row.children);
459                    }
460                  });
461                };
462                getList(list.children);
463              };
464              retainsTable();
465            });
466            this.retainerTableEl!.snapshotDataSource = this.rightArray;
467            break;
468          case 'objectName':
469            this.retainerTableEl!.snapshotDataSource = this.rightArray.sort((rightArrA, rightArrB) => {
470              return sort === 1
471                ? (rightArrA.objectName + '').localeCompare(rightArrB.objectName + '')
472                : (rightArrB.objectName + '').localeCompare(rightArrA.objectName + '');
473            });
474            this.rightArray.forEach((list) => {
475              let retainsTable = function () {
476                const getList = function (listArr: Array<ConstructorItem>) {
477                  listArr.sort((listArrA, listArrB) => {
478                    return sort === 1
479                      ? (listArrA.objectName + '').localeCompare(listArrB.objectName + '')
480                      : (listArrB.objectName + '').localeCompare(listArrA.objectName + '');
481                  });
482                  listArr.forEach(function (currentRow) {
483                    if (currentRow.children.length > 0) {
484                      getList(currentRow.children);
485                    }
486                  });
487                };
488                getList(list.children);
489              };
490              retainsTable();
491            });
492            this.retainerTableEl!.snapshotDataSource = this.rightArray;
493            break;
494        }
495        break;
496    }
497  }
498
499  classFilter() {
500    this.search!.addEventListener('keyup', () => {
501      this.comparisonFilter = [];
502      this.comparisonData.forEach((a: any, key: number) => {
503        if (a.objectName.toLowerCase().includes(this.search!.value.toLowerCase())) {
504          this.comparisonFilter.push(a);
505        } else {
506        }
507      });
508      this.comparisonTableEl!.snapshotDataSource = this.comparisonFilter;
509      let summaryTable = this.comparisonTableEl!.shadowRoot?.querySelector('.table') as HTMLDivElement;
510      summaryTable.scrollTop = 0;
511      this.comparisonTableEl!.reMeauseHeight();
512    });
513  }
514
515  clear() {
516    this.search!.value = '';
517    this.rightTheadTable!.removeAttribute('sort');
518    this.leftTheadTable!.removeAttribute('sort');
519    this.comparisonTable!.scrollTop = 0;
520  }
521
522  connectedCallback() {
523    super.connectedCallback();
524    let filterHeight = 0;
525    new ResizeObserver((entries) => {
526      let comparisonPanelFilter = this.shadowRoot!.querySelector('#filter') as HTMLElement;
527      if (comparisonPanelFilter.clientHeight > 0) filterHeight = comparisonPanelFilter.clientHeight;
528      if (this.parentElement!.clientHeight > filterHeight) {
529        comparisonPanelFilter.style.display = 'flex';
530      } else {
531        comparisonPanelFilter.style.display = 'none';
532      }
533    }).observe(this.parentElement!);
534  }
535
536  initHtml(): string {
537    return `
538        <style>
539        :host{
540            display: flex;
541            flex-direction: column;
542            padding: 10px 10px 0 10px;
543            height: calc(100% - 10px - 31px);
544        }
545        .show{
546            display: flex;
547            flex: 1;
548        }
549        .progress{
550            bottom: 33px;
551            position: absolute;
552            height: 1px;
553            left: 0;
554            right: 0;
555        }
556        selector{
557            display: none;
558        }
559        tab-pane-filter {
560            border: solid rgb(216,216,216) 1px;
561            float: left;
562            position: fixed;
563            bottom: 0;
564            width: 100%;
565        }
566        .loading{
567            bottom: 0;
568            position: absolute;
569            left: 0;
570            right: 0;
571            width:100%;
572            background:transparent;
573            z-index: 999999;
574        }
575        </style>
576        <div style="display: flex;flex-direction: row;height: 100%;">
577            <selector id='show_table' class="show">
578                <lit-slicer style="width:100%">
579                    <div style="width: 65%">
580                        <lit-table id="tb-comparison" style="height: auto" tree>
581                            <lit-table-column width="30%" title="#Constructor" data-index="" key="objectName"  align="flex-start" order>
582                            </lit-table-column>
583                            <lit-table-column width="1fr" title="#New" data-index="addedCount" key="addedCount"  align="flex-start" order>
584                            </lit-table-column>
585                            <lit-table-column width="1fr" title="#Deleted" data-index="removedCount" key="removedCount" align="flex-start"  order>
586                            </lit-table-column>
587                            <lit-table-column width="1fr" title="#Delta" data-index="deltaCount" key="deltaCount" align="flex-start"  order>
588                            </lit-table-column>
589                            <lit-table-column width="1fr" title="Alloc.Size" data-index="addedSize" key="addedSize" align="flex-start" order>
590                            </lit-table-column>
591                            <lit-table-column width="1fr" title="Freed Size" data-index="removedSize" key="removedSize" align="flex-start"  order>
592                            </lit-table-column>
593                            <lit-table-column width="1fr" title="Size Delta" data-index="deltaSize" key="deltaSize" align="flex-start"  order>
594                            </lit-table-column>
595                        </lit-table>
596                    </div>
597                    <lit-slicer-track ></lit-slicer-track>
598                    <div style="flex: 1;display: flex; flex-direction: row;">
599                        <div style="flex: 1;display: flex; flex-direction: column;">
600                            <span slot="head" >Retainers</span>
601                            <lit-table id="tb-retainer" style="height: calc(100% - 21px);" tree>
602                                <lit-table-column width="30%" title="Object" data-index="" key="objectName"  align="flex-start" order>
603                                </lit-table-column>
604                                <lit-table-column width="1fr" title="distance" data-index="distance" key="distance"  align="flex-start" order>
605                                </lit-table-column>
606                                <lit-table-column width="1fr" title="ShallowSize" data-index="shallowSize" key="shallowSize" align="flex-start"  order>
607                                </lit-table-column>
608                                <lit-table-column width="1fr" title="" data-index="shallowPercent" key="shallowPercent" align="flex-start">
609                                </lit-table-column>
610                                <lit-table-column width="1fr" title="RetainedSize" data-index="retainedSize" key="retainedSize" align="flex-start" order>
611                                </lit-table-column>
612                                <lit-table-column width="1fr" title="" data-index="retainedPercent" key="retainedPercent" align="flex-start">
613                                </lit-table-column>
614                            </div>
615                        </div>
616                    </lit-table>
617                </lit-slicer>
618            </selector>
619            <lit-progress-bar class="progress"></lit-progress-bar>
620            <tab-pane-js-memory-filter id="filter" input inputLeftText first ></tab-pane-js-memory-filter>
621            <div class="loading"></div>
622        </div>
623        `;
624  }
625}
626