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 unknown KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { SpSystemTrace } from './SpSystemTrace'; 17import { TabPaneFrequencySample } from './trace/sheet/cpu/TabPaneFrequencySample'; 18import { TabPaneCounterSample } from './trace/sheet/cpu/TabPaneCounterSample'; 19import { RangeSelect } from './trace/base/RangeSelect'; 20import { TraceRow } from './trace/base/TraceRow'; 21import { SportRuler } from './trace/timer-shaft/SportRuler'; 22import { SelectionParam } from '../bean/BoxSelection'; 23import { error, info } from '../../log/Log'; 24import { SpStatisticsHttpUtil } from '../../statistics/util/SpStatisticsHttpUtil'; 25import { queryEbpfSamplesCount, queryPlugins } from '../database/sql/Memory.sql'; 26import { SpChartManager } from './chart/SpChartManager'; 27import { ThreadStruct } from '../database/ui-worker/ProcedureWorkerThread'; 28import { FlagsConfig } from './SpFlags'; 29import { threadPool, threadPool2 } from '../database/SqlLite'; 30import { JankStruct } from '../database/ui-worker/ProcedureWorkerJank'; 31import { CpuStruct } from '../database/ui-worker/cpu/ProcedureWorkerCPU'; 32import { PairPoint } from '../database/ui-worker/ProcedureWorkerCommon'; 33import { TraceSheet } from './trace/base/TraceSheet'; 34import { TimerShaftElement } from './trace/TimerShaftElement'; 35import { SpChartList } from './trace/SpChartList'; 36type HTMLElementAlias = HTMLElement | null | undefined; 37import { Utils } from './trace/base/Utils'; 38import { fuzzyQueryFuncRowData, queryFuncRowData } from '../database/sql/Func.sql'; 39import { convertTitle } from './chart/SpXpowerChart'; 40 41// 所有插件以及对应的表 42const pluginArray = [ 43 { 44 pluginName: 'ftrace-plugin', 45 tables: [ 46 'animation', 'app_startup', 'args', 'callstack', 'clk_event_filter', 47 'clock_event_filter', 'cpu_measure_filter', 'device_info', 'dynamic_frame', 'frame_maps', 48 'frame_slice', 'gpu_slice', 'instant', 'irq', 'process_measure_filter', 'process_measure', 49 'sched_slice', 'static_initalize', 'symbols', 'syscall', 'task_pool', 'thread_state', 'dma_fence' 50 ] 51 }, 52 { 53 pluginName: 'hiperf-plugin', 54 tables: [ 55 'perf_callchain', 'perf_files', 'perf_report', 'perf_sample', 'perf_thread' 56 ] 57 }, 58 { 59 pluginName: 'nativehook-plugin', 60 tables: [ 61 'native_hook', 'native_hook_frame', 'native_hook_statistic' 62 ] 63 }, 64 { 65 pluginName: 'arkTs-plugin', 66 tables: [ 67 'js_config', 'js_cpu_profiler_node', 'js_cpu_profiler_sample', 'js_heap_files', 'js_heap_info', 'js_heap_location', 68 'js_heap_nodes', 'js_heap_sample', 'js_heap_string', 'js_heap_trace_function_info', 'js_heap_trace_node', 'js_heap_edges' 69 ] 70 }, 71 { 72 pluginName: 'memory-plugin', 73 tables: [ 74 'memory_ashmem', 'memory_cpu', 'memory_dma', 'memory_process_gpu', 'memory_profile,', 'memory_rs_image', 'memory_window_gpu', 'smaps', 'sys_event_filter', 'sys_mem_measure' 75 ] 76 }, 77 { 78 pluginName: 'hisysevent-plugin', 79 tables: [ 80 'app_name', 'device_state', 'hisys_all_event', 'hisys_event_measure' 81 ] 82 }, 83 { 84 pluginName: 'ebpf-plugin', 85 tables: [ 86 'bio_latency_sample', 'ebpf_callstack', 'file_system_sample', 'paged_memory_sample' 87 ] 88 }, 89 { 90 pluginName: 'cpu-plugin', 91 tables: [ 92 'cpu_usage' 93 ] 94 }, 95 { 96 pluginName: 'diskio-plugin', 97 tables: [ 98 'diskio' 99 ] 100 }, 101 { 102 pluginName: 'hidump-plugin', 103 tables: [ 104 'hidump' 105 ] 106 }, 107 { 108 pluginName: 'process-plugin', 109 tables: [ 110 'live_process' 111 ] 112 }, 113 { 114 pluginName: 'hilog-plugin', 115 tables: [ 116 'log' 117 ] 118 }, 119 { 120 pluginName: 'network-plugin', 121 tables: [ 122 'network' 123 ] 124 }, 125 { 126 pluginName: 'xpower-plugin', 127 tables: [ 128 'xpower_measure' 129 ] 130 } 131]; 132 133function rightButtonOnClick(sp: SpSystemTrace, rightStar: HTMLElementAlias): unknown { 134 Object.assign(sp, { 135 ext(): string { 136 return 'Handle the right button click event'; 137 }, 138 }); 139 140 return function (event: unknown): void { 141 if (SpSystemTrace.btnTimer) { 142 return; 143 } 144 sp.checkclick = true; 145 // 唤醒树有值则不再重复添加 146 const startIndex = CpuStruct.selectCpuStruct!.displayProcess?.indexOf('['); 147 if (SpSystemTrace.wakeupList.length === 0) { 148 SpSystemTrace.wakeupList.unshift(CpuStruct.wakeupBean!); 149 sp.queryCPUWakeUpList(CpuStruct.wakeupBean!); 150 CpuStruct.selectCpuStruct!.ts = CpuStruct.selectCpuStruct!.startTime; 151 CpuStruct.selectCpuStruct!.thread = CpuStruct.selectCpuStruct!.name; 152 CpuStruct.selectCpuStruct!.pid = CpuStruct.selectCpuStruct!.processId; 153 CpuStruct.selectCpuStruct!.process = CpuStruct.selectCpuStruct!.displayProcess?.substring(0, startIndex).trim() || CpuStruct.selectCpuStruct!.processName; 154 CpuStruct.selectCpuStruct!.itid = CpuStruct.wakeupBean!.itid; 155 sessionStorage.setItem('saveselectcpustruct', JSON.stringify(CpuStruct.selectCpuStruct)); 156 } else { 157 sp.wakeupListNull(); 158 SpSystemTrace.wakeupList.unshift(CpuStruct.wakeupBean!); 159 sp.queryCPUWakeUpList(CpuStruct.wakeupBean!); 160 CpuStruct.selectCpuStruct!.ts = CpuStruct.selectCpuStruct!.startTime; 161 CpuStruct.selectCpuStruct!.thread = CpuStruct.selectCpuStruct!.name; 162 CpuStruct.selectCpuStruct!.pid = CpuStruct.selectCpuStruct!.processId; 163 CpuStruct.selectCpuStruct!.process = CpuStruct.selectCpuStruct!.displayProcess?.substring(0, startIndex).trim() || CpuStruct.selectCpuStruct!.processName; 164 CpuStruct.selectCpuStruct!.itid = CpuStruct.wakeupBean!.itid; 165 sessionStorage.setItem('saveselectcpustruct', JSON.stringify(CpuStruct.selectCpuStruct)); 166 } 167 let rightButton: HTMLElement | null | undefined = sp.traceSheetEL?.shadowRoot 168 ?.querySelector('#current-selection > tabpane-current-selection') 169 ?.shadowRoot?.querySelector('#rightButton'); 170 rightButton?.blur(); 171 setTimeout(() => { 172 requestAnimationFrame(() => sp.refreshCanvas(false)); 173 }, 300); 174 rightStar!.style.visibility = 'visible'; 175 rightStar!.style.cursor = 'pointer'; 176 SpSystemTrace.btnTimer = setTimeout((): void => { 177 SpSystemTrace.btnTimer = null; // 2.清空节流阀,方便下次开启定时器 178 }, 2000); 179 }; 180} 181function rightStarOnClick(sp: SpSystemTrace) { 182 return function (ev: unknown): void { 183 let wakeupLists = []; 184 wakeupLists.push(CpuStruct.selectCpuStruct?.cpu); 185 for (let wakeupBean of SpSystemTrace.wakeupList) { 186 wakeupLists.push(wakeupBean.cpu); 187 } 188 let wakeupCpuLists = Array.from(new Set(wakeupLists)).sort(); 189 for (let wakeupCpu of wakeupCpuLists) { 190 // @ts-ignore 191 let cpuFavoriteRow: unknown = sp.shadowRoot?.querySelector<TraceRow<unknown>>( 192 `trace-row[row-type='cpu-data'][row-id='${Utils.getDistributedRowId(wakeupCpu)}']` 193 ); 194 if (cpuFavoriteRow === null || cpuFavoriteRow === undefined) { 195 continue; 196 } 197 // @ts-ignore 198 cpuFavoriteRow!.setAttribute('collect-type', ''); 199 let replaceRow = document.createElement('div'); 200 // @ts-ignore 201 replaceRow.setAttribute('row-id', `${cpuFavoriteRow.rowId}-${cpuFavoriteRow.rowType}`); 202 replaceRow.setAttribute('type', 'replaceRow'); 203 // @ts-ignore 204 replaceRow.setAttribute('row-parent-id', cpuFavoriteRow.rowParentId); 205 replaceRow.style.display = 'none'; 206 // @ts-ignore 207 cpuFavoriteRow.rowHidden = !cpuFavoriteRow.hasAttribute('scene'); 208 // @ts-ignore 209 if (sp.rowsEL!.contains(cpuFavoriteRow)) { 210 // @ts-ignore 211 sp.rowsEL!.replaceChild(replaceRow, cpuFavoriteRow); 212 } 213 // @ts-ignore 214 cpuFavoriteRow.tampName = cpuFavoriteRow.name; 215 // @ts-ignore 216 sp.favoriteChartListEL!.insertRow(cpuFavoriteRow, cpuFavoriteRow.traceId || sp.currentCollectGroup, true); 217 // @ts-ignore 218 sp.collectRows.push(cpuFavoriteRow); 219 sp.timerShaftEL?.displayCollect(sp.collectRows.length !== 0); 220 sp.currentClickRow = null; 221 // @ts-ignore 222 cpuFavoriteRow.setAttribute('draggable', 'true'); 223 // @ts-ignore 224 cpuFavoriteRow.addEventListener('dragstart', cpuFavoriteRowDragStart(sp, cpuFavoriteRow)); 225 // @ts-ignore 226 cpuFavoriteRow.addEventListener('dragover', cpuFavoriteRowDragOver(sp)); 227 // @ts-ignore 228 cpuFavoriteRow.addEventListener('drop', cpuFavoriteRowDropHandler(sp, cpuFavoriteRow)); 229 // @ts-ignore 230 cpuFavoriteRow.addEventListener('dragend', cpuFavoriteRowDragendHandler(sp)); 231 } 232 sp.refreshFavoriteCanvas(); 233 sp.refreshCanvas(true); 234 }; 235} 236function cpuFavoriteRowDragStart(sp: SpSystemTrace, cpuFavoriteRow: unknown) { 237 return function (): void { 238 // @ts-ignore 239 sp.currentClickRow = cpuFavoriteRow; 240 }; 241} 242function cpuFavoriteRowDragOver(sp: SpSystemTrace) { 243 return function (ev: unknown): void { 244 // @ts-ignore 245 ev.preventDefault(); 246 // @ts-ignore 247 ev.dataTransfer.dropEffect = 'move'; 248 }; 249} 250function cpuFavoriteRowDropHandler(sp: SpSystemTrace, cpuFavoriteRow: unknown) { 251 return function (ev: unknown): void { 252 if (sp.favoriteChartListEL && sp.currentClickRow && sp.currentClickRow !== cpuFavoriteRow) { 253 // @ts-ignore 254 let rect = cpuFavoriteRow.getBoundingClientRect(); 255 // @ts-ignore 256 if (ev.clientY >= rect.top && ev.clientY < rect.top + rect.height / 2) { 257 //向上移动 258 // @ts-ignore 259 sp.favoriteChartListEL.insertRowBefore(sp.currentClickRow, cpuFavoriteRow); 260 // @ts-ignore 261 } else if (ev.clientY <= rect.bottom && ev.clientY > rect.top + rect.height / 2) { 262 //向下移动 263 // @ts-ignore 264 sp.favoriteChartListEL.insertRowBefore(sp.currentClickRow, cpuFavoriteRow.nextSibling); 265 } 266 sp.refreshFavoriteCanvas(); 267 } 268 }; 269} 270function cpuFavoriteRowDragendHandler(sp: SpSystemTrace): () => void { 271 return function (): void { 272 sp.linkNodes.forEach((itln) => { 273 if (itln[0].rowEL.collect) { 274 itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195; 275 } else { 276 itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - sp.rowsPaneEL!.scrollTop; 277 } 278 if (itln[1].rowEL.collect) { 279 itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195; 280 } else { 281 itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - sp.rowsPaneEL!.scrollTop; 282 } 283 itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY; 284 itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY; 285 }); 286 sp.currentClickRow = null; 287 }; 288} 289function triangleFlagHandler(sp: SpSystemTrace): (event: unknown) => void { 290 return function (event: unknown): void { 291 //@ts-ignore 292 let temporaryTime = sp.timerShaftEL?.drawTriangle(event.detail.time, event.detail.type); 293 //@ts-ignore 294 if (event.detail.timeCallback && temporaryTime) { 295 //@ts-ignore 296 event.detail.timeCallback(temporaryTime); 297 } 298 }; 299} 300function numberCalibrationHandler(sp: SpSystemTrace): (event: unknown) => void { 301 return function (event: unknown): void { 302 // @ts-ignore 303 sp.timerShaftEL!.sportRuler!.times = event.detail.time; 304 // @ts-ignore 305 sp.timerShaftEL!.sportRuler!.counts = event.detail.counts; 306 // @ts-ignore 307 sp.timerShaftEL!.sportRuler!.durations = event.detail.durations; 308 sp.timerShaftEL!.sportRuler?.draw(); 309 }; 310} 311function flagChangeHandler(sp: SpSystemTrace): (event: unknown) => void { 312 return function (event: unknown): void { 313 // @ts-ignore 314 sp.timerShaftEL?.modifyFlagList(event.detail); 315 // @ts-ignore 316 if (event.detail.hidden) { 317 //@ts-ignore 318 sp.selectFlag = undefined; 319 if (sp._flagList.length <= 0) { 320 let showTab = sp.getShowTab(); 321 showTab = showTab.filter((it) => it !== 'box-flag'); 322 if (TraceRow.rangeSelectObject && showTab.length > 0) { 323 sp.traceSheetEL?.displayTab(...showTab); 324 } else { 325 sp.traceSheetEL?.setMode('hidden'); 326 } 327 } 328 sp.refreshCanvas(true); 329 } 330 }; 331} 332function slicesChangeHandler(sp: SpSystemTrace): (event: unknown) => void { 333 return function (event: unknown): void { 334 // @ts-ignore 335 sp.timerShaftEL?.modifySlicesList(event.detail); 336 // @ts-ignore 337 if (event.detail.hidden) { 338 sp.slicestime = null; 339 if (sp._slicesList.length <= 0) { 340 let showTab = sp.getShowTab(); 341 showTab = showTab.filter((it) => it !== 'tabpane-current'); 342 if (TraceRow.rangeSelectObject && showTab.length > 0) { 343 sp.traceSheetEL?.displayTab(...showTab); 344 } else { 345 sp.traceSheetEL?.setMode('hidden'); 346 } 347 } 348 sp.refreshCanvas(true); 349 } 350 }; 351} 352function collectHandler(sp: SpSystemTrace): (event: unknown) => void { 353 return function (event: unknown): void { 354 // @ts-ignore 355 let currentRow = event.detail.row; 356 if (currentRow.collect) { 357 collectHandlerYes(sp, currentRow, event); 358 } else { 359 collectHandlerNo(sp, currentRow, event); 360 } 361 sp.timerShaftEL?.displayCollect(sp.collectRows.length !== 0); 362 sp.refreshFavoriteCanvas(); 363 sp.refreshCanvas(true); 364 sp.linkNodes.forEach((itln) => { 365 if (itln[0].rowEL === currentRow) { 366 if (itln[0].rowEL.collect) { 367 itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195; 368 } else { 369 itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - sp.rowsPaneEL!.scrollTop; 370 } 371 itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY; 372 } else if (itln[1].rowEL === currentRow) { 373 if (itln[1].rowEL.collect) { 374 itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195; 375 } else { 376 itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - sp.rowsPaneEL!.scrollTop; 377 } 378 itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY; 379 } 380 }); 381 // 收藏夹元素拖动排序功能 382 sp.currentClickRow = null; 383 currentRow.setAttribute('draggable', 'true'); 384 currentRow.addEventListener('dragstart', () => { 385 sp.currentClickRow = currentRow; 386 }); 387 currentRow.addEventListener('dragover', (ev: unknown) => { 388 // @ts-ignore 389 ev.preventDefault(); 390 // @ts-ignore 391 ev.dataTransfer.dropEffect = 'move'; 392 }); 393 currentRow.addEventListener('drop', collectHandlerDrop(sp, currentRow)); 394 currentRow.addEventListener('dragend', collectHandlerDragEnd(sp)); 395 }; 396} 397function collectHandlerNo(sp: SpSystemTrace, currentRow: unknown, event: unknown): void { 398 // @ts-ignore 399 sp.favoriteChartListEL?.deleteRow(currentRow, event.detail.type !== 'auto-collect'); 400 // @ts-ignore 401 if (event.detail.type !== 'auto-collect') { 402 // @ts-ignore 403 let rowIndex = sp.collectRows.indexOf(currentRow); 404 if (rowIndex !== -1) { 405 sp.collectRows.splice(rowIndex, 1); 406 } 407 } 408 let row = currentRow; 409 let allowExpansionRow = []; 410 // @ts-ignore 411 while (row.hasParentRowEl) { 412 // @ts-ignore 413 let parent = row.parentRowEl; 414 allowExpansionRow.push(parent); 415 row = parent; 416 } 417 if (allowExpansionRow.length === 1) { 418 for (let index: number = allowExpansionRow.length - 1; index >= 0; index--) { 419 if (allowExpansionRow[index]?.hasAttribute('scene')) { 420 if (allowExpansionRow[index]!.expansion) { 421 allowExpansionRow[index].updateChildRowStatus(); 422 } else { 423 allowExpansionRow[index].expansion = true; 424 } 425 } 426 } 427 } else { 428 for (let index: number = allowExpansionRow.length - 1; index >= 0; index--) { 429 let currentItemRow = allowExpansionRow[index]; 430 if (currentItemRow.hasAttribute('scene')) { 431 if (currentItemRow.rowParentId !== '') { 432 if (currentItemRow.expansion) { 433 currentItemRow.updateChildRowStatus(); 434 } else { 435 currentItemRow.expansion = true; 436 } 437 } 438 else { 439 currentItemRow.expansion = true; 440 let number = currentItemRow.childrenList.indexOf(currentRow); 441 if (number !== -1) {// 确保 currentRow 在 childrenList 中 442 let childrenEl = currentItemRow.childrenList[number]; 443 let childrenNextEl = currentItemRow.childrenList[number + 1]; 444 if (childrenEl) { 445 if (childrenNextEl) { 446 currentItemRow.parentNode.insertBefore(childrenEl, currentItemRow.childrenList[number + 1]); 447 } else if (childrenEl.nextSibling) { 448 currentItemRow.parentNode.insertBefore(childrenEl, childrenEl.nextSibling); 449 } else { 450 currentItemRow.parentNode.appendChild(childrenEl); 451 } 452 } 453 } 454 } 455 } 456 } 457 } 458 allowExpansionRow.length = 0; 459 // @ts-ignore 460 let traceId = currentRow.traceId ? `${currentRow.traceId}-` : ''; 461 let replaceRow = sp.rowsEL!.querySelector<HTMLCanvasElement>( 462 // @ts-ignore 463 `div[row-id='${traceId}${currentRow.rowId}-${currentRow.rowType}']` 464 ); 465 //@ts-ignore 466 if (currentRow!.tampName.startsWith("CallChart")) { 467 // @ts-ignore 468 let index = currentRow!.name.indexOf(']') + 1; 469 // @ts-ignore 470 currentRow!.tampName = index !== -1 ? currentRow!.name.substring(0, index) : currentRow!.name; 471 } 472 // 取消收藏时,删除父亲ID 473 // @ts-ignore 474 currentRow.name = currentRow.tampName; 475 //@ts-ignore xpower转换名称 476 if (currentRow.rowType === 'xpower-system' || (currentRow.parentRowEl && currentRow.parentRowEl.rowType === 'xpower-bundle-name-group')) { 477 //@ts-ignore 478 let titleEl = currentRow.shadowRoot?.querySelector('.name') as HTMLLabelElement; 479 //@ts-ignore 480 titleEl.title = convertTitle(currentRow.tampName); 481 } 482 if (replaceRow !== null) { 483 // @ts-ignore 484 sp.rowsEL!.replaceChild(currentRow, replaceRow); 485 // @ts-ignore 486 currentRow.style.boxShadow = '0 10px 10px #00000000'; 487 } 488} 489function collectHandlerYes(sp: SpSystemTrace, currentRow: unknown, event: unknown): void { 490 if (!sp.collectRows.find((find) => find === currentRow)) { 491 // @ts-ignore 492 sp.collectRows.push(currentRow); 493 } 494 let replaceRow = document.createElement('div'); 495 // @ts-ignore 496 let traceId = currentRow.traceId ? `${currentRow.traceId}-` : ''; 497 // @ts-ignore 498 replaceRow.setAttribute('row-id', `${traceId}${currentRow.rowId}-${currentRow.rowType}`); 499 replaceRow.setAttribute('type', 'replaceRow'); 500 // @ts-ignore 501 replaceRow.setAttribute('row-parent-id', currentRow.rowParentId); 502 replaceRow.style.display = 'none'; 503 // @ts-ignore 504 if (!currentRow.hasAttribute('scene')) { 505 // @ts-ignore 506 currentRow.setAttribute('row-hidden', ''); 507 } else { 508 // @ts-ignore 509 currentRow.removeAttribute('row-hidden'); 510 } 511 // 添加收藏时,在线程名前面追加父亲ID 512 // @ts-ignore 513 let rowParentId = currentRow.rowParentId; 514 // @ts-ignore 515 currentRow.tampName = currentRow.name; 516 if (rowParentId) { 517 // @ts-ignore 518 let parentRows = sp.shadowRoot?.querySelectorAll<TraceRow<unknown>>(`trace-row[row-id='${rowParentId}']`); 519 parentRows?.forEach((parentRow) => { 520 if ( 521 parentRow?.name && 522 // @ts-ignore 523 parentRow?.name !== currentRow.name && 524 !parentRow.rowType!.startsWith('cpu') && 525 !parentRow.rowType!.startsWith('thread') && 526 !parentRow.rowType!.startsWith('func') && 527 // @ts-ignore 528 !currentRow.name.includes(parentRow.name) 529 ) { 530 //@ts-ignore 531 currentRow.name = currentRow.protoParentId ? `${currentRow.name} (${currentRow.protoParentId})` : 532 //@ts-ignore 533 `${currentRow.name} (${parentRow.name})`; 534 } 535 }); 536 } 537 // @ts-ignore 538 if (!currentRow.hasParentRowEl) { 539 // @ts-ignore 540 sp.rowsEL!.replaceChild(replaceRow, currentRow); 541 } 542 //@ts-ignore xpower转换名称 543 if (currentRow.rowType === 'xpower-system' || (currentRow.parentRowEl && currentRow.parentRowEl.rowType === 'xpower-bundle-name-group')) { 544 //@ts-ignore 545 let titleEl = currentRow.shadowRoot?.querySelector('.name') as HTMLLabelElement; 546 //@ts-ignore 547 titleEl.title = convertTitle(currentRow.tampName); 548 } 549 // @ts-ignore 550 let group = currentRow.traceId || sp.currentCollectGroup; 551 // @ts-ignore 552 sp.favoriteChartListEL?.insertRow(currentRow, group, event.detail.type !== 'auto-collect'); 553} 554function collectHandlerDrop(sp: SpSystemTrace, currentRow: HTMLDivElement | undefined | null): (ev: unknown) => void { 555 return function (ev: unknown) { 556 if (sp.favoriteChartListEL !== null && sp.currentClickRow !== null && sp.currentClickRow !== currentRow) { 557 // @ts-ignore 558 let rect = currentRow!.getBoundingClientRect(); 559 // @ts-ignore 560 if (ev.clientY >= rect.top && ev.clientY < rect.top + rect.height / 2) { 561 //向上移动 562 sp.favoriteChartListEL!.insertRowBefore(sp.currentClickRow!, currentRow!); 563 // @ts-ignore 564 } else if (ev.clientY <= rect.bottom && ev.clientY > rect.top + rect.height / 2) { 565 //向下移动 566 sp.favoriteChartListEL!.insertRowBefore(sp.currentClickRow!, currentRow!.nextSibling!); 567 } 568 sp.refreshFavoriteCanvas(); 569 } 570 }; 571} 572function collectHandlerDragEnd(sp: SpSystemTrace): (ev: unknown) => void { 573 return function (ev: unknown): void { 574 sp.linkNodes.forEach((itln) => { 575 if (itln[0].rowEL.collect) { 576 if (sp.timerShaftEL?._checkExpand) { 577 itln[0].rowEL.translateY = 578 itln[0].rowEL.getBoundingClientRect().top - 195 + sp.timerShaftEL._usageFoldHeight!; 579 } else { 580 itln[0].rowEL.translateY = itln[0].rowEL.getBoundingClientRect().top - 195; 581 } 582 } else { 583 itln[0].rowEL.translateY = itln[0].rowEL.offsetTop - sp.rowsPaneEL!.scrollTop; 584 } 585 if (itln[1].rowEL.collect) { 586 if (sp.timerShaftEL?._checkExpand) { 587 itln[1].rowEL.translateY = 588 itln[1].rowEL.getBoundingClientRect().top - 195 + sp.timerShaftEL._usageFoldHeight!; 589 } else { 590 itln[1].rowEL.translateY = itln[1].rowEL.getBoundingClientRect().top - 195; 591 } 592 } else { 593 itln[1].rowEL.translateY = itln[1].rowEL.offsetTop - sp.rowsPaneEL!.scrollTop; 594 } 595 itln[0].y = itln[0].rowEL.translateY + itln[0].offsetY; 596 itln[1].y = itln[1].rowEL.translateY + itln[1].offsetY; 597 }); 598 sp.currentClickRow = null; 599 }; 600} 601function selectHandler(sp: SpSystemTrace): void { 602 sp.rangeSelect.selectHandler = (rows, refreshCheckBox): void => { 603 rows.forEach((item) => { 604 sp.setAttribute('clickRow', item.rowType!); 605 sp.setAttribute('rowName', item.name); 606 sp.setAttribute('rowId', item.rowId!); 607 }); 608 if (rows.length === 0) { 609 const allRows = [ 610 // @ts-ignore 611 ...sp.shadowRoot!.querySelectorAll<TraceRow<unknown>>('trace-row'), 612 ...sp.favoriteChartListEL!.getAllCollectRows(), 613 ]; 614 for (const row of allRows) { 615 row.checkType = '-1'; 616 if (row.folder) { 617 row.childrenList.forEach((item) => { 618 row.checkType = '-1'; 619 }); 620 } 621 } 622 sp.refreshCanvas(true); 623 if (!SportRuler.isMouseInSportRuler) { 624 sp.traceSheetEL?.setMode('max'); 625 sp.traceSheetEL?.setMode('hidden'); 626 } 627 return; 628 } 629 let checkRows = rows; 630 if (!refreshCheckBox) { 631 checkRows = [ 632 ...rows, 633 // @ts-ignore 634 ...sp.shadowRoot!.querySelectorAll<TraceRow<unknown>>(`trace-row[check-type='2']`), 635 ...sp.favoriteChartListEL!.getAllSelectCollectRows(), 636 ]; 637 } 638 checkRows = checkRows.filter((item, index, self) => { 639 return self.findIndex( 640 obj => obj.rowId === item.rowId && obj.rowType === item.rowType && obj.name === item.name && obj.rowParentId === item.rowParentId 641 ) === index; 642 }); 643 selectHandlerRefreshCheckBox(sp, checkRows, refreshCheckBox); 644 if (!sp.isSelectClick) { 645 sp.rangeTraceRow = []; 646 } 647 selectHandlerRows(sp, checkRows); 648 }; 649} 650// @ts-ignore 651function selectHandlerRefreshCheckBox(sp: SpSystemTrace, rows: Array<TraceRow<unknown>>, refreshCheckBox: boolean): void { 652 if (refreshCheckBox) { 653 if (rows.length > 0) { 654 sp.queryAllTraceRow().forEach((row) => (row.checkType = '0')); 655 rows.forEach((it) => (it.checkType = '2')); 656 } else { 657 sp.queryAllTraceRow().forEach((row) => (row.checkType = '-1')); 658 return; 659 } 660 } 661} 662// @ts-ignore 663function selectHandlerRows(sp: SpSystemTrace, rows: Array<TraceRow<unknown>>): void { 664 Utils.isRangeSelectRefresh = true; 665 let selection = new SelectionParam(); 666 selection.traceId = Utils.currentSelectTrace; 667 selection.cpuStateRowsId = sp.stateRowsId; 668 selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0; 669 selection.rightNs = TraceRow.rangeSelectObject?.endNS || 0; 670 selection.recordStartNs = Utils.getInstance().getRecordStartNS(Utils.currentSelectTrace); 671 rows.forEach((it) => { 672 selection.pushSelection(it, sp); 673 if (sp.rangeTraceRow!.length !== rows.length) { 674 let event = sp.createPointEvent(it); 675 SpStatisticsHttpUtil.addOrdinaryVisitAction({ 676 action: 'trace_row', // @ts-ignore 677 event: event, 678 }); 679 } 680 sp.setParentCheckStatus(it); 681 }); 682 if (selection.diskIOipids.length > 0 && !selection.diskIOLatency) { 683 selection.promiseList.push( 684 queryEbpfSamplesCount( 685 TraceRow.rangeSelectObject?.startNS || 0, 686 TraceRow.rangeSelectObject?.endNS || 0, 687 selection.diskIOipids 688 ).then((res) => { 689 if (res.length > 0) { 690 //@ts-ignore 691 selection.fsCount = res[0].fsCount; 692 //@ts-ignore 693 selection.vmCount = res[0].vmCount; 694 } 695 return new Promise((resolve) => resolve(1)); 696 }) 697 ); 698 } 699 sp.rangeTraceRow = rows; 700 sp.isSelectClick = false; 701 sp.selectStructNull(); 702 sp.timerShaftEL?.removeTriangle('inverted'); 703 if (selection.promiseList.length > 0) { 704 Promise.all(selection.promiseList).then(() => { 705 selection.promiseList = []; 706 sp.traceSheetEL?.rangeSelect(selection); 707 }); 708 } else { 709 sp.traceSheetEL?.rangeSelect(selection); 710 } 711 sp.timerShaftEL!.selectionList.push(selection); // 保持选中对象,为后面的再次选中该框选区域做准备。 712 sp.selectionParam = selection; 713 sp.refreshCanvas(true); 714} 715function resizeObserverHandler(sp: SpSystemTrace): void { 716 // @ts-ignore 717 new ResizeObserver((entries) => { 718 TraceRow.FRAME_WIDTH = sp.clientWidth - 249 - sp.getScrollWidth(); 719 requestAnimationFrame(() => { 720 sp.timerShaftEL?.updateWidth(sp.clientWidth - 1 - sp.getScrollWidth()); 721 // @ts-ignore 722 sp.shadowRoot!.querySelectorAll<TraceRow<unknown>>('trace-row').forEach((it) => { 723 it.updateWidth(sp.clientWidth); 724 }); 725 }); 726 }).observe(sp); 727 728 new ResizeObserver((entries) => { 729 sp.canvasPanelConfig(); 730 if (sp.traceSheetEL!.getAttribute('mode') === 'hidden') { 731 sp.timerShaftEL?.removeTriangle('triangle'); 732 } 733 if (sp.favoriteChartListEL?.style.display === 'flex') { 734 sp.refreshFavoriteCanvas(); 735 } 736 sp.refreshCanvas(true); 737 }).observe(sp.rowsPaneEL!); 738} 739function mutationObserverHandler(sp: SpSystemTrace): void { 740 new MutationObserver((mutations, observer) => { 741 for (const mutation of mutations) { 742 if (mutation.type === 'attributes') { 743 if (sp.style.visibility === 'visible') { 744 if (TraceRow.rangeSelectObject && SpSystemTrace.sliceRangeMark) { 745 sp.timerShaftEL?.setSlicesMark( 746 TraceRow.rangeSelectObject.startNS || 0, 747 TraceRow.rangeSelectObject.endNS || 0, 748 false 749 ); 750 SpSystemTrace.sliceRangeMark = undefined; 751 window.publish(window.SmartEvent.UI.RefreshCanvas, {}); 752 } 753 } 754 } 755 } 756 }).observe(sp, { 757 attributes: true, 758 childList: false, 759 subtree: false, 760 }); 761} 762function intersectionObserverHandler(sp: SpSystemTrace): void { 763 sp.intersectionObserver = new IntersectionObserver( 764 (entries) => { 765 entries.forEach((it) => { 766 // @ts-ignore 767 let tr = it.target as TraceRow<unknown>; 768 // 目标元素的可见比例 769 tr.intersectionRatio = it.intersectionRatio; 770 // 判断目标元素是否可见 isIntersecting为true是可见 771 if (!it.isIntersecting) { 772 tr.sleeping = true; 773 sp.invisibleRows.indexOf(tr) === -1 && sp.invisibleRows.push(tr); 774 } else { 775 tr.sleeping = false; 776 sp.visibleRows.indexOf(tr) === -1 && sp.visibleRows.push(tr); 777 } 778 }); 779 //更新可见泳道及不可见泳道值 780 sp.visibleRows = sp.visibleRows.filter((it) => !it.sleeping); 781 sp.invisibleRows = sp.invisibleRows.filter((it) => it.sleeping); 782 if (sp.handler === -1) { 783 cancelAnimationFrame(sp.handler); 784 } 785 sp.handler = requestAnimationFrame(() => sp.refreshCanvas(false)); 786 }, 787 { threshold: [0, 0.01, 0.99, 1] } 788 ); 789} 790function observerHandler(sp: SpSystemTrace): void { 791 resizeObserverHandler(sp); 792 mutationObserverHandler(sp); 793 intersectionObserverHandler(sp); 794} 795function windowKeyDownHandler(sp: SpSystemTrace): (ev: KeyboardEvent) => void { 796 return function (ev: KeyboardEvent) { 797 if (ev.key.toLocaleLowerCase() === 'escape') { 798 sp.queryAllTraceRow().forEach((it) => { 799 it.checkType = '-1'; 800 }); 801 TraceRow.rangeSelectObject = undefined; 802 sp.rangeSelect.rangeTraceRow = []; 803 sp.selectStructNull(); 804 sp.timerShaftEL?.setSlicesMark(); 805 sp.traceSheetEL?.setMode('hidden'); 806 sp.removeLinkLinesByBusinessType('janks', 'task'); 807 } 808 }; 809} 810function smartEventSubscribe(sp: SpSystemTrace): void { 811 window.subscribe(window.SmartEvent.UI.SliceMark, (data) => sp.sliceMarkEventHandler(data)); 812 window.subscribe(window.SmartEvent.UI.TraceRowComplete, (tr) => { }); 813 window.subscribe(window.SmartEvent.UI.RefreshCanvas, () => sp.refreshCanvas(false)); 814 window.subscribe(window.SmartEvent.UI.KeyboardEnable, (tr) => { 815 //@ts-ignore 816 sp.keyboardEnable = tr.enable; 817 if (!sp.keyboardEnable) { 818 sp.stopWASD(); 819 } 820 }); //@ts-ignore 821 window.subscribe(window.SmartEvent.UI.CollapseAllLane, (collapse: boolean) => { 822 if (!collapse) { 823 // 一键折叠之前,记录当前打开的泳道图 824 // @ts-ignore 825 sp.expandRowList = Array.from(sp.rowsEL!.querySelectorAll<TraceRow<unknown>>('trace-row[folder][expansion]')) || []; 826 } 827 sp.collapseAll = true; 828 sp.setAttribute('disable', ''); 829 sp.expandRowList!.forEach((it) => (it.expansion = collapse)); 830 sp.collapseAll = false; 831 sp.removeAttribute('disable'); 832 sp.refreshCanvas(true); 833 }); 834 window.subscribe(window.SmartEvent.UI.MouseEventEnable, (tr) => { 835 //@ts-ignore 836 sp.mouseEventEnable = tr.mouseEnable; 837 if (sp.mouseEventEnable) { 838 sp.removeAttribute('disable'); 839 } else { 840 sp.setAttribute('disable', ''); 841 } 842 }); //@ts-ignore 843 window.subscribe(window.SmartEvent.UI.CollectGroupChange, (group: string) => (sp.currentCollectGroup = group)); 844} 845 846export function documentInitEvent(sp: SpSystemTrace): void { 847 if (!document) { 848 return; 849 } 850 document.addEventListener('triangle-flag', triangleFlagHandler(sp)); 851 document.addEventListener('number_calibration', numberCalibrationHandler(sp)); 852 document.addEventListener('flag-change', flagChangeHandler(sp)); 853 document.addEventListener('slices-change', slicesChangeHandler(sp)); 854 if (sp.timerShaftEL?.collecBtn) { 855 sp.timerShaftEL.collecBtn.onclick = (): void => { 856 if (sp.timerShaftEL!.collecBtn!.hasAttribute('close')) { 857 sp.timerShaftEL!.collecBtn!.removeAttribute('close'); 858 sp.favoriteChartListEL?.showCollectArea(); 859 } else { 860 sp.timerShaftEL!.collecBtn!.setAttribute('close', ''); 861 sp.favoriteChartListEL?.hideCollectArea(); 862 } 863 }; 864 } 865 document.addEventListener('collect', collectHandler(sp)); 866} 867 868export function spSystemTraceInitElement(sp: SpSystemTrace): void { 869 window.subscribe(window.SmartEvent.UI.LoadFinishFrame, () => sp.drawAllLines()); 870 sp.traceSheetEL = sp.shadowRoot?.querySelector<TraceSheet>('.trace-sheet'); 871 if (!sp || !sp.shadowRoot || !sp.traceSheetEL) { 872 return; 873 } 874 let rightButton: HTMLElement | null | undefined = sp.traceSheetEL.shadowRoot 875 ?.querySelector('#current-selection > tabpane-current-selection') 876 ?.shadowRoot?.querySelector('#rightButton'); 877 let rightStar: HTMLElement | null | undefined = sp.traceSheetEL.shadowRoot 878 ?.querySelector('#current-selection > tabpane-current-selection') 879 ?.shadowRoot?.querySelector('#right-star'); 880 sp.tipEL = sp.shadowRoot.querySelector<HTMLDivElement>('.tip'); 881 sp.rowsPaneEL = sp.shadowRoot.querySelector<HTMLDivElement>('.rows-pane'); 882 sp.rowsEL = sp.rowsPaneEL; 883 sp.spacerEL = sp.shadowRoot.querySelector<HTMLDivElement>('.spacer'); 884 sp.timerShaftEL = sp.shadowRoot.querySelector<TimerShaftElement>('.timer-shaft'); 885 sp.favoriteChartListEL = sp.shadowRoot.querySelector<SpChartList>('#favorite-chart-list'); 886 sp.collectEl1 = sp.favoriteChartListEL?.shadowRoot?.querySelector<HTMLDivElement>('#collect-group-1'); 887 sp.collectEl2 = sp.favoriteChartListEL?.shadowRoot?.querySelector<HTMLDivElement>('#collect-group-2'); 888 sp.groupTitle1 = sp.favoriteChartListEL?.shadowRoot?.querySelector<HTMLDivElement>('#group-1-title'); 889 sp.groupTitle2 = sp.favoriteChartListEL?.shadowRoot?.querySelector<HTMLDivElement>('#group-2-title'); 890 if (!sp.traceSheetEL.shadowRoot) { 891 return; 892 } 893 sp.tabCpuFreq = sp.traceSheetEL.shadowRoot.querySelector<TabPaneFrequencySample>('tabpane-frequency-sample'); 894 sp.tabCpuState = sp.traceSheetEL.shadowRoot.querySelector<TabPaneCounterSample>('tabpane-counter-sample'); 895 sp.wakeupListTbl = sp.traceSheetEL.shadowRoot?.querySelector('#current-selection > tabpane-current-selection')?. 896 shadowRoot?.querySelector('#wakeupListTbl'); 897 sp.rangeSelect = new RangeSelect(sp); 898 // @ts-ignore 899 rightButton?.addEventListener('click', rightButtonOnClick(sp, rightStar)); 900 rightStar?.addEventListener('click', rightStarOnClick(sp)); 901 documentInitEvent(sp); 902 SpSystemTrace.scrollViewWidth = sp.getScrollWidth(); 903 selectHandler(sp); 904 observerHandler(sp); 905 window.addEventListener('keydown', windowKeyDownHandler(sp)); 906 sp.chartManager = new SpChartManager(sp); 907 sp.canvasPanel = sp.shadowRoot.querySelector<HTMLCanvasElement>('#canvas-panel')!; 908 sp.canvasPanelCtx = sp.canvasPanel.getContext('2d'); 909 sp.canvasFavoritePanelCtx = sp.favoriteChartListEL!.context(); 910 sp.canvasPanelConfig(); 911 smartEventSubscribe(sp); 912} 913 914function moveRangeToCenterAndHighlight(sp: SpSystemTrace, findEntry: unknown, currentEntry: unknown): void { 915 if (findEntry) { 916 //findEntry不在range范围内,会把它移动到泳道最左侧 917 // @ts-ignore 918 if (findEntry.startTime + findEntry.dur > TraceRow.range!.endNS || findEntry.startTime < TraceRow.range!.startNS) { 919 // @ts-ignore 920 sp.moveRangeToLeft(findEntry.startTime!, findEntry.dur!); 921 } 922 cancelCurrentTraceRowHighlight(sp, currentEntry); 923 // @ts-ignore 924 if (findEntry.type === 'cpu') { 925 findEntryTypeCpu(sp, findEntry); 926 // @ts-ignore 927 } else if (findEntry.type === 'func') { 928 findEntryTypeFunc(sp, findEntry); 929 // @ts-ignore 930 } else if (findEntry.type === 'thread||process') { 931 findEntryTypeThreadProcess(sp, findEntry); 932 // @ts-ignore 933 } else if (findEntry.type === 'sdk') { 934 findEntryTypeSdk(sp, findEntry); 935 } 936 } 937} 938 939export function cancelCurrentTraceRowHighlight(sp: SpSystemTrace, currentEntry: unknown): void { 940 // @ts-ignore 941 if (currentEntry?.type === 'cpu') { 942 // @ts-ignore 943 sp.queryAllTraceRow(`trace-row[row-type='cpu-data'][row-id='${currentEntry.cpu}']`, 944 // @ts-ignore 945 (row) => row.rowType === 'cpu-data' && row.rowId === `${currentEntry.cpu}`)[0].highlight = false; 946 // @ts-ignore 947 } else if (currentEntry?.type === 'func') { 948 // @ts-ignore 949 let funId = (currentEntry.rowId === null || currentEntry.rowId === undefined) ? `${currentEntry.funName}-${currentEntry.pid}` : currentEntry.rowId; 950 // @ts-ignore 951 let funcRowID = (currentEntry.cookie === null || currentEntry.cookie === undefined) ? `${Utils.getDistributedRowId(currentEntry.tid)}` : funId; 952 // @ts-ignore 953 let parentRow = sp.queryAllTraceRow(`trace-row[row-id='${Utils.getDistributedRowId(currentEntry.pid)}'][folder]`, 954 // @ts-ignore 955 (row) => row.rowId === `trace-row[row-id='${Utils.getDistributedRowId(currentEntry.pid)}'][folder]`)[0]; 956 if (!parentRow) { 957 return; 958 } 959 // @ts-ignore 960 let filterRow: TraceRow<unknown> | undefined; 961 parentRow.childrenList.forEach((item) => { 962 if (item.rowId === 'sameThreadProcess') { 963 filterRow = parentRow.childrenList.concat(item.childrenList).filter((child) => child.rowId === funcRowID && child.rowType === 'func')[0]; 964 } else { 965 filterRow = parentRow.childrenList.filter((child) => child.rowId === funcRowID && child.rowType === 'func')[0]; 966 } 967 }); 968 if (!filterRow) { 969 let rowsPaneEL = document.querySelector('body > sp-application')?.shadowRoot?.querySelector('#sp-system-trace')?.shadowRoot?.querySelector('div > div.rows-pane'); 970 // @ts-ignore 971 let funcRow = rowsPaneEL?.querySelector<TraceRow<unknown>>(`trace-row[row-id='${funcRowID}'][row-type='func']`); 972 if (funcRow) { 973 filterRow = funcRow; 974 } else { 975 return; 976 } 977 } 978 filterRow.highlight = false; 979 // @ts-ignore 980 } else if (currentEntry?.type === 'sdk') { 981 // @ts-ignore 982 let parentRow = sp.shadowRoot!.querySelector<TraceRow<unknown>>("trace-row[row-type='sdk'][folder]"); 983 if (parentRow) { 984 let sdkRow = parentRow.childrenList.filter( 985 // @ts-ignore 986 (child) => child.rowId === currentEntry.rowId && child.rowType === currentEntry.rowType 987 )[0]; 988 sdkRow!.highlight = false; 989 } 990 } 991} 992 993export function spSystemTraceShowStruct( 994 sp: SpSystemTrace, 995 previous: boolean, 996 currentIndex: number, 997 structs: Array<unknown>, 998 retargetIndex?: number 999): number { 1000 if (structs.length === 0) { 1001 return 0; 1002 } 1003 let findIndex = spSystemTraceShowStructFindIndex(previous, currentIndex, structs, retargetIndex); 1004 let findEntry: unknown = structs[findIndex]; 1005 let currentEntry: unknown = undefined; 1006 if (currentIndex >= 0) { 1007 currentEntry = structs[currentIndex]; 1008 } 1009 moveRangeToCenterAndHighlight(sp, findEntry, currentEntry); 1010 return findIndex; 1011} 1012 1013function spSystemTraceShowStructFindIndex( 1014 previous: boolean, 1015 currentIndex: number, 1016 structs: Array<unknown>, 1017 retargetIndex: number | undefined 1018): number { 1019 const rangeStart = TraceRow.range!.startNS; 1020 const rangeEnd = TraceRow.range!.endNS; 1021 let findIndex = -1; 1022 if (retargetIndex) {//如果Go有值,直接跳转 1023 findIndex = retargetIndex - 1; 1024 } else if (previous) { 1025 //case1:current.start在start边界以右,需要从当前项往第一项遍历,找到structs[index].start < end 1026 //@ts-ignore 1027 if (structs[currentIndex].startTime! >= Math.round(rangeStart)) { 1028 findIndex = findPreviousOne(currentIndex - 1, 0, structs); 1029 //处理当前项如果是第一项 1030 findIndex = findIndex === -1 ? structs.length - 1 : findIndex; 1031 } else { 1032 //case2:current.start在start边界以左,需要从最后一项到当前项遍历,找到structs[index].start < end 1033 findIndex = findPreviousOne(structs.length - 1, currentIndex + 1, structs); 1034 } 1035 } else {//向后查找 1036 if (currentIndex === -1) {//输入框内输入内容后第一次搜索 1037 findIndex = findNextOne(0, structs.length - 1, structs); 1038 //处理当所有的项都在start以左 1039 return findIndex === -1 ? 0 : findIndex; 1040 } 1041 //case1:current.start 在end左侧 从当前项到最后一项遍历,找到startTime>start 1042 //@ts-ignore 1043 if (structs[currentIndex].startTime! < Math.round(rangeEnd)) {//case1 1044 findIndex = findNextOne(currentIndex + 1, structs.length - 1, structs); 1045 //处理当前项是最后一项 1046 findIndex = findIndex === -1 ? 0 : findIndex; 1047 } else { 1048 //case2: current.start 在end右侧 从第一项到当前项遍历,找到startTime>start 1049 findIndex = findNextOne(0, currentIndex - 1, structs); 1050 } 1051 } 1052 return findIndex; 1053} 1054//向前查找逻辑 1055function findPreviousOne(start: number, end: number, structs: Array<unknown>): number { 1056 let findIndex = -1; 1057 const rangeEnd = TraceRow.range!.endNS; 1058 for (let i = start; i >= end; i--) { 1059 let it = structs[i]; 1060 //@ts-ignore 1061 if (it.startTime! < rangeEnd) { 1062 findIndex = i; 1063 break; 1064 } 1065 } 1066 return findIndex; 1067} 1068//向后查找 1069function findNextOne(start: number, end: number, structs: Array<unknown>): number { 1070 let findIndex = -1; 1071 const rangeStart = TraceRow.range!.startNS; 1072 for (let i = start; i <= end; i++) { 1073 let it = structs[i]; 1074 //@ts-ignore 1075 if (it.startTime > rangeStart) { 1076 findIndex = i; 1077 break; 1078 } 1079 } 1080 return findIndex; 1081} 1082function findEntryTypeCpu(sp: SpSystemTrace, findEntry: unknown): void { 1083 // @ts-ignore 1084 CpuStruct.selectCpuStruct = findEntry; 1085 CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; 1086 sp.queryAllTraceRow(`trace-row[row-type='cpu-data']`, (row): boolean => row.rowType === 'cpu-data').forEach( 1087 (item): void => { 1088 // @ts-ignore 1089 if (item.rowId === `${Utils.getDistributedRowId(findEntry.cpu)}`) { 1090 sp.rechargeCpuData( 1091 // @ts-ignore 1092 findEntry, // @ts-ignore 1093 item.dataListCache.find((it) => it.startTime > findEntry.startTime) 1094 ); 1095 let _findEntry = JSON.parse(JSON.stringify(findEntry)); 1096 _findEntry.type = 'thread'; 1097 item.fixedList = [_findEntry]; 1098 } 1099 // @ts-ignore 1100 item.highlight = item.rowId === `${Utils.getDistributedRowId(findEntry.cpu)}`; 1101 item.draw(true); 1102 } 1103 ); 1104 // @ts-ignore 1105 sp.scrollToProcess(`${findEntry.cpu}`, '', 'cpu-data', true); 1106 sp.onClickHandler(TraceRow.ROW_TYPE_CPU); 1107} 1108function findEntryTypeFunc(sp: SpSystemTrace, findEntry: unknown): void { 1109 sp.observerScrollHeightEnable = true; 1110 sp.scrollToActFunc( 1111 { 1112 // @ts-ignore 1113 startTs: findEntry.startTime, 1114 // @ts-ignore 1115 dur: findEntry.dur, 1116 // @ts-ignore 1117 tid: findEntry.tid, 1118 // @ts-ignore 1119 pid: findEntry.pid, 1120 // @ts-ignore 1121 depth: findEntry.depth, 1122 // @ts-ignore 1123 argsetid: findEntry.argsetid, 1124 // @ts-ignore 1125 funName: findEntry.funName, 1126 // @ts-ignore 1127 cookie: findEntry.cookie, 1128 // @ts-ignore 1129 trace_level: findEntry.trace_level, 1130 // @ts-ignore 1131 trace_tag: findEntry.trace_tag, 1132 // @ts-ignore 1133 custom_args: findEntry.custom_args, 1134 // @ts-ignore 1135 category:findEntry.category, 1136 // @ts-ignore 1137 //因异步trace分类出的rowId类型有三种,故新增row_id字段,该字段为异步方法的对应的rowId,支持搜索查询定位到该方法属于那个row,只有缓存的异步trace数据中含该字段 1138 row_id: findEntry.rowId ? findEntry.rowId : null, 1139 }, 1140 true 1141 ); 1142} 1143function findEntryTypeThreadProcess(sp: SpSystemTrace, findEntry: unknown): void { 1144 let threadProcessRow = sp.rowsEL?.querySelectorAll<TraceRow<ThreadStruct>>('trace-row')[0]; 1145 if (threadProcessRow) { 1146 let filterRow = threadProcessRow.childrenList.filter( 1147 // @ts-ignore 1148 (row) => row.rowId === Utils.getDistributedRowId(findEntry.rowId) && row.rowId === findEntry.rowType 1149 )[0]; 1150 filterRow!.highlight = true; 1151 // @ts-ignore 1152 sp.closeAllExpandRows(Utils.getDistributedRowId(findEntry.rowParentId)); 1153 // @ts-ignore 1154 sp.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); 1155 let completeEntry = (): void => { 1156 sp.hoverStructNull(); 1157 sp.selectStructNull(); 1158 sp.wakeupListNull(); 1159 // @ts-ignore 1160 sp.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); 1161 }; 1162 if (filterRow!.isComplete) { 1163 completeEntry(); 1164 } else { 1165 filterRow!.onComplete = completeEntry; 1166 } 1167 } 1168} 1169function findEntryTypeSdk(sp: SpSystemTrace, findEntry: unknown): void { 1170 // @ts-ignore 1171 let parentRow = sp.shadowRoot!.querySelector<TraceRow<unknown>>(`trace-row[row-type='sdk'][folder]`); 1172 if (parentRow) { 1173 let sdkRow = parentRow.childrenList.filter( 1174 // @ts-ignore 1175 (child) => child.rowId === findEntry.rowId && child.rowType === findEntry.rowType 1176 )[0]; 1177 sdkRow!.highlight = true; 1178 } 1179 sp.hoverStructNull(); 1180 sp.selectStructNull(); 1181 sp.wakeupListNull(); 1182 // @ts-ignore 1183 sp.onClickHandler(findEntry.rowType!); 1184 // @ts-ignore 1185 sp.closeAllExpandRows(findEntry.rowParentId); 1186 // @ts-ignore 1187 sp.scrollToProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); 1188} 1189async function spSystemTraceInitBuffer( 1190 sp: SpSystemTrace, 1191 param: { buf?: ArrayBuffer; Url?: string; buf2?: ArrayBuffer }, 1192 wasmConfigUri: string, 1193 configUri: string, 1194 progress: Function 1195): Promise<{ 1196 status: boolean; 1197 msg: string; 1198} | null> { 1199 if (param.buf) { 1200 let configJson = ''; 1201 try { 1202 configJson = await fetch(wasmConfigUri).then((res) => res.text()); 1203 } catch (e) { 1204 error('getWasmConfigFailed', e); 1205 } 1206 let parseConfig = FlagsConfig.getSpTraceStreamParseConfig(); 1207 let systemParseConfigJson = ''; 1208 try { 1209 systemParseConfigJson = await fetch(configUri).then((res) => res.text()); 1210 let systemParseConfig = JSON.parse(systemParseConfigJson); 1211 let parseConfigObj = JSON.parse(parseConfig); 1212 systemParseConfig.config = parseConfigObj.config; 1213 systemParseConfigJson = JSON.stringify(systemParseConfig); 1214 } catch (e) { 1215 systemParseConfigJson = parseConfig; 1216 error('systemParseConfigJsonFailed', e); 1217 } 1218 let { status, msg, sdkConfigMap } = await threadPool.initSqlite(param.buf, systemParseConfigJson, configJson, progress); 1219 if (!status) { 1220 return { status: false, msg: msg }; 1221 } 1222 SpSystemTrace.SDK_CONFIG_MAP = sdkConfigMap; 1223 if (param.buf2) { 1224 let { status, msg } = await threadPool2.initSqlite(param.buf2, systemParseConfigJson, configJson, progress); 1225 if (!status) { 1226 return { status: false, msg: msg }; 1227 } 1228 } 1229 return null; 1230 } else { 1231 return null; 1232 } 1233} 1234async function spSystemTraceInitUrl( 1235 sp: SpSystemTrace, 1236 param: { buf?: ArrayBuffer; url?: string }, 1237 wasmConfigUri: string, 1238 configUri: string, 1239 progress: Function 1240): Promise<{ 1241 status: boolean; 1242 msg: string; 1243} | null> { 1244 if (param.url) { 1245 let { status, msg } = await threadPool.initServer(param.url, progress); 1246 if (!status) { 1247 return { status: false, msg: msg }; 1248 } else { 1249 return null; 1250 } 1251 } else { 1252 return null; 1253 } 1254} 1255export async function spSystemTraceInit( 1256 sp: SpSystemTrace, 1257 param: { buf?: ArrayBuffer; url?: string; buf2?: ArrayBuffer; fileName1?: string; fileName2?: string }, 1258 wasmConfigUri: string, 1259 configUri: string, 1260 progress: Function, 1261 isDistributed: boolean 1262): Promise<unknown> { 1263 progress('Load database', 6); 1264 sp.rowsPaneEL!.scroll({ top: 0, left: 0 }); 1265 let rsBuf = await spSystemTraceInitBuffer(sp, param, wasmConfigUri, configUri, progress); 1266 if (rsBuf) { 1267 return rsBuf; 1268 } 1269 let rsUrl = await spSystemTraceInitUrl(sp, param, wasmConfigUri, configUri, progress); 1270 if (rsUrl) { 1271 return rsUrl; 1272 } 1273 if (isDistributed) { 1274 await sp.chartManager?.initDistributedChart(progress, param.fileName1 || 'Trace 1', param.fileName2 || 'Trace 2'); 1275 } else { 1276 await sp.chartManager?.init(progress); 1277 } 1278 let rowId: string = ''; 1279 // @ts-ignore 1280 sp.rowsEL?.querySelectorAll<TraceRow<unknown>>('trace-row').forEach((it) => { 1281 if (it.name.includes('Ark Ts')) { 1282 rowId = it.rowId!; 1283 } 1284 if (it.folder) { 1285 it.addEventListener('expansion-change', sp.extracted(it)); 1286 } 1287 }); 1288 progress('completed', 100); 1289 info('All TraceRow Data initialized'); 1290 sp.loadTraceCompleted = true; 1291 // @ts-ignore 1292 sp.rowsEL!.querySelectorAll<TraceRow<unknown>>('trace-row').forEach((it) => { 1293 if (rowId !== '' && (it.rowId?.includes(rowId) || it.name.includes(rowId))) { 1294 it.addTemplateTypes('Ark Ts'); 1295 for (let child of it.childrenList) { 1296 child.addTemplateTypes('Ark Ts'); 1297 } 1298 } 1299 if (it.folder) { 1300 let offsetYTimeOut: unknown = undefined; 1301 it.addEventListener('expansion-change', expansionChangeHandler(sp, offsetYTimeOut)); 1302 } 1303 if (sp.loadTraceCompleted) { 1304 sp.traceSheetEL?.displaySystemLogsData(); 1305 sp.traceSheetEL?.displayHangsData(); 1306 sp.traceSheetEL?.displaySystemStatesData(); 1307 } 1308 // 如果有render_service进程,查询该进程下对应泳道的方法存起来,以便框选时直接使用 1309 if (it.getAttribute('name')?.includes('render_service') && it.getAttribute('row-type') === 'process') { 1310 queryRowsData(sp, it.childrenList); 1311 } 1312 sp.intersectionObserver?.observe(it); 1313 }); 1314 1315 for (let i = 0; i < pluginArray.length; i++) { 1316 let item = pluginArray[i]; 1317 for (let j = 0; j < item.tables.length; j++) { 1318 let tableItem = item.tables[j]; 1319 let res = await queryPlugins(tableItem) || []; 1320 if (res.length > 0) { 1321 SpStatisticsHttpUtil.recordPlugin.push(item.pluginName); 1322 break; 1323 } else { 1324 continue; 1325 } 1326 } 1327 } 1328 1329 // 统计插件 1330 SpStatisticsHttpUtil.recordPluginUsage(); 1331 // trace文件加载完毕,将动效json文件读取并存入缓存 1332 let funDetailUrl = `https://${window.location.host.split(':')[0]}:${window.location.port 1333 }${window.location.pathname}doc/funDetail.json`; 1334 let xhr = new XMLHttpRequest(); 1335 // 创建XMLHttpRequest对象 1336 xhr.open('GET', funDetailUrl); 1337 xhr.onreadystatechange = function (): void { 1338 if (xhr.readyState === 4 && xhr.status === 200) { 1339 let content = xhr.responseText; 1340 caches.open('/funDetail').then((cache) => { 1341 let headers = new Headers(); 1342 headers.append('Content-Type', 'application/json'); 1343 return cache 1344 .put( 1345 '/funDetail', 1346 new Response(content, { 1347 status: 200, 1348 headers, 1349 }) 1350 ) 1351 .then(); 1352 }); 1353 } 1354 }; 1355 xhr.send(); // 发送请求 1356 return { status: true, msg: 'success' }; 1357} 1358function expansionChangeHandler(sp: SpSystemTrace, offsetYTimeOut: unknown): (event: unknown) => void { 1359 return function (event: unknown) { 1360 sp.scrollH = sp.rowsPaneEL!.scrollHeight; 1361 let max = [...sp.rowsPaneEL!.querySelectorAll('trace-row')].reduce((pre, cur) => pre + cur.clientHeight!, 0); 1362 let offset = sp.rowsPaneEL!.scrollHeight - max; 1363 sp.rowsPaneEL!.scrollTop = sp.rowsPaneEL!.scrollTop - offset; 1364 JankStruct.delJankLineFlag = false; 1365 if (offsetYTimeOut) { 1366 // @ts-ignore 1367 clearTimeout(offsetYTimeOut); 1368 } 1369 // @ts-ignore 1370 if (event.detail.expansion) { 1371 offsetYTimeOut = setTimeout(() => { 1372 sp.linkNodes.forEach((linkNode) => { 1373 JankStruct.selectJankStructList?.forEach((selectStruct: unknown) => { 1374 // @ts-ignore 1375 if (event.detail.rowId === selectStruct.pid) { 1376 // @ts-ignore 1377 JankStruct.selectJankStruct = selectStruct; 1378 // @ts-ignore 1379 JankStruct.hoverJankStruct = selectStruct; 1380 } 1381 }); 1382 linkNodeHandler(linkNode, sp); 1383 }); 1384 }, 300); 1385 } else { 1386 if (JankStruct!.selectJankStruct) { 1387 JankStruct.selectJankStructList?.push(<JankStruct>JankStruct!.selectJankStruct); 1388 } 1389 offsetYTimeOut = setTimeout(() => { 1390 sp.linkNodes?.forEach((linkNode) => linkNodeHandler(linkNode, sp)); 1391 }, 300); 1392 } 1393 let refreshTimeOut = setTimeout(() => { 1394 sp.refreshCanvas(true); 1395 clearTimeout(refreshTimeOut); 1396 }, 360); 1397 }; 1398} 1399// 查询render_service对应方法行的所有数据 1400// @ts-ignore 1401function queryRowsData(sp: SpSystemTrace, rowList: Array<TraceRow<unknown>>): void { 1402 rowList.forEach((row): void => { 1403 if (row.getAttribute('row-type') === 'func') { 1404 if (row.getAttribute('name')?.startsWith('render_service')) { 1405 saveFrameRateData(sp, row, 'H:RSMainThread::DoComposition'); 1406 } else if (row.getAttribute('name')?.startsWith('RSHardwareThrea')) { 1407 saveFrameRateData(sp, row, 'H:Repaint'); 1408 } else if (row.getAttribute('name')?.startsWith('Present')) { 1409 savePresentData(sp, row, 'H:Waiting for Present Fence'); 1410 } 1411 } 1412 }); 1413} 1414 1415// 查到所有的数据存储起来 1416// @ts-ignore 1417function saveFrameRateData(sp: SpSystemTrace, row: TraceRow<unknown>, funcName: string): void { 1418 let dataList: unknown = []; 1419 queryFuncRowData(funcName, Number(row?.getAttribute('row-id'))).then((res): void => { 1420 if (res.length) { 1421 res.forEach((item): void => { 1422 // @ts-ignore 1423 dataList?.push({ startTime: item.startTime!, tid: item.tid }); 1424 }); 1425 if (funcName === 'H:RSMainThread::DoComposition') { 1426 // @ts-ignore 1427 sp.docomList = dataList; 1428 } else { 1429 // @ts-ignore 1430 sp.repaintList = dataList; 1431 } 1432 } 1433 }); 1434} 1435// 查到present泳道所有的数据存储起来 1436// @ts-ignore 1437function savePresentData(sp: SpSystemTrace, row: TraceRow<unknown>, funcName: string): void { 1438 let dataList: unknown = []; 1439 fuzzyQueryFuncRowData(funcName, Number(row?.getAttribute('row-id'))).then((res): void => { 1440 if (res.length) { 1441 res.forEach((item): void => { 1442 // @ts-ignore 1443 dataList?.push({ endTime: item.endTime!, tid: item.tid }); 1444 }); // @ts-ignore 1445 sp.presentList = dataList; 1446 } 1447 }); 1448} 1449function linkNodeHandler(linkNode: PairPoint[], sp: SpSystemTrace): void { 1450 sp.handleCollectFunc([linkNode]); 1451} 1452 1453const eventMap = { 1454 'cpu-data': 'Cpu', 1455 'cpu-state': 'Cpu State', 1456 'cpu-freq': 'Cpu Frequency', 1457 'cpu-limit-freq': 'Cpu Freq Limit', 1458 process: 'Process', 1459 'native-memory': 'Native Memory', 1460 thread: 'Thread', 1461 func: 'Func', 1462 mem: 'Memory', 1463 'virtual-memory-cell': 'Virtual Memory', 1464 'virtual-memory-group': 'Virtual Memory', 1465 fps: 'FPS', 1466 'ability-monitor': 'Ability Monitor', 1467 'cpu-ability': 'Cpu Ability', 1468 'memory-ability': 'Memory Ability', 1469 'disk-ability': 'DiskIO Ability', 1470 'network-ability': 'Network Ability', 1471 sdk: 'Sdk', 1472 'sdk-counter': 'SDK Counter', 1473 'sdk-slice': 'Sdk Slice', 1474 energy: 'Energy', 1475 'power-energy': 'Power Event', 1476 'system-energy': 'System Event', 1477 'anomaly-energy': 'Anomaly Event', 1478 'clock-group': 'Clocks', 1479 clock: 'clock', 1480 'irq-group': 'Irqs', 1481 irq: 'irq', 1482 hiperf: 'HiPerf (All)', 1483 'hiperf-event': 'HiPerf Event', 1484 'hiperf-report': 'HiPerf Report', 1485 'hiperf-process': 'HiPerf Process', 1486 'hiperf-thread': 'HiPerf Thread', 1487 'js-memory': 'Js Memory', 1488}; 1489export function spSystemTraceInitPointToEvent(sp: SpSystemTrace): void { 1490 sp.eventMap = eventMap; 1491} 1492 1493export function spSystemTraceParentRowSticky(sp: SpSystemTrace, deltaY: number): void { 1494 if (deltaY > 0) { 1495 // 从上往下划 1496 const expandRowList = sp.visibleRows.filter((vr) => vr.expansion); 1497 // @ts-ignore 1498 expandRowList.forEach((vr: TraceRow<unknown>) => { 1499 // @ts-ignore 1500 const visibleNotCollectList = vr.childrenList.filter((child: TraceRow<unknown>) => !child.collect && !child.sleeping); 1501 vr.sticky = visibleNotCollectList.length > 0; 1502 }); 1503 } else if (deltaY < 0) { 1504 // 从下往上划 1505 sp.visibleRows 1506 .filter((vr) => !vr.folder && vr.parentRowEl && vr.parentRowEl.expansion && !vr.collect) 1507 .forEach((vr) => (vr.parentRowEl!.sticky = true)); 1508 } else { 1509 return; 1510 } 1511} 1512