• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF 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