• 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 "./trace/TimerShaftElement.js";
18import "./trace/base/TraceRow.js";
19import {
20    querySearchFunc,
21    threadPool
22} from "../database/SqlLite.js";
23import {TraceRow} from "./trace/base/TraceRow.js";
24import {TimerShaftElement} from "./trace/TimerShaftElement.js";
25import {CpuStruct} from "../bean/CpuStruct.js";
26import {CpuFreqStruct} from "../bean/CpuFreqStruct.js";
27import {ColorUtils} from "./trace/base/ColorUtils.js";
28import "./trace/base/TraceSheet.js";
29import {TraceSheet} from "./trace/base/TraceSheet.js";
30import {ThreadStruct} from "../bean/ThreadStruct.js";
31import {ProcessMemStruct} from "../bean/ProcessMemStruct.js";
32import {FuncStruct} from "../bean/FuncStruct.js";
33import {FpsStruct} from "../bean/FpsStruct.js";
34import {RangeSelect} from "./trace/base/RangeSelect.js";
35import {SelectionParam} from "../bean/BoxSelection.js";
36import {HeapStruct} from "../bean/HeapStruct.js";
37import {procedurePool} from "../database/Procedure.js";
38import {Utils} from "./trace/base/Utils.js";
39import {SpApplication} from "../SpApplication.js";
40import {SPT} from "../bean/StateProcessThread.js";
41import {Flag} from "./trace/timer-shaft/Flag.js";
42import {SportRuler} from "./trace/timer-shaft/SportRuler.js";
43import {CpuAbilityMonitorStruct} from "../bean/CpuAbilityMonitorStruct.js";
44import {MemoryAbilityMonitorStruct} from "../bean/MemoryAbilityMonitorStruct.js";
45import {DiskAbilityMonitorStruct} from "../bean/DiskAbilityMonitorStruct.js";
46import {NetworkAbilityMonitorStruct} from "../bean/NetworkAbilityMonitorStruct.js";
47import {SpHiPerf} from "./chart/SpHiPerf.js";
48import {perfDataQuery} from "./chart/PerfDataQuery.js";
49import {SearchThreadProcessBean} from "../bean/SearchFuncBean.js";
50import {error, info} from "../../log/Log.js";
51import {ns2x} from "../database/ui-worker/ProcedureWorkerCommon.js";
52import {SpChartManager} from "./chart/SpChartManager.js";
53import {VirtualMemoryStruct} from "../database/ui-worker/ProcedureWorkerVirtualMemory.js";
54import {ProcessStruct} from "../bean/ProcessStruct.js";
55import {SpFileSystemChart} from "./chart/SpFileSystemChart.js";
56import {CounterStruct, SdkSliceStruct} from "../bean/SdkStruct.js";
57import {SpFreqChart} from "./chart/SpFreqChart.js";
58import {EnergyStateStruct,EnergyAnomalyStruct, EnergyPowerStruct, EnergySystemStruct} from "../bean/EnergyStruct.js";
59import {SmapsShowStruct} from "../bean/SmapsShowStruct.js";
60import {CpuFreqLimitsStruct} from "../database/ui-worker/ProcedureWorkerCpuFreqLimits.js";
61
62@element('sp-system-trace')
63export class SpSystemTrace extends BaseElement {
64    static scrollViewWidth = 0
65    static isCanvasOffScreen = true;
66    static SPT_DATA: Array<SPT> = [];
67    static DATA_DICT: Map<number, string> = new Map<number, string>();
68    static SDK_CONFIG_MAP: any;
69    rowsEL: HTMLDivElement | undefined | null;
70    spacerEL: HTMLDivElement | undefined | null;
71    visibleRows: Array<TraceRow<any>> = [];
72    keyboardEnable = true;
73    currentRowType = "";/*保存当前鼠标所在行的类型*/
74    observerScrollHeightEnable: boolean = false;
75    observerScrollHeightCallback: Function | undefined;
76    // @ts-ignore
77    observer = new ResizeObserver((entries) => {
78        if (this.observerScrollHeightEnable && this.observerScrollHeightCallback) {
79            this.observerScrollHeightCallback();
80        }
81    });
82    isMousePointInSheet = false;
83    hoverFlag: Flag | undefined | null = undefined
84    selectFlag: Flag | undefined | null = undefined
85    public timerShaftEL: TimerShaftElement | null | undefined;
86    private traceSheetEL: TraceSheet | undefined | null;
87    private rangeSelect!: RangeSelect;
88    private chartManager: SpChartManager | undefined | null;
89    private loadTraceCompleted: boolean = false;
90
91    initElements(): void {
92        this.rowsEL = this.shadowRoot?.querySelector<HTMLDivElement>('.rows');
93        this.spacerEL = this.shadowRoot?.querySelector<HTMLDivElement>('.spacer');
94        this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft');
95        this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet');
96        this.rangeSelect = new RangeSelect(this.timerShaftEL);
97        this.rangeSelect.rowsEL = this.rowsEL;
98        document?.addEventListener("triangle-flag", (event: any) => {
99            let temporaryTime = this.timerShaftEL?.drawTriangle(event.detail.time, event.detail.type);
100            if (event.detail.timeCallback && temporaryTime) event.detail.timeCallback(temporaryTime);
101        })
102
103        document?.addEventListener("flag-change", (event: any) => {
104            this.timerShaftEL?.modifyFlagList(event.detail)
105            if (event.detail.hidden) {
106                this.selectFlag = undefined;
107                this.traceSheetEL?.setAttribute("mode", 'hidden');
108                this.visibleRows.forEach(it => it.draw(true));
109            }
110        })
111
112        SpSystemTrace.scrollViewWidth = this.getScrollWidth();
113        this.rangeSelect.selectHandler = (rows, refreshCheckBox) => {
114            if (rows.length == 0) {
115                this.rowsEL!.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => {
116                    it.checkType = "-1"
117                })
118                this.getVisibleRows().forEach(it => {
119                    it.draw(true);
120                });
121                this.traceSheetEL?.setAttribute("mode", 'hidden');
122                return;
123            }
124            if (refreshCheckBox) {
125                if (rows.length > 0) {
126                    this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(row => row.checkType = "0")
127                    rows.forEach(it => it.checkType = "2")
128                } else {
129                    this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(row => row.checkType = "-1")
130                    return
131                }
132            }
133            let selection = new SelectionParam();
134            selection.leftNs = 0;
135            selection.rightNs = 0;
136            selection.recordStartNs = (window as any).recordStartNS
137            let native_memory = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"];
138            rows.forEach(it => {
139                if (it.rowType == TraceRow.ROW_TYPE_CPU) {
140                    selection.cpus.push(parseInt(it.rowId!))
141                    info("load CPU traceRow id is : ", it.rowId)
142                } else if (it.rowType == TraceRow.ROW_TYPE_CPU_STATE) {
143                    let filterId = parseInt(it.rowId!);
144                    if (selection.cpuStateFilterIds.indexOf(filterId) == -1) {
145                        selection.cpuStateFilterIds.push(filterId);
146                    }
147                } else if(it.rowType == TraceRow.ROW_TYPE_CPU_FREQ){
148                    let filterId = parseInt(it.rowId!);
149                    if(selection.cpuFreqFilterIds.indexOf(filterId) == -1){
150                        selection.cpuFreqFilterIds.push(filterId);
151                    }
152                } else if(it.rowType == TraceRow.ROW_TYPE_CPU_FREQ_LIMIT){
153                    selection.cpuFreqLimitDatas.push(it.dataList!)
154                } else if (it.rowType == TraceRow.ROW_TYPE_PROCESS) {
155                    this.rowsEL?.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`).forEach(th => {
156                        th.rangeSelect = true;
157                        th.checkType = "2"
158                        if (th.rowType == TraceRow.ROW_TYPE_THREAD) {
159                            selection.threadIds.push(parseInt(th.rowId!))
160                        } else if (th.rowType == TraceRow.ROW_TYPE_FUNC) {
161                            if (th.asyncFuncName) {
162                                selection.funAsync.push({
163                                    name: th.asyncFuncName,
164                                    pid: th.asyncFuncNamePID || 0,
165                                })
166                            } else {
167                                selection.funTids.push(parseInt(th.rowId!))
168                            }
169                        } else if (th.rowType == TraceRow.ROW_TYPE_MEM) {
170                            selection.processTrackIds.push(parseInt(th.rowId!))
171                        }
172                    })
173                    info("load process traceRow id is : ", it.rowId)
174                } else if (it.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY) {
175                    this.rowsEL?.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`).forEach(th => {
176                        th.rangeSelect = true;
177                        th.checkType = "2"
178                        selection.nativeMemory.push(th.rowId!);
179                    })
180                    info("load nativeMemory traceRow id is : ", it.rowId)
181                } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) {
182                    selection.threadIds.push(parseInt(it.rowId!))
183                    info("load thread traceRow id is : ", it.rowId)
184                } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) {
185                    if (it.asyncFuncName) {
186                        selection.funAsync.push({
187                            name: it.asyncFuncName,
188                            pid: it.asyncFuncNamePID || 0,
189                        })
190                    } else {
191                        selection.funTids.push(parseInt(it.rowId!))
192                    }
193                    info("load func traceRow id is : ", it.rowId)
194                } else if (it.rowType == TraceRow.ROW_TYPE_MEM || it.rowType == TraceRow.ROW_TYPE_VIRTUAL_MEMORY) {
195                    if (it.rowType == TraceRow.ROW_TYPE_MEM) {
196                        selection.processTrackIds.push(parseInt(it.rowId!))
197                    } else {
198                        selection.virtualTrackIds.push(parseInt(it.rowId!))
199                    }
200                    info("load memory traceRow id is : ", it.rowId)
201                } else if (it.rowType == TraceRow.ROW_TYPE_FPS) {
202                    selection.hasFps = true;
203                    info("load FPS traceRow id is : ", it.rowId)
204                } else if (it.rowType == TraceRow.ROW_TYPE_HEAP) {
205                    if (native_memory.indexOf(it.rowId ?? "") != -1) {
206                        selection.nativeMemory.push(it.rowId!);
207                        info("load nativeMemory traceRow id is : ", it.rowId)
208                    } else {
209                        selection.heapIds.push(parseInt(it.rowId!))
210                        info("load heap traceRow id is : ", it.rowId)
211                    }
212                } else if (it.rowType == TraceRow.ROW_TYPE_CPU_ABILITY) {
213                    selection.cpuAbilityIds.push(it.rowId!)
214                    info("load CPU Ability traceRow id is : ", it.rowId)
215                } else if (it.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY) {
216                    selection.memoryAbilityIds.push(it.rowId!)
217                    info("load Memory Ability traceRow id is : ", it.rowId)
218                } else if (it.rowType == TraceRow.ROW_TYPE_DISK_ABILITY) {
219                    selection.diskAbilityIds.push(it.rowId!)
220                    info("load DiskIo Ability traceRow id is : ", it.rowId)
221                } else if (it.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) {
222                    selection.networkAbilityIds.push(it.rowId!)
223                    info("load Network Ability traceRow id is : ", it.rowId)
224                } else if (it.rowType == TraceRow.ROW_TYPE_SDK_COUNTER) {
225                    selection.sdkCounterIds.push(it.rowId!)
226                } else if (it.rowType == TraceRow.ROW_TYPE_SDK_SLICE) {
227                    selection.sdkSliceIds.push(it.rowId!)
228                } else if (it.rowType?.startsWith("hiperf")) {
229                    if (it.rowType == TraceRow.ROW_TYPE_HIPERF_EVENT || it.rowType == TraceRow.ROW_TYPE_HIPERF_REPORT) {
230                        return;
231                    }
232                    selection.perfSampleIds.push(1)
233                    if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) {
234                        this.rowsEL?.querySelectorAll<TraceRow<any>>(`trace-row[row-parent-id='${it.rowId}']`).forEach(th => {
235                            th.rangeSelect = true;
236                            th.checkType = "2"
237                        })
238                    }
239                    if (it.rowType == TraceRow.ROW_TYPE_HIPERF || it.rowId == "HiPerf-cpu-merge") {
240                        selection.perfAll = true;
241                    }
242                    if (it.rowType == TraceRow.ROW_TYPE_HIPERF_CPU) {
243                        selection.perfCpus.push(it.index);
244                    }
245                    if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) {
246                        selection.perfProcess.push(parseInt(it.rowId!.split("-")[0]));
247                    }
248                    if (it.rowType == TraceRow.ROW_TYPE_HIPERF_THREAD) {
249                        selection.perfThread.push(parseInt(it.rowId!.split("-")[0]));
250                    }
251                } else if (it.rowType == TraceRow.ROW_TYPE_FILE_SYSTEM) {
252                    if (it.rowId == "FileSystemLogicalWrite" || it.rowId == "FileSystemLogicalRead") {
253                        selection.fileSystemType = [0, 1, 2, 3];
254                    } else if (it.rowId == "FileSystemVirtualMemory") {
255                        selection.fileSysVirtualMemory = true;
256                    } else if (it.rowId == "FileSystemDiskIOLatency") {
257                        selection.diskIOLatency = true;
258                    } else {
259                        let arr = it.rowId!.split("-").reverse();
260                        let ipid = parseInt(arr[0]);
261                        if (selection.diskIOipids.indexOf(ipid) == -1) {
262                            selection.diskIOipids.push(ipid);
263                        }
264                    }
265                } else if (it.rowType == TraceRow.ROW_TYPE_POWER_ENERGY) {
266                    selection.powerEnergy.push(it.rowId!)
267                } else if (it.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
268                    selection.systemEnergy.push(it.rowId!)
269                } else if (it.rowType == TraceRow.ROW_TYPE_ANOMALY_ENERGY) {
270                    selection.anomalyEnergy.push(it.rowId!)
271                } else if (it.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
272                    info("load anomaly Energy traceRow id is : ", it.rowId)
273                } else if (it.rowType == TraceRow.ROW_TYPE_SMAPS) {
274                    selection.smapsType.push(it.rowId!)
275                }
276            })
277            selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0;
278            selection.rightNs = TraceRow.rangeSelectObject?.endNS || 0;
279            this.selectStructNull();
280            this.timerShaftEL?.removeTriangle("inverted")
281            this.traceSheetEL?.rangeSelect(selection);
282        }
283        // @ts-ignore
284        new ResizeObserver((entries) => {
285            let width = entries[0].contentRect.width - 1 - SpSystemTrace.scrollViewWidth;
286            requestAnimationFrame(() => {
287                this.timerShaftEL?.updateWidth(width)
288                this.shadowRoot!.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.updateWidth(width))
289            })
290        }).observe(this);
291
292        new ResizeObserver((entries) => {
293            this.getVisibleRows().forEach(it => {
294                it.draw(true);
295            });
296            if (this.traceSheetEL!.getAttribute("mode") == "hidden") {
297                this.timerShaftEL?.removeTriangle("triangle")
298            }
299        }).observe(this.rowsEL!);
300        window.addEventListener("keydown", ev => {
301            if (ev.key.toLocaleLowerCase() === "escape") {
302                this.selectStructNull();
303                this.timerShaftEL?.setSlicesMark();
304                this.traceSheetEL?.setAttribute("mode", 'hidden');
305                TraceRow.rangeSelectObject = undefined;
306            }
307        });
308        this.chartManager = new SpChartManager(this);
309    }
310
311    getScrollWidth() {
312        let totalScrollDiv, scrollDiv, overflowDiv = document.createElement('div');
313        overflowDiv.style.cssText = 'position:absolute; top:-2000px;width:200px; height:200px; overflow:hidden;';
314        totalScrollDiv = document.body.appendChild(overflowDiv).clientWidth;
315        overflowDiv.style.overflowY = 'scroll';
316        scrollDiv = overflowDiv.clientWidth;
317        document.body.removeChild(overflowDiv);
318        return totalScrollDiv - scrollDiv;
319    }
320
321    getVisibleRows(): Array<TraceRow<any>> {
322        let scrollTop = this.rowsEL?.scrollTop || 0;
323        let scrollHeight = this.rowsEL?.clientHeight || 0;
324        let res = [...this.rowsEL!.querySelectorAll<TraceRow<any>>("trace-row")].filter((it) => {
325            let tr = (it as TraceRow<any>);
326            let top = it.offsetTop - (this.rowsEL?.offsetTop || 0);
327            if ((top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) || it.collect) {
328                it.sleeping = false;
329                return true
330            } else {
331                if (!it.hasAttribute("collect-type")) {
332                    it.sleeping = true;
333                }
334                return false;
335            }
336        })
337        this.visibleRows = res;
338        info("Visible TraceRow size is :", this.visibleRows!.length)
339        return res;
340    }
341
342    timerShaftELFlagClickHandler = (flag: Flag | undefined | null) => {
343        if (flag) {
344            setTimeout(() => {
345                this.traceSheetEL?.displayFlagData(flag);
346            }, 100)
347        }
348    }
349
350    timerShaftELFlagChange = (hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => {
351        this.hoverFlag = hoverFlag;
352        this.selectFlag = selectFlag;
353        this.visibleRows.forEach(it => it.draw(true));
354    }
355
356    timerShaftELRangeChange = (e: any) => {
357        TraceRow.range = e;
358        if (TraceRow.rangeSelectObject) {
359            TraceRow.rangeSelectObject!.startX = Math.floor(ns2x(TraceRow.rangeSelectObject!.startNS!, TraceRow.range?.startNS!, TraceRow.range?.endNS!, TraceRow.range?.totalNS!, this.timerShaftEL!.sportRuler!.frame));
360            TraceRow.rangeSelectObject!.endX = Math.floor(ns2x(TraceRow.rangeSelectObject!.endNS!, TraceRow.range?.startNS!, TraceRow.range?.endNS!, TraceRow.range?.totalNS!, this.timerShaftEL!.sportRuler!.frame));
361        }
362        //在rowsEL显示范围内的 trace-row组件将收到时间区间变化通知
363        for (let i = 0; i < this.visibleRows.length; i++) {
364            this.visibleRows[i].draw();
365        }
366    }
367
368    rowsElOnScroll = (e: any) => {
369        this.hoverStructNull();
370        if (TraceRow.range) {
371            TraceRow.range.refresh = true;
372        }
373        this.visibleRows = this.getVisibleRows();
374        for (let index = 0; index < this.visibleRows.length; index++) {
375            if (index == 0 || index == this.visibleRows.length - 1) {
376                this.visibleRows[index].isHover = false;
377            }
378        }
379    }
380
381    documentOnMouseDown = (ev: MouseEvent) => {
382        if (!this.loadTraceCompleted) return;
383        TraceRow.isUserInteraction = true;
384        if (this.isMouseInSheet(ev)) return;
385        this.observerScrollHeightEnable = false;
386        if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
387            let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft;
388            let y = ev.offsetY;
389            this.timerShaftEL?.documentOnMouseDown(ev);
390            if (this.timerShaftEL!.sportRuler!.frame.contains(x, y) && x > (TraceRow.rangeSelectObject?.startX || 0) && x < (TraceRow.rangeSelectObject?.endX || 0)) {
391                let time = Math.round((x * (TraceRow.range?.endNS! - TraceRow.range?.startNS!) / this.timerShaftEL!.canvas!.offsetWidth) + TraceRow.range?.startNS!);
392                this.timerShaftEL!.sportRuler!.drawTriangle(time, "triangle")
393            } else {
394                this.rangeSelect.mouseDown(ev)
395            }
396            this.visibleRows.forEach(it => it.draw());
397        }
398    }
399
400    documentOnMouseUp = (ev: MouseEvent) => {
401        if (!this.loadTraceCompleted) return;
402        TraceRow.isUserInteraction = false;
403        this.rangeSelect.isMouseDown = false;
404        if (this.isMouseInSheet(ev)) return;
405        let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft;
406        let y = ev.offsetY;
407        if (this.timerShaftEL!.sportRuler!.frame.contains(x, y) && x > (TraceRow.rangeSelectObject?.startX || 0) && x < (TraceRow.rangeSelectObject?.endX || 0)) {
408        } else {
409            this.rangeSelect.mouseUp(ev);
410            this.timerShaftEL?.documentOnMouseUp(ev)
411        }
412    }
413
414    documentOnMouseOut = (ev: MouseEvent) => {
415        if (!this.loadTraceCompleted) return;
416        if (this.isMouseInSheet(ev)) return;
417        if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
418            this.timerShaftEL?.documentOnMouseOut(ev)
419        }
420    }
421
422    documentOnKeyPress = (ev: KeyboardEvent) => {
423        if (!this.loadTraceCompleted) return;
424        TraceRow.isUserInteraction = true;
425        if (ev.key.toLocaleLowerCase() == "m") {
426            if (CpuStruct.selectCpuStruct) {
427                this.timerShaftEL?.setSlicesMark((CpuStruct.selectCpuStruct.startTime || 0), (CpuStruct.selectCpuStruct.startTime || 0) + (CpuStruct.selectCpuStruct.dur || 0));
428            } else if (ThreadStruct.selectThreadStruct) {
429                this.timerShaftEL?.setSlicesMark((ThreadStruct.selectThreadStruct.startTime || 0), (ThreadStruct.selectThreadStruct.startTime || 0) + (ThreadStruct.selectThreadStruct.dur || 0));
430            } else if (FuncStruct.selectFuncStruct) {
431                this.timerShaftEL?.setSlicesMark((FuncStruct.selectFuncStruct.startTs || 0), (FuncStruct.selectFuncStruct.startTs || 0) + (FuncStruct.selectFuncStruct.dur || 0));
432            } else if (TraceRow.rangeSelectObject) {
433                this.timerShaftEL?.setSlicesMark((TraceRow.rangeSelectObject.startNS || 0), (TraceRow.rangeSelectObject.endNS || 0));
434            } else {
435                this.timerShaftEL?.setSlicesMark();
436            }
437        }
438        if (this.isMousePointInSheet) {
439            return;
440        }
441        this.observerScrollHeightEnable = false;
442        this.keyboardEnable && this.timerShaftEL!.documentOnKeyPress(ev);
443    }
444
445    documentOnKeyUp = (ev: KeyboardEvent) => {
446        if (!this.loadTraceCompleted) return;
447        TraceRow.isUserInteraction = false;
448        this.observerScrollHeightEnable = false;
449        this.keyboardEnable && this.timerShaftEL!.documentOnKeyUp(ev);
450        if (ev.code == "Enter") {
451            if (ev.shiftKey) {
452                this.dispatchEvent(new CustomEvent("previous-data", {
453                    detail: {},
454                    composed: false
455                }));
456            } else {
457                this.dispatchEvent(new CustomEvent("next-data", {
458                    detail: {},
459                    composed: false
460                }));
461            }
462        }
463    }
464
465    isMouseInSheet = (ev: MouseEvent) => {
466        this.isMousePointInSheet = this.traceSheetEL?.getAttribute("mode") != "hidden" && ev.offsetX > this.traceSheetEL!.offsetLeft && ev.offsetY > this.traceSheetEL!.offsetTop;
467        return this.isMousePointInSheet;
468    }
469
470    favoriteChangeHandler = (row: TraceRow<any>) => {
471        info("favoriteChangeHandler", row.frame, row.offsetTop, row.offsetHeight);
472        this.getVisibleRows();
473    }
474
475    selectChangeHandler = (rows: Array<TraceRow<any>>) => {
476        this.rangeSelect.rangeTraceRow = rows;
477        this.rangeSelect.selectHandler?.(this.rangeSelect.rangeTraceRow, false);
478    }
479
480    documentOnMouseMove = (ev: MouseEvent) => {
481        if ((window as any).isSheetMove) return;
482        if (!this.loadTraceCompleted || (window as any).flagInputFocus) return;
483        if (this.isMouseInSheet(ev)) {
484            this.hoverStructNull();
485            return;
486        }
487        let rows = this.visibleRows;
488        if (this.timerShaftEL?.isScaling()) {
489            return;
490        }
491        this.timerShaftEL?.documentOnMouseMove(ev)
492        this.rangeSelect.mouseMove(rows, ev);
493        if (this.rangeSelect.isMouseDown) {
494            for (let i = 0; i < rows.length; i++) {
495                rows[i].tipEL!.style.display = "none";
496                rows[i].draw(true);
497            }
498        } else {
499            for (let i = 0; i < rows.length; i++) {
500                let tr = rows[i];
501                let rowsELScrollTop = this.rowsEL?.scrollTop || 0;
502                let x = ev.offsetX - (tr.canvasContainer?.offsetLeft || 0);
503                let y = ev.offsetY - (tr.canvasContainer?.offsetTop || 0) + rowsELScrollTop;
504                if ((!tr.collect && x > tr.frame.x && x < tr.frame.x + tr.frame.width && ev.offsetY + rowsELScrollTop > tr.offsetTop && ev.offsetY + rowsELScrollTop < tr.offsetTop + tr.frame.height) ||
505                    (tr.collect && x > tr.frame.x && x < tr.frame.x + tr.frame.width && ev.offsetY > tr.offsetTop - 48 && ev.offsetY < tr.offsetTop - 48 + tr.frame.height)) {
506                    tr.isHover = true;
507                    tr.hoverX = x;
508                    tr.hoverY = tr.collect ? (ev.offsetY + 48 - tr.offsetTop) : y;
509                    if (tr.rowType === TraceRow.ROW_TYPE_CPU) {
510                        this.currentRowType = TraceRow.ROW_TYPE_CPU;
511                        CpuFreqStruct.hoverCpuFreqStruct = undefined;
512                        SpFreqChart.hoverStateStruct = undefined;
513                        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined
514                        if (CpuStruct.hoverCpuStruct) {
515                            tr.tip = `<span>P:${CpuStruct.hoverCpuStruct.processName || "Process"} [${CpuStruct.hoverCpuStruct.processId}]</span><span>T:${CpuStruct.hoverCpuStruct.name} [${CpuStruct.hoverCpuStruct.tid}] [Prio:${CpuStruct.hoverCpuStruct.priority||0}]</span>`;
516                        }
517                        tr.setTipLeft(x, CpuStruct.hoverCpuStruct)
518                    } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_STATE) {
519                        this.currentRowType = TraceRow.ROW_TYPE_CPU_STATE;
520                        CpuFreqStruct.hoverCpuFreqStruct = undefined;
521                        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined
522
523                        if (SpFreqChart.hoverStateStruct) {
524                            tr.tip = `<span>State: ${SpFreqChart.hoverStateStruct.value}</span>`
525                        }
526                        tr.setTipLeft(x, SpFreqChart.hoverStateStruct)
527                    } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ_LIMIT){
528                        CpuFreqStruct.hoverCpuFreqStruct = undefined;
529                        SpFreqChart.hoverStateStruct = undefined;
530                        if (CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct) {
531                            tr.tip = `<span>Max Freq: ${ColorUtils.formatNumberComma(CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct.max!)} kHz</span><span>Min Freq: ${ColorUtils.formatNumberComma(CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct.min!)} kHz</span>`
532                        }
533                        tr.setTipLeft(x, CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct)
534                    }else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ) {
535                        this.currentRowType = TraceRow.ROW_TYPE_CPU_FREQ;
536                        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined
537                        SpFreqChart.hoverStateStruct = undefined;
538                        if (CpuFreqStruct.hoverCpuFreqStruct) {
539                            CpuStruct.hoverCpuStruct = undefined;
540                            tr.tip = `<span>${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct.value!)} kHz</span>`
541                        }
542                        tr.setTipLeft(x, CpuFreqStruct.hoverCpuFreqStruct)
543                    } else if (tr.rowType === TraceRow.ROW_TYPE_FPS) {
544                        this.currentRowType = TraceRow.ROW_TYPE_FPS;
545                        if (FpsStruct.hoverFpsStruct) {
546                            tr.tip = `<span>${FpsStruct.hoverFpsStruct.fps}</span>`
547                        }
548                        tr.setTipLeft(x, FpsStruct.hoverFpsStruct)
549                    } else if (tr.rowType === TraceRow.ROW_TYPE_THREAD) {
550                        FuncStruct.hoverFuncStruct = undefined;
551                        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined
552                        this.currentRowType = TraceRow.ROW_TYPE_THREAD;
553                    } else if (tr.rowType === TraceRow.ROW_TYPE_FUNC) {
554                        ThreadStruct.hoverThreadStruct = undefined;
555                        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined
556                        this.currentRowType = TraceRow.ROW_TYPE_FUNC;
557                    } else if (tr.rowType === TraceRow.ROW_TYPE_HEAP) {
558                        this.currentRowType = TraceRow.ROW_TYPE_HEAP;
559                        if (HeapStruct.hoverHeapStruct) {
560                            if (tr.drawType === 1) {
561                                tr.tip = `<span>${HeapStruct.hoverHeapStruct.heapsize}</span>`
562                            } else {
563                                tr.tip = `<span>${Utils.getByteWithUnit(HeapStruct.hoverHeapStruct.heapsize!)}</span>`
564                            }
565                        }
566                        tr.setTipLeft(x, HeapStruct.hoverHeapStruct)
567                    } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_ABILITY) {
568                        this.currentRowType = TraceRow.ROW_TYPE_CPU_ABILITY;
569                        if (!SpSystemTrace.isCanvasOffScreen) CpuAbilityMonitorStruct.hoverCpuAbilityStruct = tr.onMouseHover(x, y);
570                        if (CpuAbilityMonitorStruct.hoverCpuAbilityStruct) {
571                            let monitorCpuTip = (CpuAbilityMonitorStruct.hoverCpuAbilityStruct.value!).toFixed(2) + "%"
572                            tr.tip = `<span>${monitorCpuTip}</span>`
573                        }
574                        tr.setTipLeft(x, CpuAbilityMonitorStruct.hoverCpuAbilityStruct)
575                    } else if (tr.rowType === TraceRow.ROW_TYPE_MEMORY_ABILITY) {
576                        this.currentRowType = TraceRow.ROW_TYPE_MEMORY_ABILITY;
577                        if (!SpSystemTrace.isCanvasOffScreen) MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = tr.onMouseHover(x, y);
578                        if (MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct) {
579                            tr.tip = `<span>${Utils.getBinaryByteWithUnit(MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct.value!)}</span>`
580                        }
581                        tr.setTipLeft(x, MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct)
582                    } else if (tr.rowType === TraceRow.ROW_TYPE_DISK_ABILITY) {
583                        this.currentRowType = TraceRow.ROW_TYPE_DISK_ABILITY;
584                        if (!SpSystemTrace.isCanvasOffScreen) DiskAbilityMonitorStruct.hoverDiskAbilityStruct = tr.onMouseHover(x, y);
585                        if (DiskAbilityMonitorStruct.hoverDiskAbilityStruct) {
586                            tr.tip = `<span>${DiskAbilityMonitorStruct.hoverDiskAbilityStruct.value!} KB/S</span>`
587                        }
588                        tr.setTipLeft(x, DiskAbilityMonitorStruct.hoverDiskAbilityStruct)
589                    } else if (tr.rowType === TraceRow.ROW_TYPE_NETWORK_ABILITY) {
590                        this.currentRowType = TraceRow.ROW_TYPE_NETWORK_ABILITY;
591                        if (!SpSystemTrace.isCanvasOffScreen) NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = tr.onMouseHover(x, y);
592                        if (NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct) {
593                            tr.tip = `<span>${Utils.getBinaryByteWithUnit(NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct.value!)}</span>`
594                        }
595                        tr.setTipLeft(x, NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct)
596                    } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_CPU) {
597                        this.currentRowType = TraceRow.ROW_TYPE_HIPERF_CPU;
598                        if (SpHiPerf.hoverCpuStruct) {
599                            let num = Math.trunc((SpHiPerf.hoverCpuStruct.height || 0) / 40 * 100);
600                            if (num > 0) {
601                                if (tr.rowId == "HiPerf-cpu-merge") {
602                                    tr.tip = `<span>${num * (this.chartManager!.perf!.maxCpuId + 1)}% (10.00ms)</span>`
603                                } else {
604                                    tr.tip = `<span>${num}% (10.00ms)</span>`
605                                }
606                            } else {
607                                let perfCall = perfDataQuery.callChainMap.get(SpHiPerf.hoverCpuStruct.callchain_id || 0);
608                                tr.tip = `<span>${perfCall ? perfCall.name : ''} (${perfCall ? perfCall.depth : '0'} other frames)</span>`
609                            }
610                        }
611                        tr.setTipLeft(x, SpHiPerf.hoverCpuStruct)
612                    } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_EVENT) {
613                        this.currentRowType = TraceRow.ROW_TYPE_HIPERF_EVENT;
614                        if (SpHiPerf.hoverEventuctStruct) {
615                            let num = Math.trunc((SpHiPerf.hoverEventuctStruct.sum || 0) / (SpHiPerf.hoverEventuctStruct.max || 0) * 100);
616                            if (num > 0) {
617                                tr.tip = `<span>${num}% (10.00ms)</span>`
618                            } else {
619                                let perfCall = perfDataQuery.callChainMap.get(SpHiPerf.hoverEventuctStruct.callchain_id || 0);
620                                tr.tip = `<span>${perfCall ? perfCall.name : ''} (${perfCall ? perfCall.depth : '0'} other frames)</span>`
621                            }
622                        }
623                        tr.setTipLeft(x, SpHiPerf.hoverEventuctStruct)
624                    } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_PROCESS) {
625                        this.currentRowType = TraceRow.ROW_TYPE_HIPERF_PROCESS;
626                        if (SpHiPerf.hoverProcessStruct) {
627                            let num = Math.trunc((SpHiPerf.hoverProcessStruct.height || 0) / 40 * 100);
628                            if (num > 0) {
629                                tr.tip = `<span>${num}% (10.00ms)</span>`
630                            } else {
631                                let perfCall = perfDataQuery.callChainMap.get(SpHiPerf.hoverProcessStruct.callchain_id || 0);
632                                tr.tip = `<span>${perfCall ? perfCall.name : ''} (${perfCall ? perfCall.depth : '0'} other frames)</span>`
633                            }
634                        }
635                        tr.setTipLeft(x, SpHiPerf.hoverProcessStruct)
636                    } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_THREAD) {
637                        this.currentRowType = TraceRow.ROW_TYPE_HIPERF_THREAD;
638                        if (SpHiPerf.hoverThreadStruct) {
639                            let num = Math.trunc((SpHiPerf.hoverThreadStruct.height || 0) / 40 * 100);
640                            if (num > 0) {
641                                tr.tip = `<span>${num}% (10.00ms)</span>`
642                            } else {
643                                let perfCall = perfDataQuery.callChainMap.get(SpHiPerf.hoverThreadStruct.callchain_id || -1);
644                                tr.tip = `<span>${perfCall ? perfCall.name : ''} (${perfCall ? perfCall.depth : '0'} other frames)</span>`
645                            }
646                        }
647                        tr.setTipLeft(x, SpHiPerf.hoverThreadStruct)
648                    } else if (tr.rowType === TraceRow.ROW_TYPE_FILE_SYSTEM) {
649                        this.currentRowType = TraceRow.ROW_TYPE_FILE_SYSTEM;
650                        let num = 0;
651                        if (SpFileSystemChart.hoverFileSysStruct) {
652                            num = SpFileSystemChart.hoverFileSysStruct.size ?? 0;
653                            let group10Ms = SpFileSystemChart.hoverFileSysStruct.group10Ms ?? false;
654                            if (tr.rowId!.startsWith("FileSystemDiskIOLatency")) {
655                                if (num > 0) {
656                                    let tipStr = Utils.getProbablyTime(num);
657                                    tr.tip = `<span>${tipStr} (10.00ms)</span>`
658                                }
659                            } else {
660                                if (num > 0) {
661                                    if (group10Ms) {
662                                        tr.tip = `<span>${num} (10.00ms)</span>`
663                                    } else {
664                                        tr.tip = `<span>${num}</span>`
665                                    }
666                                }
667                            }
668                        }
669                        tr.setTipLeft(x, num > 0 ? SpFileSystemChart.hoverFileSysStruct : null)
670                    } else if (tr.rowType == TraceRow.ROW_TYPE_MEM) {
671                        if (ProcessMemStruct.hoverProcessMemStruct) {
672                            CpuStruct.hoverCpuStruct = undefined;
673                            tr.tip = `<span>${ProcessMemStruct.hoverProcessMemStruct.value}</span>`
674                        }
675                        tr.setTipLeft(x, ProcessMemStruct.hoverProcessMemStruct)
676                    } else if (tr.rowType === TraceRow.ROW_TYPE_SDK_COUNTER) {
677                        this.currentRowType = TraceRow.ROW_TYPE_SDK_COUNTER;
678                        if (!SpSystemTrace.isCanvasOffScreen) CounterStruct.hoverCounterStruct = tr.onMouseHover(x, y);
679                        if (CounterStruct.hoverCounterStruct) {
680                            let gpuTip = (CounterStruct.hoverCounterStruct.value!).toFixed(2)
681                            tr.tip = `<span>${gpuTip}</span>`
682                        }
683                        tr.setTipLeft(x, CounterStruct.hoverCounterStruct)
684                    } else if (tr.rowType === TraceRow.ROW_TYPE_SDK_SLICE) {
685                        this.currentRowType = TraceRow.ROW_TYPE_SDK_SLICE;
686                        if (!SpSystemTrace.isCanvasOffScreen) SdkSliceStruct.hoverSdkSliceStruct = tr.onMouseHover(x, y);
687                        if (SdkSliceStruct.hoverSdkSliceStruct) {
688                            tr.tip = `<span>${SdkSliceStruct.hoverSdkSliceStruct?.value}</span>`;
689                        }
690                        tr.setTipLeft(x, SdkSliceStruct.hoverSdkSliceStruct)
691                    } else if (tr.rowType == TraceRow.ROW_TYPE_VIRTUAL_MEMORY) {
692                        if (VirtualMemoryStruct.hoverStruct) {
693                            CpuStruct.hoverCpuStruct = undefined;
694                            tr.tip = `<span>value:${VirtualMemoryStruct.hoverStruct.value}</span>`
695                        }
696                        tr.setTipLeft(x, VirtualMemoryStruct.hoverStruct)
697                    } else if (tr.rowType == TraceRow.ROW_TYPE_POWER_ENERGY) {
698                        this.currentRowType = TraceRow.ROW_TYPE_POWER_ENERGY;
699                        if (!SpSystemTrace.isCanvasOffScreen) EnergyPowerStruct.hoverEnergyPowerStruct = tr.onMouseHover(x, y);
700                        if (EnergyPowerStruct.hoverEnergyPowerStruct) {
701                            tr.tip = `<div style="width: 120px">
702                                <div style="display: flex"><div style="width: 80%;text-align: left">CPU: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.cpu!}</div></div>
703                                <div style="display: flex"><div style="width: 80%;text-align: left">location: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.location!}</div></div>
704                                <div style="display: flex"><div style="width: 80%;text-align: left">GPU: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.gpu!}</div></div>
705                                <div style="display: flex"><div style="width: 80%;text-align: left">display: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.display!}</div></div>
706                                <div style="display: flex"><div style="width: 80%;text-align: left">camera: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.camera!}</div></div>
707                                <div style="display: flex"><div style="width: 80%;text-align: left">bluetooth: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.bluetooth!}</div></div>
708                                <div style="display: flex"><div style="width: 80%;text-align: left">flashlight: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.flashlight!}</div></div>
709                                <div style="display: flex"><div style="width: 80%;text-align: left">audio: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.audio!}</div></div>
710                                <div style="display: flex"><div style="width: 80%;text-align: left">wifiScan: </div><div style="width: 20%;text-align: left">${EnergyPowerStruct.hoverEnergyPowerStruct.wifiscan!}</div></div>
711                            </div>`
712                        }
713                        tr.setTipLeft(x, EnergyPowerStruct.hoverEnergyPowerStruct)
714                    } else if (tr.rowType == TraceRow.ROW_TYPE_SYSTEM_ENERGY) {
715                        this.currentRowType = TraceRow.ROW_TYPE_SYSTEM_ENERGY;
716                        if (!SpSystemTrace.isCanvasOffScreen) EnergySystemStruct.hoverEnergySystemStruct = tr.onMouseHover(x, y);
717                        if (EnergySystemStruct.hoverEnergySystemStruct) {
718                            tr.tip = `<div style="width: 250px">
719                                <div style="display: flex"><div style="width: 75%;text-align: left">WORKSCHEDULER: </div><div style="width: 20%;text-align: left">${EnergySystemStruct.hoverEnergySystemStruct.workScheduler!}</div></div>
720                                <div style="display: flex"><div style="width: 75%;text-align: left">POWER_RUNNINGLOCK: </div><div style="width: 20%;text-align: left">${EnergySystemStruct.hoverEnergySystemStruct.power!}</div></div>
721                                <div style="display: flex"><div style="width: 75%;text-align: left">LOCATION: </div><div style="width: 20%;text-align: left">${EnergySystemStruct.hoverEnergySystemStruct.location!}</div></div>
722                            </div>`
723                        }
724                        tr.setTipLeft(x, EnergySystemStruct.hoverEnergySystemStruct)
725                    } else if (tr.rowType == TraceRow.ROW_TYPE_ANOMALY_ENERGY) {
726                        this.currentRowType = TraceRow.ROW_TYPE_ANOMALY_ENERGY;
727                        if (!SpSystemTrace.isCanvasOffScreen) EnergyAnomalyStruct.hoverEnergyAnomalyStruct = tr.onMouseHover(x, y);
728                        if (EnergyAnomalyStruct.hoverEnergyAnomalyStruct) {
729                            tr.tip = `<span>AnomalyName:${EnergyAnomalyStruct.hoverEnergyAnomalyStruct.eventName}</span>`
730                        }
731                        tr.setTipLeft(x, EnergyAnomalyStruct.hoverEnergyAnomalyStruct)
732                    } else if (tr.rowType == TraceRow.ROW_TYPE_STATE_ENERGY) {
733                        this.currentRowType = TraceRow.ROW_TYPE_STATE_ENERGY;
734                        if (!SpSystemTrace.isCanvasOffScreen) EnergyStateStruct.hoverEnergyStateStruct = tr.onMouseHover(x, y);
735                        if (EnergyStateStruct.hoverEnergyStateStruct) {
736                            if (EnergyStateStruct.hoverEnergyStateStruct.type!.toLocaleLowerCase().includes("state")) {
737                                tr.tip = `<span>Switch Status: ${EnergyStateStruct.hoverEnergyStateStruct.value == 1 ? 'disable' : 'enable'}</span>`
738                            } else {
739                                tr.tip = `<span>value: ${EnergyStateStruct.hoverEnergyStateStruct.value}</span>`
740                            }
741                        }
742                        tr.setTipLeft(x, EnergyStateStruct.hoverEnergyStateStruct)
743                    } else if (tr.rowType == TraceRow.ROW_TYPE_SMAPS) {
744                        this.currentRowType = TraceRow.ROW_TYPE_SMAPS;
745                        if (!SpSystemTrace.isCanvasOffScreen) SmapsShowStruct.hoverStruct = tr.onMouseHover(x, y);
746                        if (SmapsShowStruct.hoverStruct) {
747                            let value = 0;
748                            if (SmapsShowStruct.hoverStruct.value != undefined) {
749                                value = SmapsShowStruct.hoverStruct.value
750                            }
751                            tr.tip = `<span>${Utils.getBinaryByteWithUnit( value * 1024)}</span>`
752                        }
753                        tr.setTipLeft(x, SmapsShowStruct.hoverStruct)
754                    } else {
755                        this.hoverStructNull();
756                    }
757                    if (tr.isComplete) {
758                        tr.draw(true);
759                    }
760                } else {
761                    tr.onMouseLeave(x, y);
762                    tr.isHover = false;
763                    tr.hoverX = x;
764                    tr.hoverY = y;
765                }
766
767            }
768            if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft!
769                && ev.offsetX < this.timerShaftEL!.canvas!.offsetLeft! + this.timerShaftEL!.canvas!.offsetWidth!
770                && ev.offsetY > this.rowsEL!.offsetTop
771                && ev.offsetY < this.rowsEL!.offsetTop + this.rowsEL!.offsetHeight
772            ) {
773            } else {
774                this.hoverStructNull();
775                for (let i = 0, len = rows.length; i < len; i++) {
776                    if (!(rows[i].rowType === TraceRow.ROW_TYPE_PROCESS) && this.currentRowType === rows[i].rowType) { //
777                        if (rows[i].isComplete) {
778                            rows[i].draw(true);
779                        }
780                    }
781                }
782            }
783        }
784    }
785
786    hoverStructNull() {
787        CpuStruct.hoverCpuStruct = undefined;
788        CpuFreqStruct.hoverCpuFreqStruct = undefined;
789        ThreadStruct.hoverThreadStruct = undefined;
790        FuncStruct.hoverFuncStruct = undefined;
791        SpHiPerf.hoverCpuStruct = undefined;
792        SpFreqChart.hoverStateStruct = undefined;
793        CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = undefined
794    }
795
796    selectStructNull() {
797        CpuStruct.selectCpuStruct = undefined;
798        CpuStruct.wakeupBean = null;
799        CpuFreqStruct.selectCpuFreqStruct = undefined;
800        ThreadStruct.selectThreadStruct = undefined;
801        FuncStruct.selectFuncStruct = undefined;
802        SpHiPerf.selectCpuStruct = undefined;
803        SpFreqChart.selectStateStruct = undefined;
804        CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = undefined
805    }
806
807    documentOnClick = (ev: MouseEvent) => {
808        if (!this.loadTraceCompleted) return;
809        if (this.isMouseInSheet(ev)) return;
810        if ((window as any).isPackUpTable) {
811            (window as any).isPackUpTable = false;
812            return;
813        }
814        if (this.rangeSelect.isDrag()) {
815            return;
816        }
817        let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft;
818        let y = ev.offsetY;
819        if (this.timerShaftEL!.sportRuler!.frame.contains(x, y) && x > (TraceRow.rangeSelectObject?.startX || 0) && x < (TraceRow.rangeSelectObject?.endX || 0)) {
820        } else {
821            this.onClickHandler();
822            this.documentOnMouseMove(ev)
823        }
824    }
825
826    onClickHandler() {
827        if (!this.loadTraceCompleted) return;
828        this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.rangeSelect = false)
829        this.selectStructNull();
830        let threadClickHandler: any;
831        let cpuClickHandler: any;
832        threadClickHandler = (d: ThreadStruct) => {
833            this.observerScrollHeightEnable = false;
834            this.scrollToProcess(`${d.cpu}`, "", "cpu-data", true);
835            let cpuRow = this.rowsEL?.querySelectorAll<TraceRow<CpuStruct>>(`trace-row[row-id='${d.cpu}'][row-type='cpu-data']`)[0];
836            let findEntry = cpuRow!.dataList!.find((dat: any) => dat.startTime === d.startTime);
837            if (findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || findEntry!.startTime! > TraceRow.range!.endNS) {
838                this.timerShaftEL?.setRangeNS(findEntry!.startTime! - findEntry!.dur! * 2, findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2);
839            }
840            this.hoverStructNull();
841            this.selectStructNull();
842            CpuStruct.hoverCpuStruct = findEntry;
843            CpuStruct.selectCpuStruct = findEntry;
844            this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, "inverted");
845            cpuRow!.draw();
846            this.traceSheetEL?.displayCpuData(CpuStruct.selectCpuStruct!, (wakeUpBean) => {
847                CpuStruct.wakeupBean = wakeUpBean;
848                this.visibleRows.forEach(it => it.draw());
849            }, cpuClickHandler);
850        }
851
852        cpuClickHandler = (d: CpuStruct) => {
853            this.observerScrollHeightEnable = true;
854            let threadRow = this.rowsEL?.querySelectorAll<TraceRow<ThreadStruct>>(`trace-row[row-id='${d.tid}'][row-type='thread']`)[0];
855            let task = () => {
856                if(threadRow){
857                    if (threadRow!.isComplete) {
858                        let findEntry = threadRow!.dataList!.find((dat) => dat.startTime === d.startTime);
859                        if (findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || findEntry!.startTime! > TraceRow.range!.endNS) {
860                            this.timerShaftEL?.setRangeNS(findEntry!.startTime! - findEntry!.dur! * 2, findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2);
861                        }
862                        this.hoverStructNull();
863                        this.selectStructNull();
864                        ThreadStruct.hoverThreadStruct = findEntry;
865                        ThreadStruct.selectThreadStruct = findEntry;
866                        this.closeAllExpandRows(d.processId + "")
867                        this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, "inverted");
868                        threadRow!.draw();
869                        this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler, cpuClickHandler);
870                        this.scrollToProcess(`${d.tid}`, `${d.processId}`, "thread", true)
871                    } else {
872                        threadRow!.onComplete = () => {
873                            let findEntry = threadRow!.dataList!.find((dat) => dat.startTime === d.startTime);
874                            if (findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || findEntry!.startTime! > TraceRow.range!.endNS) {
875                                this.timerShaftEL?.setRangeNS(findEntry!.startTime! - findEntry!.dur! * 2, findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2);
876                            }
877                            this.hoverStructNull();
878                            this.selectStructNull();
879                            ThreadStruct.hoverThreadStruct = findEntry;
880                            ThreadStruct.selectThreadStruct = findEntry;
881                            this.closeAllExpandRows(d.processId + "")
882                            this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, "inverted");
883                            threadRow!.draw();
884                            this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler, cpuClickHandler);
885                            this.scrollToProcess(`${d.tid}`, `${d.processId}`, "thread", false);
886                        }
887                    }
888                }
889            }
890            this.observerScrollHeightCallback = () => task();
891            if(threadRow){
892                this.scrollToProcess(`${d.tid}`, `${d.processId}`, "thread", true);
893            }
894            task();
895        }
896
897        if (CpuStruct.hoverCpuStruct) {
898            CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct
899            this.timerShaftEL?.drawTriangle(CpuStruct.selectCpuStruct!.startTime || 0, "inverted");
900            this.traceSheetEL?.displayCpuData(CpuStruct.selectCpuStruct, (wakeUpBean) => {
901                CpuStruct.wakeupBean = wakeUpBean;
902                this.visibleRows.forEach(it => it.draw());
903            }, cpuClickHandler);
904            this.timerShaftEL?.modifyFlagList(undefined);
905        } else if (ThreadStruct.hoverThreadStruct) {
906            ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct;
907            this.timerShaftEL?.drawTriangle(ThreadStruct.selectThreadStruct!.startTime || 0, "inverted");
908            this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct, threadClickHandler, cpuClickHandler);
909            this.timerShaftEL?.modifyFlagList(undefined);
910        } else if (FuncStruct.hoverFuncStruct) {
911            FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct;
912            this.timerShaftEL?.drawTriangle(FuncStruct.selectFuncStruct!.startTs || 0, "inverted");
913            this.traceSheetEL?.displayFuncData(FuncStruct.hoverFuncStruct, (funcStract: any) => {
914                this.observerScrollHeightEnable = true;
915                this.moveRangeToCenter(funcStract.startTime!, funcStract.dur!)
916                this.scrollToActFunc(funcStract, false)
917            })
918            this.timerShaftEL?.modifyFlagList(undefined);
919        } else if (CpuFreqStruct.hoverCpuFreqStruct) {
920            CpuFreqStruct.selectCpuFreqStruct = CpuFreqStruct.hoverCpuFreqStruct
921            this.traceSheetEL?.displayFreqData()
922            this.timerShaftEL?.modifyFlagList(undefined);
923        }else if (SpFreqChart.hoverStateStruct) {
924            SpFreqChart.selectStateStruct = SpFreqChart.hoverStateStruct;
925            this.traceSheetEL?.displayCpuStateData()
926            this.timerShaftEL?.modifyFlagList(undefined);
927        } else if (CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct) {
928            CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct
929            this.traceSheetEL?.displayFreqLimitData()
930            this.timerShaftEL?.modifyFlagList(undefined);
931        } else {
932            this.observerScrollHeightEnable = false;
933            this.selectFlag = null;
934            this.timerShaftEL?.removeTriangle("inverted");
935            if (!SportRuler.isMouseInSportRuler) {
936                this.traceSheetEL?.setAttribute("mode", 'hidden');
937                this.getVisibleRows().forEach(it => it.draw(true));
938            }
939        }
940    }
941
942    connectedCallback() {
943        /**
944         * 监听时间轴区间变化
945         */
946        this.timerShaftEL!.rangeChangeHandler = this.timerShaftELRangeChange;
947        this.timerShaftEL!.flagChangeHandler = this.timerShaftELFlagChange;
948        this.timerShaftEL!.flagClickHandler = this.timerShaftELFlagClickHandler;
949        /**
950         * 监听rowsEL的滚动时间,刷新可见区域的trace-row组件的时间区间(将触发trace-row组件重绘)
951         */
952        this.rowsEL?.addEventListener('scroll', this.rowsElOnScroll)
953        /**
954         * 监听document的mousemove事件 坐标通过换算后找到当前鼠标所在的trace-row组件,将坐标传入
955         */
956        this.addEventListener('mousemove', this.documentOnMouseMove)
957        this.addEventListener('click', this.documentOnClick)
958        this.addEventListener('mousedown', this.documentOnMouseDown)
959        this.addEventListener('mouseup', this.documentOnMouseUp)
960        this.addEventListener('mouseout', this.documentOnMouseOut)
961        document.addEventListener('keypress', this.documentOnKeyPress)
962        document.addEventListener('keyup', this.documentOnKeyUp)
963        SpApplication.skinChange2 = (val: boolean) => {
964            this.timerShaftEL?.render()
965            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row:not([sleeping])`).forEach(it => {
966                this.hoverStructNull();
967                it.draw();
968            })
969        }
970    }
971
972    scrollToProcess(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true) {
973        let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
974        if (row) {
975            row.expansion = true
976        }
977        let rootRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
978        this.rowsEL!.scroll({
979            top: (rootRow?.offsetTop || 0) - this.rowsEL!.offsetTop - this.rowsEL!.offsetHeight + (rootRow?.offsetHeight || 0),
980            left: 0,
981            behavior: smooth ? "smooth" : undefined
982        })
983    }
984
985    scrollToDepth(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true, depth: number) {
986        let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
987        if (row) {
988            row.expansion = true
989        }
990        let rootRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
991        this.rowsEL!.scroll({
992            top: (rootRow?.offsetTop || 0) - this.rowsEL!.offsetTop - this.rowsEL!.offsetHeight + ((++depth) * 20 || 0),
993            left: 0,
994            behavior: smooth ? "smooth" : undefined
995        })
996    }
997
998    scrollToFunction(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true, afterScroll: any) {
999        let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
1000        if (row) {
1001            row.expansion = true
1002        }
1003        let funcRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
1004        if (funcRow == null) {
1005            let threadRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='thread']`);
1006            this.rowsEL!.scroll({
1007                top: threadRow!.offsetTop - this.rowsEL!.offsetTop - this.rowsEL!.offsetHeight + threadRow!.offsetHeight + threadRow!.offsetHeight,
1008                left: 0,
1009                behavior: smooth ? "smooth" : undefined
1010            })
1011            if (threadRow != null) {
1012                if (threadRow.isComplete) {
1013                    afterScroll()
1014                } else {
1015                    threadRow.onComplete = () => {
1016                        funcRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
1017                        afterScroll()
1018                    }
1019                }
1020            }
1021        } else {
1022            afterScroll()
1023        }
1024    }
1025
1026    rowScrollTo(offset: number, callback: Function) {
1027        const fixedOffset = offset;
1028        const onScroll = () => {
1029            if (this.rowsEL!.scrollTop === fixedOffset) {
1030                this.rowsEL!.removeEventListener('scroll', onScroll)
1031                callback()
1032            }
1033        }
1034
1035        this.rowsEL!.addEventListener('scroll', onScroll)
1036        onScroll()
1037        this.rowsEL!.scrollTo({
1038            top: offset,
1039            behavior: 'smooth'
1040        })
1041    }
1042
1043    disconnectedCallback() {
1044        this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange);
1045        this.rowsEL?.removeEventListener('scroll', this.rowsElOnScroll);
1046        this.removeEventListener('mousemove', this.documentOnMouseMove);
1047        this.removeEventListener('click', this.documentOnClick);
1048        this.removeEventListener('mousedown', this.documentOnMouseDown)
1049        this.removeEventListener('mouseup', this.documentOnMouseUp)
1050        this.removeEventListener('mouseout', this.documentOnMouseOut)
1051        document.removeEventListener('keypress', this.documentOnKeyPress)
1052        document.removeEventListener('keyup', this.documentOnKeyUp)
1053    }
1054
1055    loadDatabaseUrl(url: string, progress: Function, complete?: ((res: { status: boolean, msg: string }) => void) | undefined) {
1056        this.observerScrollHeightEnable = false;
1057        this.init({url: url}, "", progress).then((res) => {
1058            if (complete) {
1059                complete(res);
1060            }
1061        })
1062    }
1063
1064    loadDatabaseArrayBuffer(buf: ArrayBuffer, thirdPartyWasmConfigUrl: string, progress: ((name: string, percent: number) => void), complete?: ((res: { status: boolean, msg: string }) => void) | undefined) {
1065        this.observerScrollHeightEnable = false;
1066        this.init({buf}, thirdPartyWasmConfigUrl, progress).then((res) => {
1067            let scrollTop = this.rowsEL?.scrollTop || 0
1068            let scrollHeight = this.rowsEL?.clientHeight || 0
1069            this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => {
1070                this.observer.observe(it);
1071            })
1072            if (complete) {
1073                complete(res);
1074            }
1075        })
1076    }
1077
1078    search(query: string) {
1079        this.shadowRoot?.querySelectorAll<TraceRow<any>>('trace-row').forEach(item => {
1080            if (query == null || query == undefined || query == '') {
1081                if (item.rowType == TraceRow.ROW_TYPE_CPU ||
1082                    item.rowType == TraceRow.ROW_TYPE_CPU_FREQ ||
1083                    item.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY ||
1084                    item.rowType == TraceRow.ROW_TYPE_FPS ||
1085                    item.rowType == TraceRow.ROW_TYPE_PROCESS ||
1086                    item.rowType == TraceRow.ROW_TYPE_CPU_ABILITY ||
1087                    item.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY ||
1088                    item.rowType == TraceRow.ROW_TYPE_DISK_ABILITY ||
1089                    item.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) {
1090                    item.expansion = false;
1091                    item.rowHidden = false;
1092                } else {
1093                    item.rowHidden = true;
1094                }
1095            } else {
1096                if (item.name.toLowerCase().indexOf(query.toLowerCase()) >= 0) {
1097                    item.rowHidden = false;
1098                } else {
1099                    item.rowHidden = true;
1100                }
1101            }
1102        })
1103        this.getVisibleRows().forEach(it => it.rowHidden = false && it.draw(true))
1104    }
1105
1106    searchCPU(query: string): Array<CpuStruct> {
1107        let searchResults: Array<CpuStruct> = []
1108        this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach(item => {
1109            let res = item!.dataList!.filter(it => (it.name && it.name.search(query) >= 0) || it.tid == query
1110                || it.processId == query
1111                || (it.processName && it.processName.search(query) >= 0)
1112            )
1113            searchResults.push(...res);
1114        })
1115        searchResults.sort((a, b) => (a.startTime || 0) - (b.startTime || 0));
1116        return searchResults;
1117    }
1118
1119    async searchFunction(cpuList: Array<any>, query: string): Promise<Array<any>> {
1120        let list = await querySearchFunc(query)
1121        cpuList = cpuList.concat(list)
1122        cpuList.sort((a, b) => (a.startTime || 0) - (b.startTime || 0));
1123        return cpuList
1124    }
1125
1126    searchThreadsAndProcesses(query: string): Array<any> {
1127        let searchResults: Array<any> = []
1128        this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='thread'][row-type='process']`).forEach(item => {
1129            if (item!.name.search(query) >= 0) {
1130                let searchBean = new SearchThreadProcessBean()
1131                searchBean.name = item.name
1132                searchBean.rowId = item.rowId
1133                searchBean.type = "thread||process"
1134                searchBean.rowType = item.rowType
1135                searchBean.rowParentId = item.rowParentId
1136                searchResults.push(searchBean)
1137            }
1138        })
1139        return searchResults
1140    }
1141
1142    showStruct(previous: boolean, currentIndex: number, structs: Array<any>) {
1143        if (structs.length == 0) {
1144            return 0;
1145        }
1146        let findIndex = -1;
1147        if (previous) {
1148            for (let i = structs.length - 1; i >= 0; i--) {
1149                let it = structs[i];
1150                if (i < currentIndex && (it.startTime!) >= (TraceRow.range!.startNS) && (it.startTime!) + (it.dur!) <= (TraceRow.range!.endNS)) {
1151                    findIndex = i;
1152                    break;
1153                }
1154            }
1155        } else {
1156            findIndex = structs.findIndex((it, idx) => {
1157                return idx > currentIndex && (it.startTime!) >= (TraceRow.range!.startNS) && (it.startTime!) + (it.dur!) <= (TraceRow.range!.endNS)
1158            })
1159        }
1160        let findEntry: any
1161        if (findIndex >= 0) {
1162            findEntry = structs[findIndex];
1163        } else {
1164            if (previous) {
1165                for (let i = structs.length - 1; i >= 0; i--) {
1166                    let it = structs[i];
1167                    if ((it.startTime! + it.dur!) < (TraceRow.range!.startNS)) {
1168                        findIndex = i;
1169                        break;
1170                    }
1171                }
1172                if (findIndex == -1) {
1173                    findIndex = structs.length - 1;
1174                }
1175            } else {
1176                findIndex = structs.findIndex((it) => (it.startTime!) > (TraceRow.range!.endNS))
1177                if (findIndex == -1) {
1178                    findIndex = 0;
1179                }
1180            }
1181            findEntry = structs[findIndex];
1182            this.moveRangeToCenter(findEntry.startTime!, findEntry.dur!)
1183        }
1184        this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row`).forEach(item => {
1185            item.highlight = false;
1186            if (!item.sleeping) {
1187                item.draw(true)
1188            }
1189        })
1190        if (findEntry.type == 'thread') {
1191            CpuStruct.selectCpuStruct = findEntry;
1192            CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct;
1193            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach(item => {
1194                item.highlight = item.rowId == `${findEntry.cpu}`;
1195                item.draw(true)
1196            })
1197            this.scrollToProcess(`${findEntry.cpu}`, "", "cpu-data", true)
1198            this.onClickHandler();
1199        } else if (findEntry.type == "func") {
1200            this.observerScrollHeightEnable = true;
1201            this.scrollToActFunc(findEntry, true)
1202        } else if (findEntry.type == "thread||process") {
1203            let threadProcessRow = this.rowsEL?.querySelectorAll<TraceRow<ThreadStruct>>(`trace-row[row-id='${findEntry.rowId}'][row-type='${findEntry.rowType}']`)[0];
1204            threadProcessRow!.highlight = true
1205            this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true);
1206            let completeEntry = () => {
1207                let searchEntry = threadProcessRow!.dataList!.find((dat) => dat.startTime === findEntry.startTime);
1208                this.hoverStructNull();
1209                this.selectStructNull();
1210                ThreadStruct.hoverThreadStruct = searchEntry;
1211                ThreadStruct.selectThreadStruct = searchEntry;
1212                this.closeAllExpandRows(findEntry.rowParentId)
1213                threadProcessRow!.draw();
1214            }
1215            let scrollTimer: any;
1216            this.observerScrollHeightCallback = () => {
1217                if (threadProcessRow!.isComplete) {
1218                    completeEntry()
1219                    this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true)
1220                } else {
1221                    threadProcessRow!.onComplete = () => {
1222                        completeEntry()
1223                        clearTimeout(scrollTimer);
1224                        scrollTimer = setTimeout(() => this.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, false), 100)
1225                    }
1226                }
1227            }
1228        }
1229        this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted");
1230        return findIndex;
1231    }
1232
1233    scrollToActFunc(funcStract: any, highlight: boolean) {
1234        this.scrollToFunction(`${funcStract.tid}`, `${funcStract.pid}`, funcStract.type, false, () => {
1235            let funcRow = this.rowsEL?.querySelector<TraceRow<FuncStruct>>(`trace-row[row-id='${funcStract.tid}'][row-type='func']`);
1236            if (funcRow == null) return
1237            this.scrollToDepth(`${funcStract.tid}`, `${funcStract.pid}`, "func", true, funcStract.depth || 0)
1238            funcRow!.highlight = highlight
1239            let completeEntry = () => {
1240                if (funcRow == null) return
1241                let searchEntry = funcRow!.dataList!.find((dat) => dat.startTs === funcStract.startTime);
1242                this.hoverStructNull();
1243                this.selectStructNull();
1244                FuncStruct.hoverFuncStruct = searchEntry;
1245                FuncStruct.selectFuncStruct = searchEntry;
1246                this.closeAllExpandRows(funcStract.pid)
1247                this.visibleRows.forEach(it => it.draw());
1248            }
1249            let scrollTimer: any;
1250            this.observerScrollHeightCallback = () => {
1251                funcRow = this.rowsEL?.querySelector<TraceRow<FuncStruct>>(`trace-row[row-id='${funcStract.tid}'][row-type='func']`);
1252                if (funcRow == null) {
1253                    return
1254                }
1255                if (funcRow!.isComplete) {
1256                    completeEntry()
1257                    this.onClickHandler();
1258                    this.scrollToDepth(`${funcStract.tid}`, `${funcStract.pid}`, "func", false, funcStract.depth || 0)
1259                } else {
1260                    funcRow!.onComplete = () => {
1261                        completeEntry()
1262                        this.onClickHandler();
1263                        clearTimeout(scrollTimer);
1264                        scrollTimer = setTimeout(() => this.scrollToDepth(`${funcStract.tid}`, `${funcStract.pid}`, "func", false, funcStract.depth || 0), 100)
1265                    }
1266                }
1267            }
1268            if (funcRow?.isComplete) {
1269                completeEntry()
1270                this.onClickHandler();
1271                this.scrollToProcess(`${funcStract.tid}`, `${funcStract.pid}`, "thread", false)
1272                this.scrollToDepth(`${funcStract.tid}`, `${funcStract.pid}`, "func", true, funcStract.depth || 0)
1273            }
1274        });
1275    }
1276
1277    closeAllExpandRows(pid: string) {
1278        let expandRows = this.rowsEL?.querySelectorAll<TraceRow<ProcessStruct>>(`trace-row[row-type='process'][expansion]`);
1279        expandRows?.forEach((row) => {
1280            if (row.rowId != pid) {
1281                row.expansion = false
1282            }
1283        })
1284    }
1285
1286    moveRangeToCenter(startTime: number, dur: number) {
1287        let startNS = this.timerShaftEL?.getRange()?.startNS || 0;
1288        let endNS = this.timerShaftEL?.getRange()?.endNS || 0;
1289        let harfDur = Math.trunc((endNS - startNS) / 2 - dur / 2);
1290        this.timerShaftEL?.setRangeNS(startTime - harfDur, startTime + dur + harfDur);
1291    }
1292
1293    showPreCpuStruct(currentIndex: number, cpuStructs: Array<CpuStruct>): number {
1294        if (cpuStructs.length == 0) {
1295            return 0;
1296        }
1297        let findIndex = -1;
1298        for (let i = cpuStructs.length - 1; i >= 0; i--) {
1299            let it = cpuStructs[i];
1300            if (i < currentIndex && (it.startTime!) >= (TraceRow.range!.startNS) && (it.startTime!) + (it.dur!) <= (TraceRow.range!.endNS)) {
1301                findIndex = i;
1302                break;
1303            }
1304        }
1305        if (findIndex >= 0) {
1306            let findEntry = cpuStructs[findIndex];
1307            CpuStruct.selectCpuStruct = findEntry;
1308            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach(item => {
1309                item.highlight = item.rowId == `${findEntry.cpu}`;
1310                item.draw(true);
1311            })
1312            this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted");
1313        } else {
1314            for (let i = cpuStructs.length - 1; i >= 0; i--) {
1315                let it = cpuStructs[i];
1316                if ((it.startTime! + it.dur!) < (TraceRow.range!.startNS)) {
1317                    findIndex = i;
1318                    break;
1319                }
1320            }
1321            let findEntry: CpuStruct;
1322            if (findIndex == -1) {
1323                findIndex = cpuStructs.length - 1;
1324            }
1325            findEntry = cpuStructs[findIndex];
1326            CpuStruct.selectCpuStruct = findEntry;
1327            let startNS = this.timerShaftEL?.getRange()?.startNS || 0;
1328            let endNS = this.timerShaftEL?.getRange()?.endNS || 0;
1329            let harfDur = Math.trunc((endNS - startNS) / 2 - findEntry.dur! / 2);
1330            this.timerShaftEL?.setRangeNS(findEntry.startTime! - harfDur, findEntry.startTime! + findEntry.dur! + harfDur);
1331            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach(item => {
1332                item.highlight = item.rowId == `${findEntry.cpu}`;
1333                item.draw(true)
1334            })
1335            this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted");
1336        }
1337        CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct;
1338        this.onClickHandler();
1339        return findIndex;
1340    }
1341
1342    showNextCpuStruct(currentIndex: number, cpuStructs: Array<CpuStruct>): number {
1343        if (cpuStructs.length == 0) {
1344            return 0;
1345        }
1346        let findIndex = cpuStructs.findIndex((it, idx) => {
1347            return idx > currentIndex && (it.startTime!) >= (TraceRow.range!.startNS) && (it.startTime!) + (it.dur!) <= (TraceRow.range!.endNS)
1348        })
1349        if (findIndex >= 0) {
1350            let findEntry = cpuStructs[findIndex];
1351            CpuStruct.selectCpuStruct = findEntry;
1352            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach(item => {
1353                item.highlight = item.rowId == `${findEntry.cpu}`;
1354                item.draw(true);
1355            })
1356            this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted");
1357        } else {
1358            findIndex = cpuStructs.findIndex((it) => (it.startTime!) > (TraceRow.range!.endNS))
1359            let findEntry: CpuStruct;
1360            if (findIndex == -1) {
1361                findIndex = 0;
1362            }
1363            findEntry = cpuStructs[findIndex];
1364            CpuStruct.selectCpuStruct = findEntry;
1365            let startNS = this.timerShaftEL?.getRange()?.startNS || 0;
1366            let endNS = this.timerShaftEL?.getRange()?.endNS || 0;
1367            let harfDur = Math.trunc((endNS - startNS) / 2 - findEntry.dur! / 2);
1368            this.timerShaftEL?.setRangeNS(findEntry.startTime! - harfDur, findEntry.startTime! + findEntry.dur! + harfDur);
1369            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row[row-type='cpu-data']`).forEach(item => {
1370                item.highlight = item.rowId == `${findEntry.cpu}`;
1371                item.draw(true);
1372            })
1373            this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted");
1374        }
1375        CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct;
1376        this.onClickHandler();
1377        return findIndex;
1378    }
1379
1380    reset(progress: Function | undefined | null) {
1381        this.loadTraceCompleted = false;
1382        if (this.rowsEL) this.rowsEL.innerHTML = ''
1383        this.spacerEL!.style.height = '0px';
1384        this.rangeSelect.rangeTraceRow = [];
1385        CpuStruct.wakeupBean = undefined;
1386        this.selectStructNull();
1387        this.hoverStructNull();
1388        this.traceSheetEL?.setAttribute("mode", "hidden")
1389        progress && progress("rest timershaft", 8);
1390        this.timerShaftEL?.reset();
1391        progress && progress("clear cache", 10);
1392        procedurePool.clearCache();
1393    }
1394
1395    init = async (param: { buf?: ArrayBuffer, url?: string }, wasmConfigUri: string, progress: Function) => {
1396        progress("Load database", 6);
1397        this.reset(progress);
1398        if (param.buf) {
1399            let configJson = "";
1400            try {
1401                configJson = await fetch(wasmConfigUri).then(res => res.text());
1402            } catch (e) {
1403                error("getWasmConfigFailed", e)
1404            }
1405            let {status, msg, sdkConfigMap} = await threadPool.initSqlite(param.buf, configJson, progress);
1406            if (!status) {
1407                return {status: false, msg: msg}
1408            }
1409            SpSystemTrace.SDK_CONFIG_MAP = sdkConfigMap == undefined ? undefined : sdkConfigMap;
1410        }
1411        if (param.url) {
1412            let {status, msg} = await threadPool.initServer(param.url, progress);
1413            if (!status) {
1414                return {status: false, msg: msg}
1415            }
1416        }
1417        await this.chartManager?.init(progress);
1418        this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach((it: any) => {
1419            it.addEventListener('expansion-change', () => {
1420                this.getVisibleRows().forEach(it2 => it2.draw());
1421            })
1422        })
1423        progress("completed", 100);
1424        info("All TraceRow Data initialized")
1425        this.loadTraceCompleted = true;
1426        this.getVisibleRows().forEach(it => {
1427            it.draw();
1428        });
1429        return {status: true, msg: "success"}
1430    }
1431
1432    initHtml(): string {
1433        return `
1434        <style>
1435        :host{
1436            display: block;
1437            width: 100%;
1438            height: 100%;
1439        }
1440        .timer-shaft{
1441            width: 100%;
1442            z-index: 2;
1443        }
1444        .rows{
1445            color: #fff;
1446            display: block;
1447            box-sizing: border-box;
1448            /*flex-direction: column;*/
1449            /*overflow-y: auto;*/
1450            overflow: overlay;
1451            overflow-anchor: none;
1452            max-height: calc(100vh - 147px - 48px);
1453            flex: 1;
1454            width: 100%;
1455            background: var(--dark-background4,#ffffff);
1456            /*scroll-behavior: smooth;*/
1457        }
1458        .container{
1459            width: 100%;
1460            box-sizing: border-box;
1461            height: 100%;
1462            display: grid;
1463            grid-template-columns: 1fr;
1464            grid-template-rows: min-content min-content 1fr min-content;
1465        }
1466        .trace-sheet{
1467            cursor: default;
1468        }
1469
1470        </style>
1471        <div class="container">
1472            <timer-shaft-element class="timer-shaft">
1473            </timer-shaft-element>
1474            <div class="spacer"></div>
1475            <div class="rows"></div>
1476            <trace-sheet class="trace-sheet" mode="hidden">
1477            </trace-sheet>
1478        </div>
1479        `;
1480    }
1481}
1482