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