• 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 "./TabPaneFilter.js";
19import {FilterData, TabPaneFilter} from "./TabPaneFilter.js";
20import {SelectionParam} from "../../../bean/BoxSelection.js";
21import {PerfCallChainMerageData} from "../../../bean/PerfProfile.js";
22import "../../FrameChart.js";
23import {FrameChart} from "../../FrameChart.js";
24import {ChartMode} from "../../../database/ProcedureWorkerCommon.js";
25import '../../DisassemblingWindow.js'
26import {DisassemblingWindow} from "../../DisassemblingWindow.js";
27import {Cmd} from "../../../../command/Cmd.js";
28import {SpApplication} from "../../../SpApplication.js";
29import "../../../../base-ui/slicer/lit-slicer.js";
30import "../../../../base-ui/progress-bar/LitProgressBar.js";
31import {query, queryPerfSampleIdsByTimeRange} from "../../../database/SqlLite.js";
32import {LitProgressBar} from "../../../../base-ui/progress-bar/LitProgressBar.js";
33
34@element('tabpane-perf-profile')
35export class TabpanePerfProfile extends BaseElement {
36    private tbl: LitTable | null | undefined;
37    private tbr: LitTable | null | undefined;
38    private progressEL:LitProgressBar | null | undefined;
39    private rightSource: Array<PerfCallChainMerageData> = [];
40    private filter: any
41    private sampleIds: string[] = []
42    private dataSource: any[] = []
43    private sortKey = "weight";
44    private sortType = 0;
45    private currentSelectedData: any = undefined
46    private frameChart: FrameChart | null | undefined;
47    private isChartShow: boolean = false;
48    private systmeRuleName = "/system/"
49    private numRuleName = "/max/min/"
50    private modal: DisassemblingWindow | null | undefined;
51    private needShowMenu = true;
52    private searchValue: string = ""
53    private loadingList:number[] = []
54    private loadingPage:any;
55
56    set data(val: SelectionParam | any) {
57        this.modal!.style.display = 'none';
58        this.tbl!.style.visibility = "visible";
59        if (this.parentElement!.clientHeight > this.filter!.clientHeight) {
60            this.filter!.style.display = "flex";
61        } else {
62            this.filter!.style.display = "none";
63        }
64        this.filter!.initializeFilterTree(true, true, true)
65        this.filter!.filterValue = ""
66        this.progressEL!.loading = true
67        this.loadingPage.style.visibility = "visible"
68        queryPerfSampleIdsByTimeRange(val.leftNs, val.rightNs, val.perfAll ? [] : val.perfCpus, val.perfAll ? [] : val.perfProcess, val.perfAll ? [] : val.perfThread)
69            .then((results) => {
70                this.sampleIds = results.map((sample) => {
71                    return sample.sampleId + ""
72                })
73                this.getDataByWorker([{
74                    funcName: "setSearchValue",
75                    funcArgs: [""]
76                }, {
77                    funcName: "getCallChainsBySampleIds",
78                    funcArgs: [this.sampleIds, true]
79                }], (results: any[]) => {
80                    this.setLTableData(results)
81                    this.tbr!.recycleDataSource = []
82                    this.frameChart!.mode = ChartMode.Count;
83                    this.frameChart!.data = this.dataSource;
84                    this.frameChart?.updateCanvas(true, this.clientWidth);
85                    this.frameChart?.calculateChartData();
86                })
87            })
88    }
89
90    getParentTree(src: Array<PerfCallChainMerageData>, target: PerfCallChainMerageData, parents: Array<PerfCallChainMerageData>): boolean {
91        for (let call of src) {
92            if (call.id == target.id) {
93                parents.push(call)
94                return true
95            } else {
96                if (this.getParentTree(call.children as Array<PerfCallChainMerageData>, target, parents)) {
97                    parents.push(call);
98                    return true;
99                }
100            }
101        }
102        return false;
103    }
104
105    getChildTree(src: Array<PerfCallChainMerageData>, id: string, children: Array<PerfCallChainMerageData>): boolean {
106        for (let call of src) {
107            if (call.id == id && call.children.length == 0) {
108                children.push(call)
109                return true
110            } else {
111                if (this.getChildTree(call.children as Array<PerfCallChainMerageData>, id, children)) {
112                    children.push(call);
113                    return true;
114                }
115            }
116        }
117        return false;
118    }
119
120    setRightTableData(call: PerfCallChainMerageData) {
121        let parents: Array<PerfCallChainMerageData> = [];
122        let children: Array<PerfCallChainMerageData> = [];
123        this.getParentTree(this.dataSource, call, parents);
124        let maxId = call.id;
125        let maxDur = 0;
126
127        function findMaxStack(call: PerfCallChainMerageData) {
128            if (call.children.length == 0) {
129                if (call.dur > maxDur) {
130                    maxDur = call.dur;
131                    maxId = call.id;
132                }
133            } else {
134                call.children.map((callChild) => {
135                    findMaxStack(<PerfCallChainMerageData>callChild);
136                })
137            }
138        }
139
140        findMaxStack(call);
141        this.getChildTree(call.children as Array<PerfCallChainMerageData>, maxId, children);
142        let arr = parents.reverse().concat(children.reverse());
143        for (let data of arr) {
144            data.type = (data.libName.endsWith(".so.1") || data.libName.endsWith(".dll") || data.libName.endsWith(".so")) ? 0 : 1;
145        }
146        let len = arr.length;
147        this.rightSource = arr;
148        this.tbr!.dataSource = len == 0 ? [] : this.rightSource.slice(3, len);
149    }
150
151    showButtomMenu(isShow: boolean) {
152        if (isShow) {
153            this.filter.setAttribute('tree', '');
154            this.filter.setAttribute('input', '');
155            this.filter.setAttribute('inputLeftText', '');
156        } else {
157            this.filter.removeAttribute('tree');
158            this.filter.removeAttribute('input');
159            this.filter.removeAttribute('inputLeftText')
160        }
161    }
162
163    initElements(): void {
164        this.tbl = this.shadowRoot?.querySelector<LitTable>('#tb-perf-profile');
165        this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar
166        this.frameChart = this.shadowRoot?.querySelector<FrameChart>('#framechart');
167        this.modal = this.shadowRoot?.querySelector<DisassemblingWindow>('tab-native-data-modal');
168        this.loadingPage = this.shadowRoot?.querySelector('.loading');
169        this.parentElement!.onscroll = () => {
170            this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop;
171        };
172        this.frameChart!.addChartClickListener((needShowMenu: boolean) => {
173            this.parentElement!.scrollTo(0, 0);
174            this.showButtomMenu(needShowMenu)
175            this.needShowMenu = needShowMenu;
176        });
177        this.tbl!.rememberScrollTop = true;
178        this.filter = this.shadowRoot?.querySelector<TabPaneFilter>("#filter")
179        this.tbl!.addEventListener('row-click', (evt: any) => {
180            // @ts-ignore
181            let data = (evt.detail.data as PerfCallChainMerageData);
182            this.setRightTableData(data);
183            data.isSelected = true;
184            this.currentSelectedData = data;
185            this.tbr?.clearAllSelection(data);
186            this.tbr?.setCurrentSelection(data);
187            // @ts-ignore
188            if ((evt.detail as any).callBack) {
189                // @ts-ignore
190                (evt.detail as any).callBack(true)
191            }
192        })
193        this.tbr = this.shadowRoot?.querySelector<LitTable>('#tb-perf-list');
194        let lastClikTime = 0;
195        this.tbr!.addEventListener('row-click', (evt: any) => {
196            // @ts-ignore
197            let data = (evt.detail.data as PerfCallChainMerageData);
198            this.tbl?.clearAllSelection(data);
199            (data as any).isSelected = true
200            this.tbl!.scrollToData(data)
201            // @ts-ignore
202            if ((evt.detail as any).callBack) {
203                // @ts-ignore
204                (evt.detail as any).callBack(true)
205            }
206            let spApplication = <SpApplication>document.getElementsByTagName("sp-application")[0];
207            if (Date.now() - lastClikTime < 200 && spApplication.vs) {
208                this.tbl!.style.visibility = "hidden";
209                this.filter.style.display = "none";
210                new ResizeObserver((entries) => {
211                    this.modal!.style.width = this.tbl!.clientWidth + 'px';
212                    this.modal!.style.height = this.tbl!.clientHeight + 'px';
213                }).observe(this.tbl!)
214                this.modal!.showLoading();
215                // @ts-ignore
216                let data = (evt.detail.data as PerfCallChainMerageData);
217                let path = data.path;
218                let addr = data.vaddrInFile;
219                let addrHex = addr.toString(16);
220                if (path.trim() === '[kernel.kallsyms]') {
221                    this.modal?.showContent(`error : Symbol ${data.symbol} lib is [kernel.kallsyms] ,not support `, addrHex);
222                } else if (path.trim() === '') {
223                    this.modal?.showContent(`error : Symbol ${data.symbol} lib is null `, addrHex);
224                } else if (addr < 0) {
225                    this.modal?.showContent(`error : Symbol ${data.symbol} current addr is error ` + addrHex, addrHex);
226                } else {
227                    const binDir = 'C:/binary_cache';
228                    let binPath = binDir + path;
229                    let cmd = 'C:/binary_cache/llvm-objdump.exe -S ' + binPath;
230                    Cmd.execObjDump(cmd, addrHex, (result: any) => {
231                        this.modal?.showContent(result, addrHex);
232                    })
233                }
234            }
235            lastClikTime = Date.now();
236        })
237        this.modal!.setCloseListener(() => {
238            this.modal!.style.display = 'none';
239            this.tbl!.style.visibility = "visible";
240            this.shadowRoot!.querySelector<TabPaneFilter>("#filter")!.style.display = 'flex';
241        });
242        this.tbr = this.shadowRoot?.querySelector<LitTable>('#tb-perf-list');
243        let filterHeight = 0;
244        new ResizeObserver((entries) => {
245            let tabPaneFilter = this.shadowRoot!.querySelector("#filter") as HTMLElement;
246            if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight;
247            if (this.parentElement!.clientHeight > filterHeight) {
248                tabPaneFilter.style.display = "flex";
249            } else {
250                tabPaneFilter.style.display = "none";
251            }
252            this.modal!.style.height = this.tbl!.clientHeight - 2 + 'px'; //2 is borderWidth
253            if (this.tbl!.style.visibility == "hidden") {
254                tabPaneFilter.style.display = "none";
255            }
256            if (this.parentElement?.clientHeight != 0) {
257                if (this.isChartShow) {
258                    this.frameChart?.updateCanvas(false, entries[0].contentRect.width);
259                    this.frameChart?.calculateChartData();
260                }
261                // @ts-ignore
262                this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 10 - 35) + "px"
263                this.tbl?.reMeauseHeight()
264                // @ts-ignore
265                this.tbr?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45 - 21) + "px"
266                this.tbr?.reMeauseHeight()
267                this.loadingPage.style.height = (this.parentElement!.clientHeight - 24) + "px"
268            }
269        }).observe(this.parentElement!)
270        let filterFunc = (data: any) => {
271            let args: any[] = []
272            if (data.type == "check") {
273                if (data.item.checked) {
274                    args.push({
275                        funcName: "splitTree",
276                        funcArgs: [data.item.name, data.item.select == "0", data.item.type == "symbol"]
277                    })
278                } else {
279                    args.push({
280                        funcName: "resotreAllNode",
281                        funcArgs: [[data.item.name]]
282                    })
283                    args.push({
284                        funcName: "resetAllNode",
285                        funcArgs: []
286                    })
287                    args.push({
288                        funcName: "clearSplitMapData",
289                        funcArgs: [data.item.name]
290                    })
291                }
292            } else if (data.type == "select") {
293                args.push({
294                    funcName: "resotreAllNode",
295                    funcArgs: [[data.item.name]]
296                })
297                args.push({
298                    funcName: "clearSplitMapData",
299                    funcArgs: [data.item.name]
300                })
301                args.push({
302                    funcName: "splitTree",
303                    funcArgs: [data.item.name, data.item.select == "0", data.item.type == "symbol"]
304                })
305            } else if (data.type == "button") {
306                if (data.item == "symbol") {
307                    if (this.currentSelectedData && !this.currentSelectedData.canCharge) {
308                        return
309                    }
310                    if (this.currentSelectedData != undefined) {
311                        this.filter!.addDataMining({name: this.currentSelectedData.symbolName}, data.item)
312                        args.push({
313                            funcName: "splitTree",
314                            funcArgs: [this.currentSelectedData.symbolName, false, true]
315                        })
316                    } else {
317                        return
318                    }
319                } else if (data.item == "library") {
320                    if (this.currentSelectedData && !this.currentSelectedData.canCharge) {
321                        return
322                    }
323                    if (this.currentSelectedData != undefined && this.currentSelectedData.libName != "") {
324                        this.filter!.addDataMining({name: this.currentSelectedData.libName}, data.item)
325                        args.push({
326                            funcName: "splitTree",
327                            funcArgs: [this.currentSelectedData.libName, false, false]
328                        })
329                    } else {
330                        return
331                    }
332                } else if (data.item == "restore") {
333                    if (data.remove != undefined && data.remove.length > 0) {
334                        let list = data.remove.map((item: any) => {
335                            return item.name
336                        })
337                        args.push({
338                            funcName: "resotreAllNode",
339                            funcArgs: [list]
340                        })
341                        args.push({
342                            funcName: "resetAllNode",
343                            funcArgs: []
344                        })
345                        list.forEach((symbolName: string) => {
346                            args.push({
347                                funcName: "clearSplitMapData",
348                                funcArgs: [symbolName]
349                            })
350                        })
351                    }
352                }
353            }
354            this.getDataByWorker(args, (result: any[]) => {
355                this.setLTableData(result)
356                this.frameChart!.data = this.dataSource;
357                if (this.isChartShow) this.frameChart?.calculateChartData();
358                this.tbl!.move1px()
359                if (this.currentSelectedData) {
360                    this.currentSelectedData.isSelected = false;
361                    this.tbl?.clearAllSelection(this.currentSelectedData)
362                    this.tbr!.recycleDataSource = []
363                    this.currentSelectedData = undefined
364                }
365            })
366        }
367        this.filter!.getDataLibrary(filterFunc)
368        this.filter!.getDataMining(filterFunc)
369        this.filter!.getCallTreeData((data: any) => {
370            if (data.value == 0) {
371                this.refreshAllNode({...this.filter!.getFilterTreeData(), callTree: data.checks})
372            } else {
373                let args: any[] = []
374                if (data.checks[1]) {
375                    args.push({
376                        funcName: "hideSystemLibrary",
377                        funcArgs: []
378                    })
379                    args.push({
380                        funcName: "resetAllNode",
381                        funcArgs: []
382                    })
383                } else {
384                    args.push({
385                        funcName: "resotreAllNode",
386                        funcArgs: [[this.systmeRuleName]]
387                    })
388                    args.push({
389                        funcName: "resetAllNode",
390                        funcArgs: []
391                    })
392                    args.push({
393                        funcName: "clearSplitMapData",
394                        funcArgs: [this.systmeRuleName]
395                    })
396                }
397                this.getDataByWorker(args, (result: any[]) => {
398                    this.setLTableData(result)
399                    this.frameChart!.data = this.dataSource;
400                    if (this.isChartShow) this.frameChart?.calculateChartData();
401                })
402
403            }
404        })
405        this.filter!.getCallTreeConstraintsData((data: any) => {
406            let args: any[] = [{
407                funcName: "resotreAllNode",
408                funcArgs: [[this.numRuleName]]
409            }, {
410                funcName: "clearSplitMapData",
411                funcArgs: [this.numRuleName]
412            }]
413            if (data.checked) {
414                args.push({
415                    funcName: "hideNumMaxAndMin",
416                    funcArgs: [parseInt(data.min), data.max]
417                })
418            }
419            args.push({
420                funcName: "resetAllNode",
421                funcArgs: []
422            })
423            this.getDataByWorker(args, (result: any[]) => {
424                this.setLTableData(result)
425                this.frameChart!.data = this.dataSource;
426                if (this.isChartShow) this.frameChart?.calculateChartData();
427            })
428
429        })
430        this.filter!.getFilterData((data: FilterData) => {
431            if (this.searchValue != this.filter!.filterValue) {
432                this.searchValue = this.filter!.filterValue
433                let args = [
434                    {
435                        funcName: "setSearchValue",
436                        funcArgs: [this.searchValue]
437                    },
438                    {
439                        funcName: "resetAllNode",
440                        funcArgs: []
441                    }
442                ]
443                this.getDataByWorker(args, (result: any[]) => {
444                    this.setLTableData(result)
445                    this.frameChart!.data = this.dataSource;
446                    this.switchFlameChart(data)
447                })
448            }else {
449                this.switchFlameChart(data)
450            }
451
452        })
453        this.tbl!.addEventListener('column-click', (evt) => {
454            // @ts-ignore
455            this.sortKey = evt.detail.key
456            // @ts-ignore
457            this.sortType = evt.detail.sort
458            // @ts-ignore
459            this.setLTableData(this.dataSource)
460            this.frameChart!.data = this.dataSource;
461        });
462    }
463
464    switchFlameChart(data:any){
465        let pageTab = this.shadowRoot?.querySelector('#show_table');
466        let pageChart = this.shadowRoot?.querySelector('#show_chart');
467        if (data.icon == 'block') {
468            pageChart?.setAttribute('class', 'show');
469            pageTab?.setAttribute('class', '');
470            this.isChartShow = true;
471            this.filter!.disabledMining = true;
472            this.showButtomMenu(this.needShowMenu);
473            this.frameChart!.data = this.dataSource;
474            this.frameChart?.calculateChartData();
475        } else if (data.icon == 'tree') {
476            pageChart?.setAttribute('class', '');
477            pageTab?.setAttribute('class', 'show');
478            this.showButtomMenu(true);
479            this.isChartShow = false;
480            this.filter!.disabledMining = false;
481            this.frameChart!.clearCanvas();
482            this.tbl!.reMeauseHeight()
483        }
484    }
485
486    filterSampleIds(checked: boolean, min: string, max: string): Array<string> {
487        let ids: Array<string> = [];
488        if (checked) {
489            let minId = parseInt(min);
490            let maxId = max == "∞" ? -999 : parseInt(max);
491            if (minId != NaN && maxId != NaN) {
492                for (let sampleId of this.sampleIds) {
493                    let id = parseInt(sampleId);
494                    if (id != NaN) {
495                        if (id >= minId) {
496                            if (maxId == -999) {
497                                ids.push(sampleId);
498                            } else if (id <= maxId) {
499                                ids.push(sampleId);
500                            } else {
501                                continue;
502                            }
503                        }
504                    }
505                }
506            }
507        } else {
508            ids.push(...this.sampleIds)
509        }
510        return ids;
511    }
512
513    refreshAllNode(filterData: any) {
514        let args:any[] = []
515        let isTopDown: boolean = !filterData.callTree[0];
516        let isHideSystemLibrary = filterData.callTree[1];
517        let list = filterData.dataMining.concat(filterData.dataLibrary);
518        args.push({
519            funcName: "getCallChainsBySampleIds",
520            funcArgs: [this.sampleIds, isTopDown]
521        })
522        this.tbr!.recycleDataSource = []
523        if (isHideSystemLibrary) {
524            args.push({
525                funcName: "hideSystemLibrary",
526                funcArgs: []
527            })
528        }
529        if (filterData.callTreeConstraints.checked) {
530            args.push({
531                funcName: "hideNumMaxAndMin",
532                funcArgs: [parseInt(filterData.callTreeConstraints.inputs[0]), filterData.callTreeConstraints.inputs[1]]
533            })
534        }
535        args.push({
536            funcName: "splitAllProcess",
537            funcArgs: [list]
538        })
539        args.push({
540            funcName: "resetAllNode",
541            funcArgs: []
542        })
543        this.getDataByWorker(args, (result: any[]) => {
544            this.setLTableData(result)
545            this.frameChart!.data = this.dataSource;
546            if (this.isChartShow) this.frameChart?.calculateChartData();
547        })
548    }
549
550    setLTableData(resultData:any[]) {
551        this.dataSource = this.sortTree(resultData)
552        this.tbl!.recycleDataSource = this.dataSource
553    }
554
555    sortTree(arr: Array<any>): Array<any> {
556        let sortArr = arr.sort((a, b) => {
557            if (this.sortKey == 'self') {
558                if (this.sortType == 0) {
559                    return b.dur - a.dur;
560                } else if (this.sortType == 1) {
561                    return a.selfDur - b.selfDur;
562                } else {
563                    return b.selfDur - a.selfDur;
564                }
565            } else {
566                if (this.sortType == 0) {
567                    return b.dur - a.dur;
568                } else if (this.sortType == 1) {
569                    return a.dur - b.dur;
570                } else {
571                    return b.dur - a.dur;
572                }
573            }
574        })
575        sortArr.map((call) => {
576            call.children = this.sortTree(call.children);
577        })
578        return sortArr;
579    }
580
581    getDataByWorker(args: any[], handler: Function) {
582        this.loadingList.push(1)
583        this.progressEL!.loading = true
584        this.loadingPage.style.visibility = "visible"
585        query("perfDataQuery", "", args, "perf-action").then((results) => {
586            handler(results)
587            this.loadingList.splice(0,1)
588            if(this.loadingList.length == 0) {
589                this.progressEL!.loading = false
590                this.loadingPage.style.visibility = "hidden"
591            }
592        })
593    }
594
595    initHtml(): string {
596        return `
597        <style>
598        :host{
599            display: flex;
600            flex-direction: column;
601            padding: 10px 10px 0 10px;
602        }
603        tab-pane-filter {
604            border: solid rgb(216,216,216) 1px;
605            float: left;
606            position: fixed;
607            bottom: 0;
608            width: 100%;
609        }
610        selector{
611            display: none;
612        }
613        .show{
614            display: flex;
615            flex: 1;
616        }
617        .progress{
618            bottom: 33px;
619            position: absolute;
620            height: 1px;
621            left: 0;
622            right: 0;
623        }
624        .loading{
625            bottom: 0;
626            position: absolute;
627            left: 0;
628            right: 0;
629            width:100%;
630            background:transparent;
631            z-index: 999999;
632        }
633    </style>
634    <div style="display: flex;flex-direction: row">
635
636    <selector id='show_table' class="show">
637        <lit-slicer style="width:100%">
638        <div id="left_table" style="width: 65%">
639            <tab-native-data-modal id="modal"></tab-native-data-modal>
640            <lit-table id="tb-perf-profile" style="height: auto" tree>
641                <lit-table-column width="70%" title="Call Stack" data-index="symbol" key="symbol"  align="flex-start" ></lit-table-column>
642                <lit-table-column width="1fr" title="Local" data-index="self" key="self"  align="flex-start"  order></lit-table-column>
643                <lit-table-column width="1fr" title="Weight" data-index="weight" key="weight"  align="flex-start"  order></lit-table-column>
644                <lit-table-column width="1fr" title="%" data-index="weightPercent" key="weightPercent"  align="flex-start"  order></lit-table-column>
645            </lit-table>
646
647        </div>
648        <lit-slicer-track ></lit-slicer-track>
649        <lit-table id="tb-perf-list" no-head style="height: auto;border-left: 1px solid var(--dark-border1,#e2e2e2)">
650            <span slot="head">Heaviest Stack Trace</span>
651            <lit-table-column width="60px" title="" data-index="type" key="type"  align="flex-start" >
652                <template>
653                    <img src="img/library.png" size="20" v-if=" type == 1 ">
654                    <img src="img/function.png" size="20" v-if=" type == 0 ">
655                </template>
656            </lit-table-column>
657            <lit-table-column width="1fr" title="" data-index="symbolName" key="symbolName"  align="flex-start"></lit-table-column>
658        </lit-table>
659        </div>
660        </lit-slicer>
661     </selector>
662     <tab-pane-filter id="filter" input inputLeftText icon tree></tab-pane-filter>
663     <lit-progress-bar class="progress"></lit-progress-bar>
664    <selector id='show_chart'>
665        <tab-framechart id='framechart' style='width: 100%;height: auto'> </tab-framechart>
666    </selector>
667    <div class="loading"></div>
668    </div>`;
669    }
670}
671