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