• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// @ts-nocheck
2/*
3 * Copyright (C) 2022 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {BaseElement, element} from "../../base-ui/BaseElement.js";
18import "./trace/TimerShaftElement.js";
19import "./trace/base/TraceRow.js";
20import "./trace/base/TraceRowRecyclerView.js"
21import {
22    getAsyncEvents,
23    getCpuUtilizationRate, getFps, getFunDataByTid,
24    queryCpuData,
25    queryCpuFreq, queryCpuFreqData, queryCpuMax, queryCpuMaxFreq, queryHeapByPid, queryHeapPid,
26    queryProcess, queryProcessData, queryProcessMem, queryProcessMemData, queryProcessThreads, queryThreadData,
27    queryTotalTime, threadPool
28} from "../database/SqlLite.js";
29import {TraceRow} from "./trace/base/TraceRow.js";
30import {TimerShaftElement} from "./trace/TimerShaftElement.js";
31import {TimeRange} from "./trace/timer-shaft/RangeRuler.js";
32import {CpuStruct} from "../bean/CpuStruct.js";
33import {CpuFreqStruct} from "../bean/CpuFreqStruct.js";
34import {ProcessStruct} from "../bean/ProcessStruct.js";
35import {ColorUtils} from "./trace/base/ColorUtils.js";
36import "./trace/base/TraceSheet.js";
37import {TraceSheet} from "./trace/base/TraceSheet.js";
38import {ThreadStruct} from "../bean/ThreadStruct.js";
39import {ProcessMemStruct} from "../bean/ProcessMemStruct.js";
40import {FuncStruct} from "../bean/FuncStruct.js";
41import {FpsStruct} from "../bean/FpsStruct.js";
42import {RangeSelect} from "./trace/base/RangeSelect.js";
43import {SelectionParam} from "../bean/BoxSelection.js";
44import {procedurePool} from "../database/Procedure.js";
45import {SportRuler} from "./trace/timer-shaft/SportRuler.js";
46import {TraceRowRecyclerView} from "./trace/base/TraceRowRecyclerView.js";
47import {TraceRowObject} from "./trace/base/TraceRowObject.js";
48import {Rect} from "./trace/timer-shaft/Rect.js";
49
50@element('sp-recycler-system-trace')
51export class SpRecyclerSystemTrace extends BaseElement {
52    rowsEL: TraceRowRecyclerView | undefined | null;
53    private timerShaftEL: TimerShaftElement | null | undefined;
54    private range: TimeRange | undefined
55    private traceSheetEL: TraceSheet | undefined | null;
56    private rangeSelect!: RangeSelect;
57    static scrollViewWidth = 0
58    private processThreads: Array<ThreadStruct> = []
59    private processAsyncEvent: Array<ProcessMemStruct> = []
60    private processMem: Array<any> = []
61
62    initElements(): void {
63        this.rowsEL = this.shadowRoot?.querySelector<TraceRowRecyclerView>('.rows')
64        this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft')
65        this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet')
66        this.rangeSelect = new RangeSelect();
67        this.rangeSelect.rowsEL = this.rowsEL;
68        document?.addEventListener("flag-change", (event: any) => {
69            this.timerShaftEL?.modifyList(event.detail.type, event.detail.flagObj)
70            if (event.detail.type == "remove") {
71                this.traceSheetEL?.setAttribute("mode", 'hidden');
72            }
73        })
74        document?.addEventListener("flag-draw", (event: any) => {
75            if (event.detail == null) {
76            }
77        })
78        SpRecyclerSystemTrace.scrollViewWidth = this.getScrollWidth()
79        this.rangeSelect.selectHandler = (rows) => {
80            let selection = new SelectionParam();
81            selection.cpus = [];
82            selection.threadIds = [];
83            selection.funTids = [];
84            selection.trackIds = [];
85            selection.leftNs = 0;
86            selection.rightNs = 0;
87            rows.forEach(it => {
88                if (it.rowType == TraceRow.ROW_TYPE_CPU) {
89                    selection.cpus.push(parseInt(it.rowId!))
90                } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) {
91                    selection.threadIds.push(parseInt(it.rowId!))
92                } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) {
93                    selection.funTids.push(parseInt(it.rowId!))
94                } else if (it.rowType == TraceRow.ROW_TYPE_MEM) {
95                    selection.trackIds.push(parseInt(it.rowId!))
96                } else if (it.rowType == TraceRow.ROW_TYPE_FPS) {
97                    selection.hasFps = true;
98                }else if(it.rowType == TraceRow.ROW_TYPE_HEAP){
99                    selection.heapIds.push(parseInt(it.rowId!))
100                }
101                if (it.rangeSelect && it.rangeSelect.startNS) {
102                    selection.leftNs = it.rangeSelect.startNS;
103                }
104                if (it.rangeSelect && it.rangeSelect.endNS) {
105                    selection.rightNs = it.rangeSelect.endNS;
106                }
107            })
108            this.traceSheetEL?.boxSelection(selection)
109        }
110        // @ts-ignore
111        new ResizeObserver((entries) => {
112            let width = entries[0].contentRect.width - 1 - SpRecyclerSystemTrace.scrollViewWidth;
113            requestAnimationFrame(() => {
114                this.timerShaftEL?.updateWidth(width)
115                this.shadowRoot!.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.updateWidth(width))
116            })
117        }).observe(this)
118
119        // @ts-ignore
120        new ResizeObserver((entries) => {
121            let width = this.clientWidth - 1 - SpRecyclerSystemTrace.scrollViewWidth
122
123            requestAnimationFrame(() => {
124                this.timerShaftEL?.updateWidth(width)
125                this.shadowRoot!.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.updateWidth(width))
126            })
127        }).observe(window.document.body)
128    }
129
130    getScrollWidth() {
131        let noScroll, scroll, oDiv = document.createElement('div');
132        oDiv.style.cssText = 'position:absolute; top:-1000px;     width:100px; height:100px; overflow:hidden;';
133        noScroll = document.body.appendChild(oDiv).clientWidth;
134        oDiv.style.overflowY = 'scroll';
135        scroll = oDiv.clientWidth;
136        document.body.removeChild(oDiv);
137        return noScroll - scroll + 1;
138    }
139
140    getVisibleRows(): Array<TraceRow<any>> {
141        return [...this.rowsEL!.shadowRoot!.querySelectorAll<TraceRow<any>>("trace-row")];
142    }
143
144    timerShaftELRangeChange = (e: any) => {
145        this.range = e.detail;
146        TraceRow.range = this.range;
147        let scrollTop = this.rowsEL?.scrollTop || 0
148        let scrollHeight = this.rowsEL?.clientHeight || 0
149        this.getVisibleRows().forEach(it => {
150            it.dataListCache.length = 0;
151            this.hoverStructNull();
152            it.drawObject();
153        })
154    }
155
156    rowsElOnScroll = (e: any) => {
157        this.hoverStructNull();
158        let rows = this.getVisibleRows();
159        rows.forEach((it, index) => {
160            if (index == 0 || index == rows.length - 1) {
161                it.dataListCache.length = 0;
162                it.drawObject();
163            }
164        })
165    }
166
167    documentOnMouseDown = (ev: MouseEvent) => {
168        this.rangeSelect.mouseDown(ev)
169    }
170    documentOnMouseUp = (ev: MouseEvent) => {
171        this.rangeSelect.mouseUp(ev);
172    }
173    documentOnMouseMove = (ev: MouseEvent) => {
174        let rows = this.getVisibleRows();
175        this.rangeSelect.mouseMove(rows, ev)
176        rows.forEach(tr => {
177            let x = ev.offsetX - (tr.canvasContainer?.offsetLeft || 0);
178            let y = ev.offsetY - (tr.canvasContainer?.offsetTop || 0) + (this.rowsEL?.scrollTop || 0);
179            if (x > tr.frame.x && x < tr.frame.x + tr.frame.width && y > tr.frame.y && y < tr.frame.y + tr.frame.height) {
180                this.hoverStructNull();
181                if (tr.rowType === TraceRow.ROW_TYPE_CPU) {
182                    CpuStruct.hoverCpuStruct = tr.onMouseHover(x, y);
183                    if (CpuStruct.hoverCpuStruct) {
184                        tr.tip = `<span>P:${CpuStruct.hoverCpuStruct.processName || "Process"} [${CpuStruct.hoverCpuStruct.processId}]</span><span>T:${CpuStruct.hoverCpuStruct.name} [${CpuStruct.hoverCpuStruct.tid}]</span>`;
185                    }
186                    tr.setTipLeft(x, CpuStruct.hoverCpuStruct)
187                } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ) {
188                    CpuFreqStruct.hoverCpuFreqStruct = tr.onMouseHover(x, y);
189                    if (CpuFreqStruct.hoverCpuFreqStruct) {
190                        tr.tip = `<span>${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct.value!)} kHz</span>`
191                    }
192                    tr.setTipLeft(x, CpuFreqStruct.hoverCpuFreqStruct)
193                } else if (tr.rowType === TraceRow.ROW_TYPE_THREAD) {
194                    ThreadStruct.hoverThreadStruct = tr.onMouseHover(x, y, false);
195                } else if (tr.rowType === TraceRow.ROW_TYPE_FUNC) {
196                    FuncStruct.hoverFuncStruct = tr.onMouseHover(x, y, false)
197                } else if (tr.rowType === TraceRow.ROW_TYPE_HEAP) {
198                    HeapStruct.hoverHeapStruct = tr.onMouseHover(x, y, false)
199                    if (HeapStruct.hoverHeapStruct) {
200                        tr.tip = `<span>${ColorUtils.formatNumberComma(HeapStruct.hoverHeapStruct.heapsize!)} byte</span>`
201                    }
202                    tr.setTipLeft(x, HeapStruct.hoverHeapStruct)
203                } else {
204                    this.hoverStructNull();
205                }
206            } else {
207                tr.onMouseLeave(x, y);
208            }
209            tr.drawObject();
210        })
211    }
212
213    hoverStructNull() {
214        CpuStruct.hoverCpuStruct = undefined;
215        CpuFreqStruct.hoverCpuFreqStruct = undefined;
216        ThreadStruct.hoverThreadStruct = undefined;
217        FuncStruct.hoverFuncStruct = undefined;
218    }
219
220    selectStructNull() {
221        CpuStruct.selectCpuStruct = undefined;
222        CpuFreqStruct.selectCpuFreqStruct = undefined;
223        ThreadStruct.selectThreadStruct = undefined;
224        FuncStruct.selectFuncStruct = undefined;
225    }
226
227    documentOnClick = (ev: MouseEvent) => {
228        if (this.rangeSelect.isDrag()) {
229            return;
230        }
231        this.rowsEL?.querySelectorAll<TraceRow<any>>("trace-row").forEach(it => it.rangeSelect = undefined)
232        this.selectStructNull();
233        if (CpuStruct.hoverCpuStruct) {
234            CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct
235            this.traceSheetEL?.displayCpuData(CpuStruct.hoverCpuStruct);
236        } else if (ThreadStruct.hoverThreadStruct) {
237            ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct;
238            this.traceSheetEL?.displayThreadData(ThreadStruct.hoverThreadStruct)
239        } else if (FuncStruct.hoverFuncStruct) {
240            FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct;
241            this.traceSheetEL?.displayFuncData(FuncStruct.hoverFuncStruct)
242        } else if (SportRuler.rulerFlagObj) {
243
244        } else {
245            this.traceSheetEL?.setAttribute("mode", 'hidden');
246        }
247        this.documentOnMouseMove(ev)
248    }
249
250    connectedCallback() {
251        this.timerShaftEL?.addEventListener('range-change', this.timerShaftELRangeChange)
252        this.rowsEL?.addEventListener('scroll', this.rowsElOnScroll)
253        document.addEventListener('mousemove', this.documentOnMouseMove)
254        document.addEventListener('mousedown', this.documentOnMouseDown)
255        document.addEventListener('mouseup', this.documentOnMouseUp)
256        document.addEventListener('click', this.documentOnClick)
257    }
258
259    disconnectedCallback() {
260        this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange);
261        this.rowsEL?.removeEventListener('scroll', this.rowsElOnScroll);
262        document.removeEventListener('mousemove', this.documentOnMouseMove);
263        document.removeEventListener('click', this.documentOnClick);
264    }
265
266    loadDatabaseUrl(url: string, complete?: Function) {
267        this.init({url: url}).then(() => {
268            let scrollTop = this.rowsEL?.scrollTop || 0
269            let scrollHeight = this.rowsEL?.clientHeight || 0
270            this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => {
271                let top = it.offsetTop - (this.rowsEL?.offsetTop || 0);
272                if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) {
273                    (it as TraceRow<any>).dataListCache.length = 0;
274                }
275            })
276            if (complete) {
277                complete();
278            }
279        })
280    }
281
282    loadDatabaseArrayBuffer(buf: ArrayBuffer, complete?: Function) {
283        this.init({buf}).then(() => {
284            let scrollTop = this.rowsEL?.scrollTop || 0
285            let scrollHeight = this.rowsEL?.clientHeight || 0
286            this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => {
287                let top = it.offsetTop - (this.rowsEL?.offsetTop || 0);
288                if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) {
289                    (it as TraceRow<any>).dataListCache.length = 0;
290                }
291            })
292            if (complete) {
293                complete();
294            }
295        })
296    }
297
298    init = async (param: { buf?: ArrayBuffer, url?: string }) => {
299        if (this.rowsEL) this.rowsEL.innerHTML = ''
300        this.traceSheetEL?.setAttribute("mode", "hidden")
301        this.timerShaftEL?.reset();
302        procedurePool.clearCache();
303        param.buf && await threadPool.initSqlite(param.buf);
304        param.url && await threadPool.initServer(param.url);
305        this.processThreads = await queryProcessThreads();
306        this.processMem = await queryProcessMem()
307        this.processAsyncEvent = await getAsyncEvents()
308        await this.initTotalTime();
309        let cpuObjs = await this.initCpu();
310        await this.initCpuRate();
311        let freqObjs = await this.initCpuFreq();
312        let fpsObjs = await this.initFPS();
313        let processObjs = await this.initProcess();
314        this.rowsEL.dataSource = [...cpuObjs, ...freqObjs, ...fpsObjs, ...processObjs]
315        this.getVisibleRows().forEach(it => it.drawObject());
316    }
317    initCpuRate = async () => {
318        let rates = await getCpuUtilizationRate(0, this.timerShaftEL?.totalNS || 0);
319        if (this.timerShaftEL) this.timerShaftEL.cpuUsage = rates;
320    }
321    initTotalTime = async () => {
322        let res = await queryTotalTime();
323        if (this.timerShaftEL) {
324            this.timerShaftEL.totalNS = res[0].total
325            this.timerShaftEL.loadComplete = true;
326        }
327    }
328    initCpu = async () => {
329        let objs = [];
330        let array = await queryCpuMax();
331        if (array && array.length > 0 && array[0]) {
332            let cpuMax = array[0].cpu
333            CpuStruct.cpuCount = cpuMax + 1;
334            for (let i1 = 0; i1 < CpuStruct.cpuCount; i1++) {
335                const cpuId = i1;
336                let traceRow = new TraceRowObject();
337                traceRow.rowId = `${cpuId}`
338                traceRow.rowType = TraceRow.ROW_TYPE_CPU
339                traceRow.rowParentId = ''
340                traceRow.rowHeight = 40
341                traceRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, traceRow.rowHeight)
342                traceRow.name = `Cpu ${cpuId}`
343                traceRow.supplier = () => queryCpuData(cpuId, 0, this.timerShaftEL?.totalNS || 0)
344                traceRow.onThreadHandler = ((row, ctx) => {
345                    procedurePool.submitWithName("cpu", `cpu${cpuId}`, {
346                        list: traceRow.must ? traceRow.dataList : undefined,
347                        startNS: TraceRow.range?.startNS || 0,
348                        endNS: TraceRow.range?.endNS || 0,
349                        totalNS: TraceRow.range?.totalNS || 0,
350                        frame: traceRow.frame
351                    }, (res: any) => {
352                        traceRow.dataListCache = res;
353                        traceRow.must = false;
354
355                        row.clearCanvas();
356                        row.c!.beginPath();
357                        row.drawLines();
358                        for (let i = 0; i < res.length; i++) {
359                            CpuStruct.draw(ctx, res[i])
360                        }
361                        row.drawSelection();
362                        row.c!.closePath();
363                    })
364                })
365                objs.push(traceRow)
366            }
367        }
368        return objs;
369    }
370
371    initCpuFreq = async () => {
372        let objs = [];
373        let freqList = await queryCpuFreq();
374        let freqMaxList = await queryCpuMaxFreq();
375        CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq;
376        let math = () => {
377            let units: Array<string> = ["", "K", "M", "G", "T", "E"];
378            let sb = " ";
379            CpuFreqStruct.maxFreqName = " ";
380            if (CpuFreqStruct.maxFreq > 0) {
381                let log10: number = Math.ceil(Math.log10(CpuFreqStruct.maxFreq));
382                let pow10: number = Math.pow(10, log10);
383                let afterCeil: number = Math.ceil(CpuFreqStruct.maxFreq / (pow10 / 4)) * (pow10 / 4);
384                CpuFreqStruct.maxFreq = afterCeil;
385                let unitIndex: number = Math.floor(log10 / 3);
386                sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}hz`
387            }
388            CpuFreqStruct.maxFreqName = sb.toString();
389        }
390        math();
391        for (let i = 0; i < freqList.length; i++) {
392            const it = freqList[i];
393            let traceRow = new TraceRowObject();
394            traceRow.rowId = `${it.cpu}`
395            traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ
396            traceRow.rowParentId = ''
397            traceRow.rowHeight = 40
398            traceRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, traceRow.rowHeight)
399            traceRow.name = `Cpu ${it.cpu} Frequency`;
400            traceRow.supplier = () => queryCpuFreqData(it.cpu)
401            traceRow.onThreadHandler = (row, ctx) => {
402                procedurePool.submitWithName("freq", `freq${it.cpu}`, {
403                    list: traceRow.must ? traceRow.dataList : undefined,
404                    startNS: TraceRow.range?.startNS || 0,
405                    endNS: TraceRow.range?.endNS || 0,
406                    totalNS: TraceRow.range?.totalNS || 0,
407                    frame: traceRow.frame
408                }, (res: any) => {
409                    traceRow.dataListCache = res;
410                    traceRow.must = false;
411                    row.clearCanvas();
412                    row.drawLines();
413                    row.c!.beginPath();
414                    for (let i = 0; i < res.length; i++) {
415                        CpuFreqStruct.draw(ctx, res[i])
416                    }
417                    row.drawSelection();
418                    row.c!.closePath();
419                    let s = CpuFreqStruct.maxFreqName
420                    let textMetrics = ctx.measureText(s);
421                    row.c!.globalAlpha = 0.8
422                    row.c!.fillStyle = "#f0f0f0"
423                    row.c!.fillRect(0, 5, textMetrics.width + 8, 18)
424                    row.c!.globalAlpha = 1
425                    row.c!.fillStyle = "#333"
426                    ctx.textBaseline="middle"
427                    ctx.fillText(maxFps, 4, 5+9)
428                })
429            }
430            objs.push(traceRow)
431        }
432        return objs;
433    }
434
435    initFPS = async () => {
436        let objs = [];
437        let fpsRow = new TraceRowObject();
438        fpsRow.rowId = `fps`
439        fpsRow.rowType = TraceRow.ROW_TYPE_FPS
440        fpsRow.rowParentId = ''
441        FpsStruct.maxFps = 0
442        fpsRow.rowHeight = 40
443        fpsRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, fpsRow.rowHeight)
444        fpsRow.name = "FPS"
445        fpsRow.supplier = () => getFps()
446        fpsRow.onDrawHandler = (row, ctx) => {
447            if (fpsRow.dataListCache.length > 0) {
448                for (let i = 0; i < fpsRow.dataListCache.length; i++) {
449                    FpsStruct.draw(ctx, fpsRow.dataListCache[i])
450                }
451            } else {
452                if (fpsRow.dataList) {
453                    for (let i = 0; i < fpsRow.dataList.length; i++) {
454                        let it = fpsRow.dataList[i];
455                        if ((it.fps || 0) > FpsStruct.maxFps) {
456                            FpsStruct.maxFps = it.fps || 0
457                        }
458                        if (i === fpsRow.dataList.length - 1) {
459                            it.dur = (TraceRow.range?.endNS || 0) - (it.startNS || 0)
460                        } else {
461                            it.dur = (fpsRow.dataList[i + 1].startNS || 0) - (it.startNS || 0)
462                        }
463                        if ((it.startNS || 0) + (it.dur || 0) > (TraceRow.range?.startNS || 0) && (it.startNS || 0) < (TraceRow.range?.endNS || 0)) {
464                            FpsStruct.setFrame(fpsRow.dataList[i], 5, TraceRow.range?.startNS || 0, TraceRow.range?.endNS || 0, TraceRow.range?.totalNS || 0, fpsRow.frame)
465                            if (i > 0 && ((fpsRow.dataList[i - 1].frame?.x || 0) == (fpsRow.dataList[i].frame?.x || 0) && (fpsRow.dataList[i - 1].frame?.width || 0) == (fpsRow.dataList[i].frame?.width || 0))) {
466                                continue;
467                            } else {
468                                fpsRow.dataListCache.push(fpsRow.dataList[i])
469                                FpsStruct.draw(ctx, fpsRow.dataList[i])
470                            }
471                        }
472                    }
473                }
474            }
475            if (ctx){
476                let maxFps = FpsStruct.maxFps + "FPS"
477                let textMetrics = ctx.measureText(maxFps);
478                ctx.globalAlpha = 0.8
479                ctx.fillStyle = "#f0f0f0"
480                ctx.fillRect(0, 5, textMetrics.width + 8, 18)
481                ctx.globalAlpha = 1
482                ctx.fillStyle = "#333"
483                ctx.textBaseline="middle"
484                ctx.fillText(maxFps, 4, 5+9)
485            }
486        }
487        objs.push(fpsRow)
488        return objs;
489    }
490
491    initProcess = async () => {
492        let objs = [];
493        let processList = await queryProcess();
494        let heapPidList = await queryHeapPid()
495        for (let i = 0; i < processList.length; i++) {
496            const it = processList[i];
497            let processRow = new TraceRowObject<ProcessStruct>();
498            processRow.rowId = `${it.pid}`
499            processRow.rowType = TraceRow.ROW_TYPE_PROCESS
500            processRow.rowParentId = ''
501            processRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, processRow.rowHeight);
502            processRow.folder = true;
503            processRow.name = `${it.processName || "Process"} ${it.pid}`;
504            processRow.supplier = () => queryProcessData(it.pid || -1, 0, TraceRow.range?.totalNS || 0)
505            processRow.onThreadHandler = (row, ctx) => {
506                procedurePool.submitWithName("process", `process ${it.pid} ${it.processName}`, {
507                    list: processRow.must ? processRow.dataList : undefined,
508                    startNS: TraceRow.range?.startNS || 0,
509                    endNS: TraceRow.range?.endNS || 0,
510                    totalNS: TraceRow.range?.totalNS || 0,
511                    frame: processRow.frame
512                }, (res: any) => {
513                    processRow.dataListCache = res;
514                    processRow.must = false;
515                    row.clearCanvas();
516                    row.drawLines();
517                    row.c!.beginPath();
518                    for (let i = 0; i < res.length; i++) {
519                        ProcessStruct.draw(ctx, res[i])
520                    }
521                    row.drawSelection();
522                    row.c!.closePath();
523                })
524            }
525            objs.push(processRow);
526            if (heapPidList != undefined && Array.isArray(heapPidList) && heapPidList.filter((item) => {
527                return item.pid == it.pid
528            }).length > 0) {
529                let allHeapRow = new TraceRowObject<HeapStruct>();
530                allHeapRow.rowParentId = `${it.pid}`
531                allHeapRow.rowHidden = !processRow.expansion
532                allHeapRow.rowHeight = 40
533                allHeapRow.name = "All Heap Allocations";
534                allHeapRow.folder = false;
535                allHeapRow.rowType = TraceRow.ROW_TYPE_HEAP
536                allHeapRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, allHeapRow.rowHeight)
537                allHeapRow.children = true
538                allHeapRow.supplier = () => queryHeapByPid(0, TraceRow.range?.totalNS || 0, it.pid || 0).then((res) => {
539                    let heapList: HeapStruct[] = []
540                    let allocMap: Map<string, HeapBean[]> = new Map<string, HeapBean[]>()
541                    let currentHeapSize = 0
542                    let maxHeapSize = 0;
543                    for (let j = 0; j < res.length; j++) {
544                        let struct = new HeapStruct();
545                        if (res[j].eventType == "AllocEvent") {
546                            currentHeapSize += (res[j].heapsize || 0)
547                            if (allocMap.has(res[j].addr || "")) {
548                                allocMap.get(res[j].addr || "")?.push(res[j])
549                            } else {
550                                allocMap.set(res[j].addr || "", [res[j]])
551                            }
552                        } else if (res[j].eventType == "FreeEvent") {
553                            if (allocMap.has(res[j].addr || "")) {
554                                let allocList = allocMap.get(res[j].addr || "");
555                                if (allocList != undefined && allocList.length > 0) {
556                                    currentHeapSize -= allocList[allocList.length - 1].heapsize || 0
557                                }
558                            }
559                        }
560                        if (currentHeapSize > maxHeapSize) {
561                            maxHeapSize = currentHeapSize
562                        }
563                        struct.pid = it.pid + ""
564                        struct.startTime = res[j].startTime
565                        if (j != res.length - 1) {
566                            struct.endTime = res[j + 1].startTime
567                        } else {
568                            struct.endTime = allHeapRow.range?.totalNS || 0
569                        }
570                        struct.duration = (struct.endTime || 0) - (struct.startTime || 0)
571                        struct.heapsize = currentHeapSize
572                        heapList.push(struct)
573                    }
574                    for (let j = 0; j < heapList.length; j++) {
575                        heapList[j].maxHeapSize = maxHeapSize
576                    }
577                    return heapList
578                })
579                allHeapRow.onDrawHandler = ctx => {
580                    if (allHeapRow.dataList) {
581                        for (let i = 0; i < allHeapRow.dataList.length; i++) {
582                            let it = allHeapRow.dataList[i];
583                            if ((it.startTime || 0) + (it.duration || 0) > (TraceRow.range?.startNS || 0) && (it.startTime || 0) < (TraceRow.range?.endNS || 0)) {
584                                HeapStruct.setFrame(allHeapRow.dataList[i], 5, TraceRow.range?.startNS || 0, TraceRow.range?.endNS || 0, TraceRow.range?.totalNS || 0, allHeapRow.frame)
585                                HeapStruct.draw(ctx, allHeapRow.dataList[i])
586                            }
587                        }
588                    }
589                }
590                objs.push(allHeapRow);
591            }
592
593            let processMem = this.processMem.filter(mem => mem.pid === it.pid);
594            processMem.forEach(mem => {
595                let row = new TraceRowObject<ProcessMemStruct>();
596                row.rowId = `${mem.trackId}`
597                row.rowType = TraceRow.ROW_TYPE_MEM
598                row.rowParentId = `${it.pid}`
599                row.rowHidden = !processRow.expansion
600                row.rowHeight = 40
601                row.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, row.rowHeight)
602                row.name = `${mem.trackName}`;
603                row.children = true;
604                row.supplier = () => queryProcessMemData(mem.trackId).then(res => {
605                    let maxValue = Math.max(...res.map(it => it.value || 0))
606                    for (let j = 0; j < res.length; j++) {
607                        res[j].maxValue = maxValue;
608                        if (j == res.length - 1) {
609                            res[j].duration = this.range?.totalNS || 0;
610                        } else {
611                            res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0);
612                        }
613                        if (j > 0) {
614                            res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0);
615                        } else {
616                            res[j].delta = 0;
617                        }
618                    }
619                    return res
620                });
621                row.onThreadHandler = (r, ctx) => {
622                    procedurePool.submitWithName("mem", `mem ${mem.trackId} ${mem.trackName}`, {
623                        list: row.must ? row.dataList : undefined,
624                        startNS: TraceRow.range?.startNS || 0,
625                        endNS: TraceRow.range?.endNS || 0,
626                        totalNS: TraceRow.range?.totalNS || 0,
627                        frame: row.frame
628                    }, (res: any) => {
629                        row.dataListCache = res;
630                        row.must = false;
631                        r.clearCanvas();
632                        r.drawLines();
633                        r.c!.beginPath();
634                        for (let i = 0; i < res.length; i++) {
635                            ProcessMemStruct.draw(ctx, res[i])
636                        }
637                        r.drawSelection();
638                        r.c!.closePath();
639                    })
640                }
641                objs.push(row);
642            });
643
644            let threads = this.processThreads.filter(thread => thread.pid === it.pid && thread.tid != 0 && thread.threadName != null);
645            threads.forEach((thread, i) => {
646                // if(i>0) return;
647                let threadRow = new TraceRowObject<ThreadStruct>();
648                threadRow.rowId = `${thread.tid}`
649                threadRow.rowType = TraceRow.ROW_TYPE_THREAD
650                threadRow.rowParentId = `${it.pid}`
651                threadRow.rowHidden = !processRow.expansion
652                threadRow.rowHeight = 40
653                threadRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, threadRow.rowHeight);
654                threadRow.name = `${thread.threadName} ${thread.tid}`;
655                threadRow.children = true;
656                threadRow.supplier = () => queryThreadData(thread.tid || 0).then(res => {
657                    getFunDataByTid(thread.tid || 0).then(funs => {
658                        if (funs.length > 0) {
659                            let maxHeight = (Math.max(...funs.map(it => it.depth || 0)) + 1) * 20 + 20;
660                            let funcRow = new TraceRowObject<FuncStruct>();
661                            funcRow.rowId = `${thread.tid}`
662                            funcRow.rowType = TraceRow.ROW_TYPE_FUNC
663                            funcRow.rowParentId = `${it.pid}`
664                            funcRow.rowHidden = !processRow.expansion
665                            funcRow.rowHeight = maxHeight;
666                            funcRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, funcRow.rowHeight);
667                            funcRow.name = `${thread.threadName} ${thread.tid}`;
668                            funcRow.children = true;
669                            funcRow.supplier = () => new Promise((resolve, reject) => resolve(funs))
670                            funcRow.onThreadHandler = (r, ctx) => {
671                                procedurePool.submitWithName("func", `func ${thread.tid} ${thread.threadName}`, {
672                                    list: funcRow.must ? funcRow.dataList : undefined,
673                                    startNS: TraceRow.range?.startNS || 0,
674                                    endNS: TraceRow.range?.endNS || 0,
675                                    totalNS: TraceRow.range?.totalNS || 0,
676                                    frame: threadRow.frame
677                                }, (res: any) => {
678                                    funcRow.must = false;
679                                    funcRow.dataListCache = res;
680                                    r.clearCanvas();
681                                    r.drawLines();
682                                    r.c!.beginPath();
683                                    for (let i = 0; i < res.length; i++) {
684                                        FuncStruct.draw(ctx, res[i])
685                                    }
686                                    r.drawSelection();
687                                    r.c!.closePath();
688                                })
689                            }
690                        }
691                    })
692                    return res;
693                })
694                threadRow.onThreadHandler = (r, ctx) => {
695                    procedurePool.submitWithName("thread", `thread ${thread.tid} ${thread.threadName}`, {
696                        list: threadRow.must ? threadRow.dataList : undefined,
697                        startNS: TraceRow.range?.startNS || 0,
698                        endNS: TraceRow.range?.endNS || 0,
699                        totalNS: TraceRow.range?.totalNS || 0,
700                        frame: threadRow.frame
701                    }, (res: any) => {
702                        threadRow.dataListCache = res;
703                        threadRow.must = false;
704                        r.clearCanvas();
705                        r.drawLines();
706                        r.c!.beginPath();
707                        for (let i = 0; i < res.length; i++) {
708                            ThreadStruct.draw(ctx, res[i])
709                        }
710                        r.drawSelection();
711                        r.c!.closePath();
712                    })
713                }
714                objs.push(threadRow);
715            })
716        }
717        return objs;
718    }
719
720    insertAfter(newEl: HTMLElement, targetEl: HTMLElement) {
721        let parentEl = targetEl.parentNode;
722        if (parentEl!.lastChild == targetEl) {
723            parentEl!.appendChild(newEl);
724        } else {
725            parentEl!.insertBefore(newEl, targetEl.nextSibling);
726        }
727    }
728
729    initHtml(): string {
730        return `
731<style>
732:host{
733    display: block;
734    width: 100%;
735    height: 100%;
736}
737.timer-shaft{
738    width: 100%;
739    z-index: 2;
740}
741.rows{
742    display: flex;
743    box-sizing: border-box;
744    flex-direction: column;
745    overflow-y: auto;
746    max-height: calc(100vh - 150px - 48px);
747    flex: 1;
748    width: 100%;
749}
750.container{
751    width: 100%;
752    box-sizing: border-box;
753    height: 100%;
754    display: grid;
755    grid-template-columns: 1fr;
756    grid-template-rows: min-content 1fr min-content;
757}
758
759</style>
760<div class="container">
761    <timer-shaft-element class="timer-shaft"></timer-shaft-element>
762    <trace-row-recycler-view class="rows"></trace-row-recycler-view>
763    <trace-sheet class="trace-sheet" mode="hidden"></trace-sheet>
764</div>
765        `;
766    }
767
768}
769