// @ts-nocheck /* * Copyright (C) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import {BaseElement, element} from "../../base-ui/BaseElement.js"; import "./trace/TimerShaftElement.js"; import "./trace/base/TraceRow.js"; import "./trace/base/TraceRowRecyclerView.js" import { getAsyncEvents, getCpuUtilizationRate, getFps, getFunDataByTid, queryCpuData, queryCpuFreq, queryCpuFreqData, queryCpuMax, queryCpuMaxFreq, queryHeapByPid, queryHeapPid, queryProcess, queryProcessData, queryProcessMem, queryProcessMemData, queryProcessThreads, queryThreadData, queryTotalTime, threadPool } from "../database/SqlLite.js"; import {TraceRow} from "./trace/base/TraceRow.js"; import {TimerShaftElement} from "./trace/TimerShaftElement.js"; import {TimeRange} from "./trace/timer-shaft/RangeRuler.js"; import {CpuStruct} from "../bean/CpuStruct.js"; import {CpuFreqStruct} from "../bean/CpuFreqStruct.js"; import {ProcessStruct} from "../bean/ProcessStruct.js"; import {ColorUtils} from "./trace/base/ColorUtils.js"; import "./trace/base/TraceSheet.js"; import {TraceSheet} from "./trace/base/TraceSheet.js"; import {ThreadStruct} from "../bean/ThreadStruct.js"; import {ProcessMemStruct} from "../bean/ProcessMemStruct.js"; import {FuncStruct} from "../bean/FuncStruct.js"; import {FpsStruct} from "../bean/FpsStruct.js"; import {RangeSelect} from "./trace/base/RangeSelect.js"; import {SelectionParam} from "../bean/BoxSelection.js"; import {procedurePool} from "../database/Procedure.js"; import {SportRuler} from "./trace/timer-shaft/SportRuler.js"; import {TraceRowRecyclerView} from "./trace/base/TraceRowRecyclerView.js"; import {TraceRowObject} from "./trace/base/TraceRowObject.js"; import {Rect} from "./trace/timer-shaft/Rect.js"; @element('sp-recycler-system-trace') export class SpRecyclerSystemTrace extends BaseElement { rowsEL: TraceRowRecyclerView | undefined | null; private timerShaftEL: TimerShaftElement | null | undefined; private range: TimeRange | undefined private traceSheetEL: TraceSheet | undefined | null; private rangeSelect!: RangeSelect; static scrollViewWidth = 0 private processThreads: Array = [] private processAsyncEvent: Array = [] private processMem: Array = [] initElements(): void { this.rowsEL = this.shadowRoot?.querySelector('.rows') this.timerShaftEL = this.shadowRoot?.querySelector('.timer-shaft') this.traceSheetEL = this.shadowRoot?.querySelector('.trace-sheet') this.rangeSelect = new RangeSelect(); this.rangeSelect.rowsEL = this.rowsEL; document?.addEventListener("flag-change", (event: any) => { this.timerShaftEL?.modifyList(event.detail.type, event.detail.flagObj) if (event.detail.type == "remove") { this.traceSheetEL?.setAttribute("mode", 'hidden'); } }) document?.addEventListener("flag-draw", (event: any) => { if (event.detail == null) { } }) SpRecyclerSystemTrace.scrollViewWidth = this.getScrollWidth() this.rangeSelect.selectHandler = (rows) => { let selection = new SelectionParam(); selection.cpus = []; selection.threadIds = []; selection.funTids = []; selection.trackIds = []; selection.leftNs = 0; selection.rightNs = 0; rows.forEach(it => { if (it.rowType == TraceRow.ROW_TYPE_CPU) { selection.cpus.push(parseInt(it.rowId!)) } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) { selection.threadIds.push(parseInt(it.rowId!)) } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) { selection.funTids.push(parseInt(it.rowId!)) } else if (it.rowType == TraceRow.ROW_TYPE_MEM) { selection.trackIds.push(parseInt(it.rowId!)) } else if (it.rowType == TraceRow.ROW_TYPE_FPS) { selection.hasFps = true; }else if(it.rowType == TraceRow.ROW_TYPE_HEAP){ selection.heapIds.push(parseInt(it.rowId!)) } if (it.rangeSelect && it.rangeSelect.startNS) { selection.leftNs = it.rangeSelect.startNS; } if (it.rangeSelect && it.rangeSelect.endNS) { selection.rightNs = it.rangeSelect.endNS; } }) this.traceSheetEL?.boxSelection(selection) } // @ts-ignore new ResizeObserver((entries) => { let width = entries[0].contentRect.width - 1 - SpRecyclerSystemTrace.scrollViewWidth; requestAnimationFrame(() => { this.timerShaftEL?.updateWidth(width) this.shadowRoot!.querySelectorAll>("trace-row").forEach(it => it.updateWidth(width)) }) }).observe(this) // @ts-ignore new ResizeObserver((entries) => { let width = this.clientWidth - 1 - SpRecyclerSystemTrace.scrollViewWidth requestAnimationFrame(() => { this.timerShaftEL?.updateWidth(width) this.shadowRoot!.querySelectorAll>("trace-row").forEach(it => it.updateWidth(width)) }) }).observe(window.document.body) } getScrollWidth() { let noScroll, scroll, oDiv = document.createElement('div'); oDiv.style.cssText = 'position:absolute; top:-1000px; width:100px; height:100px; overflow:hidden;'; noScroll = document.body.appendChild(oDiv).clientWidth; oDiv.style.overflowY = 'scroll'; scroll = oDiv.clientWidth; document.body.removeChild(oDiv); return noScroll - scroll + 1; } getVisibleRows(): Array> { return [...this.rowsEL!.shadowRoot!.querySelectorAll>("trace-row")]; } timerShaftELRangeChange = (e: any) => { this.range = e.detail; TraceRow.range = this.range; let scrollTop = this.rowsEL?.scrollTop || 0 let scrollHeight = this.rowsEL?.clientHeight || 0 this.getVisibleRows().forEach(it => { it.dataListCache.length = 0; this.hoverStructNull(); it.drawObject(); }) } rowsElOnScroll = (e: any) => { this.hoverStructNull(); let rows = this.getVisibleRows(); rows.forEach((it, index) => { if (index == 0 || index == rows.length - 1) { it.dataListCache.length = 0; it.drawObject(); } }) } documentOnMouseDown = (ev: MouseEvent) => { this.rangeSelect.mouseDown(ev) } documentOnMouseUp = (ev: MouseEvent) => { this.rangeSelect.mouseUp(ev); } documentOnMouseMove = (ev: MouseEvent) => { let rows = this.getVisibleRows(); this.rangeSelect.mouseMove(rows, ev) rows.forEach(tr => { let x = ev.offsetX - (tr.canvasContainer?.offsetLeft || 0); let y = ev.offsetY - (tr.canvasContainer?.offsetTop || 0) + (this.rowsEL?.scrollTop || 0); if (x > tr.frame.x && x < tr.frame.x + tr.frame.width && y > tr.frame.y && y < tr.frame.y + tr.frame.height) { this.hoverStructNull(); if (tr.rowType === TraceRow.ROW_TYPE_CPU) { CpuStruct.hoverCpuStruct = tr.onMouseHover(x, y); if (CpuStruct.hoverCpuStruct) { tr.tip = `P:${CpuStruct.hoverCpuStruct.processName || "Process"} [${CpuStruct.hoverCpuStruct.processId}]T:${CpuStruct.hoverCpuStruct.name} [${CpuStruct.hoverCpuStruct.tid}]`; } tr.setTipLeft(x, CpuStruct.hoverCpuStruct) } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ) { CpuFreqStruct.hoverCpuFreqStruct = tr.onMouseHover(x, y); if (CpuFreqStruct.hoverCpuFreqStruct) { tr.tip = `${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct.value!)} kHz` } tr.setTipLeft(x, CpuFreqStruct.hoverCpuFreqStruct) } else if (tr.rowType === TraceRow.ROW_TYPE_THREAD) { ThreadStruct.hoverThreadStruct = tr.onMouseHover(x, y, false); } else if (tr.rowType === TraceRow.ROW_TYPE_FUNC) { FuncStruct.hoverFuncStruct = tr.onMouseHover(x, y, false) } else if (tr.rowType === TraceRow.ROW_TYPE_HEAP) { HeapStruct.hoverHeapStruct = tr.onMouseHover(x, y, false) if (HeapStruct.hoverHeapStruct) { tr.tip = `${ColorUtils.formatNumberComma(HeapStruct.hoverHeapStruct.heapsize!)} byte` } tr.setTipLeft(x, HeapStruct.hoverHeapStruct) } else { this.hoverStructNull(); } } else { tr.onMouseLeave(x, y); } tr.drawObject(); }) } hoverStructNull() { CpuStruct.hoverCpuStruct = undefined; CpuFreqStruct.hoverCpuFreqStruct = undefined; ThreadStruct.hoverThreadStruct = undefined; FuncStruct.hoverFuncStruct = undefined; } selectStructNull() { CpuStruct.selectCpuStruct = undefined; CpuFreqStruct.selectCpuFreqStruct = undefined; ThreadStruct.selectThreadStruct = undefined; FuncStruct.selectFuncStruct = undefined; } documentOnClick = (ev: MouseEvent) => { if (this.rangeSelect.isDrag()) { return; } this.rowsEL?.querySelectorAll>("trace-row").forEach(it => it.rangeSelect = undefined) this.selectStructNull(); if (CpuStruct.hoverCpuStruct) { CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct this.traceSheetEL?.displayCpuData(CpuStruct.hoverCpuStruct); } else if (ThreadStruct.hoverThreadStruct) { ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct; this.traceSheetEL?.displayThreadData(ThreadStruct.hoverThreadStruct) } else if (FuncStruct.hoverFuncStruct) { FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct; this.traceSheetEL?.displayFuncData(FuncStruct.hoverFuncStruct) } else if (SportRuler.rulerFlagObj) { } else { this.traceSheetEL?.setAttribute("mode", 'hidden'); } this.documentOnMouseMove(ev) } connectedCallback() { this.timerShaftEL?.addEventListener('range-change', this.timerShaftELRangeChange) this.rowsEL?.addEventListener('scroll', this.rowsElOnScroll) document.addEventListener('mousemove', this.documentOnMouseMove) document.addEventListener('mousedown', this.documentOnMouseDown) document.addEventListener('mouseup', this.documentOnMouseUp) document.addEventListener('click', this.documentOnClick) } disconnectedCallback() { this.timerShaftEL?.removeEventListener('range-change', this.timerShaftELRangeChange); this.rowsEL?.removeEventListener('scroll', this.rowsElOnScroll); document.removeEventListener('mousemove', this.documentOnMouseMove); document.removeEventListener('click', this.documentOnClick); } loadDatabaseUrl(url: string, complete?: Function) { this.init({url: url}).then(() => { let scrollTop = this.rowsEL?.scrollTop || 0 let scrollHeight = this.rowsEL?.clientHeight || 0 this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => { let top = it.offsetTop - (this.rowsEL?.offsetTop || 0); if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) { (it as TraceRow).dataListCache.length = 0; } }) if (complete) { complete(); } }) } loadDatabaseArrayBuffer(buf: ArrayBuffer, complete?: Function) { this.init({buf}).then(() => { let scrollTop = this.rowsEL?.scrollTop || 0 let scrollHeight = this.rowsEL?.clientHeight || 0 this.rowsEL?.querySelectorAll("trace-row").forEach((it: any) => { let top = it.offsetTop - (this.rowsEL?.offsetTop || 0); if (top + it.clientHeight > scrollTop && top + it.clientHeight < scrollTop + scrollHeight + it.clientHeight) { (it as TraceRow).dataListCache.length = 0; } }) if (complete) { complete(); } }) } init = async (param: { buf?: ArrayBuffer, url?: string }) => { if (this.rowsEL) this.rowsEL.innerHTML = '' this.traceSheetEL?.setAttribute("mode", "hidden") this.timerShaftEL?.reset(); procedurePool.clearCache(); param.buf && await threadPool.initSqlite(param.buf); param.url && await threadPool.initServer(param.url); this.processThreads = await queryProcessThreads(); this.processMem = await queryProcessMem() this.processAsyncEvent = await getAsyncEvents() await this.initTotalTime(); let cpuObjs = await this.initCpu(); await this.initCpuRate(); let freqObjs = await this.initCpuFreq(); let fpsObjs = await this.initFPS(); let processObjs = await this.initProcess(); this.rowsEL.dataSource = [...cpuObjs, ...freqObjs, ...fpsObjs, ...processObjs] this.getVisibleRows().forEach(it => it.drawObject()); } initCpuRate = async () => { let rates = await getCpuUtilizationRate(0, this.timerShaftEL?.totalNS || 0); if (this.timerShaftEL) this.timerShaftEL.cpuUsage = rates; } initTotalTime = async () => { let res = await queryTotalTime(); if (this.timerShaftEL) { this.timerShaftEL.totalNS = res[0].total this.timerShaftEL.loadComplete = true; } } initCpu = async () => { let objs = []; let array = await queryCpuMax(); if (array && array.length > 0 && array[0]) { let cpuMax = array[0].cpu CpuStruct.cpuCount = cpuMax + 1; for (let i1 = 0; i1 < CpuStruct.cpuCount; i1++) { const cpuId = i1; let traceRow = new TraceRowObject(); traceRow.rowId = `${cpuId}` traceRow.rowType = TraceRow.ROW_TYPE_CPU traceRow.rowParentId = '' traceRow.rowHeight = 40 traceRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, traceRow.rowHeight) traceRow.name = `Cpu ${cpuId}` traceRow.supplier = () => queryCpuData(cpuId, 0, this.timerShaftEL?.totalNS || 0) traceRow.onThreadHandler = ((row, ctx) => { procedurePool.submitWithName("cpu", `cpu${cpuId}`, { list: traceRow.must ? traceRow.dataList : undefined, startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, frame: traceRow.frame }, (res: any) => { traceRow.dataListCache = res; traceRow.must = false; row.clearCanvas(); row.c!.beginPath(); row.drawLines(); for (let i = 0; i < res.length; i++) { CpuStruct.draw(ctx, res[i]) } row.drawSelection(); row.c!.closePath(); }) }) objs.push(traceRow) } } return objs; } initCpuFreq = async () => { let objs = []; let freqList = await queryCpuFreq(); let freqMaxList = await queryCpuMaxFreq(); CpuFreqStruct.maxFreq = freqMaxList[0].maxFreq; let math = () => { let units: Array = ["", "K", "M", "G", "T", "E"]; let sb = " "; CpuFreqStruct.maxFreqName = " "; if (CpuFreqStruct.maxFreq > 0) { let log10: number = Math.ceil(Math.log10(CpuFreqStruct.maxFreq)); let pow10: number = Math.pow(10, log10); let afterCeil: number = Math.ceil(CpuFreqStruct.maxFreq / (pow10 / 4)) * (pow10 / 4); CpuFreqStruct.maxFreq = afterCeil; let unitIndex: number = Math.floor(log10 / 3); sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}hz` } CpuFreqStruct.maxFreqName = sb.toString(); } math(); for (let i = 0; i < freqList.length; i++) { const it = freqList[i]; let traceRow = new TraceRowObject(); traceRow.rowId = `${it.cpu}` traceRow.rowType = TraceRow.ROW_TYPE_CPU_FREQ traceRow.rowParentId = '' traceRow.rowHeight = 40 traceRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, traceRow.rowHeight) traceRow.name = `Cpu ${it.cpu} Frequency`; traceRow.supplier = () => queryCpuFreqData(it.cpu) traceRow.onThreadHandler = (row, ctx) => { procedurePool.submitWithName("freq", `freq${it.cpu}`, { list: traceRow.must ? traceRow.dataList : undefined, startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, frame: traceRow.frame }, (res: any) => { traceRow.dataListCache = res; traceRow.must = false; row.clearCanvas(); row.drawLines(); row.c!.beginPath(); for (let i = 0; i < res.length; i++) { CpuFreqStruct.draw(ctx, res[i]) } row.drawSelection(); row.c!.closePath(); let s = CpuFreqStruct.maxFreqName let textMetrics = ctx.measureText(s); row.c!.globalAlpha = 0.8 row.c!.fillStyle = "#f0f0f0" row.c!.fillRect(0, 5, textMetrics.width + 8, 18) row.c!.globalAlpha = 1 row.c!.fillStyle = "#333" ctx.textBaseline="middle" ctx.fillText(maxFps, 4, 5+9) }) } objs.push(traceRow) } return objs; } initFPS = async () => { let objs = []; let fpsRow = new TraceRowObject(); fpsRow.rowId = `fps` fpsRow.rowType = TraceRow.ROW_TYPE_FPS fpsRow.rowParentId = '' FpsStruct.maxFps = 0 fpsRow.rowHeight = 40 fpsRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, fpsRow.rowHeight) fpsRow.name = "FPS" fpsRow.supplier = () => getFps() fpsRow.onDrawHandler = (row, ctx) => { if (fpsRow.dataListCache.length > 0) { for (let i = 0; i < fpsRow.dataListCache.length; i++) { FpsStruct.draw(ctx, fpsRow.dataListCache[i]) } } else { if (fpsRow.dataList) { for (let i = 0; i < fpsRow.dataList.length; i++) { let it = fpsRow.dataList[i]; if ((it.fps || 0) > FpsStruct.maxFps) { FpsStruct.maxFps = it.fps || 0 } if (i === fpsRow.dataList.length - 1) { it.dur = (TraceRow.range?.endNS || 0) - (it.startNS || 0) } else { it.dur = (fpsRow.dataList[i + 1].startNS || 0) - (it.startNS || 0) } if ((it.startNS || 0) + (it.dur || 0) > (TraceRow.range?.startNS || 0) && (it.startNS || 0) < (TraceRow.range?.endNS || 0)) { FpsStruct.setFrame(fpsRow.dataList[i], 5, TraceRow.range?.startNS || 0, TraceRow.range?.endNS || 0, TraceRow.range?.totalNS || 0, fpsRow.frame) 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))) { continue; } else { fpsRow.dataListCache.push(fpsRow.dataList[i]) FpsStruct.draw(ctx, fpsRow.dataList[i]) } } } } } if (ctx){ let maxFps = FpsStruct.maxFps + "FPS" let textMetrics = ctx.measureText(maxFps); ctx.globalAlpha = 0.8 ctx.fillStyle = "#f0f0f0" ctx.fillRect(0, 5, textMetrics.width + 8, 18) ctx.globalAlpha = 1 ctx.fillStyle = "#333" ctx.textBaseline="middle" ctx.fillText(maxFps, 4, 5+9) } } objs.push(fpsRow) return objs; } initProcess = async () => { let objs = []; let processList = await queryProcess(); let heapPidList = await queryHeapPid() for (let i = 0; i < processList.length; i++) { const it = processList[i]; let processRow = new TraceRowObject(); processRow.rowId = `${it.pid}` processRow.rowType = TraceRow.ROW_TYPE_PROCESS processRow.rowParentId = '' processRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, processRow.rowHeight); processRow.folder = true; processRow.name = `${it.processName || "Process"} ${it.pid}`; processRow.supplier = () => queryProcessData(it.pid || -1, 0, TraceRow.range?.totalNS || 0) processRow.onThreadHandler = (row, ctx) => { procedurePool.submitWithName("process", `process ${it.pid} ${it.processName}`, { list: processRow.must ? processRow.dataList : undefined, startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, frame: processRow.frame }, (res: any) => { processRow.dataListCache = res; processRow.must = false; row.clearCanvas(); row.drawLines(); row.c!.beginPath(); for (let i = 0; i < res.length; i++) { ProcessStruct.draw(ctx, res[i]) } row.drawSelection(); row.c!.closePath(); }) } objs.push(processRow); if (heapPidList != undefined && Array.isArray(heapPidList) && heapPidList.filter((item) => { return item.pid == it.pid }).length > 0) { let allHeapRow = new TraceRowObject(); allHeapRow.rowParentId = `${it.pid}` allHeapRow.rowHidden = !processRow.expansion allHeapRow.rowHeight = 40 allHeapRow.name = "All Heap Allocations"; allHeapRow.folder = false; allHeapRow.rowType = TraceRow.ROW_TYPE_HEAP allHeapRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, allHeapRow.rowHeight) allHeapRow.children = true allHeapRow.supplier = () => queryHeapByPid(0, TraceRow.range?.totalNS || 0, it.pid || 0).then((res) => { let heapList: HeapStruct[] = [] let allocMap: Map = new Map() let currentHeapSize = 0 let maxHeapSize = 0; for (let j = 0; j < res.length; j++) { let struct = new HeapStruct(); if (res[j].eventType == "AllocEvent") { currentHeapSize += (res[j].heapsize || 0) if (allocMap.has(res[j].addr || "")) { allocMap.get(res[j].addr || "")?.push(res[j]) } else { allocMap.set(res[j].addr || "", [res[j]]) } } else if (res[j].eventType == "FreeEvent") { if (allocMap.has(res[j].addr || "")) { let allocList = allocMap.get(res[j].addr || ""); if (allocList != undefined && allocList.length > 0) { currentHeapSize -= allocList[allocList.length - 1].heapsize || 0 } } } if (currentHeapSize > maxHeapSize) { maxHeapSize = currentHeapSize } struct.pid = it.pid + "" struct.startTime = res[j].startTime if (j != res.length - 1) { struct.endTime = res[j + 1].startTime } else { struct.endTime = allHeapRow.range?.totalNS || 0 } struct.duration = (struct.endTime || 0) - (struct.startTime || 0) struct.heapsize = currentHeapSize heapList.push(struct) } for (let j = 0; j < heapList.length; j++) { heapList[j].maxHeapSize = maxHeapSize } return heapList }) allHeapRow.onDrawHandler = ctx => { if (allHeapRow.dataList) { for (let i = 0; i < allHeapRow.dataList.length; i++) { let it = allHeapRow.dataList[i]; if ((it.startTime || 0) + (it.duration || 0) > (TraceRow.range?.startNS || 0) && (it.startTime || 0) < (TraceRow.range?.endNS || 0)) { HeapStruct.setFrame(allHeapRow.dataList[i], 5, TraceRow.range?.startNS || 0, TraceRow.range?.endNS || 0, TraceRow.range?.totalNS || 0, allHeapRow.frame) HeapStruct.draw(ctx, allHeapRow.dataList[i]) } } } } objs.push(allHeapRow); } let processMem = this.processMem.filter(mem => mem.pid === it.pid); processMem.forEach(mem => { let row = new TraceRowObject(); row.rowId = `${mem.trackId}` row.rowType = TraceRow.ROW_TYPE_MEM row.rowParentId = `${it.pid}` row.rowHidden = !processRow.expansion row.rowHeight = 40 row.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, row.rowHeight) row.name = `${mem.trackName}`; row.children = true; row.supplier = () => queryProcessMemData(mem.trackId).then(res => { let maxValue = Math.max(...res.map(it => it.value || 0)) for (let j = 0; j < res.length; j++) { res[j].maxValue = maxValue; if (j == res.length - 1) { res[j].duration = this.range?.totalNS || 0; } else { res[j].duration = (res[j + 1].startTime || 0) - (res[j].startTime || 0); } if (j > 0) { res[j].delta = (res[j].value || 0) - (res[j - 1].value || 0); } else { res[j].delta = 0; } } return res }); row.onThreadHandler = (r, ctx) => { procedurePool.submitWithName("mem", `mem ${mem.trackId} ${mem.trackName}`, { list: row.must ? row.dataList : undefined, startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, frame: row.frame }, (res: any) => { row.dataListCache = res; row.must = false; r.clearCanvas(); r.drawLines(); r.c!.beginPath(); for (let i = 0; i < res.length; i++) { ProcessMemStruct.draw(ctx, res[i]) } r.drawSelection(); r.c!.closePath(); }) } objs.push(row); }); let threads = this.processThreads.filter(thread => thread.pid === it.pid && thread.tid != 0 && thread.threadName != null); threads.forEach((thread, i) => { // if(i>0) return; let threadRow = new TraceRowObject(); threadRow.rowId = `${thread.tid}` threadRow.rowType = TraceRow.ROW_TYPE_THREAD threadRow.rowParentId = `${it.pid}` threadRow.rowHidden = !processRow.expansion threadRow.rowHeight = 40 threadRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, threadRow.rowHeight); threadRow.name = `${thread.threadName} ${thread.tid}`; threadRow.children = true; threadRow.supplier = () => queryThreadData(thread.tid || 0).then(res => { getFunDataByTid(thread.tid || 0).then(funs => { if (funs.length > 0) { let maxHeight = (Math.max(...funs.map(it => it.depth || 0)) + 1) * 20 + 20; let funcRow = new TraceRowObject(); funcRow.rowId = `${thread.tid}` funcRow.rowType = TraceRow.ROW_TYPE_FUNC funcRow.rowParentId = `${it.pid}` funcRow.rowHidden = !processRow.expansion funcRow.rowHeight = maxHeight; funcRow.frame = new Rect(0, 0, this.rowsEL.clientWidth - 248, funcRow.rowHeight); funcRow.name = `${thread.threadName} ${thread.tid}`; funcRow.children = true; funcRow.supplier = () => new Promise((resolve, reject) => resolve(funs)) funcRow.onThreadHandler = (r, ctx) => { procedurePool.submitWithName("func", `func ${thread.tid} ${thread.threadName}`, { list: funcRow.must ? funcRow.dataList : undefined, startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, frame: threadRow.frame }, (res: any) => { funcRow.must = false; funcRow.dataListCache = res; r.clearCanvas(); r.drawLines(); r.c!.beginPath(); for (let i = 0; i < res.length; i++) { FuncStruct.draw(ctx, res[i]) } r.drawSelection(); r.c!.closePath(); }) } } }) return res; }) threadRow.onThreadHandler = (r, ctx) => { procedurePool.submitWithName("thread", `thread ${thread.tid} ${thread.threadName}`, { list: threadRow.must ? threadRow.dataList : undefined, startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, frame: threadRow.frame }, (res: any) => { threadRow.dataListCache = res; threadRow.must = false; r.clearCanvas(); r.drawLines(); r.c!.beginPath(); for (let i = 0; i < res.length; i++) { ThreadStruct.draw(ctx, res[i]) } r.drawSelection(); r.c!.closePath(); }) } objs.push(threadRow); }) } return objs; } insertAfter(newEl: HTMLElement, targetEl: HTMLElement) { let parentEl = targetEl.parentNode; if (parentEl!.lastChild == targetEl) { parentEl!.appendChild(newEl); } else { parentEl!.insertBefore(newEl, targetEl.nextSibling); } } initHtml(): string { return `
`; } }