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