• 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    DbPool,
21    getAsyncEvents,
22    getCpuUtilizationRate,
23    getFps,
24    getFunDataByTid,
25    queryCpuData,
26    queryCpuFreq,
27    queryCpuFreqData,
28    queryCpuMax,
29    queryCpuMaxFreq,
30    queryHeapByPid,
31    queryHeapPid,
32    queryProcess,
33    queryProcessData,
34    queryProcessMem,
35    queryProcessMemData,
36    queryProcessThreads,
37    queryThreadData,
38    queryTotalTime,
39    threadPool
40} from "../database/SqlLite.js";
41import {TraceRow} from "./trace/base/TraceRow.js";
42import {TimerShaftElement} from "./trace/TimerShaftElement.js";
43import {TimeRange} from "./trace/timer-shaft/RangeRuler.js";
44import {CpuStruct} from "../bean/CpuStruct.js";
45import {CpuFreqStruct} from "../bean/CpuFreqStruct.js";
46import {ProcessStruct} from "../bean/ProcessStruct.js";
47import {ColorUtils} from "./trace/base/ColorUtils.js";
48import "./trace/base/TraceSheet.js";
49import {TraceSheet} from "./trace/base/TraceSheet.js";
50import {ThreadStruct} from "../bean/ThreadStruct.js";
51import {ProcessMemStruct} from "../bean/ProcessMemStruct.js";
52import {FuncStruct} from "../bean/FuncStruct.js";
53import {FpsStruct} from "../bean/FpsStruct.js";
54import {RangeSelect} from "./trace/base/RangeSelect.js";
55import {SelectionParam} from "../bean/BoxSelection.js";
56import {HeapStruct} from "../bean/HeapStruct.js";
57import {procedurePool} from "../database/Procedure.js";
58import {SportRuler} from "./trace/timer-shaft/SportRuler.js";
59import {Utils} from "./trace/base/Utils.js";
60import {SpApplication} from "../SpApplication.js";
61
62@element('sp-system-trace')
63export class SpSystemTrace extends BaseElement {
64    static scrollViewWidth = 0
65    static isCanvasOffScreen = true;
66
67    rowsEL: HTMLDivElement | undefined | null;
68    visibleRows: Array<TraceRow<any>> = [];
69    keyboardEnable = true;
70    currentRowType = "";
71    private timerShaftEL: TimerShaftElement | null | undefined;
72    private traceSheetEL: TraceSheet | undefined | null;
73    private rangeSelect!: RangeSelect;
74
75    private processThreads: Array<ThreadStruct> = []
76    private processAsyncEvent: Array<ProcessMemStruct> = []
77    private processMem: Array<any> = []
78
79    initElements(): void {
80        this.rowsEL = this.shadowRoot?.querySelector<HTMLDivElement>('.rows')
81        this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft')
82        this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet')
83        this.rangeSelect = new RangeSelect();
84        this.rangeSelect.rowsEL = this.rowsEL;
85        document?.addEventListener("flag-change", (event: any) => {
86            this.timerShaftEL?.modifyList(event.detail.type, event.detail.flagObj)
87            if (event.detail.type == "remove") {
88                this.traceSheetEL?.setAttribute("mode", 'hidden');
89            }
90        })
91        document?.addEventListener("flag-draw", (event: any) => {
92            if (event.detail == null) {
93            }
94        })
95
96        SpSystemTrace.scrollViewWidth = this.getScrollWidth()
97        this.rangeSelect.selectHandler = (rows) => {
98            if (rows.length > 0) {
99                this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(row => row.checkType = "0")
100                rows.forEach(it => it.checkType = "2")
101            } else {
102                this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(row => row.checkType = "-1")
103                return
104            }
105            let selection = new SelectionParam();
106            selection.cpus = [];
107            selection.threadIds = [];
108            selection.funTids = [];
109            selection.trackIds = [];
110            selection.leftNs = 0;
111            selection.rightNs = 0;
112            rows.forEach(it => {
113                if (it.rowType == TraceRow.ROW_TYPE_CPU) {
114                    selection.cpus.push(parseInt(it.rowId!))
115                } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) {
116                    selection.threadIds.push(parseInt(it.rowId!))
117                } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) {
118                    selection.funTids.push(parseInt(it.rowId!))
119                } else if (it.rowType == TraceRow.ROW_TYPE_MEM) {
120                    selection.trackIds.push(parseInt(it.rowId!))
121                } else if (it.rowType == TraceRow.ROW_TYPE_FPS) {
122                    selection.hasFps = true;
123                } else if (it.rowType == TraceRow.ROW_TYPE_HEAP) {
124                    selection.heapIds.push(parseInt(it.rowId!))
125                }
126            })
127            selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0;
128            selection.rightNs = TraceRow.rangeSelectObject?.endNS || 0;
129            this.traceSheetEL?.boxSelection(selection);
130        }
131        // @ts-ignore
132        new ResizeObserver((entries) => {
133            let width = entries[0].contentRect.width - 1 - SpSystemTrace.scrollViewWidth;
134            requestAnimationFrame(() => {
135                this.timerShaftEL?.updateWidth(width)
136                this.shadowRoot!.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.updateWidth(width))
137            })
138        }).observe(this)
139    }
140
141    getScrollWidth() {
142        let noScroll, scroll, oDiv = document.createElement('div');
143        oDiv.style.cssText = 'position:absolute; top:-1000px;     width:100px; height:100px; overflow:hidden;';
144        noScroll = document.body.appendChild(oDiv).clientWidth;
145        oDiv.style.overflowY = 'scroll';
146        scroll = oDiv.clientWidth;
147        document.body.removeChild(oDiv);
148        return noScroll - scroll + 1;
149    }
150
151    getVisibleRows(): Array<TraceRow<any>> {
152        let scrollTop = this.rowsEL?.scrollTop || 0;
153        let scrollHeight = this.rowsEL?.clientHeight || 0;
154        let res = [...this.rowsEL!.querySelectorAll<TraceRow<any>>("trace-row")].filter((it) => {
155            let tr = (it as TraceRow<any>);
156            let top = it.offsetTop - (this.rowsEL?.offsetTop || 0);
157            if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) {
158                it.sleeping = false;
159                return true
160            } else {
161                it.sleeping = true;
162                return false;
163            }
164        })
165        this.visibleRows = res;
166        return res;
167    }
168
169    timerShaftELRangeChange = (e: any) => {
170        TraceRow.range = e;
171        let scrollTop = this.rowsEL?.scrollTop || 0
172        let scrollHeight = this.rowsEL?.clientHeight || 0
173        for (let i = 0; i < this.visibleRows.length; i++) {
174            this.visibleRows[i].dataListCache.length = 0;
175            this.visibleRows[i].isHover = false;
176            this.hoverStructNull();
177            this.visibleRows[i].draw();
178        }
179    }
180
181    rowsElOnScroll = (e: any) => {
182        this.hoverStructNull();
183        this.visibleRows = this.getVisibleRows();
184        for (let index = 0; index < this.visibleRows.length; index++) {
185            if (index == 0 || index == this.visibleRows.length - 1) {
186                this.visibleRows[index].isHover = false;
187                this.visibleRows[index].dataListCache.length = 0;
188            }
189        }
190    }
191    documentOnMouseDown = (ev: MouseEvent) => {
192        if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
193            this.rangeSelect.mouseDown(ev)
194            this.timerShaftEL?.documentOnMouseDown(ev)
195            this.visibleRows.forEach(it => {
196                it.draw();
197            })
198        }
199    }
200    documentOnMouseUp = (ev: MouseEvent) => {
201        if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
202            this.rangeSelect.mouseUp(ev);
203            this.timerShaftEL?.documentOnMouseUp(ev)
204        }
205    }
206    documentOnMouseOut = (ev: MouseEvent) => {
207        if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) {
208            this.timerShaftEL?.documentOnMouseOut(ev)
209        }
210    }
211
212    documentOnKeyPress = (ev: KeyboardEvent) => {
213        this.keyboardEnable && this.timerShaftEL!.documentOnKeyPress(ev);
214    }
215
216    documentOnKeyUp = (ev: KeyboardEvent) => {
217        this.keyboardEnable && this.timerShaftEL!.documentOnKeyUp(ev);
218    }
219
220    documentOnMouseMove = (ev: MouseEvent) => {
221        let rows = this.visibleRows;
222        if (this.timerShaftEL?.isScaling()) {
223            rows.forEach(it => it.isHover = false);
224            this.hoverStructNull();
225            return;
226        }
227        this.timerShaftEL?.documentOnMouseMove(ev)
228        this.rangeSelect.mouseMove(rows, ev);
229        if (this.rangeSelect.isMouseDown) {
230            for (let i = 0; i < rows.length; i++) {
231                rows[i].tipEL!.style.display = "none";
232                rows[i].draw(true);
233            }
234        } else {
235            for (let i = 0; i < rows.length; i++) {
236                let tr = rows[i];
237                let x = ev.offsetX - (tr.canvasContainer?.offsetLeft || 0);
238                let y = ev.offsetY - (tr.canvasContainer?.offsetTop || 0) + (this.rowsEL?.scrollTop || 0);
239
240                if (x > tr.frame.x && x < tr.frame.x + tr.frame.width && y > tr.frame.y && y < tr.frame.y + tr.frame.height) {
241                    tr.isHover = true;
242                    tr.hoverX = x;
243                    tr.hoverY = y;
244                    if (!SpSystemTrace.isCanvasOffScreen) this.hoverStructNull();
245                    if (tr.rowType === TraceRow.ROW_TYPE_CPU) {
246                        this.currentRowType = TraceRow.ROW_TYPE_CPU;
247                        if (!SpSystemTrace.isCanvasOffScreen) CpuStruct.hoverCpuStruct = tr.onMouseHover(x, y);
248                        if (CpuStruct.hoverCpuStruct) {
249                            tr.tip = `<span>P:${CpuStruct.hoverCpuStruct.processName || "Process"} [${CpuStruct.hoverCpuStruct.processId}]</span><span>T:${CpuStruct.hoverCpuStruct.name} [${CpuStruct.hoverCpuStruct.tid}]</span>`;
250                        }
251                        tr.setTipLeft(x, CpuStruct.hoverCpuStruct)
252                    } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ) {
253                        this.currentRowType = TraceRow.ROW_TYPE_CPU_FREQ;
254                        if (!SpSystemTrace.isCanvasOffScreen) CpuFreqStruct.hoverCpuFreqStruct = tr.onMouseHover(x, y);
255                        if (CpuFreqStruct.hoverCpuFreqStruct) {
256                            tr.tip = `<span>${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct.value!)} kHz</span>`
257                        }
258                        tr.setTipLeft(x, CpuFreqStruct.hoverCpuFreqStruct)
259                    } else if (tr.rowType === TraceRow.ROW_TYPE_THREAD) {
260                        this.currentRowType = TraceRow.ROW_TYPE_THREAD;
261                        if (!SpSystemTrace.isCanvasOffScreen) ThreadStruct.hoverThreadStruct = tr.onMouseHover(x, y, false);
262                    } else if (tr.rowType === TraceRow.ROW_TYPE_FUNC) {
263                        this.currentRowType = TraceRow.ROW_TYPE_FUNC;
264                        if (!SpSystemTrace.isCanvasOffScreen) FuncStruct.hoverFuncStruct = tr.onMouseHover(x, y, false)
265                    } else if (tr.rowType === TraceRow.ROW_TYPE_HEAP) {
266                        this.currentRowType = TraceRow.ROW_TYPE_HEAP;
267                        if (!SpSystemTrace.isCanvasOffScreen) HeapStruct.hoverHeapStruct = tr.onMouseHover(x, y, false)
268                        if (HeapStruct.hoverHeapStruct) {
269                            tr.tip = `<span>${Utils.getByteWithUnit(HeapStruct.hoverHeapStruct.heapsize!)}</span>`
270                        }
271                        tr.setTipLeft(x, HeapStruct.hoverHeapStruct)
272                    } else {
273                        this.hoverStructNull();
274                    }
275                    tr.draw(true);
276                } else {
277                    tr.onMouseLeave(x, y);
278                    tr.isHover = false;
279                    tr.hoverX = x;
280                    tr.hoverY = y;
281                    if (!SpSystemTrace.isCanvasOffScreen) this.hoverStructNull();
282                }
283
284            }
285            if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft!
286                && ev.offsetX < this.timerShaftEL!.canvas!.offsetLeft! + this.timerShaftEL!.canvas!.offsetWidth!
287                && ev.offsetY > this.rowsEL!.offsetTop
288                && ev.offsetY < this.rowsEL!.offsetTop + this.rowsEL!.offsetHeight
289            ) {
290            } else {
291                this.hoverStructNull();
292                for (let i = 0, len = rows.length; i < len; i++) {
293                    if (!(rows[i].rowType === TraceRow.ROW_TYPE_PROCESS) && this.currentRowType === rows[i].rowType) { //
294                        rows[i].draw(true);
295                    }
296                }
297            }
298        }
299    }
300
301    hoverStructNull() {
302        CpuStruct.hoverCpuStruct = undefined;
303        CpuFreqStruct.hoverCpuFreqStruct = undefined;
304        ThreadStruct.hoverThreadStruct = undefined;
305        FuncStruct.hoverFuncStruct = undefined;
306    }
307
308    selectStructNull() {
309        CpuStruct.selectCpuStruct = undefined;
310        CpuStruct.wakeupBean = null;
311        CpuFreqStruct.selectCpuFreqStruct = undefined;
312        ThreadStruct.selectThreadStruct = undefined;
313        FuncStruct.selectFuncStruct = undefined;
314    }
315
316    documentOnClick = (ev: MouseEvent) => {
317        if (this.rangeSelect.isDrag()) {
318            return;
319        }
320        this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.rangeSelect = false)
321        this.selectStructNull();
322        if (CpuStruct.hoverCpuStruct) {
323            CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct
324            this.traceSheetEL?.displayCpuData(CpuStruct.hoverCpuStruct, (wakeUpBean) => {
325                CpuStruct.wakeupBean = wakeUpBean;
326                this.visibleRows.forEach(it => it.draw());
327            })
328        } else if (ThreadStruct.hoverThreadStruct) {
329            ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct;
330            this.traceSheetEL?.displayThreadData(ThreadStruct.hoverThreadStruct)
331        } else if (FuncStruct.hoverFuncStruct) {
332            FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct;
333            this.traceSheetEL?.displayFuncData(FuncStruct.hoverFuncStruct)
334        } else if (SportRuler.rulerFlagObj) {
335
336        } else {
337            this.traceSheetEL?.setAttribute("mode", 'hidden');
338            this.getVisibleRows().forEach(it => it.draw(true));
339        }
340        this.documentOnMouseMove(ev)
341    }
342
343    connectedCallback() {
344        this.timerShaftEL!.rangeChangeHandler = this.timerShaftELRangeChange;
345        this.rowsEL?.addEventListener('scroll', this.rowsElOnScroll)
346        this.addEventListener('mousemove', this.documentOnMouseMove)
347        this.addEventListener('click', this.documentOnClick)
348        this.addEventListener('mousedown', this.documentOnMouseDown)
349        this.addEventListener('mouseup', this.documentOnMouseUp)
350        this.addEventListener('mouseout', this.documentOnMouseOut)
351        document.addEventListener('keypress', this.documentOnKeyPress)
352        document.addEventListener('keyup', this.documentOnKeyUp)
353        SpApplication.skinChange2 = (val: boolean) => {
354            this.timerShaftEL?.render()
355            this.rowsEL!.querySelectorAll<TraceRow<any>>(`trace-row:not([sleeping])`).forEach(it => {
356                this.hoverStructNull();
357                it.draw();
358            })
359        }
360    }
361
362    goProcess(rowId: string, rowParentId: string, rowType: string) {
363        let row = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowParentId}'][folder]`);
364        row!.expansion = true
365        let rootRow = this.shadowRoot!.querySelector<TraceRow<any>>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`);
366        this.rowsEL!.scrollTop = rootRow!.offsetTop - this.rowsEL!.offsetTop - this.rowsEL!.offsetHeight + rootRow!.offsetHeight
367    }
368
369    disconnectedCallback() {
370        this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange);
371        this.rowsEL?.removeEventListener('scroll', this.rowsElOnScroll);
372        this.removeEventListener('mousemove', this.documentOnMouseMove);
373        this.removeEventListener('click', this.documentOnClick);
374        this.removeEventListener('mousedown', this.documentOnMouseDown)
375        this.removeEventListener('mouseup', this.documentOnMouseUp)
376        this.removeEventListener('mouseout', this.documentOnMouseOut)
377        document.removeEventListener('keypress', this.documentOnKeyPress)
378        document.removeEventListener('keyup', this.documentOnKeyUp)
379    }
380
381    loadDatabaseUrl(url: string, progress: Function, complete?: ((res: { status: boolean, msg: string }) => void) | undefined) {
382        this.init({url: url}, progress).then((res) => {
383            let scrollTop = this.rowsEL?.scrollTop || 0
384            let scrollHeight = this.rowsEL?.clientHeight || 0
385            this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => {
386                let top = it.offsetTop - (this.rowsEL?.offsetTop || 0);
387                if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) {
388                    (it as TraceRow<any>).dataListCache.length = 0;
389                }
390            })
391            if (complete) {
392                complete(res);
393            }
394        })
395    }
396
397    loadDatabaseArrayBuffer(buf: ArrayBuffer, progress: ((name: string, percent: number) => void), complete?: ((res: { status: boolean, msg: string }) => void) | undefined) {
398        this.init({buf}, progress).then((res) => {
399            let scrollTop = this.rowsEL?.scrollTop || 0
400            let scrollHeight = this.rowsEL?.clientHeight || 0
401            this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => {
402                let top = it.offsetTop - (this.rowsEL?.offsetTop || 0);
403                if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) {
404                    (it as TraceRow<any>).dataListCache.length = 0;
405                }
406            })
407            if (complete) {
408                complete(res);
409            }
410        })
411    }
412
413    init = async (param: { buf?: ArrayBuffer, url?: string }, progress: Function) => {
414        progress("Load database", 6);
415        if (param.buf) {
416            let {status, msg} = await threadPool.initSqlite(param.buf, progress);
417            if (!status) {
418                return {status: false, msg: msg}
419            }
420        }
421        if (param.url) {
422            let {status, msg} = await threadPool.initServer(param.url, progress);
423            if (!status) {
424                return {status: false, msg: msg}
425            }
426        }
427        if (this.rowsEL) this.rowsEL.innerHTML = ''
428        this.traceSheetEL?.setAttribute("mode", "hidden")
429        progress("rest timershaft", 8);
430        this.timerShaftEL?.reset();
431        progress("clear cache", 10);
432        procedurePool.clearCache();
433
434        progress("load process threads", 50);
435        this.processThreads = await queryProcessThreads();
436        progress("process memory", 60);
437        this.processMem = await queryProcessMem()
438        progress("async event", 63);
439        this.processAsyncEvent = await getAsyncEvents()
440        progress("time range", 65);
441        await this.initTotalTime();
442        progress("cpu", 70);
443        await this.initCpu();
444        progress("cpu rate", 75);
445        await this.initCpuRate();
446        progress("cpu freq", 80);
447        await this.initCpuFreq();
448        progress("fps", 85);
449        await this.initFPS();
450        progress("process", 90);
451        await this.initProcess();
452        progress("display", 95);
453        this.getVisibleRows().forEach(it => {
454            it.draw();
455        });
456        this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach((it: any) => {
457            it.addEventListener('expansion-change', () => {
458                this.getVisibleRows().forEach(it2 => it2.draw());
459            })
460        })
461        progress("completed", 100);
462        return {status: true, msg: "success"}
463    }
464
465    initCpuRate = async () => {
466        let rates = await getCpuUtilizationRate(0, this.timerShaftEL?.totalNS || 0);
467        if (this.timerShaftEL) this.timerShaftEL.cpuUsage = rates;
468    }
469    initTotalTime = async () => {
470        let res = await queryTotalTime();
471        if (this.timerShaftEL) {
472            this.timerShaftEL.totalNS = res[0].total
473            this.timerShaftEL.loadComplete = true;
474        }
475    }
476    initCpu = async () => {
477        let array = await queryCpuMax();
478        if (array && array.length > 0 && array[0]) {
479            let cpuMax = array[0].cpu
480            CpuStruct.cpuCount = cpuMax + 1;
481            for (let i1 = 0; i1 < CpuStruct.cpuCount; i1++) {
482                const cpuId = i1;
483                let traceRow = new TraceRow<CpuStruct>({
484                    alpha: true,
485                    contextId: '2d',
486                    isOffScreen: SpSystemTrace.isCanvasOffScreen
487                });
488                traceRow.rowId = `${cpuId}`
489                traceRow.rowType = TraceRow.ROW_TYPE_CPU
490                traceRow.rowParentId = ''
491                traceRow.style.height = '40px'
492                traceRow.name = `Cpu ${cpuId}`
493                traceRow.supplier = () => queryCpuData(cpuId, 0, this.timerShaftEL?.totalNS || 0)
494                traceRow.onThreadHandler = ((ctx: CanvasRenderingContext2D, useCache: boolean) => {
495                    // _measureCpu("cpu",`cpu${cpuId}`,traceRow.must ? traceRow.dataList : undefined, TraceRow.range?.startNS || 0,TraceRow.range?.endNS || 0,TraceRow.range?.totalNS || 0,traceRow.frame,ctx,traceRow);
496                    if (traceRow.dataListCache && traceRow.dataListCache.length > 0 && !traceRow.args.isOffScreen) {
497                        traceRow.clearCanvas(ctx);
498                        ctx.beginPath();
499                        traceRow.drawLines(ctx);
500                        for (let i = 0; i < traceRow.dataListCache.length; i++) {
501                            CpuStruct.draw(ctx, traceRow.dataListCache[i])
502                        }
503                        traceRow.drawSelection(ctx);
504                        ctx.closePath();
505                        return;
506                    }
507                    procedurePool.submitWithName(`cpu${cpuId % procedurePool.cpusLen.length}`, `cpu${cpuId}`, {
508                        list: traceRow.must ? traceRow.dataList : undefined,
509                        offscreen: traceRow.must ? traceRow.offscreen : undefined,
510                        dpr: traceRow.dpr,
511                        xs: TraceRow.range?.xs,
512                        isHover: traceRow.isHover,
513                        hoverX: traceRow.hoverX,
514                        hoverY: traceRow.hoverY,
515                        canvasWidth: traceRow.canvasWidth,
516                        canvasHeight: traceRow.canvasHeight,
517                        hoverCpuStruct: CpuStruct.hoverCpuStruct,
518                        selectCpuStruct: CpuStruct.selectCpuStruct,
519                        wakeupBean: CpuStruct.wakeupBean,
520                        isRangeSelect: traceRow.rangeSelect,
521                        rangeSelectObject: TraceRow.rangeSelectObject,
522                        useCache: useCache,
523                        lineColor: traceRow.getLineColor(),
524                        startNS: TraceRow.range?.startNS || 0,
525                        endNS: TraceRow.range?.endNS || 0,
526                        totalNS: TraceRow.range?.totalNS || 0,
527                        frame: traceRow.frame
528                    }, traceRow.must && traceRow.args.isOffScreen ? traceRow.offscreen : undefined, (res: any, hover: any) => {
529                        traceRow.must = false;
530                        if (traceRow.args.isOffScreen == true) {
531                            if (traceRow.isHover) {
532                                CpuStruct.hoverCpuStruct = hover;
533                                this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_CPU && it.name !== traceRow.name).forEach(it => it.draw(true));
534                            }
535                            return;
536                        }
537                        traceRow.dataListCache = [...res];
538                        traceRow.clearCanvas(ctx);
539                        ctx.beginPath();
540                        traceRow.drawLines(ctx);
541                        for (let re of res) {
542                            CpuStruct.draw(ctx, re)
543                        }
544
545                        traceRow.drawSelection(ctx);
546                        ctx.closePath();
547
548                    })
549                })
550                this.rowsEL?.appendChild(traceRow)
551            }
552        }
553    }
554
555    initCpuFreq = async () => {
556        let freqList = await queryCpuFreq();
557        let freqMaxList = await queryCpuMaxFreq();
558        CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq;
559        let math = () => {
560            let units: Array<string> = ["", "K", "M", "G", "T", "E"];
561            let sb = " ";
562            CpuFreqStruct.maxFreqName = " ";
563            if (CpuFreqStruct.maxFreq > 0) {
564                let log10: number = Math.ceil(Math.log10(CpuFreqStruct.maxFreq));
565                let pow10: number = Math.pow(10, log10);
566                let afterCeil: number = Math.ceil(CpuFreqStruct.maxFreq / (pow10 / 4)) * (pow10 / 4);
567                CpuFreqStruct.maxFreq = afterCeil;
568                let unitIndex: number = Math.floor(log10 / 3);
569                sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}hz`
570            }
571            CpuFreqStruct.maxFreqName = sb.toString();
572        }
573        math();
574        for (let i = 0; i < freqList.length; i++) {
575            const it = freqList[i];
576            let traceRow = new TraceRow<CpuFreqStruct>({
577                alpha: true,
578                contextId: '2d',
579                isOffScreen: SpSystemTrace.isCanvasOffScreen
580            });
581            traceRow.rowId = `${it.cpu}`
582            traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ
583            traceRow.rowParentId = ''
584            traceRow.style.height = '40px'
585            traceRow.name = `Cpu ${it.cpu} Frequency`;
586            traceRow.supplier = () => queryCpuFreqData(it.cpu)
587            traceRow.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
588                if (traceRow.dataListCache && traceRow.dataListCache.length > 0 && !traceRow.args.isOffScree) {
589                    traceRow.clearCanvas(ctx);
590                    traceRow.drawLines(ctx);
591                    ctx.beginPath();
592                    for (let i = 0; i < traceRow.dataListCache.length; i++) {
593                        CpuFreqStruct.draw(ctx, traceRow.dataListCache[i])
594                    }
595                    traceRow.drawSelection(ctx);
596                    ctx.closePath();
597                    let s = CpuFreqStruct.maxFreqName
598                    let textMetrics = ctx.measureText(s);
599                    ctx.globalAlpha = 0.8
600                    ctx.fillStyle = "#f0f0f0"
601                    ctx.fillRect(0, 5, textMetrics.width + 8, 18)
602                    ctx.globalAlpha = 1
603                    ctx.fillStyle = "#333"
604                    ctx.textBaseline = "middle"
605                    ctx.fillText(s, 4, 5 + 9)
606                    return;
607                }
608                procedurePool.submitWithName(`process${it.cpu % procedurePool.processLen.length}`, `freq${it.cpu}`, {
609                    list: traceRow.must ? traceRow.dataList : undefined,
610                    offscreen: traceRow.must ? traceRow.offscreen : undefined,
611                    xs: TraceRow.range?.xs,
612                    dpr: traceRow.dpr,
613                    isHover: traceRow.isHover,
614                    hoverX: traceRow.hoverX,
615                    hoverY: traceRow.hoverY,
616                    canvasWidth: traceRow.canvasWidth,
617                    canvasHeight: traceRow.canvasHeight,
618                    hoverCpuFreqStruct: CpuFreqStruct.hoverCpuFreqStruct,
619                    selectCpuFreqStruct: CpuFreqStruct.selectCpuFreqStruct,
620                    wakeupBean: CpuStruct.wakeupBean,
621                    isRangeSelect: traceRow.rangeSelect,
622                    rangeSelectObject: TraceRow.rangeSelectObject,
623                    maxFreq: CpuFreqStruct.maxFreq,
624                    maxFreqName: CpuFreqStruct.maxFreqName,
625                    useCache: useCache,
626                    lineColor: traceRow.getLineColor(),
627                    startNS: TraceRow.range?.startNS || 0,
628                    endNS: TraceRow.range?.endNS || 0,
629                    totalNS: TraceRow.range?.totalNS || 0,
630                    frame: traceRow.frame
631                }, traceRow.must && traceRow.args.isOffScreen ? traceRow.offscreen : undefined, (res: any, hover: any) => {
632                    traceRow.must = false;
633                    if (traceRow.args.isOffScreen == true) {
634                        if (traceRow.isHover) {
635                            CpuFreqStruct.hoverCpuFreqStruct = hover;
636                            this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_CPU_FREQ && it.name !== traceRow.name).forEach(it => it.draw(true));
637                        }
638                        return;
639                    }
640                    traceRow.dataListCache = [...res];
641                    traceRow.clearCanvas(ctx);
642                    traceRow.drawLines(ctx);
643                    ctx.beginPath();
644                    for (let re of res) {
645                        CpuFreqStruct.draw(ctx, re)
646                    }
647                    traceRow.drawSelection(ctx);
648                    ctx.closePath();
649                    let s = CpuFreqStruct.maxFreqName
650                    let textMetrics = ctx.measureText(s);
651                    ctx.globalAlpha = 0.8
652                    ctx.fillStyle = "#f0f0f0"
653                    ctx.fillRect(0, 5, textMetrics.width + 8, 18)
654                    ctx.globalAlpha = 1
655                    ctx.fillStyle = "#333"
656                    ctx.textBaseline = "middle"
657                    ctx.fillText(s, 4, 5 + 9)
658                })
659            }
660            this.rowsEL?.appendChild(traceRow)
661        }
662    }
663
664    initFPS = async () => {
665        let fpsRow = new TraceRow<FpsStruct>({alpha: true, contextId: '2d', isOffScreen: true});
666        fpsRow.rowId = `fps`
667        fpsRow.rowType = TraceRow.ROW_TYPE_FPS
668        fpsRow.rowParentId = ''
669        FpsStruct.maxFps = 0
670        fpsRow.style.height = '40px'
671        fpsRow.name = "FPS"
672        fpsRow.supplier = () => getFps()
673        fpsRow.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
674            procedurePool.submitWithName(`process0`, `fps0`, {
675                list: fpsRow.must ? fpsRow.dataList : undefined,
676                offscreen: fpsRow.must ? fpsRow.offscreen : undefined,
677                xs: TraceRow.range?.xs,
678                dpr: fpsRow.dpr,
679                isHover: fpsRow.isHover,
680                hoverX: fpsRow.hoverX,
681                hoverY: fpsRow.hoverY,
682                canvasWidth: fpsRow.canvasWidth,
683                canvasHeight: fpsRow.canvasHeight,
684                wakeupBean: CpuStruct.wakeupBean,
685                isRangeSelect: fpsRow.rangeSelect,
686                rangeSelectObject: TraceRow.rangeSelectObject,
687                useCache: useCache,
688                lineColor: fpsRow.getLineColor(),
689                startNS: TraceRow.range?.startNS || 0,
690                endNS: TraceRow.range?.endNS || 0,
691                totalNS: TraceRow.range?.totalNS || 0,
692                frame: fpsRow.frame
693            }, fpsRow.must && fpsRow.args.isOffScreen ? fpsRow.offscreen : undefined, (res: any, hover: any) => {
694                fpsRow.must = false;
695                if (fpsRow.args.isOffScreen == true) {
696                    return;
697                }
698            })
699        }
700        this.rowsEL?.appendChild(fpsRow)
701    }
702
703    initProcess = async () => {
704        let processList = await queryProcess();
705        let heapPidList = await queryHeapPid()
706        for (let i = 0; i < processList.length; i++) {
707            const it = processList[i];
708            let processRow = new TraceRow<ProcessStruct>({
709                alpha: false,
710                contextId: '2d',
711                isOffScreen: SpSystemTrace.isCanvasOffScreen
712            });
713            processRow.rowId = `${it.pid}`
714            processRow.index = i;
715            processRow.rowType = TraceRow.ROW_TYPE_PROCESS
716            processRow.rowParentId = '';
717            processRow.folder = true;
718            processRow.name = `${it.processName || "Process"} ${it.pid}`;
719            processRow.supplier = () => queryProcessData(it.pid || -1, 0, TraceRow.range?.totalNS || 0);
720            processRow.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
721                if (processRow.dataListCache && processRow.dataListCache.length > 0 && !processRow.args.isOffScreen) {
722                    processRow.clearCanvas(ctx);
723                    processRow.drawLines(ctx);
724                    ctx.beginPath();
725                    for (let i = 0; i < processRow.dataListCache.length; i++) {
726                        ProcessStruct.draw(ctx, processRow.dataListCache[i])
727                    }
728                    processRow.drawSelection(ctx);
729                    ctx.closePath();
730                    return;
731                }
732                procedurePool.submitWithName(`process${(processRow.index) % procedurePool.processLen.length}`, `process ${processRow.index} ${it.processName}`, {
733                    list: processRow.must ? processRow.dataList : undefined,
734                    offscreen: processRow.must ? processRow.offscreen : undefined,
735                    xs: TraceRow.range?.xs,
736                    dpr: processRow.dpr,
737                    isHover: processRow.isHover,
738                    hoverX: processRow.hoverX,
739                    hoverY: processRow.hoverY,
740                    canvasWidth: processRow.canvasWidth,
741                    canvasHeight: processRow.canvasHeight,
742                    isRangeSelect: processRow.rangeSelect,
743                    rangeSelectObject: TraceRow.rangeSelectObject,
744                    wakeupBean: CpuStruct.wakeupBean,
745                    cpuCount: CpuStruct.cpuCount,
746                    useCache: useCache,
747                    lineColor: processRow.getLineColor(),
748                    startNS: TraceRow.range?.startNS || 0,
749                    endNS: TraceRow.range?.endNS || 0,
750                    totalNS: TraceRow.range?.totalNS || 0,
751                    frame: processRow.frame
752                }, processRow.must && processRow.args.isOffScreen ? processRow.offscreen : undefined, (res: any) => {
753                    processRow.must = false;
754                    if (processRow.args.isOffScreen == true) {
755                        return;
756                    }
757                    processRow.dataListCache = [...res];
758                    processRow.clearCanvas(ctx);
759                    processRow.drawLines(ctx);
760                    ctx.beginPath();
761                    for (let re of res) {
762                        ProcessStruct.draw(ctx, re)
763                    }
764                    processRow.drawSelection(ctx);
765                    ctx.closePath();
766                })
767            }
768            this.rowsEL?.appendChild(processRow)
769            if (heapPidList != undefined && Array.isArray(heapPidList) && heapPidList.filter((item) => {
770                return item.pid == it.pid
771            }).length > 0) {
772                let heapPid = heapPidList.filter((item) => {
773                    return item.pid == it.pid
774                })[0];
775                let allHeapRow = new TraceRow<HeapStruct>({alpha: false, contextId: '2d', isOffScreen: true});
776                allHeapRow.rowParentId = `${it.pid}`
777                allHeapRow.rowHidden = !processRow.expansion
778                allHeapRow.style.height = '40px'
779                allHeapRow.name = "All Heap Allocations";
780                allHeapRow.rowId = heapPid.ipid
781                allHeapRow.folder = false;
782                allHeapRow.rowType = TraceRow.ROW_TYPE_HEAP
783                allHeapRow.setAttribute('children', '')
784                allHeapRow.supplier = () => queryHeapByPid(0, TraceRow.range?.totalNS || 0, heapPid.ipid || 0)
785                allHeapRow.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
786                    procedurePool.submitWithName(`process0`, `heap0`, {
787                        list: allHeapRow.must ? allHeapRow.dataList : undefined,
788                        offscreen: allHeapRow.must ? allHeapRow.offscreen : undefined,
789                        xs: TraceRow.range?.xs,
790                        dpr: allHeapRow.dpr,
791                        isHover: allHeapRow.isHover,
792                        hoverX: allHeapRow.hoverX,
793                        hoverY: allHeapRow.hoverY,
794                        canvasWidth: allHeapRow.canvasWidth,
795                        canvasHeight: allHeapRow.canvasHeight,
796                        isRangeSelect: allHeapRow.rangeSelect,
797                        rangeSelectObject: TraceRow.rangeSelectObject,
798                        wakeupBean: CpuStruct.wakeupBean,
799                        useCache: useCache,
800                        lineColor: allHeapRow.getLineColor(),
801                        startNS: TraceRow.range?.startNS || 0,
802                        endNS: TraceRow.range?.endNS || 0,
803                        totalNS: TraceRow.range?.totalNS || 0,
804                        frame: allHeapRow.frame
805                    }, allHeapRow.must && allHeapRow.args.isOffScreen ? allHeapRow.offscreen : undefined, (res: any, hover: any) => {
806                        allHeapRow.must = false;
807                        if (allHeapRow.args.isOffScreen == true) {
808                            if (allHeapRow.isHover) {
809                                HeapStruct.hoverHeapStruct = hover;
810                            }
811                            return;
812                        }
813                    })
814                }
815                this.rowsEL?.appendChild(allHeapRow)
816            }
817
818            let processMem = this.processMem.filter(mem => mem.pid === it.pid);
819            processMem.forEach(mem => {
820                let row = new TraceRow<ProcessMemStruct>({
821                    alpha: false,
822                    contextId: '2d',
823                    isOffScreen: SpSystemTrace.isCanvasOffScreen
824                });
825                row.rowId = `${mem.trackId}`
826                row.rowType = TraceRow.ROW_TYPE_MEM
827                row.rowParentId = `${it.pid}`
828                row.rowHidden = !processRow.expansion
829                row.style.height = '40px'
830                row.style.width = `100%`;
831                row.name = `${mem.trackName}`;
832                row.setAttribute('children', '');
833                row.supplier = () => queryProcessMemData(mem.trackId).then(res => {
834                    let maxValue = Math.max(...res.map(it => it.value || 0))
835                    for (let j = 0; j < res.length; j++) {
836                        res[j].maxValue = maxValue;
837                        if (j == res.length - 1) {
838                            res[j].duration = (TraceRow.range?.totalNS || 0) - (res[j].startTime || 0);
839                        } else {
840                            res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0);
841                        }
842                        if (j > 0) {
843                            res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0);
844                        } else {
845                            res[j].delta = 0;
846                        }
847                    }
848                    return res
849                });
850                row.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
851                    if (row.dataListCache && row.dataListCache.length > 0 && !row.args.isOffScreen) {
852                        row.clearCanvas(ctx);
853                        row.drawLines(ctx);
854                        ctx.beginPath();
855                        for (let i = 0; i < row.dataListCache.length; i++) {
856                            ProcessMemStruct.draw(ctx, row.dataListCache[i])
857                        }
858                        row.drawSelection(ctx);
859                        ctx.closePath();
860                        return;
861                    }
862                    procedurePool.submitWithName(`cpu${mem.trackId % procedurePool.cpusLen.length}`, `mem ${mem.trackId} ${mem.trackName}`, {
863                        list: row.must ? row.dataList : undefined,
864                        offscreen: row.must ? row.offscreen : undefined,
865                        dpr: row.dpr,
866                        xs: TraceRow.range?.xs,
867                        isHover: row.isHover,
868                        hoverX: row.hoverX,
869                        hoverY: row.hoverY,
870                        canvasWidth: row.canvasWidth,
871                        canvasHeight: row.canvasHeight,
872                        wakeupBean: CpuStruct.wakeupBean,
873                        isRangeSelect: row.rangeSelect,
874                        rangeSelectObject: TraceRow.rangeSelectObject,
875                        useCache: useCache,
876                        lineColor: row.getLineColor(),
877                        startNS: TraceRow.range?.startNS || 0,
878                        endNS: TraceRow.range?.endNS || 0,
879                        totalNS: TraceRow.range?.totalNS || 0,
880                        frame: row.frame
881                    }, row.must && row.args.isOffScreen ? row.offscreen : undefined, (res: any) => {
882                        row.must = false;
883
884                        if (row.args.isOffScreen == true) {
885                            return;
886                        }
887                        row.dataListCache = [...res];
888                        row.clearCanvas(ctx);
889                        row.drawLines(ctx);
890                        ctx.beginPath();
891                        for (let re of res) {
892                            ProcessMemStruct.draw(ctx, re)
893                        }
894                        row.drawSelection(ctx);
895                        ctx.closePath();
896                    })
897                }
898                this.rowsEL?.appendChild(row)
899            });
900            let threads = this.processThreads.filter(thread => thread.pid === it.pid && thread.tid != 0 && thread.threadName != null);
901            threads.forEach((thread, i) => {
902                let threadRow = new TraceRow<ThreadStruct>({
903                    alpha: false,
904                    contextId: '2d',
905                    isOffScreen: SpSystemTrace.isCanvasOffScreen
906                });
907                threadRow.rowId = `${thread.tid}`
908                threadRow.rowType = TraceRow.ROW_TYPE_THREAD
909                threadRow.rowParentId = `${it.pid}`
910                threadRow.rowHidden = !processRow.expansion
911                threadRow.style.height = '40px'
912                threadRow.style.width = `100%`;
913                threadRow.name = `${thread.threadName} ${thread.tid}`;
914                threadRow.setAttribute('children', '')
915                threadRow.supplier = () => queryThreadData(thread.tid || 0).then(res => {
916                    getFunDataByTid(thread.tid || 0).then((funs: Array<FuncStruct>) => {
917                        if (funs.length > 0) {
918                            let maxHeight = (Math.max(...funs.map(it => it.depth || 0)) + 1) * 20 + 20;
919                            let funcRow = new TraceRow<FuncStruct>({
920                                alpha: false,
921                                contextId: '2d',
922                                isOffScreen: SpSystemTrace.isCanvasOffScreen
923                            });
924                            funcRow.rowId = `${thread.tid}`
925                            funcRow.rowType = TraceRow.ROW_TYPE_FUNC
926                            funcRow.rowParentId = `${it.pid}`
927                            funcRow.rowHidden = !processRow.expansion
928                            funcRow.style.width = `100%`;
929                            funcRow.setAttribute("height", `${maxHeight}`);
930                            funcRow.name = `${thread.threadName} ${thread.tid}`;
931                            funcRow.setAttribute('children', '')
932                            funcRow.supplier = () => new Promise((resolve, reject) => resolve(funs))
933                            funcRow.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
934                                if (funcRow.dataListCache && funcRow.dataListCache.length > 0 && !funcRow.args.isOffScreen) {
935                                    funcRow.clearCanvas(ctx);
936                                    funcRow.drawLines(ctx);
937                                    ctx.beginPath();
938                                    for (let i = 0; i < funcRow.dataListCache.length; i++) {
939                                        FuncStruct.draw(ctx, funcRow.dataListCache[i])
940                                    }
941                                    funcRow.drawSelection(ctx);
942                                    ctx.closePath();
943                                    return;
944                                }
945                                procedurePool.submitWithName(`cpu${(thread.tid || 0) % procedurePool.cpusLen.length}`, `func ${thread.tid} ${thread.threadName}`, {
946                                    list: funcRow.must ? funcRow.dataList : undefined,
947                                    offscreen: funcRow.must ? funcRow.offscreen : undefined,
948                                    dpr: funcRow.dpr,
949                                    xs: TraceRow.range?.xs,
950                                    isHover: funcRow.isHover,
951                                    hoverX: funcRow.hoverX,
952                                    hoverY: funcRow.hoverY,
953                                    canvasWidth: funcRow.canvasWidth,
954                                    canvasHeight: funcRow.canvasHeight,
955                                    maxHeight: maxHeight,
956                                    hoverFuncStruct: FuncStruct.hoverFuncStruct,
957                                    selectFuncStruct: FuncStruct.selectFuncStruct,
958                                    wakeupBean: CpuStruct.wakeupBean,
959                                    isRangeSelect: funcRow.rangeSelect,
960                                    rangeSelectObject: TraceRow.rangeSelectObject,
961                                    useCache: useCache,
962                                    lineColor: funcRow.getLineColor(),
963                                    startNS: TraceRow.range?.startNS || 0,
964                                    endNS: TraceRow.range?.endNS || 0,
965                                    totalNS: TraceRow.range?.totalNS || 0,
966                                    frame: funcRow.frame
967                                }, funcRow.must && funcRow.args.isOffScreen ? funcRow.offscreen : undefined, (res: any, hover: any) => {
968                                    funcRow.must = false;
969                                    if (funcRow.args.isOffScreen == true) {
970                                        if (funcRow.isHover) {
971                                            FuncStruct.hoverFuncStruct = hover;
972                                        }
973                                        return;
974                                    }
975                                    funcRow.dataListCache = [...res];
976                                    funcRow.clearCanvas(ctx);
977                                    funcRow.drawLines(ctx);
978                                    ctx.beginPath();
979                                    for (let re of res) {
980                                        FuncStruct.draw(ctx, re)
981                                    }
982                                    funcRow.drawSelection(ctx);
983                                    ctx.closePath();
984                                })
985                            }
986                            this.insertAfter(funcRow, threadRow)
987                            funcRow.draw();
988                            this.getVisibleRows();
989                        }
990                    })
991                    return res;
992                })
993                threadRow.onThreadHandler = (ctx: CanvasRenderingContext2D, useCache) => {
994                    if (threadRow.dataListCache && threadRow.dataListCache.length > 0 && !threadRow.args.isOffScreen) {
995                        threadRow.clearCanvas(ctx);
996                        threadRow.drawLines(ctx);
997                        ctx.beginPath();
998                        for (let i = 0; i < threadRow.dataListCache.length; i++) {
999                            ThreadStruct.draw(ctx, threadRow.dataListCache[i])
1000                        }
1001                        threadRow.drawSelection(ctx);
1002                        ctx.closePath();
1003                        return;
1004                    }
1005                    procedurePool.submitWithName(`cpu${(thread.tid || 0) % procedurePool.cpusLen.length}`, `thread ${thread.tid} ${thread.threadName}`, {
1006                        list: threadRow.must ? threadRow.dataList : undefined,
1007                        offscreen: threadRow.must ? threadRow.offscreen : undefined,
1008                        dpr: threadRow.dpr,
1009                        xs: TraceRow.range?.xs,
1010                        isHover: threadRow.isHover,
1011                        hoverX: threadRow.hoverX,
1012                        hoverY: threadRow.hoverY,
1013                        canvasWidth: threadRow.canvasWidth,
1014                        canvasHeight: threadRow.canvasHeight,
1015                        hoverThreadStruct: ThreadStruct.hoverThreadStruct,
1016                        selectThreadStruct: ThreadStruct.selectThreadStruct,
1017                        wakeupBean: CpuStruct.wakeupBean,
1018                        isRangeSelect: threadRow.rangeSelect,
1019                        rangeSelectObject: TraceRow.rangeSelectObject,
1020                        useCache: useCache,
1021                        lineColor: threadRow.getLineColor(),
1022                        startNS: TraceRow.range?.startNS || 0,
1023                        endNS: TraceRow.range?.endNS || 0,
1024                        totalNS: TraceRow.range?.totalNS || 0,
1025                        frame: threadRow.frame
1026                    }, threadRow.must && threadRow.args.isOffScreen ? threadRow.offscreen : undefined, (res: any, hover: any) => {
1027                        threadRow.must = false;
1028                        if (threadRow.args.isOffScreen == true) {
1029                            if (threadRow.isHover) {
1030                                ThreadStruct.hoverThreadStruct = hover;
1031                            }
1032                            return;
1033                        }
1034                        threadRow.dataListCache = [...res];
1035                        threadRow.clearCanvas(ctx);
1036                        threadRow.drawLines(ctx);
1037                        ctx.beginPath();
1038                        for (let re of res) {
1039                            ThreadStruct.draw(ctx, re)
1040                        }
1041                        threadRow.drawSelection(ctx);
1042                        ctx.closePath();
1043                    })
1044                }
1045                this.rowsEL?.appendChild(threadRow)
1046            })
1047        }
1048    }
1049
1050    insertAfter(newEl: HTMLElement, targetEl: HTMLElement) {
1051        let parentEl = targetEl.parentNode;
1052        if (parentEl!.lastChild == targetEl) {
1053            parentEl!.appendChild(newEl);
1054        } else {
1055            parentEl!.insertBefore(newEl, targetEl.nextSibling);
1056        }
1057    }
1058
1059    initHtml(): string {
1060        return `
1061<style>
1062:host{
1063    display: block;
1064    width: 100%;
1065    height: 100%;
1066}
1067.timer-shaft{
1068    width: 100%;
1069    z-index: 2;
1070}
1071.rows{
1072     color: #fff;
1073    display: flex;
1074    box-sizing: border-box;
1075    flex-direction: column;
1076    overflow: overlay;
1077    max-height: calc(100vh - 147px - 48px);
1078    flex: 1;
1079    width: 100%;
1080    background: var(--dark-background4,#ffffff);
1081    scroll-behavior:smooth;
1082}
1083.container{
1084    width: 100%;
1085    box-sizing: border-box;
1086    height: 100%;
1087    display: grid;
1088    grid-template-columns: 1fr;
1089    grid-template-rows: min-content 1fr min-content;
1090}
1091
1092</style>
1093<div class="container">
1094    <timer-shaft-element class="timer-shaft"></timer-shaft-element>
1095    <div class="rows"></div>
1096    <trace-sheet class="trace-sheet" mode="hidden"></trace-sheet>
1097</div>
1098        `;
1099    }
1100}
1101