• 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 {SpSystemTrace} from "../SpSystemTrace.js";
17import {
18    getAsyncEvents,
19    getFunDataByTid,
20    queryEventCountMap,
21    queryProcess,
22    queryProcessAsyncFunc,
23    queryProcessByTable, queryProcessContentCount,
24    queryProcessData,
25    queryProcessMem,
26    queryProcessMemData,
27    queryProcessThreads,
28    queryProcessThreadsByTable,
29    queryThreadData
30} from "../../database/SqlLite.js";
31import {Utils} from "../trace/base/Utils.js";
32import {info} from "../../../log/Log.js";
33import {TraceRow} from "../trace/base/TraceRow.js";
34import {ProcessStruct} from "../../bean/ProcessStruct.js";
35import {procedurePool} from "../../database/Procedure.js";
36import {CpuStruct} from "../../bean/CpuStruct.js";
37import {FuncStruct} from "../../bean/FuncStruct.js";
38import {ProcessMemStruct} from "../../bean/ProcessMemStruct.js";
39import {ThreadStruct} from "../../bean/ThreadStruct.js";
40
41export class SpProcessChart {
42    private trace: SpSystemTrace;
43    private processAsyncFuncMap: any = {}
44    private eventCountMap: any;
45    private processThreads: Array<ThreadStruct> = []
46    private processAsyncEvent: Array<ProcessMemStruct> = []
47    private processMem: Array<any> = []
48    private processThreadDataCountMap: Map<number, number> = new Map();
49    private processFuncDataCountMap: Map<number, number> = new Map();
50    private processMemDataCountMap: Map<number, number> = new Map();
51
52    constructor(trace: SpSystemTrace) {
53        this.trace = trace;
54    }
55
56    initAsyncFuncData = async () => {
57        let asyncFuncList: any[] = await queryProcessAsyncFunc();
58        info("AsyncFuncData Count is: ", asyncFuncList!.length)
59        this.processAsyncFuncMap = Utils.groupBy(asyncFuncList, "pid");
60    }
61
62    async init() {
63        let pidCountArray = await queryProcessContentCount();
64        pidCountArray.forEach(it => {
65            this.processThreadDataCountMap.set(it.pid, it.switch_count);
66            this.processFuncDataCountMap.set(it.pid, it.slice_count);
67            this.processMemDataCountMap.set(it.pid, it.mem_count);
68        })
69        let queryProcessThreadResult = await queryProcessThreads();
70        let queryProcessThreadsByTableResult = await queryProcessThreadsByTable()
71        this.processAsyncEvent = await getAsyncEvents();
72        info("The amount of initialized process Event data is : ", this.processAsyncEvent!.length)
73        this.processMem = await queryProcessMem();
74        info("The amount of initialized process memory data is : ", this.processMem!.length)
75        let eventCountList: Array<any> = await queryEventCountMap();
76        this.eventCountMap = eventCountList.reduce((pre, current) => {
77            pre[`${current.eventName}`] = current.count;
78            return pre;
79        }, {});
80        this.processThreads = Utils.removeDuplicates(queryProcessThreadResult, queryProcessThreadsByTableResult, "tid")
81        info("The amount of initialized process threads data is : ", this.processThreads!.length)
82        if (this.eventCountMap["print"] == 0 &&
83            this.eventCountMap["tracing_mark_write"] == 0 &&
84            this.eventCountMap["sched_switch"] == 0) {
85            return;
86        }
87        let time = new Date().getTime();
88        let processes = await queryProcess();
89        let processFromTable = await queryProcessByTable();
90        let processList = Utils.removeDuplicates(processes, processFromTable, "pid")
91        info("ProcessList Data size is: ", processList!.length)
92        for (let i = 0; i < processList.length; i++) {
93            const it = processList[i];
94            if ((this.processThreadDataCountMap.get(it.pid) || 0) == 0 &&
95                (this.processFuncDataCountMap.get(it.pid) || 0) == 0 &&
96                (this.processMemDataCountMap.get(it.pid) || 0) == 0) {
97                continue;
98            }
99            let processRow = new TraceRow<ProcessStruct>({
100                canvasNumber: 1, alpha: false, contextId: "2d", isOffScreen: true, skeleton: false
101            });
102            processRow.rowId = `${it.pid}`
103            processRow.index = i;
104            processRow.rowType = TraceRow.ROW_TYPE_PROCESS
105            processRow.rowParentId = '';
106            processRow.folder = true;
107            processRow.name = `${it.processName || "Process"} ${it.pid}`;
108            processRow.supplier = () => queryProcessData(it.pid || -1, 0, TraceRow.range?.totalNS || 0);
109            processRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
110            processRow.selectChangeHandler = this.trace.selectChangeHandler;
111            processRow.onThreadHandler = (useCache) => {
112                procedurePool.submitWithName(`process${(processRow.index) % procedurePool.processLen.length}`, `process ${processRow.index} ${it.processName}`, {
113                    list: processRow.must ? processRow.dataList : undefined,
114                    offscreen: !processRow.isTransferCanvas ? processRow.offscreen[0] : undefined,
115                    pid: it.pid,
116                    xs: TraceRow.range?.xs,
117                    dpr: processRow.dpr,
118                    isHover: processRow.isHover,
119                    flagMoveInfo: this.trace.hoverFlag,
120                    flagSelectedInfo: this.trace.selectFlag,
121                    hoverX: processRow.hoverX,
122                    hoverY: processRow.hoverY,
123                    canvasWidth: processRow.canvasWidth,
124                    canvasHeight: processRow.canvasHeight,
125                    isRangeSelect: processRow.rangeSelect,
126                    rangeSelectObject: TraceRow.rangeSelectObject,
127                    wakeupBean: CpuStruct.wakeupBean,
128                    cpuCount: CpuStruct.cpuCount,
129                    useCache: useCache,
130                    lineColor: processRow.getLineColor(),
131                    startNS: TraceRow.range?.startNS || 0,
132                    endNS: TraceRow.range?.endNS || 0,
133                    totalNS: TraceRow.range?.totalNS || 0,
134                    slicesTime: TraceRow.range?.slicesTime,
135                    range: TraceRow.range,
136                    frame: processRow.frame
137                }, !processRow.isTransferCanvas ? processRow.offscreen[0] : undefined, () => {
138                    processRow.must = false;
139                })
140                processRow.isTransferCanvas = true;
141            }
142            this.trace.rowsEL?.appendChild(processRow)
143            /**
144             * Async Function
145             */
146            let asyncFuncList = this.processAsyncFuncMap[it.pid] || [];
147            let asyncFuncGroup = Utils.groupBy(asyncFuncList, "funName");
148            Reflect.ownKeys(asyncFuncGroup).map((key: any) => {
149                let asyncFunctions: Array<any> = asyncFuncGroup[key];
150                if (asyncFunctions.length > 0) {
151                    let isIntersect = (a: any, b: any) => (Math.max(a.startTs + a.dur, b.startTs + b.dur) - Math.min(a.startTs, b.startTs) < a.dur + b.dur);
152                    let depthArray: any = []
153                    let createDepth = (currentDepth: number, index: number) => {
154                        if (depthArray[currentDepth] == undefined || !isIntersect(depthArray[currentDepth], asyncFunctions[index])) {
155                            asyncFunctions[index].depth = currentDepth;
156                            depthArray[currentDepth] = asyncFunctions[index]
157                        } else {
158                            createDepth(++currentDepth, index)
159                        }
160                    }
161                    asyncFunctions.forEach((it, i) => {
162                        if (it.dur == -1) {
163                            it.dur = TraceRow.range?.endNS || 0 - it.startTs;
164                        }
165                        createDepth(0, i);
166                    });
167                    const groupedBy: Array<any> = [];
168                    for (let i = 0; i < asyncFunctions.length; i++) {
169                        if (groupedBy[asyncFunctions[i].depth || 0]) {
170                            groupedBy[asyncFunctions[i].depth || 0].push(asyncFunctions[i]);
171                        } else {
172                            groupedBy[asyncFunctions[i].depth || 0] = [asyncFunctions[i]];
173                        }
174                    }
175                    let max = Math.max(...asyncFunctions.map(it => it.depth || 0)) + 1
176                    let maxHeight = max * 20;
177                    let funcRow = new TraceRow<FuncStruct>({
178                        canvasNumber: max,
179                        alpha: false,
180                        contextId: '2d',
181                        isOffScreen: SpSystemTrace.isCanvasOffScreen,
182                        skeleton: false
183                    });
184                    funcRow.rowId = `${asyncFunctions[0].funName}-${it.pid}`
185                    funcRow.asyncFuncName = asyncFunctions[0].funName;
186                    funcRow.asyncFuncNamePID = it.pid;
187                    funcRow.rowType = TraceRow.ROW_TYPE_FUNC
188                    funcRow.rowParentId = `${it.pid}`
189                    funcRow.rowHidden = !processRow.expansion
190                    funcRow.style.width = `100%`;
191                    funcRow.setAttribute("height", `${maxHeight}`);
192                    funcRow.name = `${asyncFunctions[0].funName}`;
193                    funcRow.setAttribute('children', '')
194                    funcRow.supplier = () => new Promise((resolve) => resolve(asyncFunctions))
195                    funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
196                    funcRow.selectChangeHandler = this.trace.selectChangeHandler;
197                    funcRow.onThreadHandler = (useCache) => {
198                        let asy = async (useCache: boolean) => {
199                            let scrollTop = this.trace.rowsEL?.scrollTop || 0;
200                            let scrollHeight = this.trace.rowsEL?.clientHeight || 0;
201                            let promises: Array<any> = [];
202                            for (let k = 0; k < groupedBy.length; k++) {
203                                let top = funcRow.offsetTop - (this.trace.rowsEL?.offsetTop || 0) - scrollTop + funcRow.canvas[k].offsetTop;
204                                let isLive = ((top + funcRow.canvas[k].clientHeight >= 0) && (top < scrollHeight)) || funcRow.collect
205                                let promise = await procedurePool.submitWithNamePromise(`cpu${k % procedurePool.cpusLen.length}`, `func-${asyncFunctions[0].funName}-${it.pid}-${k}`, {
206                                    isLive: isLive,
207                                    list: funcRow.must ? groupedBy[k] : undefined,
208                                    offscreen: !funcRow.isTransferCanvas ? funcRow.offscreen[k] : undefined,//是否离屏
209                                    dpr: funcRow.dpr,//屏幕dpr值
210                                    xs: TraceRow.range?.xs,//线条坐标信息
211                                    isHover: funcRow.isHover,
212                                    flagMoveInfo: this.trace.hoverFlag,
213                                    flagSelectedInfo: this.trace.selectFlag,
214                                    hoverX: funcRow.hoverX,
215                                    hoverY: funcRow.hoverY,
216                                    depth: k,
217                                    canvasWidth: funcRow.canvasWidth,
218                                    canvasHeight: funcRow.canvasHeight,
219                                    maxHeight: maxHeight,
220                                    hoverFuncStruct: FuncStruct.hoverFuncStruct,
221                                    selectFuncStruct: FuncStruct.selectFuncStruct,
222                                    wakeupBean: CpuStruct.wakeupBean,
223                                    isRangeSelect: funcRow.rangeSelect,
224                                    rangeSelectObject: TraceRow.rangeSelectObject,
225                                    useCache: useCache,
226                                    lineColor: funcRow.getLineColor(),
227                                    startNS: TraceRow.range?.startNS || 0,
228                                    endNS: TraceRow.range?.endNS || 0,
229                                    totalNS: TraceRow.range?.totalNS || 0,
230                                    slicesTime: TraceRow.range?.slicesTime,
231                                    range: TraceRow.range,
232                                    frame: funcRow.frame
233                                }, !funcRow.isTransferCanvas ? funcRow.offscreen[k] : undefined)
234                                if (funcRow.isHover && promise.hover) {
235                                    FuncStruct.hoverFuncStruct = promise.hover;
236                                }
237                                promises.push(promise);
238                            }
239                            if (funcRow.isHover && promises.every(it => !it.hover)) {
240                                FuncStruct.hoverFuncStruct = undefined;
241                            }
242                            funcRow.must = false;
243                            funcRow.isTransferCanvas = true;
244                        }
245                        asy(useCache).then()
246                    }
247                    this.trace.rowsEL?.appendChild(funcRow);
248                }
249            });
250
251            /**
252             * 添加进程内存信息
253             */
254            let processMem = this.processMem.filter(mem => mem.pid === it.pid);
255            processMem.forEach(mem => {
256                let row = new TraceRow<ProcessMemStruct>(
257                    {canvasNumber: 1, alpha: false, contextId: "2d", isOffScreen: true, skeleton: false}
258                );
259                row.rowId = `${mem.trackId}`
260                row.rowType = TraceRow.ROW_TYPE_MEM
261                row.rowParentId = `${it.pid}`
262                row.rowHidden = !processRow.expansion
263                row.style.height = '40px'
264                row.style.width = `100%`;
265                row.name = `${mem.trackName}`;
266                row.setAttribute('children', '');
267                row.favoriteChangeHandler = this.trace.favoriteChangeHandler;
268                row.selectChangeHandler = this.trace.selectChangeHandler;
269                row.supplier = () => queryProcessMemData(mem.trackId).then(res => {
270                    let maxValue = Math.max(...res.map(it => it.value || 0))
271                    for (let j = 0; j < res.length; j++) {
272                        res[j].maxValue = maxValue;
273                        if (j == res.length - 1) {
274                            res[j].duration = (TraceRow.range?.totalNS || 0) - (res[j].startTime || 0);
275                        } else {
276                            res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0);
277                        }
278                        if (j > 0) {
279                            res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0);
280                        } else {
281                            res[j].delta = 0;
282                        }
283                    }
284                    return res
285                });
286                row.onThreadHandler = (useCache) => {
287                    procedurePool.submitWithName(`cpu${mem.trackId % procedurePool.cpusLen.length}`, `mem ${mem.trackId} ${mem.trackName}`, {
288                        list: row.must ? row.dataList : undefined,
289                        offscreen: !row.isTransferCanvas ? row.offscreen[0] : undefined,//是否离屏
290                        dpr: row.dpr,//屏幕dpr值
291                        xs: TraceRow.range?.xs,//线条坐标信息
292                        isHover: row.isHover,
293                        flagMoveInfo: this.trace.hoverFlag,
294                        flagSelectedInfo: this.trace.selectFlag,
295                        hoverX: row.hoverX,
296                        hoverY: row.hoverY,
297                        canvasWidth: row.canvasWidth,
298                        canvasHeight: row.canvasHeight,
299                        wakeupBean: CpuStruct.wakeupBean,
300                        isRangeSelect: row.rangeSelect,
301                        rangeSelectObject: TraceRow.rangeSelectObject,
302                        useCache: useCache,
303                        lineColor: row.getLineColor(),
304                        startNS: TraceRow.range?.startNS || 0,
305                        endNS: TraceRow.range?.endNS || 0,
306                        totalNS: TraceRow.range?.totalNS || 0,
307                        slicesTime: TraceRow.range?.slicesTime,
308                        hoverProcessMemStruct: ProcessMemStruct.hoverProcessMemStruct,
309                        range: TraceRow.range,
310                        frame: row.frame
311                    }, row.getTransferArray(), (res: any, hover: any) => {
312                        row.must = false;
313                        if (row.isHover) {
314                            ProcessMemStruct.hoverProcessMemStruct = hover;
315                        }
316                        return;
317                    });
318                    row.isTransferCanvas = true;
319                }
320                this.trace.rowsEL?.appendChild(row)
321            });
322            /**
323             * add thread list
324             */
325            let threads = this.processThreads.filter(thread => thread.pid === it.pid && thread.tid != 0);
326            for (let j = 0; j < threads.length; j++) {
327                let thread = threads[j];
328                let threadRow = new TraceRow<ThreadStruct>({
329                    canvasNumber: 1,
330                    alpha: false,
331                    contextId: "2d",
332                    isOffScreen: true,
333                    skeleton: false
334                });
335                threadRow.rowId = `${thread.tid}`
336                threadRow.rowType = TraceRow.ROW_TYPE_THREAD
337                threadRow.rowParentId = `${it.pid}`
338                threadRow.rowHidden = !processRow.expansion
339                threadRow.index = j
340                threadRow.style.height = '30px'
341                threadRow.setAttribute("height", `30`);
342                threadRow.style.width = `100%`;
343                threadRow.name = `${thread.threadName || 'Thread'} ${thread.tid}`;
344                threadRow.setAttribute('children', '')
345                threadRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
346                threadRow.selectChangeHandler = this.trace.selectChangeHandler;
347                threadRow.supplier = () => queryThreadData(thread.tid || 0).then(res => {
348                    getFunDataByTid(thread.tid || 0).then((funs: Array<FuncStruct>) => {
349                        if (funs.length > 0) {
350                            let isBinder = (data: FuncStruct): boolean => {
351                                return data.funName != null && (
352                                    data.funName.toLowerCase().startsWith("binder transaction async") //binder transaction
353                                    || data.funName.toLowerCase().startsWith("binder async")
354                                    || data.funName.toLowerCase().startsWith("binder reply")
355                                );
356                            }
357                            funs.forEach(fun => {
358                                if (isBinder(fun)) {
359                                } else {
360                                    if (fun.dur == -1) {
361                                        fun.dur = (TraceRow.range?.totalNS || 0) - (fun.startTs || 0);
362                                    }
363                                }
364                            })
365                            const groupedBy: Array<any> = [];
366                            for (let i = 0; i < funs.length; i++) {
367                                if (groupedBy[funs[i].depth || 0]) {
368                                    groupedBy[funs[i].depth || 0].push(funs[i]);
369                                } else {
370                                    groupedBy[funs[i].depth || 0] = [funs[i]];
371                                }
372                            }
373                            let max = Math.max(...funs.map(it => it.depth || 0)) + 1
374                            let maxHeight = max * 20;
375                            let funcRow = new TraceRow<FuncStruct>({
376                                canvasNumber: max,
377                                alpha: false,
378                                contextId: '2d',
379                                isOffScreen: SpSystemTrace.isCanvasOffScreen,
380                                skeleton: false
381                            });
382                            funcRow.rowId = `${thread.tid}`
383                            funcRow.rowType = TraceRow.ROW_TYPE_FUNC
384                            funcRow.rowParentId = `${it.pid}`
385                            funcRow.rowHidden = !processRow.expansion
386                            funcRow.checkType = threadRow.checkType;
387                            funcRow.style.width = `100%`;
388                            funcRow.setAttribute("height", `${maxHeight}`);
389                            funcRow.name = `${thread.threadName || 'Thread'} ${thread.tid}`;
390                            funcRow.setAttribute('children', '')
391                            funcRow.supplier = () => new Promise((resolve) => resolve(funs))
392                            funcRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
393                            funcRow.selectChangeHandler = this.trace.selectChangeHandler;
394                            funcRow.onThreadHandler = (useCache) => {
395                                let asy = async (useCache: boolean) => {
396                                    let scrollTop = this.trace.rowsEL?.scrollTop || 0;
397                                    let scrollHeight = this.trace.rowsEL?.clientHeight || 0;
398                                    let promises: Array<any> = [];
399                                    for (let k = 0; k < groupedBy.length; k++) {
400                                        let top = funcRow.offsetTop - (this.trace.rowsEL?.offsetTop || 0) - scrollTop + funcRow.canvas[k].offsetTop;
401                                        let isLive = ((top + funcRow.canvas[k].clientHeight >= 0) && (top < scrollHeight)) || funcRow.collect
402                                        let promise = await procedurePool.submitWithNamePromise(`cpu${k % procedurePool.cpusLen.length}`, `func${thread.tid}${k}${thread.threadName}`, {
403                                            isLive: isLive,
404                                            list: funcRow.must ? groupedBy[k] : undefined,
405                                            offscreen: !funcRow.isTransferCanvas ? funcRow.offscreen[k] : undefined,//是否离屏
406                                            dpr: funcRow.dpr,//屏幕dpr值
407                                            xs: TraceRow.range?.xs,//线条坐标信息
408                                            isHover: funcRow.isHover,
409                                            flagMoveInfo: this.trace.hoverFlag,
410                                            flagSelectedInfo: this.trace.selectFlag,
411                                            hoverX: funcRow.hoverX,
412                                            hoverY: funcRow.hoverY,
413                                            depth: k,
414                                            canvasWidth: funcRow.canvasWidth,
415                                            canvasHeight: funcRow.canvasHeight,
416                                            maxHeight: maxHeight,
417                                            hoverFuncStruct: FuncStruct.hoverFuncStruct,
418                                            selectFuncStruct: FuncStruct.selectFuncStruct,
419                                            wakeupBean: CpuStruct.wakeupBean,
420                                            isRangeSelect: funcRow.rangeSelect,
421                                            rangeSelectObject: TraceRow.rangeSelectObject,
422                                            useCache: useCache,
423                                            lineColor: funcRow.getLineColor(),
424                                            startNS: TraceRow.range?.startNS || 0,
425                                            endNS: TraceRow.range?.endNS || 0,
426                                            totalNS: TraceRow.range?.totalNS || 0,
427                                            slicesTime: TraceRow.range?.slicesTime,
428                                            range: TraceRow.range,
429                                            frame: funcRow.frame
430                                        }, !funcRow.isTransferCanvas ? funcRow.offscreen[k] : undefined);
431                                        if (funcRow.isHover && promise.hover) {
432                                            FuncStruct.hoverFuncStruct = promise.hover;
433                                        }
434                                        promises.push(promise);
435                                    }
436                                    if (funcRow.isHover && promises.every(it => !it.hover)) {
437                                        FuncStruct.hoverFuncStruct = undefined;
438                                    }
439                                    funcRow.must = false;
440                                    funcRow.isTransferCanvas = true;
441                                }
442                                asy(useCache).then();
443                            }
444                            this.insertAfter(funcRow, threadRow)
445                            this.trace.observer.observe(funcRow)
446                            funcRow.draw();
447                            if (threadRow.onComplete) {
448                                threadRow.onComplete()
449                            }
450                            this.trace.getVisibleRows();//function 由于后插入dom,所以需要重新获取可见行
451                        }
452                    })
453                    if ((res instanceof ArrayBuffer && res.byteLength <= 0) || (res.length <= 0)) {
454                        threadRow.rowDiscard = true;
455                    }
456                    return res;
457                })
458                threadRow.onThreadHandler = (useCache) => {
459                    procedurePool.submitWithName(`process${(threadRow.index) % procedurePool.processLen.length}`, `thread ${thread.tid} ${thread.threadName}`, {
460                        list: threadRow.must ? threadRow.dataList : undefined,
461                        offscreen: !threadRow.isTransferCanvas ? threadRow.offscreen[0] : undefined,//是否离屏
462                        dpr: threadRow.dpr,//屏幕dpr值
463                        xs: TraceRow.range?.xs,//线条坐标信息
464                        isHover: threadRow.isHover,
465                        flagMoveInfo: this.trace.hoverFlag,
466                        flagSelectedInfo: this.trace.selectFlag,
467                        hoverX: threadRow.hoverX,
468                        hoverY: threadRow.hoverY,
469                        canvasWidth: threadRow.canvasWidth,
470                        canvasHeight: threadRow.canvasHeight,
471                        hoverThreadStruct: ThreadStruct.hoverThreadStruct,
472                        selectThreadStruct: ThreadStruct.selectThreadStruct,
473                        wakeupBean: CpuStruct.wakeupBean,
474                        isRangeSelect: threadRow.rangeSelect,
475                        rangeSelectObject: TraceRow.rangeSelectObject,
476                        useCache: useCache,
477                        lineColor: threadRow.getLineColor(),
478                        startNS: TraceRow.range?.startNS || 0,
479                        endNS: TraceRow.range?.endNS || 0,
480                        totalNS: TraceRow.range?.totalNS || 0,
481                        slicesTime: TraceRow.range?.slicesTime,
482                        range: TraceRow.range,
483                        frame: threadRow.frame
484                    }, !threadRow.isTransferCanvas ? threadRow.offscreen[0] : undefined, (res: any, hover: any) => {
485                        threadRow.must = false;
486                        if (threadRow.args.isOffScreen == true) {
487                            if (threadRow.isHover) {
488                                ThreadStruct.hoverThreadStruct = hover;
489                            }
490                            return;
491                        }
492                    })
493                    threadRow.isTransferCanvas = true;
494                }
495                if (threadRow.rowId == threadRow.rowParentId) {
496                    this.insertAfter(threadRow, processRow)
497                } else {
498                    this.trace.rowsEL?.appendChild(threadRow)
499                }
500            }
501
502        }
503        let durTime = new Date().getTime() - time;
504        info('The time to load the Process data is: ', durTime)
505    }
506
507    insertAfter(newEl: HTMLElement, targetEl: HTMLElement) {
508        let parentEl = targetEl.parentNode;
509        if (parentEl!.lastChild == targetEl) {
510            parentEl!.appendChild(newEl);
511        } else {
512            parentEl!.insertBefore(newEl, targetEl.nextSibling);
513        }
514    }
515}