• 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 ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../../../../base-ui/BaseElement';
17import { type LitTable } from '../../../../base-ui/table/lit-table';
18import '../../../../base-ui/table/lit-table-column';
19import { AllAppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAllAppStartup';
20
21import { type WakeupBean } from '../../../bean/WakeupBean';
22import { SpApplication } from '../../../SpApplication';
23import { TraceRow } from '../base/TraceRow';
24import { CpuStruct } from '../../../database/ui-worker/cpu/ProcedureWorkerCPU';
25import { ThreadStruct } from '../../../database/ui-worker/ProcedureWorkerThread';
26import { FuncStruct } from '../../../database/ui-worker/ProcedureWorkerFunc';
27import { ProcessMemStruct } from '../../../database/ui-worker/ProcedureWorkerMem';
28import { ClockStruct } from '../../../database/ui-worker/ProcedureWorkerClock';
29import { DmaFenceStruct } from '../../../database/ui-worker/ProcedureWorkerDmaFence';
30import { ColorUtils } from '../base/ColorUtils';
31import { IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq';
32import { BinderArgBean } from '../../../bean/BinderArgBean';
33import { JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank';
34import { Utils } from '../base/Utils';
35import { SpSystemTrace } from '../../SpSystemTrace';
36import { AppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAppStartup';
37import { SoStruct } from '../../../database/ui-worker/ProcedureWorkerSoInit';
38import { type SelectionParam } from '../../../bean/BoxSelection';
39import { type FrameAnimationStruct } from '../../../database/ui-worker/ProcedureWorkerFrameAnimation';
40import {
41  queryBinderByArgsId,
42  queryBinderBySliceId,
43  queryFlowsData,
44  queryPrecedingData,
45  queryThreadByItid,
46  queryFpsSourceList,
47  queryStateFreqList,
48} from '../../../database/sql/SqlLite.sql';
49import {
50  queryBinderArgsByArgset,
51  queryDistributedRelationAllData,
52  queryRWakeUpFrom,
53  queryRunnableTimeByRunning,
54  querySysCallEventDetail,
55  queryThreadStateArgs,
56  queryThreadWakeUp,
57  queryThreadWakeUpFrom,
58  sqlPrioCount,
59} from '../../../database/sql/ProcessThread.sql';
60import { queryGpuDur } from '../../../database/sql/Gpu.sql';
61import { queryWakeupListPriority } from '../../../database/sql/Cpu.sql';
62import { TabPaneCurrentSelectionHtml } from './TabPaneCurrentSelection.html';
63import { queryRealTime } from '../../../database/sql/Clock.sql';
64import { PerfToolStruct } from '../../../database/ui-worker/ProcedureWorkerPerfTool';
65import { TraceMode } from '../../../SpApplicationPublicFunc';
66import { threadPool, threadPool2 } from '../../../database/SqlLite';
67import { threadNearData } from '../../../database/data-trafic/SliceSender';
68import { HangStruct } from '../../../database/ui-worker/ProcedureWorkerHang';
69import { XpowerStruct } from '../../../database/ui-worker/ProcedureWorkerXpower';
70import { XpowerAppDetailStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerAppDetail';
71import { XpowerWifiStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerWifi';
72import { XpowerThreadCountStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerThreadCount';
73import { XpowerGpuFreqCountStruct } from '../../../database/ui-worker/ProcedureWorkerXpowerGpuFreqCount';
74import { ThreadSysCallStruct } from '../../../database/ui-worker/ProcedureWorkerThreadSysCall';
75
76const INPUT_WORD =
77  'This is the interval from when the task became eligible to run \n(e.g.because of notifying a wait queue it was a suspended on) to\n when it started running.';
78
79const CLOCK_STARTTIME_ABSALUTED_ID: string = 'clockStartTimeAbsaluteId';
80const CLOCK_TRANSF_BTN_ID: string = 'clockTransfBtnId';
81const CPU_STARTTIME_ABSALUTED_ID: string = 'cpuStartTimeAbsaluteId';
82const CPU_TRANSF_BTN_ID: string = 'cpuTransfBtnId';
83const THREAD_STARTTIME_ABSALUTED_ID: string = 'threadStartTimeAbsaluteId';
84const THREAD_TRANSF_BTN_ID: string = 'threadTransfBtnId';
85const FUN_STARTTIME_ABSALUTED_ID: string = 'funStartTimeAbsaluteId';
86const FUN_TRANSF_BTN_ID: string = 'funTransfBtnId';
87
88export function getTimeString(ns: number): string {
89  if (ns === 0) {
90    return '0';
91  }
92  let currentTimeNs = ns;
93  let hour1 = 3600_000_000_000;
94  let minute1 = 60_000_000_000;
95  let second1 = 1_000_000_000; // 1 second
96  let millisecond1 = 1_000_000; // 1 millisecond
97  let microsecond1 = 1_000; // 1 microsecond
98  let res = '';
99  if (currentTimeNs >= hour1) {
100    res += Math.floor(currentTimeNs / hour1) + 'h ';
101    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / hour1) * hour1;
102  }
103  if (currentTimeNs >= minute1) {
104    res += Math.floor(currentTimeNs / minute1) + 'm ';
105    currentTimeNs = currentTimeNs - Math.floor(ns / minute1) * minute1;
106  }
107  if (currentTimeNs >= second1) {
108    res += Math.floor(currentTimeNs / second1) + 's ';
109    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / second1) * second1;
110  }
111  if (currentTimeNs >= millisecond1) {
112    res += Math.floor(currentTimeNs / millisecond1) + 'ms ';
113    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / millisecond1) * millisecond1;
114  }
115  if (currentTimeNs >= microsecond1) {
116    res += Math.floor(currentTimeNs / microsecond1) + 'μs ';
117    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / microsecond1) * microsecond1;
118  }
119  if (currentTimeNs > 0) {
120    res += currentTimeNs.toFixed(0) + 'ns ';
121  }
122  return res;
123}
124
125function compare(property: string, sort: number, type: string) {
126  return function (xpowerSortLeftData: SortData, xpowerSortRightData: SortData): number {
127    if (type === 'number') {
128      return sort === 2 // @ts-ignore
129        ? parseFloat(xpowerSortRightData[property]) - parseFloat(xpowerSortLeftData[property]) // @ts-ignore
130        : parseFloat(xpowerSortLeftData[property]) - parseFloat(xpowerSortRightData[property]);
131    } else if (type === 'duration') {
132      return sort === 2
133        ? xpowerSortRightData.dur - xpowerSortLeftData.dur
134        : xpowerSortLeftData.dur - xpowerSortRightData.dur;
135    } else if (type === 'bytes') {
136      return sort === 2
137        ? xpowerSortRightData.bytes - xpowerSortLeftData.bytes
138        : xpowerSortLeftData.bytes - xpowerSortRightData.bytes;
139    } {
140      // @ts-ignore
141      if (xpowerSortRightData[property] > xpowerSortLeftData[property]) {
142        return sort === 2 ? 1 : -1;
143      } else {
144        // @ts-ignore
145        if (xpowerSortRightData[property] === xpowerSortLeftData[property]) {
146          return 0;
147        } else {
148          return sort === 2 ? -1 : 1;
149        }
150      }
151    }
152  };
153}
154
155@element('tabpane-current-selection')
156export class TabPaneCurrentSelection extends BaseElement {
157  weakUpBean: WakeupBean | null | undefined;
158  selectWakeupBean: unknown;
159  private currentSelectionTbl: LitTable | null | undefined;
160  private tableObserver: MutationObserver | undefined;
161  private wakeupListTbl: LitTable | undefined | null;
162  private scrollView: HTMLDivElement | null | undefined;
163  // @ts-ignore
164  private dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
165  private wakeUp: string = '';
166  private isFpsAvailable: boolean = true;
167  private realTime: number = 0;
168  private bootTime: number = 0;
169  private funcDetailMap: Map<string, Array<object>> = new Map();
170  private topChainStr: string = '';
171  private fpsResult: Array<unknown> = [];
172
173  set data(selection: unknown) {
174    // @ts-ignore
175    if (selection !== undefined && selection.constructor && selection.constructor.name !== 'SelectionParam') {
176      // @ts-ignore
177      this.setCpuData(selection);
178    }
179  }
180
181  /**
182   * 创建StartTime的Dom节点
183   * @param selectTable面板的dom树对象
184   * @param startTs 开始时间
185   * @param transfBtnId 转换按钮id
186   * @param startTimeAbsaluteId 开始时间的id
187   */
188  createStartTimeNode(list: unknown[], startTs: number, transfBtnId: string, startTimeAbsaluteId: string): void {
189    let timeStr: string = '';
190    let startTimeValue: string = '';
191    let startTimeAbsolute = startTs + Utils.getInstance().getRecordStartNS();
192    if (this.realTime > 0) {
193      if (Utils.isTransformed) {
194        timeStr = this.getRealTimeStr(startTimeAbsolute);
195      } else {
196        timeStr = startTimeAbsolute / 1000000000 + 's';
197      }
198      startTimeValue = `<div style="white-space: nowrap;display: flex;align-items: center">
199                            <div id="${startTimeAbsaluteId}" style="white-space:pre-wrap" >${timeStr}</div>
200                            <lit-icon id="${transfBtnId}" class="temp-icon" title="Convert to realtime" name="restore" size="30"
201                                  style="position: relative; top: 5px; left: 10px;"></lit-icon>
202                        </div>`;
203    } else {
204      startTimeValue = startTimeAbsolute / 1000000000 + 's';
205    }
206    list.push({
207      name: 'StartTime(Absolute)',
208      value: startTimeValue,
209    });
210  }
211
212  /**
213   * 给转换按钮添加点击事件
214   * @param startTimeAbsolute 开始时间
215   * @param transfBtnId 转换按钮id
216   * @param startTimeAbsaluteId 开始时间ID
217   */
218  addClickToTransfBtn(startTimeAbsolute: number, transfBtnId: string, startTimeAbsaluteId: string): void {
219    let transfBtn = this.currentSelectionTbl?.shadowRoot?.querySelector(`#${transfBtnId}`);
220    transfBtn?.addEventListener('click', () => {
221      let startTimeAbsalute = this.currentSelectionTbl?.shadowRoot?.querySelector(`#${startTimeAbsaluteId}`);
222      if (startTimeAbsalute) {
223        if (Utils.isTransformed) {
224          startTimeAbsalute!.innerHTML = startTimeAbsolute / 1000000000 + 's';
225          Utils.isTransformed = false;
226        } else {
227          startTimeAbsalute!.innerHTML = this.getRealTimeStr(startTimeAbsolute);
228          Utils.isTransformed = true;
229        }
230      }
231    });
232  }
233
234  async setCpuData(
235    data: CpuStruct,
236    callback: ((data: WakeupBean | null) => void) | undefined = undefined,
237    scrollCallback?: (data: CpuStruct) => void
238  ): Promise<void> {
239    if (SpApplication.traceType.indexOf('SQLite') === -1) {
240      await this.setRealTime();
241    }
242    this.setTableHeight('650px');
243    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
244    if (leftTitle) {
245      leftTitle.innerText = 'Slice Details';
246    }
247    this.currentSelectionTbl!.loading = true;
248    let list: unknown[] = [];
249    this.updateUI(data, list);
250    Promise.all([this.queryThreadStateDArgs(data.argSetID), this.queryCPUWakeUpFromData(data)]).then((resArr) => {
251      let args = resArr[0];
252      let bean = resArr[1];
253      if (callback) {
254        callback(bean);
255      }
256      if (args.length > 0) {
257        args.forEach((arg) => {
258          list.push({ name: arg.keyName, value: arg.strValue });
259        });
260      }
261      this.currentSelectionTbl!.dataSource = list;
262      this.currentSelectionTbl!.loading = false;
263      let startTimeAbsolute = (data.startTime || 0) + Utils.getInstance().getRecordStartNS();
264      this.addClickToTransfBtn(startTimeAbsolute, CPU_TRANSF_BTN_ID, CPU_STARTTIME_ABSALUTED_ID);
265
266      let rightArea: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#table-right');
267      let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
268      let rightButton: HTMLElement | null | undefined = this?.shadowRoot
269        ?.querySelector('#rightButton')
270        ?.shadowRoot?.querySelector('#custom-button');
271      let rightStar: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#right-star');
272      this.threadClickEvent(scrollCallback, data);
273      let canvas = this.initCanvas();
274      if (bean !== null) {
275        this.selectWakeupBean = {
276          process: `${this.transferString(data.processName || 'Process')}(${data.processId})`,
277          thread: `${this.transferString(data.name || 'Thread')}(${data.tid})`,
278          cpu: data.cpu,
279          dur: data.dur,
280          priority: data.priority,
281          isSelected: false,
282        };
283
284        this.weakUpBean = bean;
285        this.updateRightTitleUI(rightArea!, rightTitle!, rightButton!, rightStar!);
286        this.drawRight(canvas, bean);
287      } else {
288        this.handleNullBeanUI(rightArea!, rightTitle!, rightButton!, rightStar!);
289      }
290    });
291  }
292
293  private threadClickEvent(scrollCallback: ((data: CpuStruct) => void) | undefined, data: CpuStruct): void {
294    let threadClick = this.currentSelectionTbl?.shadowRoot?.querySelector('#thread-id');
295    threadClick?.addEventListener('click', () => {
296      //cpu点击
297      if (scrollCallback) {
298        data.state = 'Running';
299        scrollCallback(data);
300      }
301    });
302  }
303
304  private updateRightTitleUI(
305    rightArea: HTMLElement,
306    rightTitle: HTMLElement,
307    rightButton: HTMLElement,
308    rightStar: HTMLElement
309  ): void {
310    if (rightArea !== null && rightArea) {
311      rightArea.style.visibility = 'visible';
312    }
313    if (rightTitle !== null && rightTitle) {
314      rightTitle.style.visibility = 'visible';
315      rightButton!.style.visibility = 'visible';
316      rightStar!.style.visibility = 'hidden';
317      SpSystemTrace.btnTimer = null;
318    }
319  }
320
321  private handleNullBeanUI(
322    rightArea: HTMLElement,
323    rightTitle: HTMLElement,
324    rightButton: HTMLElement,
325    rightStar: HTMLElement
326  ): void {
327    this.weakUpBean = null;
328    if (rightArea !== null && rightArea) {
329      rightArea.style.visibility = 'hidden';
330    }
331    if (rightTitle !== null && rightTitle) {
332      rightTitle.style.visibility = 'hidden';
333      rightButton!.style.visibility = 'hidden';
334      rightStar!.style.visibility = 'hidden';
335    }
336  }
337
338  private updateUI(data: CpuStruct, list: unknown[]): void {
339    let process = this.transferString(data.processName || 'Process');
340    let processId = data.processId || data.tid;
341    let state = '';
342    if (data.end_state) {
343      state = Utils.getEndState(data.end_state);
344    } else if (data.end_state === '' || data.end_state === null) {
345      state = '';
346    } else {
347      state = 'Unknown State';
348    }
349    list.push({
350      name: 'Process',
351      value: `${process || 'Process'} [${processId}]`,
352    });
353    let name = this.transferString(data.name ?? '');
354    if (data.processId) {
355      list.push({
356        name: 'Thread',
357        value: `<div style="white-space: nowrap;display: flex;align-items: center">
358<div style="white-space:pre-wrap">${name || 'Process'} [${data.tid}]</div>
359<lit-icon style="cursor:pointer;margin-left: 5px" id="thread-id" name="select" color="#7fa1e7" size="20"></lit-icon>
360</div>`,
361      });
362    } else {
363      list.push({
364        name: 'Thread',
365        value: `<div style="white-space: nowrap;display: flex;align-items: center">
366<div style="white-space:pre-wrap">${name || 'Process'} [${data.tid}]</div>
367</div>`,
368      });
369    }
370
371    list.push({ name: 'StartTime(Relative)', value: getTimeString(data.startTime || 0) });
372    this.createStartTimeNode(list, data.startTime || 0, CPU_TRANSF_BTN_ID, CPU_STARTTIME_ABSALUTED_ID);
373    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
374    list.push({ name: 'Prio', value: data.priority || 0 });
375    list.push({ name: 'End State', value: state });
376  }
377  // 设置真实时间和启动时间的值
378  private async setRealTime(): Promise<unknown> {
379    return queryRealTime().then((result) => {
380      if (result && result.length > 0) {
381        result.forEach((item) => {
382          if (item.name === 'realtime') {
383            this.realTime = item.ts;
384          } else {
385            this.bootTime = item.ts;
386          }
387        });
388      }
389    });
390  }
391
392  async setFunctionData(
393    data: FuncStruct,
394    threadName: string,
395    scrollCallback: Function,
396    callback?: (data: Array<unknown>, str: string, binderTid: number) => void,
397    distributedCallback?: Function,
398  ): Promise<void> {
399    //方法信息
400    if (SpApplication.traceType.indexOf('SQLite') === -1) {
401      await this.setRealTime();
402    }
403    this.tabCurrentSelectionInit('Slice Details');
404    let list: unknown[] = [];
405    let name = this.transferString(data.funName ?? '');
406    // 从缓存中拿到详细信息的表
407    let information: string = '';
408    let FunDetailList: Array<FunDetail> = new Array();
409    if (this.funcDetailMap.size === 0) {
410      await caches.match('/funDetail').then((res) => {
411        let result: Promise<string> | undefined;
412        if (res) {
413          result = res!.text();
414        }
415        return result;
416      }).then((res) => {
417        if (res) {
418          let funcDetail = JSON.parse(res);
419          for (let key in funcDetail) {
420            this.funcDetailMap.set(key, funcDetail[key]);
421          }
422        }
423      });
424    }
425    // @ts-ignore
426    FunDetailList = this.funcDetailMap.has(threadName) ? this.funcDetailMap.get('threadName') : this.funcDetailMap.get('anothers');
427    if (Array.isArray(FunDetailList)) {
428      // 筛选当前函数块的信息项
429      let informationList: Array<FunDetail> = FunDetailList.filter((v: FunDetail) => {
430        return v.slice.indexOf(name) > -1 || name.indexOf(v.slice) > -1;
431      });
432      information = informationList && informationList.length > 0 ? informationList[0].CN :
433        `<div style="white-space: nowrap;display: flex;align-items: center">
434           <div style="white-space:pre-wrap">无相关描述,如您知道具体含义可点击反馈</div>
435               <lit-icon style="cursor:pointer;margin-left: 5px; margin-top:5px" id="informationJump" name="select" color="#7fa1e7" size="20">
436               </lit-icon>
437           </a>
438       </div>`;
439    }
440    let isBinder = FuncStruct.isBinder(data);
441    let jankJumperList = new Array<ThreadTreeNode>();
442    let isAsyncBinder = isBinder && FuncStruct.isBinderAsync(data);
443    if (data.argsetid !== undefined && data.argsetid !== null && data.argsetid >= 0) {
444      this.setTableHeight('700px');
445      if (isAsyncBinder) {
446        this.handleAsyncBinder(data, list, jankJumperList, name, scrollCallback, information, callback);
447      } else if (isBinder) {
448        this.handleBinder(data, list, jankJumperList, name, scrollCallback, information, callback);
449      } else {
450        this.handleNonBinder(data, list, name, information);
451      }
452    } else if (data.funName && data.funName!.startsWith('H:Et') && (data.depth === 1 || data.depth === 0)) {
453      list.push({
454        name: 'StartTime(Relative)',
455        value: getTimeString(data.startTs || 0),
456      });
457      this.createStartTimeNode(list, data.startTs || 0, FUN_TRANSF_BTN_ID, FUN_STARTTIME_ABSALUTED_ID);
458      list.push({
459        name: 'Duration',
460        value: getTimeString(data.dur || 0),
461      });
462      data.funName!.split(',').map((item, index) => ({
463        name: [
464          'Sender tid',
465          'Send time',
466          'Expect handle time',
467          'Task name/ID',
468          'Prio',
469          'Sender'
470        ][index],
471        value: item,
472      })).forEach((item, index) => {
473        if (index === 0) {
474          item.value = item.value.split(':').at(-1)!;
475        }
476        list.push(item);
477      });
478      this.addTabSliceDetail(data, list)
479      this.currentSelectionTbl!.dataSource = list;
480      // @ts-ignore
481      let startTimeAbsolute = (data.startTs || 0) + (window as unknown).recordStartNS;
482      this.addClickToTransfBtn(startTimeAbsolute, FUN_TRANSF_BTN_ID, FUN_STARTTIME_ABSALUTED_ID);
483    } else {
484      this.setTableHeight('auto');
485      list.push({ name: 'Name', value: name });
486      if (data.cookie || data.cookie === 0) {
487        list.push({ name: 'TaskId', value: data.cookie });
488      }
489      let processName = Utils.getInstance().getProcessMap().get(data.pid!);
490      let threadName = Utils.getInstance().getThreadMap().get(data.tid!);
491      let dataTid = isNaN(data.tid!) ? 'NULL' : data.tid;
492      list.push({
493        name: 'Process',
494        value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
495      });
496      list.push({
497        name: 'Thread',
498        value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + dataTid + '] ',
499      });
500      this.addTabSliceDetail(data, list)
501      list.push({
502        name: 'StartTime(Relative)',
503        value: getTimeString(data.startTs || 0),
504      });
505      this.createStartTimeNode(list, data.startTs || 0, FUN_TRANSF_BTN_ID, FUN_STARTTIME_ABSALUTED_ID);
506      list.push({
507        name: 'Duration',
508        value: getTimeString(data.dur || 0),
509      });
510      list.push({ name: 'depth', value: data.depth });
511      list.push({ name: 'information:', value: information });
512      if (data.chainId) {
513        list.push({ name: 'ChainId', value: data.chainId });
514        list.push({ name: 'SpanId', value: data.spanId });
515        list.push({ name: 'ParentSpanId', value: data.parentSpanId });
516        list.push({ name: 'ChainFlag', value: data.chainFlag });
517        await this.chainSpanListCallBackHandle(data, distributedCallback);
518      }
519      this.currentSelectionTbl!.dataSource = list;
520      // @ts-ignore
521      let startTimeAbsolute = (data.startTs || 0) + (window as unknown).recordStartNS;
522      this.addClickToTransfBtn(startTimeAbsolute, FUN_TRANSF_BTN_ID, FUN_STARTTIME_ABSALUTED_ID);
523    }
524  }
525
526  // 计算真实时间
527  private getRealTimeStr(startTs: number): string {
528    let time = (startTs || 0) - Utils.getInstance().getRecordStartNS() - this.bootTime + this.realTime;
529    const formateDateStr =
530      this.getDate(parseInt(time.toString().substring(0, 13))) + '.' + time.toString().substring(10);
531    return formateDateStr;
532  }
533
534  // 格式化时间戳为字符串格式 yyyy/mm/dd hh:mi:ss
535  private getDate(timestamp: number): string {
536    let date = new Date(timestamp);
537    let gmt = date.toLocaleString();
538    return gmt;
539  }
540
541  private async chainSpanListCallBackHandle(data: FuncStruct, callBack: Function | undefined): Promise<void> {
542    let allMainChainList: FuncStruct[];
543    if (Utils.currentTraceMode === TraceMode.DISTRIBUTED) {
544      let chainAllData = await Promise.all([
545        queryDistributedRelationAllData(data.chainId!, threadPool.traceId),
546        queryDistributedRelationAllData(data.chainId!, threadPool2.traceId),
547      ]);
548      allMainChainList = [...chainAllData[0], ...chainAllData[1]];
549    } else {
550      allMainChainList = await queryDistributedRelationAllData(data.chainId!);
551    }
552    let finalChainSpanList: FuncStruct[] = allMainChainList.filter((spanNode) => spanNode.spanId === data.spanId);
553    let setParentChainList = (currentData: FuncStruct): void => {
554      let currentParentSpanList = allMainChainList.filter((spanNode) => spanNode.spanId === currentData.parentSpanId);
555      for (let index = currentParentSpanList.length - 1; index >= 0; index--) {
556        let spanStruct = currentParentSpanList[index];
557        if (finalChainSpanList.indexOf(spanStruct) < 0) {
558          finalChainSpanList.unshift(spanStruct);
559        }
560      }
561      if (
562        currentParentSpanList.length > 0 &&
563        currentParentSpanList[0].parentSpanId !== '' &&
564        currentParentSpanList[0].parentSpanId !== '0'
565      ) {
566        setParentChainList(currentParentSpanList[0]);
567      }
568    };
569    setParentChainList(data);
570    let setChildChainList = (currentData: FuncStruct): void => {
571      let currentChildSpanList = allMainChainList.filter((spanNode) => spanNode.parentSpanId === currentData.spanId);
572      currentChildSpanList.forEach((childSpan) => {
573        if (finalChainSpanList.indexOf(childSpan) < 0) {
574          finalChainSpanList.push(childSpan);
575        }
576      });
577      if (
578        currentChildSpanList.length > 0 &&
579        currentChildSpanList[0].spanId !== '' &&
580        currentChildSpanList[0].spanId !== '0'
581      ) {
582        setChildChainList(currentChildSpanList[0]);
583      }
584    };
585    setChildChainList(data);
586    if (callBack) {
587      callBack(finalChainSpanList);
588    }
589  }
590
591  private handleNonBinder(data: FuncStruct, list: unknown[], name: string, information: string): void {
592    queryBinderArgsByArgset(data.argsetid!).then((argset) => {
593      list.push({ name: 'Name', value: name });
594      let processName = Utils.getInstance().getProcessMap().get(data.pid!);
595      let threadName = Utils.getInstance().getThreadMap().get(data.tid!);
596      list.push({ name: 'Name', value: name }, {
597        name: 'Process',
598        value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
599      }, {
600        name: 'Thread',
601        value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + data.tid + '] ',
602      });
603      argset.forEach((item) => {
604        list.push({ name: item.keyName, value: item.strValue });
605      });
606      this.addTabSliceDetail(data, list)
607      this.addTabPanelContent(list, data, information);
608      this.currentSelectionTbl!.dataSource = list;
609    });
610  }
611
612  private handleBinder(
613    data: FuncStruct,
614    list: unknown[],
615    jankJumperList: ThreadTreeNode[],
616    name: string,
617    scrollCallback: Function,
618    information: string,
619    callback?: (data: Array<unknown>, str: string, binderTid: number) => void
620  ): void {
621    queryBinderArgsByArgset(data.argsetid!).then((argset) => {
622      let binderSliceId = -1;
623      let binderTid = -1;
624      let processName = Utils.getInstance().getProcessMap().get(data.pid!);
625      let threadName = Utils.getInstance().getThreadMap().get(data.tid!);
626      argset.forEach((item) => {
627        if (item.keyName === 'calling tid') {
628          binderTid = Number(item.strValue);
629        }
630        if (item.keyName === 'destination slice id') {
631          binderSliceId = Number(item.strValue);
632          list.unshift({
633            name: 'Name',
634            value: `<div style="white-space: nowrap;display: flex;align-items: center">
635<div style="white-space:pre-wrap">${name || 'binder'}</div>
636<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="function-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
637</div>`,
638          }, {
639            name: 'Process',
640            value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
641          }, {
642            name: 'Thread',
643            value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + data.tid + '] ',
644          }
645          );
646        }
647        list.push({ name: item.keyName, value: item.strValue });
648      });
649      if (binderSliceId === -1) {
650        list.unshift({
651          name: 'Name', value: name
652        }, {
653          name: 'Process',
654          value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
655        }, {
656          name: 'Thread',
657          value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + data.tid + '] ',
658        }
659        );
660      }
661      this.addTabSliceDetail(data, list)
662      this.addTabPanelContent(list, data, information);
663      this.currentSelectionTbl!.dataSource = list;
664      let funcClick = this.currentSelectionTbl?.shadowRoot?.querySelector('#function-jump');
665      funcClick?.addEventListener('click', () => {
666        if (!Number.isNaN(binderSliceId) && binderSliceId !== -1) {
667          queryBinderBySliceId(binderSliceId).then((result: unknown[]) => {
668            if (result.length > 0) {
669              // @ts-ignore
670              result[0].type = TraceRow.ROW_TYPE_FUNC;
671              scrollCallback(result[0]);
672              let timeLineNode = new ThreadTreeNode(
673                // @ts-ignore
674                result[0]?.tid,
675                // @ts-ignore
676                result[0]?.pid,
677                // @ts-ignore
678                result[0].startTs,
679                // @ts-ignore
680                result[0]?.depth
681              );
682              jankJumperList.push(timeLineNode);
683              if (callback) {
684                let linkTo = 'binder-to';
685                callback(jankJumperList, linkTo, binderTid);
686                linkTo = '';
687              }
688            }
689          });
690        }
691      });
692    });
693  }
694
695  private addTabSliceDetail(data: FuncStruct, list: unknown[]) {
696    const properties = [
697      {key: 'trace_level', name: 'TraceLevel'},
698      {key: 'trace_tag', name: 'TraceTag'},
699      {key: 'category', name: 'Category'},
700      {key: 'custom_args', name: 'CustomArgs'},
701    ];
702    properties.forEach(prop => {
703      if (data[prop.key] && list !== undefined) {
704        list!.push({name: prop.name, value: data[prop.key]});
705      }
706    });
707    return list;
708  }
709
710  private handleAsyncBinder(
711    data: FuncStruct,
712    list: unknown[],
713    jankJumperList: ThreadTreeNode[],
714    name: string,
715    scrollCallback: Function,
716    information: string,
717    callback?: (data: Array<unknown>, str: string, binderTid: number) => void
718  ): void {
719    let binderTid = -1;
720    Promise.all([
721      queryBinderByArgsId(data.argsetid!, data.startTs!, !data.funName!.endsWith('rcv')),
722      queryBinderArgsByArgset(data.argsetid!),
723    ]).then((result) => {
724      let asyncBinderRes = result[0];
725      let argsBinderRes = result[1];
726      let asyncBinderStract: unknown;
727      let processName = Utils.getInstance().getProcessMap().get(data.pid!);
728      let threadName = Utils.getInstance().getThreadMap().get(data.tid!);
729      if (asyncBinderRes.length > 0) {
730        //@ts-ignore
731        asyncBinderRes[0].type = TraceRow.ROW_TYPE_FUNC;
732        asyncBinderStract = asyncBinderRes[0];
733      }
734      if (argsBinderRes.length > 0) {
735        argsBinderRes.forEach((item) => {
736          list.push({
737            name: item.keyName,
738            value: item.strValue,
739          });
740          if (item.keyName === 'calling tid') {
741            binderTid = Number(item.strValue);
742          }
743        });
744      }
745
746      if (asyncBinderStract !== undefined) {
747        list.unshift({
748          name: 'Name',
749          value: `<div style="white-space: nowrap;display: flex;align-items: center">
750<div style="white-space:pre-wrap">${name || 'binder'}</div>
751<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="function-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
752</div>`,
753        }, {
754          name: 'Process',
755          value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
756        }, {
757          name: 'Thread',
758          value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + data.tid + '] ',
759        });
760      } else {
761        list.unshift({
762          name: 'Name',
763          value: name
764        }, {
765          name: 'Process',
766          value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
767        }, {
768          name: 'Thread',
769          value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + data.tid + '] ',
770        });
771      }
772      this.addTabSliceDetail(data, list)
773      this.addTabPanelContent(list, data, information);
774      this.currentSelectionTbl!.dataSource = list;
775      let funcClick = this.currentSelectionTbl?.shadowRoot?.querySelector('#function-jump');
776      funcClick?.addEventListener('click', () => {
777        scrollCallback(asyncBinderStract);
778        let timeLineNode = new ThreadTreeNode(
779          // @ts-ignore
780          asyncBinderStract.tid,
781          // @ts-ignore
782          asyncBinderStract.pid,
783          // @ts-ignore
784          asyncBinderStract.startTs,
785          // @ts-ignore
786          asyncBinderStract.depth
787        );
788        jankJumperList.push(timeLineNode);
789        if (callback) {
790          let linkTo = 'binder-to';
791          callback(jankJumperList, linkTo, binderTid);
792          linkTo = '';
793        }
794      });
795
796    });
797  }
798
799  private addTabPanelContent(contentList: unknown[], data: FuncStruct, information: string): void {
800    contentList.push({
801      name: 'StartTime(Relative)',
802      value: getTimeString(data.startTs || 0),
803    });
804    contentList.push({
805      name: 'StartTime(Absolute)',
806      // @ts-ignore
807      value: ((data.startTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
808    });
809    contentList.push({
810      name: 'Duration',
811      value: getTimeString(data.dur || 0),
812    });
813    contentList.push({ name: 'depth', value: data.depth });
814    if (data.argsetid && data.argsetid > -1) {
815      contentList.push({ name: 'arg_set_id', value: data.argsetid });
816    }
817    contentList.push({ name: 'information', value: information });
818  }
819
820  private tabCurrentSelectionInit(leftTitleStr: string): void {
821    this.initCanvas();
822    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
823    this.setTitleAndButtonStyle();
824    if (leftTitle) {
825      leftTitle.innerText = leftTitleStr;
826    }
827  }
828
829  private setTitleAndButtonStyle(): void {
830    let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
831    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
832      ?.querySelector('#rightButton')
833      ?.shadowRoot?.querySelector('#custom-button');
834    let rightStar: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#right-star');
835    if (rightTitle) {
836      rightTitle.style.visibility = 'hidden';
837      rightButton!.style.visibility = 'hidden';
838      rightStar!.style.visibility = 'hidden';
839    }
840  }
841
842  async setClockData(data: ClockStruct): Promise<void> {
843    if (SpApplication.traceType.indexOf('SQLite') === -1) {
844      await this.setRealTime();
845    }
846    this.setTableHeight('auto');
847    //时钟信息
848    this.tabCurrentSelectionInit('Counter Details');
849    let list: unknown[] = [];
850    list.push({
851      name: 'StartTime(Relative)',
852      value: getTimeString(data.startNS || 0),
853    });
854    this.createStartTimeNode(list, data.startNS || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
855    list.push({
856      name: 'Value',
857      value: ColorUtils.formatNumberComma(data.value || 0),
858    });
859    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
860    this.currentSelectionTbl!.dataSource = list;
861    let startTimeAbsolute = (data.startNS || 0) + Utils.getInstance().getRecordStartNS();
862    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
863  }
864
865  setDmaFenceData(data: DmaFenceStruct, rowData: unknown[]): void {
866    this.setTableHeight('auto');
867    this.tabCurrentSelectionInit('Slice Details');
868    let list: unknown[] = [];
869    list.push({
870      name: 'Title',
871      value: data.sliceName,
872    });
873    list.push({
874      name: 'StartTime(Relative)',
875      value: getTimeString(data.startTime || 0),
876    });
877    list.push({
878      name: 'StartTime(Absolute)',
879      // @ts-ignore
880      value: ((data.startTime || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
881    });
882    if (data.dur !== 0) {
883      list.push({
884        name: 'Wall Duration',
885        value: getTimeString(data.dur || 0)
886      });
887    }
888    list.push({
889      name: 'driver',
890      value: data.driver,
891    });
892    list.push({
893      name: 'context',
894      value: data.context,
895    });
896    this.currentSelectionTbl!.dataSource = list;
897  }
898
899  async setXpowerData(data: XpowerStruct): Promise<void> {
900    if (SpApplication.traceType.indexOf('SQLite') === -1) {
901      await this.setRealTime();
902    }
903    this.setTableHeight('auto');
904    this.tabCurrentSelectionInit('Counter Details');
905    let list: unknown[] = [];
906    list.push({
907      name: 'StartTime(Relative)',
908      value: getTimeString(data.startNS || 0),
909    });
910    this.createStartTimeNode(list, data.startNS || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
911    list.push({
912      name: 'Value',
913      value: String(data.value).indexOf('.') > -1 ? data.value || 0 : ColorUtils.formatNumberComma(data.value || 0),
914    });
915    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
916    this.currentSelectionTbl!.dataSource = list;
917    let startTimeAbsolute = (data.startNS || 0) + Utils.getInstance().getRecordStartNS();
918    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
919  }
920
921
922  async setXpowerTreadCountData(data: XpowerThreadCountStruct): Promise<void> {
923    if (SpApplication.traceType.indexOf('SQLite') === -1) {
924      await this.setRealTime();
925    }
926    this.setTableHeight('auto');
927    this.tabCurrentSelectionInit('Counter Details');
928    let list: unknown[] = [];
929    list.push({
930      name: 'StartTime(Relative)',
931      value: getTimeString(data.startNS || 0),
932    });
933    this.createStartTimeNode(list, data.startNS || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
934    list.push({
935      name: 'Value',
936      value: String(data.value).indexOf('.') > -1 ? data.value || 0 : ColorUtils.formatNumberComma(data.value || 0),
937    });
938    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
939    this.currentSelectionTbl!.dataSource = list;
940    let startTimeAbsolute = (data.startNS || 0) + Utils.getInstance().getRecordStartNS();
941    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
942  }
943
944  async setXpowerGpuFreqCountData(data: XpowerGpuFreqCountStruct): Promise<void> {
945    if (SpApplication.traceType.indexOf('SQLite') === -1) {
946      await this.setRealTime();
947    }
948    this.setTableHeight('auto');
949    this.tabCurrentSelectionInit('Counter Details');
950    let list: unknown[] = [];
951    list.push({
952      name: 'StartTime(Relative)',
953      value: getTimeString(data.startNS || 0),
954    });
955    this.createStartTimeNode(list, data.startNS || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
956    list.push({
957      name: 'Value',
958      value: String(data.value).indexOf('.') > -1 ? data.value || 0 : ColorUtils.formatNumberComma(data.value || 0),
959    });
960    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
961    this.currentSelectionTbl!.dataSource = list;
962    let startTimeAbsolute = (data.startNS || 0) + Utils.getInstance().getRecordStartNS();
963    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
964  }
965
966  async setXpowerDisplayData(data: XpowerAppDetailStruct): Promise<void> {
967    if (SpApplication.traceType.indexOf('SQLite') === -1) {
968      await this.setRealTime();
969    }
970    this.setTableHeight('auto');
971    this.tabCurrentSelectionInit('Display Details');
972    let list: unknown[] = [];
973    list.push({
974      name: 'StartTime(Relative)',
975      value: getTimeString(data.startTime || 0),
976    });
977    this.createStartTimeNode(list, data.startTime || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
978    let vals: { name: string, dur: number, value: string }[] = [];
979    let column = ['1hz', '5hz', '10hz', '15hz', '24hz', '30hz', '45hz', '60hz', '90hz', '120hz', '180hz'];
980    column.forEach((item) => {
981      // @ts-ignore
982      data['c' + item] !== 0 && vals.push({
983        name: item,
984        // @ts-ignore
985        dur: data['c' + item],
986        // @ts-ignore
987        value: data['c' + item] + ' ms',
988      });
989    });
990    // @ts-ignore
991    vals.sort(compare('value', 2, 'duration'));
992    list.push(...vals);
993    this.currentSelectionTbl!.dataSource = list;
994    let startTimeAbsolute = (data.startTime || 0) + Utils.getInstance().getRecordStartNS();
995    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
996  }
997
998  async setXpowerWifiBytesData(data: XpowerWifiStruct): Promise<void> {
999    if (SpApplication.traceType.indexOf('SQLite') === -1) {
1000      await this.setRealTime();
1001    }
1002    this.setTableHeight('auto');
1003    this.tabCurrentSelectionInit('WIFIBytes Details');
1004    let list: unknown[] = [];
1005    list.push({
1006      name: 'StartTime(Relative)',
1007      value: getTimeString(data.startTime || 0),
1008    });
1009    this.createStartTimeNode(list, data.startTime || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
1010    let vals: { name: string, bytes: number, value: string }[] = [];
1011    data.tx !== 0 && vals.push({
1012      name: 'send',
1013      bytes: data.tx,
1014      value: data.tx + ' B',
1015    });
1016    data.rx !== 0 && vals.push({
1017      name: 'receiver',
1018      bytes: data.rx,
1019      value: data.rx + ' B',
1020    });
1021    // @ts-ignore
1022    vals.sort(compare('value', 2, 'bytes'));
1023    list.push(...vals);
1024    this.currentSelectionTbl!.dataSource = list;
1025    let startTimeAbsolute = (data.startTime || 0) + Utils.getInstance().getRecordStartNS();
1026    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
1027  }
1028
1029  async setXpowerWifiPacketsData(data: XpowerWifiStruct): Promise<void> {
1030    if (SpApplication.traceType.indexOf('SQLite') === -1) {
1031      await this.setRealTime();
1032    }
1033    this.setTableHeight('auto');
1034    this.tabCurrentSelectionInit('WIFIPackets Details');
1035    let list: unknown[] = [];
1036    list.push({
1037      name: 'StartTime(Relative)',
1038      value: getTimeString(data.startTime || 0),
1039    });
1040    this.createStartTimeNode(list, data.startTime || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
1041    let vals: { name: string, value: string }[] = [];
1042    data.tx !== 0 && vals.push({
1043      name: 'send',
1044      value: data.tx.toString(),
1045    });
1046    data.rx !== 0 && vals.push({
1047      name: 'receiver',
1048      value: data.rx.toString(),
1049    });
1050    // @ts-ignore
1051    vals.sort(compare('value', 2, 'number'));
1052    list.push(...vals);
1053    this.currentSelectionTbl!.dataSource = list;
1054    let startTimeAbsolute = (data.startTime || 0) + Utils.getInstance().getRecordStartNS();
1055    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
1056  }
1057
1058  async setHangData(data: HangStruct, sp: SpSystemTrace, scrollCallback: Function): Promise<void> {
1059    await this.setRealTime();
1060    this.setTableHeight('auto');
1061    this.tabCurrentSelectionInit('Hang Details');
1062    let list: unknown[] = [];
1063    list.push({
1064      name: 'StartTime(Relative)',
1065      value: getTimeString(data.startTime || 0),
1066    });
1067    this.createStartTimeNode(list, data.startTime || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
1068    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1069    list.push({
1070      name: 'Hang type',
1071      value: `<div style="white-space: nowrap;display: flex;align-items: center">
1072<div style="white-space:pre-wrap">${data.type}</div>
1073<lit-icon style="cursor:pointer;margin-left: 5px" id="scroll-to-process" name="select" color="#7fa1e7" size="20"></lit-icon>
1074</div>`
1075    });
1076    data.content!.split(',').map((item, index) => ({
1077      name: [
1078        'Sender tid',
1079        'Send time',
1080        'Expect handle time',
1081        'Task name/ID',
1082        'Prio',
1083        'Sender'
1084      ][index],
1085      value: item,
1086    })).forEach((item, index) => {
1087      if (index === 0) {
1088        item.value = item.value.split(':').at(-1)!;
1089      }
1090      list.push(item);
1091    });
1092
1093    this.currentSelectionTbl!.dataSource = list;
1094    // @ts-ignore
1095    let startTimeAbsolute = (data.startTime || 0) + window.recordStartNS;
1096    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
1097    this.hangScrollHandler(data, sp, scrollCallback);
1098  }
1099
1100  private hangScrollHandler(data: HangStruct, sp: SpSystemTrace, scrollCallback: Function): void {
1101    let scrollIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#scroll-to-process');
1102    scrollIcon?.addEventListener('click', async () => {
1103      //@ts-ignore
1104      let folderRow = sp.shadowRoot?.querySelector<TraceRow<unknown>>(
1105        `trace-row[row-id='${Utils.getDistributedRowId(data.pid)}'][row-type='process']`
1106      );
1107      if (folderRow) {
1108        folderRow.expansion = true;
1109      }
1110      let funcRow = sp.queryAllTraceRow<TraceRow<FuncStruct>>(
1111        `trace-row[row-id='${Utils.getDistributedRowId(data.tid)}'][row-type='func']`,
1112        (row) => row.rowId === `${data.tid}` && row.rowType === 'func'
1113      )[0];
1114      sp.currentRow = funcRow;
1115      if (!funcRow.dataListCache || funcRow.dataListCache.length === 0) {
1116        funcRow.dataListCache = await funcRow.supplierFrame!();
1117      }
1118      const findEntry = funcRow?.dataListCache.find((funcstruct: unknown) => {
1119        //@ts-ignore
1120        return (funcstruct.startTs === data.startTime && funcstruct.funName === data.content);
1121      })
1122      scrollCallback({
1123        //@ts-ignore
1124        pid: findEntry.pid,
1125        //@ts-ignore
1126        tid: findEntry.tid,
1127        type: 'func',
1128        //@ts-ignore
1129        dur: findEntry.dur,
1130        //@ts-ignore
1131        depth: findEntry.depth,
1132        //@ts-ignore
1133        funName: findEntry.funName,
1134        //@ts-ignore
1135        startTs: findEntry.startTs,
1136        keepOpen: true
1137      })
1138    })
1139  }
1140
1141  setPerfToolsData(data: PerfToolStruct): void {
1142    this.setTableHeight('auto');
1143    //Perf Tools info
1144    this.tabCurrentSelectionInit('Slice Details');
1145    let list: unknown[] = [];
1146    list.push({
1147      name: 'Name',
1148      value: data.name,
1149    });
1150    list.push({
1151      name: 'StartTime(Relative)',
1152      value: getTimeString(data.startTs || 0),
1153    });
1154    list.push({
1155      name: 'StartTime(Absolute)',
1156      // @ts-ignore
1157      value: ((data.startTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1158    });
1159    list.push({
1160      name: 'Value',
1161      value: data.count,
1162    });
1163    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1164    this.currentSelectionTbl!.dataSource = list;
1165  }
1166
1167  setMemData(data: ProcessMemStruct): void {
1168    this.setTableHeight('auto');
1169    //时钟信息
1170    this.initCanvas();
1171    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1172    if (leftTitle) {
1173      leftTitle.innerText = 'Counter Details';
1174    }
1175    let list: object[] = [];
1176    list.push({
1177      name: 'StartTime(Relative)',
1178      value: getTimeString(data.startTime || 0),
1179    });
1180    list.push({
1181      name: 'StartTime(Absolute)',
1182      value: ((data.startTime || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1183    });
1184    list.push({ name: 'Value', value: data.value });
1185    list.push({ name: 'Delta', value: data.delta });
1186    list.push({
1187      name: 'Duration',
1188      value: getTimeString(data.duration || 0),
1189    });
1190    this.currentSelectionTbl!.dataSource = list;
1191  }
1192
1193  setIrqData(data: IrqStruct): void {
1194    this.setTableHeight('550px');
1195    this.initCanvas();
1196    this.setTitleAndButtonStyle();
1197    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1198    if (leftTitle) {
1199      leftTitle.innerText = 'Counter Details';
1200    }
1201    let list: object[] = [];
1202    list.push({
1203      name: 'StartTime(Relative)',
1204      value: getTimeString(data.startNS || 0),
1205    });
1206    list.push({
1207      name: 'StartTime(Absolute)',
1208      value: ((data.startNS || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1209    });
1210    list.push({ name: 'Name', value: data.name });
1211    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1212    queryBinderArgsByArgset(data.argSetId || 0).then((argsBinderRes) => {
1213      if (argsBinderRes.length > 0) {
1214        argsBinderRes.forEach((item) => {
1215          list.push({ name: item.keyName, value: item.strValue });
1216        });
1217      }
1218      this.currentSelectionTbl!.dataSource = list;
1219    });
1220  }
1221
1222  async setSysCallData(data: ThreadSysCallStruct) {
1223    this.setTableHeight('350px');
1224    this.initCanvas();
1225    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1226    this.setTitleAndButtonStyle();
1227    if (leftTitle) {
1228      leftTitle.innerText = 'SysCall Event';
1229    }
1230    let list: unknown[] = [];
1231    list.push({ name: 'Name', value: `${data.name} [${data.id}]` });
1232    list.push({
1233      name: 'StartTime(Relative)',
1234      value: getTimeString(data.startTs || 0),
1235    });
1236    list.push({
1237      name: 'StartTime(Absolute)',
1238      value: ((data.startTs || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1239    });
1240    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1241    const eventValue = await querySysCallEventDetail(data.itid!, data.startTs! + Utils.getInstance().getRecordStartNS(), data.dur!);
1242    if (eventValue[0]) {
1243      list.push({ name: 'Process', value: `${eventValue[0].pName} [${data.pid}]` });
1244      list.push({ name: 'Thread', value: `${eventValue[0].tName} [${data.tid}]` });
1245      list.push({ name: 'args', value: eventValue[0].args });
1246      list.push({ name: 'ret', value: eventValue[0].ret });
1247    }
1248    this.currentSelectionTbl!.dataSource = list;
1249  }
1250
1251  async setThreadData(
1252    data: ThreadStruct,
1253    scrollCallback: ((d: unknown) => void) | undefined,
1254    scrollWakeUp: (d: unknown) => void | undefined,
1255    scrollPrio: (d: unknown) => void | undefined,
1256    callback?: (data: Array<unknown>, str: string) => void
1257  ): Promise<void> {
1258    //线程信息
1259    if (SpApplication.traceType.indexOf('SQLite') === -1) {
1260      await this.setRealTime();
1261    }
1262    this.setTableHeight('550px');
1263    this.initCanvas();
1264    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1265    this.setTitleAndButtonStyle();
1266    if (leftTitle) {
1267      leftTitle.innerText = 'Thread State';
1268    }
1269    let list: unknown[] = [];
1270    let jankJumperList: Array<ThreadTreeNode> = [];
1271    this.prepareThreadInfo(list, data);
1272    let cpu = new CpuStruct();
1273    cpu.id = data.id;
1274    cpu.startTime = data.startTime;
1275    this.queryThreadDetails(data, list, jankJumperList, callback, scrollWakeUp, scrollPrio, scrollCallback);
1276  }
1277
1278  private sortByNearData(nearData: unknown[], data: ThreadStruct, list: unknown[]): unknown[] {
1279    let preData: unknown = undefined;
1280    let nextData: unknown = undefined;
1281
1282    nearData
1283      // @ts-ignore
1284      .sort((near1, near2) => near1.startTime - near2.startTime)
1285      .forEach((near) => {
1286        // @ts-ignore
1287        if (near.id === data.id) {
1288          // @ts-ignore
1289          if (near.startTime < data.startTime!) {
1290            preData = near;
1291            list.push({
1292              name: 'Previous State',
1293              value: `<div style="white-space: nowrap;display: flex;align-items: center">
1294              <div style="white-space:pre-wrap">${
1295                // @ts-ignore
1296                Utils.getEndState(near.state)
1297                }</div>
1298              <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="previous-state-click" name="select" color="#7fa1e7" size="20"></lit-icon>
1299              </div>`,
1300            });
1301          } else {
1302            nextData = near;
1303            list.push({
1304              name: 'Next State',
1305              value: `<div style="white-space: nowrap;display: flex;align-items: center">
1306              <div style="white-space:pre-wrap">${
1307                // @ts-ignore
1308                Utils.getEndState(near.state)
1309                }</div>
1310              <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="next-state-click" name="select" color="#7fa1e7" size="20"></lit-icon>
1311              </div>`,
1312            });
1313          }
1314        }
1315      });
1316    return [preData, nextData];
1317  }
1318
1319  private setWakeupData(fromBean: WakeupBean | undefined, wakeUps: WakeupBean[], list: unknown[]): void {
1320    if (fromBean !== null && fromBean !== undefined && fromBean.pid !== 0 && fromBean.tid !== 0) {
1321      list.push({
1322        name: 'wakeup from tid',
1323        value: `<div style="white-space: nowrap;display: flex;align-items: center">
1324            <div style="white-space:pre-wrap">${fromBean.tid}</div>
1325            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="wakeup-from"
1326            class="wakeup-click"  name="select" color="#7fa1e7" size="20"></lit-icon>
1327            </div>`,
1328      });
1329      list.push({
1330        name: 'wakeup from top',
1331        value: `<div style="white-space: nowrap;display: flex;align-items: center">
1332            <div style="white-space:pre-wrap" id="wakeup-top-content" style="display: none"></div>
1333            <lit-icon id="wakeup-top" class="temp-icon" title="Get to chain" name="restore" size="30"
1334              style="position: relative; top: 5px; left: 10px;"></lit-icon>
1335            </div>`,
1336      });
1337    }
1338    if (wakeUps !== null) {
1339      wakeUps.map((e) => {
1340        list.push({
1341          name: 'wakeup tid',
1342          value: `<div style="white-space: nowrap;display: flex;align-items: center">
1343            <div style="white-space:pre-wrap">${e.tid}</div>
1344            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="wakeup-${e.tid}"
1345            class="wakeup-click" name="select" color="#7fa1e7" size="20"></lit-icon>
1346            </div>`,
1347        });
1348      });
1349    }
1350  }
1351
1352  private queryThreadDetails(
1353    data: ThreadStruct,
1354    list: unknown[],
1355    jankJumperList: ThreadTreeNode[],
1356    callback: ((data: Array<unknown>, str: string) => void) | undefined,
1357    scrollWakeUp: (d: unknown) => void | undefined,
1358    scrollPrio: (d: unknown) => void | undefined,
1359    scrollCallback: ((d: unknown) => void) | undefined
1360  ): void {
1361    Promise.all([
1362      this.queryThreadWakeUpFromData(data.id!, data.startTime!, data.dur!),
1363      this.queryThreadWakeUpData(data.id!, data.startTime!, data.dur!),
1364      this.queryThreadStateDArgs(data.argSetID),
1365      threadNearData('near-data', data.pid!, data.tid!, data.startTime!),
1366    ]).then((result) => {
1367      let fromBean = result[0];
1368      let wakeUps = result[1];
1369      let args = result[2];
1370      let [preData, nextData] = this.sortByNearData(result[3], data, list);
1371      this.setWakeupData(fromBean, wakeUps, list);
1372      if (args.length > 0) {
1373        args.forEach((arg: unknown) => {
1374          // @ts-ignore
1375          list.push({ name: arg.keyName, value: arg.strValue });
1376        });
1377      }
1378      this.currentSelectionTbl!.dataSource = list;
1379      let startTimeAbsolute = (data.startTime || 0) + Utils.getInstance().getRecordStartNS();
1380      this.addClickToTransfBtn(startTimeAbsolute, THREAD_TRANSF_BTN_ID, THREAD_STARTTIME_ABSALUTED_ID);
1381      let timeLineNode = new ThreadTreeNode(data.tid!, data.pid!, data.startTime!);
1382      jankJumperList.push(timeLineNode);
1383      if (callback) {
1384        callback(jankJumperList, this.wakeUp);
1385        this.wakeUp = '';
1386      }
1387      this.stateClickHandler(preData, nextData, data, scrollWakeUp, scrollCallback, scrollPrio);
1388      this.wakeupClickHandler(wakeUps, fromBean, scrollWakeUp);
1389      this.getWakeupChainClickHandler(fromBean, list);
1390    });
1391  }
1392
1393  private wakeupClickHandler(
1394    wakeUps: WakeupBean[],
1395    fromBean: WakeupBean | undefined,
1396    scrollWakeUp: (d: unknown) => void | undefined
1397  ): void {
1398    this.currentSelectionTbl?.shadowRoot?.querySelector('#wakeup-from')?.addEventListener('click', () => {
1399      //点击跳转,唤醒和被唤醒的 线程
1400      if (fromBean && scrollWakeUp) {
1401        scrollWakeUp({
1402          processId: fromBean.pid,
1403          tid: fromBean.tid,
1404          startTime: fromBean.ts,
1405          dur: fromBean.dur,
1406          cpu: fromBean.cpu,
1407          id: fromBean.itid,
1408          state: 'Running',
1409          argSetID: fromBean.argSetID,
1410        });
1411      }
1412      this.wakeUp = 'wakeup tid';
1413    });
1414    if (wakeUps) {
1415      wakeUps.map((up) => {
1416        this.currentSelectionTbl?.shadowRoot?.querySelector(`#wakeup-${up.tid}`)?.addEventListener('click', () => {
1417          //点击跳转,唤醒和被唤醒的 线程
1418          if (up && scrollWakeUp !== undefined) {
1419            scrollWakeUp({
1420              processId: up.pid,
1421              tid: up.tid,
1422              startTime: up.ts,
1423              dur: up.dur,
1424              cpu: up.cpu,
1425              id: up.itid,
1426              state: up.state,
1427              argSetID: up.argSetID,
1428            });
1429          }
1430          this.wakeUp = 'wakeup tid';
1431        });
1432      });
1433    }
1434  }
1435
1436  private stateClickHandler(
1437    preData: unknown,
1438    nextData: unknown,
1439    data: ThreadStruct,
1440    scrollWakeUp: (d: unknown) => void | undefined,
1441    scrollCallback: ((d: unknown) => void) | undefined,
1442    scrollPrio: (d: unknown) => void | undefined
1443  ): void {
1444    this.currentSelectionTbl?.shadowRoot?.querySelector('#next-state-click')?.addEventListener('click', () => {
1445      if (nextData && scrollWakeUp !== undefined) {
1446        scrollWakeUp({
1447          // @ts-ignore
1448          processId: nextData.pid,
1449          // @ts-ignore
1450          tid: nextData.tid,
1451          // @ts-ignore
1452          startTime: nextData.startTime,
1453          // @ts-ignore
1454          dur: nextData.dur,
1455          // @ts-ignore
1456          cpu: nextData.cpu,
1457          // @ts-ignore
1458          id: nextData.id,
1459          // @ts-ignore
1460          state: nextData.state,
1461          // @ts-ignore
1462          argSetID: nextData.argSetID,
1463        });
1464      }
1465    });
1466
1467    this.currentSelectionTbl?.shadowRoot?.querySelector('#previous-state-click')?.addEventListener('click', () => {
1468      if (preData && scrollWakeUp !== undefined) {
1469        scrollWakeUp({
1470          // @ts-ignore
1471          processId: preData.pid,
1472          // @ts-ignore
1473          tid: preData.tid,
1474          // @ts-ignore
1475          startTime: preData.startTime,
1476          // @ts-ignore
1477          dur: preData.dur,
1478          // @ts-ignore
1479          cpu: preData.cpu,
1480          // @ts-ignore
1481          id: preData.id,
1482          // @ts-ignore
1483          state: preData.state,
1484          // @ts-ignore
1485          argSetID: preData.argSetID,
1486        });
1487      }
1488    });
1489
1490    this.currentSelectionTbl?.shadowRoot?.querySelector('#state-click')?.addEventListener('click', () => {
1491      //线程点击
1492      if (scrollCallback) {
1493        scrollCallback(data);
1494      }
1495    });
1496    this.currentSelectionTbl?.shadowRoot?.querySelector('#prio-click')?.addEventListener('click', (ev) => {
1497      if (scrollPrio) {
1498        sqlPrioCount(data).then((res: unknown) => {
1499          scrollPrio(res);
1500        });
1501      }
1502    });
1503  }
1504  //点击事件获取唤醒链
1505  private getWakeupChainClickHandler(fromBean: WakeupBean | undefined, list: unknown[]): void {
1506    this.currentSelectionTbl?.shadowRoot?.querySelector('#wakeup-top')?.addEventListener('click', async () => {
1507      this.topChainStr = '';
1508      //@ts-ignore
1509      let currentThread = list.filter((item) => item.name === 'Thread')?.[0].value;//点击的当前线程
1510      let previouosWakeupThread = Utils.getInstance().getThreadMap().get(fromBean!.tid!) || 'Thread';//唤醒当前线程的上个线程
1511      this.topChainStr = `-->${previouosWakeupThread} [${fromBean!.tid}]-->${currentThread}`;
1512      this.getRWakeUpChain(fromBean);
1513    })
1514  }
1515  private async prepareThreadInfo(list: unknown[], data: ThreadStruct): Promise<void> {
1516    let processName = Utils.getInstance().getProcessMap().get(data.pid!);
1517    let threadName = Utils.getInstance().getThreadMap().get(data.tid!);
1518    list.push({
1519      name: 'Process',
1520      value: (this.transferString(processName ?? '') || 'NULL') + ' [' + data.pid + '] ',
1521    });
1522    list.push({
1523      name: 'Thread',
1524      value: (this.transferString(threadName ?? '') || 'NULL') + ' [' + data.tid + '] ',
1525    });
1526    list.push({
1527      name: 'StartTime(Relative)',
1528      value: getTimeString(data.startTime || 0),
1529    });
1530    this.createStartTimeNode(list, data.startTime || 0, THREAD_TRANSF_BTN_ID, THREAD_STARTTIME_ABSALUTED_ID);
1531    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1532    let state;
1533    if (data.state) {
1534      state = Utils.getEndState(data.state);
1535    } else if (data.state === '' || data.state === null) {
1536      state = '';
1537    } else {
1538      state = 'Unknown State';
1539    }
1540    if ('Running' === state) {
1541      state = state + ' on CPU ' + data.cpu;
1542      list.push({
1543        name: 'State',
1544        value: `<div style="white-space: nowrap;display: flex;align-items: center">
1545            <div style="white-space:pre-wrap">${state}</div>
1546            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="state-click" name="select" color="#7fa1e7" size="20"></lit-icon>
1547            </div>`,
1548      });
1549    } else {
1550      list.push({ name: 'State', value: `${state}` });
1551    }
1552    if (state.includes('Running')) {
1553      let startTime: number = data.startTime || 0;
1554      let endTime: number = (data.startTime || 0) + (data.dur || 0);
1555      let freqList: Array<unknown> = [];
1556      let str = '';
1557      freqList = await queryStateFreqList(startTime, endTime, data.cpu || 0);
1558      freqList.forEach((it) => {
1559        // @ts-ignore
1560        if (it.startTime < startTime! && it.endTime > endTime!) {
1561          // @ts-ignore
1562          it.stateDur = data.dur;
1563          // @ts-ignore
1564        } else if (it.startTime < startTime! && startTime! < it.endTime && it.endTime < endTime!) {
1565          // @ts-ignore
1566          it.stateDur = it.endTime - startTime!;
1567          // @ts-ignore
1568        } else if (it.startTime > startTime! && startTime! < it.endTime && it.endTime < endTime!) {
1569          // @ts-ignore
1570          it.stateDur = it.dur;
1571          // @ts-ignore
1572        } else if (it.startTime > startTime! && endTime! > it.startTime && it.endTime > endTime!) {
1573          // @ts-ignore
1574          it.stateDur = endTime! - it.startTime;
1575        }
1576        // @ts-ignore
1577        str += '[' + it.value + ', ' + (it.stateDur || 0) / 1000 + ']' + ',';
1578      });
1579      list.push({ name: 'Freq [KHz, μs]', value: str.substring(0, str.length - 1) });
1580    }
1581    let slice = Utils.getInstance().getSchedSliceMap().get(`${data.id}-${data.startTime}`);
1582    if (slice) {
1583      list.push({
1584        name: 'Prio',
1585        value: `<div style="white-space: nowrap;display: flex;align-item: center">
1586        <div style="white-space: pre-wrap">${slice.priority}</div>
1587        <lit-icon style="cursor:pointer;transform: scalex(-1);margin-left: 5px" id="prio-click" name="select" color="#7fa1e7" size="20"></lit-icon>
1588        </div>`,
1589      });
1590    }
1591  }
1592
1593  setJankData(
1594    data: JankStruct,
1595    callback: ((data: Array<unknown>) => void) | undefined = undefined,
1596    scrollCallback: ((d: unknown) => void) | undefined
1597  ): void {
1598    //线程信息
1599    this.setTableHeight('750px');
1600    this.tabCurrentSelectionInit('Slice Details');
1601    let list: unknown[] = [];
1602    this.setJankCommonMessage(list, data);
1603    if (`${data.type}` === '0') {
1604      this.handleTypeJank(data, list, scrollCallback, callback);
1605    } else {
1606      this.currentSelectionTbl!.dataSource = list;
1607    }
1608  }
1609
1610  private handleTypeJank(
1611    data: JankStruct,
1612    list: unknown[],
1613    scrollCallback: ((d: unknown) => void) | undefined,
1614    callback: ((data: Array<unknown>) => void) | undefined
1615  ): void {
1616    this.setJankType(data, list);
1617    let jankJumperList: Array<JankTreeNode> = [];
1618    if (data.frameType === 'render_service') {
1619      queryGpuDur(data.id!).then((it) => {
1620        if (it.length > 0) {
1621          //@ts-ignore
1622          list.push({ name: 'Gpu Duration', value: getTimeString(it[0].gpu_dur) });
1623        }
1624      });
1625      this.handleRenderServiceJank(data, list, jankJumperList, scrollCallback, callback);
1626    } else if (data.frameType === 'app') {
1627      this.handleAppJank(list, data, jankJumperList, scrollCallback, callback);
1628    } else if (data.frameType === 'frameTime') {
1629      this.handleFrameTimeJank(data, list, jankJumperList, scrollCallback, callback);
1630    }
1631  }
1632
1633  private handleFrameTimeJank(
1634    data: JankStruct,
1635    list: unknown[],
1636    jankJumperList: JankTreeNode[],
1637    scrollCallback: ((d: unknown) => void) | undefined,
1638    callback: ((data: Array<unknown>) => void) | undefined
1639  ): void {
1640    queryGpuDur(data.id!).then((it) => {
1641      if (it.length > 0) {
1642        list.push({
1643          name: 'Gpu Duration',
1644          //@ts-ignore
1645          value: getTimeString(it[0].gpu_dur),
1646        });
1647      }
1648      this.addAppFrameDetails(data, list);
1649      this.addRenderServiceFrameDetails(data, list);
1650      this.addFollowingDetails(list, data);
1651      let appNode = new JankTreeNode(data.name!, data.pid!, 'app');
1652      let rsNode = new JankTreeNode(data.rs_vsync!, data.rs_pid!, 'render_service');
1653      appNode.children.push(rsNode);
1654      jankJumperList.push(appNode);
1655      this.currentSelectionTbl!.dataSource = list;
1656      this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1657    });
1658  }
1659
1660  private addRenderServiceFrameDetails(data: JankStruct, list: unknown[]): void {
1661    if (data.rs_name) {
1662      list.push({
1663        name: 'RenderService Frame',
1664        value: '',
1665      });
1666      list.push({
1667        name: 'Process',
1668        value: 'render_service ' + data.rs_pid,
1669      });
1670      list.push({
1671        name: 'StartTime(Relative)',
1672        value: getTimeString(data.rs_ts || 0),
1673      });
1674      list.push({
1675        name: 'StartTime(Absolute)',
1676        value: ((data.rs_ts || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1677      });
1678      list.push({
1679        name: 'end time',
1680        value: getTimeString(data.rs_ts! + data.rs_dur! || 0),
1681      });
1682    }
1683  }
1684
1685  private addFollowingDetails(list: unknown[], data: JankStruct): void {
1686    list.push({
1687      name: 'Following',
1688      value: '',
1689    });
1690    list.push({
1691      name: 'Slice',
1692      value:
1693        data.cmdline +
1694        ' [' +
1695        data.name +
1696        ']' +
1697        `<lit-icon class="jank_cla" style="display: inline-flex;cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="${data.type}-${data.pid}" slice_name="${data.name}"  pid="${data.pid}" name="select" color="#7fa1e7" size="20"></lit-icon>`,
1698    });
1699  }
1700
1701  private addAppFrameDetails(data: JankStruct, list: unknown[]): void {
1702    if (data.name) {
1703      list.push({
1704        name: 'App Frame',
1705        value: '',
1706      });
1707      list.push({
1708        name: 'Process',
1709        value: data.cmdline + ' ' + data.pid,
1710      });
1711      list.push({
1712        name: 'StartTime(Relative)',
1713        value: getTimeString(data.ts || 0),
1714      });
1715      list.push({
1716        name: 'StartTime(Absolute)',
1717        value: ((data.ts || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1718      });
1719      list.push({
1720        name: 'end time',
1721        value: getTimeString(data!.ts! + data.dur! || 0),
1722      });
1723    }
1724  }
1725
1726  private handleAppJank(
1727    list: unknown[],
1728    data: JankStruct,
1729    jankJumperList: JankTreeNode[],
1730    scrollCallback: ((d: unknown) => void) | undefined,
1731    callback: ((data: Array<unknown>) => void) | undefined
1732  ): void {
1733    list.push({
1734      name: 'FrameTimeLine flows',
1735      value: '',
1736    });
1737    list.push({
1738      name: 'Slice',
1739      value:
1740        data.cmdline +
1741        ' [' +
1742        data.name +
1743        ']' +
1744        `<lit-icon  class="jank_cla" style="display: inline-flex;cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="actual frameTime"  slice_name="${data.name}"  pid="${data.pid}" name="select" color="#7fa1e7" size="20"></lit-icon>`,
1745    });
1746    let timeLineNode = new JankTreeNode(data.name!, data.pid!, 'frameTime');
1747    jankJumperList.push(timeLineNode);
1748    if (data.dst_slice) {
1749      queryPrecedingData(data.dst_slice).then((it) => {
1750        if (it.length > 0) {
1751          list.push({
1752            name: 'Preceding flows',
1753            value: '',
1754          });
1755          it.forEach((a: unknown) => {
1756            // @ts-ignore
1757            let rsNode = new JankTreeNode(a.name, a.pid, 'render_service');
1758            jankJumperList.push(rsNode);
1759            list.push({
1760              name: 'Slice',
1761              value:
1762                // @ts-ignore
1763                a.cmdline +
1764                ' [' +
1765                // @ts-ignore
1766                a.name +
1767                ']' +
1768                // @ts-ignore
1769                `<lit-icon class="jank_cla" style="display: inline-flex;cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="${a.type}-${a.pid}" slice_name="${a.name}" pid="${a.pid}" name="select" color="#7fa1e7" size="20"></lit-icon>`,
1770            });
1771          });
1772          this.currentSelectionTbl!.dataSource = list;
1773          this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1774        }
1775      });
1776    } else {
1777      this.currentSelectionTbl!.dataSource = list;
1778      this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1779    }
1780  }
1781
1782  private handleRenderServiceJank(
1783    data: JankStruct,
1784    list: unknown[],
1785    jankJumperList: JankTreeNode[],
1786    scrollCallback: ((d: unknown) => void) | undefined,
1787    callback: ((data: Array<unknown>) => void) | undefined
1788  ): void {
1789    if (data.src_slice) {
1790      queryFlowsData(data.src_slice!.split(',')).then((it) => {
1791        if (it.length > 0) {
1792          list.push({
1793            name: 'FrameTimeLine flows',
1794            value: '',
1795          });
1796          it.forEach((a: unknown) => {
1797            // @ts-ignore
1798            let appNode = new JankTreeNode(a.name, a.pid, 'app');
1799            // @ts-ignore
1800            appNode.children.push(new JankTreeNode(a.name, a.pid, 'frameTime'));
1801            jankJumperList.push(appNode);
1802            list.push({
1803              name: 'Slice',
1804              value:
1805                // @ts-ignore
1806                a.cmdline +
1807                ' [' +
1808                // @ts-ignore
1809                a.name +
1810                ']' +
1811                // @ts-ignore
1812                `<lit-icon  class="jank_cla" style="display: inline-flex;cursor: pointer;transform: scaleX(-1);margin-left: 5px" id="actual frameTime" slice_name="${a.name}" pid="${a.pid}" name="select" color="#7fa1e7" size="20"></lit-icon>`,
1813            });
1814          });
1815          list.push({
1816            name: 'Following flows',
1817            value: '',
1818          });
1819          it.forEach((a: unknown) => {
1820            list.push({
1821              name: 'Slice',
1822              value:
1823                // @ts-ignore
1824                a.cmdline +
1825                ' [' +
1826                // @ts-ignore
1827                a.name +
1828                ']' +
1829                // @ts-ignore
1830                `<lit-icon class="jank_cla" style="display: inline-flex;cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="${a.type}-${a.pid}" slice_name="${a.name}"  pid="${a.pid}" name="select" color="#7fa1e7" size="20"></lit-icon>`,
1831            });
1832          });
1833          this.currentSelectionTbl!.dataSource = list;
1834          this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1835        }
1836      });
1837    } else {
1838      this.currentSelectionTbl!.dataSource = list;
1839    }
1840  }
1841
1842  setAllStartupData(data: AllAppStartupStruct, scrollCallback: Function): void {
1843    this.setTableHeight('550px');
1844    this.initCanvas();
1845    let allStartUpLeftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1846    let allStartUpmiddleTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightText');
1847    let allStartUpRightButton: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightButton');
1848    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
1849      ?.querySelector('#rightButton')
1850      ?.shadowRoot?.querySelector('#custom-button');
1851    let rightStar: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#right-star');
1852    if (rightButton) {
1853      rightButton!.style.visibility = 'hidden';
1854    }
1855    if (rightStar) {
1856      rightStar!.style.visibility = 'hidden';
1857    }
1858    if (allStartUpmiddleTitle) {
1859      allStartUpmiddleTitle.style.visibility = 'hidden';
1860    }
1861    if (allStartUpRightButton) {
1862      allStartUpRightButton.style.visibility = 'hidden';
1863    }
1864    if (allStartUpLeftTitle) {
1865      allStartUpLeftTitle.innerText = 'Details';
1866    }
1867    let list: unknown[] = [];
1868    list.push({ name: 'Name', value: data.stepName! });
1869    list.push({
1870      name: 'StartTime(Relative)',
1871      value: getTimeString(data.startTs || 0),
1872    });
1873    list.push({
1874      name: 'StartTime(Absolute)',
1875      value: ((data.startTs || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1876    });
1877    list.push({
1878      name: 'EndTime(Relative)',
1879      value: getTimeString((data.startTs || 0) + (data.dur || 0)),
1880    });
1881    list.push({
1882      name: 'EndTime(Abslute)',
1883      value: ((data.startTs || 0) + (data.dur || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1884    });
1885    list.push({
1886      name: 'Dur',
1887      value: getTimeString(data.dur || 0),
1888    });
1889    this.currentSelectionTbl!.dataSource = list;
1890  }
1891
1892  setStartupData(data: AppStartupStruct, scrollCallback: Function, rowData: unknown): void {
1893    this.setTableHeight('550px');
1894    this.initCanvas();
1895    this.setStartUpStyle();
1896    let list: unknown[] = [];
1897    list.push({ name: 'Name', value: AppStartupStruct.getStartupName(data.startName) });
1898    list.push({
1899      name: 'StartTime(Relative)',
1900      value: `
1901      <div style="display: flex;white-space: nowrap;align-items: center">
1902<div style="white-space:pre-wrap">${getTimeString(data.startTs || 0)}</div>
1903<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="start-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
1904</div>`,
1905    });
1906    list.push({
1907      name: 'StartTime(Absolute)',
1908      value: ((data.startTs || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1909    });
1910    if (data.dur && data.dur > 0) {
1911      if (data.startName > 6) {
1912        list.push({
1913          name: 'EndTime(Relative)',
1914          value: `<div style="white-space: nowrap;display: flex;align-items: center">
1915  <div style="white-space:pre-wrap">${getTimeString((data.startTs || 0) + (data.dur || 0))}</div>
1916  </div>`,
1917        });
1918      } else {
1919        list.push({
1920          name: 'EndTime(Relative)',
1921          value: `<div style="white-space: nowrap;display: flex;align-items: center">
1922  <div style="white-space:pre-wrap">${getTimeString((data.startTs || 0) + (data.dur || 0))}</div>
1923  <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="end-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
1924  </div>`,
1925        });
1926      }
1927      list.push({
1928        name: 'EndTime(Absolute)',
1929        value: ((data.startTs || 0) + (data.dur || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
1930      });
1931    } else {
1932      list.push({
1933        name: 'EndTime(Relative)',
1934        value: 'Unknown Time',
1935      });
1936      list.push({
1937        name: 'EndTime(Absolute)',
1938        value: 'Unknown Time',
1939      });
1940    }
1941    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1942    // @ts-ignore
1943    let sortedArray = rowData.slice().sort(function (a: { startTs: number }, b: { startTs: number }) {
1944      return a.startTs - b.startTs;
1945    });
1946    sortedArray.forEach((item: unknown, index: number) => {
1947      // @ts-ignore
1948      if (item.startName === data.startName) {
1949        list.push({
1950          name: 'StartSlice',
1951          value:
1952            index === 0
1953              ? 'NULL'
1954              : `${AppStartupStruct.getStartupName(sortedArray[index - 1].startName)}     ${getTimeString(
1955                sortedArray[index - 1].startTs + sortedArray[index - 1].dur
1956              )}`,
1957        });
1958        list.push({
1959          name: 'EndSlice',
1960          value:
1961            index === sortedArray.length - 1
1962              ? 'NULL'
1963              : `${AppStartupStruct.getStartupName(sortedArray[index + 1].startName)}      ${getTimeString(
1964                sortedArray[index + 1].startTs
1965              )}`,
1966        });
1967        if (data.startName === 6) {
1968          data.endstartTs = sortedArray[index + 1].startTs;
1969          data.endItid = sortedArray[index + 1].itid;
1970        } else {
1971          data.endstartTs = data.startTs! + data.dur!;
1972        }
1973      }
1974    });
1975    this.currentSelectionTbl!.dataSource = list;
1976    this.attachScrollHandlers(data, scrollCallback);
1977  }
1978
1979  private setStartUpStyle(): void {
1980    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
1981      ?.querySelector('#rightButton')
1982      ?.shadowRoot?.querySelector('#custom-button');
1983    let startUpRightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
1984    if (startUpRightTitle) {
1985      startUpRightTitle.style.visibility = 'hidden';
1986      rightButton!.style.visibility = 'hidden';
1987    }
1988    let startUpLeftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1989    if (startUpLeftTitle) {
1990      startUpLeftTitle.innerText = 'Details';
1991    }
1992  }
1993
1994  private attachScrollHandlers(data: AppStartupStruct, scrollCallback: Function): void {
1995    let startIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#start-jump');
1996    let endIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#end-jump');
1997    let scrollClick = (type: number): void => {
1998      let recordNs: number = Utils.getInstance().getRecordStartNS();
1999      queryThreadByItid(
2000        type === 0 ? data.itid! : data.endItid!,
2001        type === 0 ? recordNs + data.startTs! : recordNs + data.endstartTs!
2002      ).then((result) => {
2003        if (result.length > 0) {
2004          //@ts-ignore
2005          let pt: {
2006            pid: number;
2007            tid: number;
2008            dur: number;
2009            name: string;
2010            depth: number;
2011          } = result[0];
2012          scrollCallback({
2013            pid: pt.pid,
2014            tid: pt.tid,
2015            type: 'func',
2016            dur: pt.dur,
2017            depth: pt.depth,
2018            funName: pt.name,
2019            startTs: type === 0 ? data.startTs! : data.endstartTs!,
2020            keepOpen: true,
2021          });
2022        }
2023      });
2024    };
2025    if (startIcon) {
2026      startIcon.addEventListener('click', () => scrollClick(0));
2027    }
2028    if (endIcon) {
2029      endIcon.addEventListener('click', () => scrollClick(1));
2030    }
2031  }
2032
2033  setStaticInitData(data: SoStruct, scrollCallback: Function): void {
2034    this.setTableHeight('550px');
2035    this.initCanvas();
2036    this.setStaticInitStyle();
2037    let list: unknown[] = [];
2038    list.push({ name: 'Name', value: data.soName });
2039    list.push({
2040      name: 'StartTime(Relative)',
2041      value: `<div style="white-space: nowrap;display: flex;align-items: center">
2042<div style="white-space:pre-wrap">${getTimeString(data.startTs || 0)}</div>
2043<lit-icon id="start-jump" style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" name="select" color="#7fa1e7" size="20"></lit-icon>
2044</div>`,
2045    });
2046    list.push({
2047      name: 'StartTime(Absolute)',
2048      value: ((data.startTs || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
2049    });
2050    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
2051    this.currentSelectionTbl!.dataSource = list;
2052    this.startIconClickEvent(data, scrollCallback);
2053  }
2054
2055  private setStaticInitStyle(): void {
2056    let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
2057    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
2058      ?.querySelector('#rightButton')
2059      ?.shadowRoot?.querySelector('#custom-button');
2060    if (rightTitle) {
2061      rightTitle.style.visibility = 'hidden';
2062      rightButton!.style.visibility = 'hidden';
2063    }
2064    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
2065    if (leftTitle) {
2066      leftTitle.innerText = 'Details';
2067    }
2068  }
2069
2070  private startIconClickEvent(data: SoStruct, scrollCallback: Function): void {
2071    let startIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#start-jump');
2072    if (startIcon) {
2073      startIcon.addEventListener('click', () => {
2074        let recordNs: number = Utils.getInstance().getRecordStartNS();
2075        queryThreadByItid(data.itid!, recordNs + data.startTs!).then((result) => {
2076          if (result.length > 0) {
2077            //@ts-ignore
2078            let pt: {
2079              pid: number;
2080              tid: number;
2081              dur: number;
2082              name: string;
2083              depth: number;
2084            } = result[0];
2085            scrollCallback({
2086              pid: pt.pid,
2087              tid: pt.tid,
2088              type: 'func',
2089              dur: pt.dur,
2090              depth: pt.depth,
2091              funName: pt.name,
2092              startTs: data.startTs,
2093              keepOpen: true,
2094            });
2095          }
2096        });
2097      });
2098    }
2099  }
2100
2101  async setFrameAnimationData(data: FrameAnimationStruct, scrollCallback: Function): Promise<void> {
2102    this.setTableHeight('550px');
2103    this.tabCurrentSelectionInit('Animation Details');
2104    let list = [];
2105    let dataTs: number = data.startTs < 0 ? 0 : data.startTs;
2106    list.push({ name: 'Name', value: data.name });
2107    list.push({ name: 'Start time(Relative)', value: `${Utils.getTimeString(dataTs)}` });
2108    list.push({
2109      name: 'Start time(Absolute)',
2110      value: ((dataTs || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
2111    });
2112    list.push({
2113      name: 'End time(Relative)',
2114      value: `${Utils.getTimeString(dataTs + (data.dur || 0))}`,
2115    });
2116    list.push({
2117      name: 'End time(Absolute)',
2118      value: (dataTs + (data.dur || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
2119    });
2120    list.push({ name: 'Duration', value: `${Utils.getTimeString(data.dur || 0)}` });
2121    if (data.status === 'Completion delay') {
2122      let queryJoinName = `${data.frameInfo?.split(':')[1]}: ${data.name?.split(':')![1]}`;
2123      let frameFpsMessage = data.frameInfo?.split(':');
2124      await queryFpsSourceList(data.inputTime, data.endTime, queryJoinName).then((result) => {
2125        if (result.length > 0) {
2126          this.isFpsAvailable = true;
2127          this.fpsResult = result;
2128        } else {
2129          this.isFpsAvailable = false;
2130        }
2131      });
2132      if (frameFpsMessage) {
2133        if (frameFpsMessage[1] !== '0') {
2134          if (this.isFpsAvailable) {
2135            list.push({
2136              name: 'FPS',
2137              value: `<div style="white-space: nowrap;display: flex;align-items: center">
2138            <div style="white-space:pre-wrap">${frameFpsMessage[1]}</div>
2139            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="fps-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
2140            </div>`,
2141            });
2142          } else {
2143            list.push({ name: 'FPS', value: `${frameFpsMessage[1]}` });
2144          }
2145        } else {
2146          let fixedNumber: number = 2;
2147          let fpsValue: number = Number(frameFpsMessage[0]) / (data.dur / 1000_000_000);
2148          list.push({ name: 'FPS', value: `${fpsValue.toFixed(fixedNumber) || 0}` });
2149        }
2150      }
2151    }
2152    this.currentSelectionTbl!.dataSource = list;
2153    this.fpsClickEvent(data, scrollCallback);
2154  }
2155
2156  private fpsClickEvent(data: FrameAnimationStruct, scrollCallback: Function): void {
2157    let recordNs: number = Utils.getInstance().getRecordStartNS();
2158    this.currentSelectionTbl?.shadowRoot?.querySelector('#fps-jump')?.addEventListener('click', () => {// @ts-ignore
2159      let pt: {
2160        pid: number;
2161        tid: number;
2162        name: string;
2163        ts: number;
2164        dur: number;
2165        depth: number;
2166      } = this.fpsResult[0];
2167      scrollCallback({
2168        pid: pt.tid,
2169        tid: pt.tid,
2170        dur: pt.dur,
2171        type: 'func',
2172        depth: pt.depth,
2173        funName: pt.name,
2174        startTs: pt.ts - recordNs,
2175        keepOpen: true,
2176      });
2177    });
2178  }
2179
2180  private setJankType(data: JankStruct, list: unknown[]): void {
2181    if (data.jank_tag === 1) {
2182      if (data.frameType === 'render_service') {
2183        list.push({ name: 'Jank Type', value: 'RenderService Deadline Missed' });
2184      } else if (data.frameType === 'app') {
2185        list.push({ name: 'Jank Type', value: 'APP Deadline Missed' });
2186      } else if (data.frameType === 'frameTime') {
2187        list.push({ name: 'Jank Type', value: 'Deadline Missed' });
2188      }
2189    } else if (data.jank_tag === 3) {
2190      list.push({ name: 'Jank Type', value: 'Deadline Missed' });
2191    } else {
2192      list.push({ name: 'Jank Type', value: 'NONE' });
2193    }
2194  }
2195
2196  private setJankCommonMessage(list: unknown[], data: JankStruct): void {
2197    list.push({ name: 'Name', value: data.name });
2198    list.push({ name: 'StartTime(Relative)', value: getTimeString(data.ts || 0) });
2199    list.push({
2200      name: 'StartTime(Absolute)',
2201      value: ((data.ts || 0) + Utils.getInstance().getRecordStartNS()) / 1000000000 + 's',
2202    });
2203    list.push({ name: 'Duration', value: data.dur ? getTimeString(data.dur) : ' ' });
2204    if (data.frameType !== 'frameTime') {
2205      list.push({ name: 'Process', value: data.cmdline + ' ' + data.pid });
2206    }
2207  }
2208
2209  private setTableHeight(height: string): void {
2210    this.scrollView!.scrollTop = 0;
2211    this.currentSelectionTbl!.style.height = height;
2212    this.wakeupListTbl!.style.display = 'none';
2213  }
2214
2215  private addJankScrollCallBackEvent(
2216    scrollCallback: ((d: unknown) => void) | undefined,
2217    callback: ((data: Array<unknown>) => void) | undefined,
2218    jankJumperList: JankTreeNode[]
2219  ): void {
2220    let all = this.currentSelectionTbl?.shadowRoot?.querySelectorAll('.jank_cla');
2221    all!.forEach((a) => {
2222      a.addEventListener('click', () => {
2223        if (scrollCallback) {
2224          scrollCallback({
2225            rowId: a.id,
2226            name: a.getAttribute('slice_name'),
2227            pid: a.getAttribute('pid'),
2228          });
2229        }
2230      });
2231    });
2232    if (callback) {
2233      callback(jankJumperList);
2234    }
2235  }
2236
2237  async queryThreadStateDArgs(argSetID: number | undefined): Promise<BinderArgBean[]> {
2238    let list: Array<BinderArgBean> = [];
2239    if (argSetID !== undefined && argSetID > 0) {
2240      list = await queryThreadStateArgs(argSetID);
2241    }
2242    return list;
2243  }
2244
2245  /**
2246   * 查询出 线程被唤醒的 线程信息
2247   * @param data
2248   */
2249  async queryCPUWakeUpFromData(data: CpuStruct): Promise<WakeupBean | null> {
2250    let wb: WakeupBean | null = null;
2251    if (data.id === undefined || data.startTime === undefined) {
2252      return null;
2253    }
2254    let wakeup = await queryRunnableTimeByRunning(data.tid!, data.startTime);
2255    if (wakeup && wakeup[0]) {
2256      let wakeupTs = wakeup[0].ts as number;
2257      let recordStartTs = Utils.getInstance().getRecordStartNS();
2258      let wf = await queryThreadWakeUpFrom(data.id, wakeupTs);
2259      // @ts-ignore
2260      if (wf && wf[0]) {
2261        // @ts-ignore
2262        wb = wf[0];
2263        if (wb !== null) {
2264          wb.wakeupTime = wakeupTs - recordStartTs;
2265          wb.process = Utils.getInstance().getProcessMap().get(wb.pid!) || 'Process';
2266          wb.thread = Utils.getInstance().getThreadMap().get(wb.tid!) || 'Thread';
2267          wb.schedulingLatency = (data.startTime || 0) - (wb.wakeupTime || 0);
2268          wb.schedulingDesc = INPUT_WORD;
2269        }
2270      }
2271    }
2272    return wb;
2273  }
2274
2275  /**
2276   * 查询出 线程被唤醒的 线程链信息
2277   * @param data
2278   */
2279  static async queryCPUWakeUpListFromBean(data: WakeupBean): Promise<WakeupBean | null> {
2280    let wb: WakeupBean | null = null;
2281    let wakeup = await queryRunnableTimeByRunning(data.tid!, data.ts!);
2282    if (wakeup && wakeup[0]) {
2283      let wakeupTs = wakeup[0].ts as number;
2284      let recordStartTs = Utils.getInstance().getRecordStartNS();
2285      let wf = await queryThreadWakeUpFrom(data.itid!, wakeupTs);
2286      // @ts-ignore
2287      if (wf && wf[0]) {
2288        // @ts-ignore
2289        wb = wf[0];
2290        if (wb !== null) {
2291          wb.wakeupTime = wakeupTs - recordStartTs;
2292          wb.process = Utils.getInstance().getProcessMap().get(wb.pid!) || 'Process';
2293          wb.thread = Utils.getInstance().getThreadMap().get(wb.tid!) || 'Thread';
2294          wb.schedulingLatency = (data.ts || 0) - (wb.wakeupTime || 0);
2295          wb.schedulingDesc = INPUT_WORD;
2296        }
2297      }
2298    }
2299    return wb;
2300  }
2301
2302  /**
2303   * 查询出 线程唤醒了哪些线程信息
2304   */
2305  async queryThreadWakeUpFromData(itid: number, startTime: number, dur: number): Promise<WakeupBean | undefined> {
2306    let wakeUps = await queryThreadWakeUpFrom(itid, startTime + Utils.getInstance().getRecordStartNS());
2307    let item;
2308    // @ts-ignore
2309    if (wakeUps !== undefined && wakeUps.length > 0) {
2310      // @ts-ignore
2311      item = wakeUps[0];
2312    }
2313    return item;
2314  }
2315
2316  /**
2317   * 查询出 线程唤醒了哪些线程信息
2318   */
2319  async queryThreadWakeUpData(itid: number, startTime: number, dur: number): Promise<Array<WakeupBean>> {
2320    let list: Array<WakeupBean> = [];
2321    if (itid === undefined || startTime === undefined) {
2322      return list;
2323    }
2324    let wakeUps = await queryThreadWakeUp(itid, startTime, dur); //  3,4835380000
2325    if (wakeUps !== undefined && wakeUps.length > 0) {
2326      list.push(...wakeUps);
2327    }
2328    return list;
2329  }
2330  //递归查找R唤醒链
2331  getRWakeUpChain(data: WakeupBean | undefined): void {
2332    this.getRWakeUpChainData(data).then((wakeupFrom: unknown) => {
2333      if (wakeupFrom === null) {//当查不到数据时,处理容器状态与样式,展示内容
2334        let wakeupTopContent = this.currentSelectionTbl?.shadowRoot?.getElementById('wakeup-top-content');
2335        let wakeupTopIcon = this.currentSelectionTbl?.shadowRoot?.querySelector<HTMLDivElement>('#wakeup-top');
2336        wakeupTopContent!.innerText = 'idle' + this.topChainStr;//处理链顶部
2337        wakeupTopIcon!.style.display = 'none';
2338        wakeupTopContent!.style.display = 'block';
2339        wakeupTopContent!.style.maxHeight = '100px';//设置最大高度,超出出现滚动条
2340        wakeupTopContent!.style.overflow = 'auto';
2341        return;
2342      }
2343      //@ts-ignore
2344      this.topChainStr = `-->${wakeupFrom!.thread} [${wakeupFrom!.tid}]` + this.topChainStr;//链的拼接
2345      // @ts-ignore
2346      this.getRWakeUpChain(wakeupFrom);
2347    });
2348  }
2349
2350  /**
2351   * 获取 R的唤醒链
2352   * @param data
2353  */
2354  async getRWakeUpChainData(data: unknown): Promise<WakeupBean | null> {
2355    let wakeupFrom: WakeupBean | null = null;
2356    //@ts-ignore
2357    let wakeup = await queryRunnableTimeByRunning(data.tid!, data.ts!);//通过链上的Running块,查找前一条R信息
2358    if (wakeup && wakeup[0]) {
2359      let wakeupTs = wakeup[0].ts as number;
2360      //@ts-ignore
2361      let wf = await queryRWakeUpFrom(data.itid!, wakeupTs);//查找到的前一条R信息,对应的唤醒信息
2362      //@ts-ignore
2363      if (wf && wf[0]) {
2364        //@ts-ignore
2365        wakeupFrom = wf[0];
2366        //@ts-ignore
2367        wakeupFrom.thread = Utils.getInstance().getThreadMap().get(wakeupFrom.tid!) || 'Thread';
2368      }
2369    }
2370    return wakeupFrom;
2371  }
2372
2373  initCanvas(): HTMLCanvasElement | null {
2374    let canvas = this.shadowRoot!.querySelector<HTMLCanvasElement>('#rightDraw');
2375    let width = getComputedStyle(this.currentSelectionTbl!).getPropertyValue('width');
2376    if (canvas !== null) {
2377      canvas.width = Math.round(Number(width.replace('px', '')) * this.dpr);
2378      canvas.height = Math.round(Number(200 * this.dpr));
2379      canvas.style.width = width;
2380      canvas.style.height = '200px';
2381      canvas.getContext('2d')!.scale(this.dpr, this.dpr);
2382    }
2383    SpApplication.skinChange = (val: boolean): void => {
2384      this.drawRight(canvas, this.weakUpBean!);
2385    };
2386    return canvas;
2387  }
2388
2389  drawRight(cavs: HTMLCanvasElement | null, wakeupBean: WakeupBean | null): void {
2390    if (cavs === null) {
2391      return;
2392    }
2393    let context = cavs.getContext('2d');
2394    if (context !== null) {
2395      //绘制竖线
2396      this.drawVerticalLine(context);
2397      //绘制菱形
2398      context.lineWidth = 1;
2399      context.beginPath();
2400      context.moveTo(10, 30);
2401      context.lineTo(4, 40);
2402      context.lineTo(10, 50);
2403      context.lineTo(16, 40);
2404      context.lineTo(10, 30);
2405      context.closePath();
2406      context.fill();
2407      context.font = 12 + 'px sans-serif';
2408      //绘制wake up 文字
2409      let strList = [];
2410      strList.push('wakeup @ ' + getTimeString(wakeupBean?.wakeupTime || 0) + ' on CPU ' + wakeupBean?.cpu + ' by');
2411      strList.push('P:' + wakeupBean?.process + ' [ ' + wakeupBean?.pid + ' ]');
2412      strList.push('T:' + wakeupBean?.thread + ' [ ' + wakeupBean?.tid + ' ]');
2413      strList.forEach((str, index) => {
2414        if (context !== null) {
2415          context.fillText(str, 40, 40 + 16 * index);
2416        }
2417      });
2418      context.lineWidth = 2;
2419      context.lineJoin = 'bevel';
2420      context.moveTo(10, 95);
2421      context.lineTo(20, 90);
2422      context.moveTo(10, 95);
2423      context.lineTo(20, 100);
2424      context.moveTo(10, 95);
2425      context.lineTo(80, 95);
2426      context.lineTo(70, 90);
2427      context.moveTo(80, 95);
2428      context.lineTo(70, 100);
2429      context.stroke();
2430      //绘制latency
2431      context.font = 12 + 'px sans-serif';
2432      context.fillText('Scheduling latency:' + getTimeString(wakeupBean?.schedulingLatency || 0), 90, 100);
2433      //绘制最下方提示语句
2434      context.font = 10 + 'px sans-serif';
2435      INPUT_WORD.split('\n').forEach((str, index) => {
2436        context?.fillText(str, 90, 120 + 12 * index);
2437      });
2438    }
2439  }
2440
2441  private drawVerticalLine(context: CanvasRenderingContext2D): void {
2442    if (document.querySelector<SpApplication>('sp-application')!.dark) {
2443      context.strokeStyle = '#ffffff';
2444      context.fillStyle = '#ffffff';
2445    } else {
2446      context.strokeStyle = '#000000';
2447      context.fillStyle = '#000000';
2448    }
2449    context.lineWidth = 2;
2450    context.moveTo(10, 15);
2451    context.lineTo(10, 125);
2452    context.stroke();
2453  }
2454
2455  transferString(str: string): string {
2456    let s = '';
2457    if (str.length === 0) {
2458      return '';
2459    }
2460    s = str.replace(/&/g, '&amp;');
2461    s = s.replace(/</g, '&lt;');
2462    s = s.replace(/>/g, '&gt;');
2463    s = s.replace(/\'/g, '&#39;');
2464    s = s.replace(/\"/g, '&#quat;');
2465    return s;
2466  }
2467
2468  initElements(): void {
2469    this.currentSelectionTbl = this.shadowRoot?.querySelector<LitTable>('#selectionTbl');
2470    this.wakeupListTbl = this.shadowRoot?.querySelector<LitTable>('#wakeupListTbl');
2471    this.scrollView = this.shadowRoot?.querySelector<HTMLDivElement>('#scroll_view');
2472    this.currentSelectionTbl?.addEventListener('column-click', (ev: unknown): void => { }); //@ts-ignore
2473    window.subscribe(window.SmartEvent.UI.WakeupList, (data: Array<WakeupBean>) => this.showWakeupListTableData(data));
2474  }
2475
2476  showWakeupListTableData(data: Array<WakeupBean>): void {
2477    this.wakeupListTbl!.style.display = 'flex';
2478    let cpus: number[] = [];
2479    let itids: number[] = [];
2480    let ts: number[] = [];
2481    let maxPriority = 0;
2482    let maxPriorityDuration = 0;
2483    let maxDuration = 0;
2484    data.forEach((it) => {
2485      cpus.push(it.cpu!);
2486      itids.push(it.itid!);
2487      ts.push(it.ts!);
2488    });
2489    queryWakeupListPriority(itids, ts, cpus).then((res) => {
2490      let resource = data.map((it) => {
2491        let wake = {
2492          process: `${it.process}(${it.pid})`,
2493          thread: `${it.thread}(${it.tid})`,
2494          cpu: it.cpu,
2495          dur: it.dur,
2496          priority: 0,
2497          isSelected: false,
2498        };
2499        //@ts-ignore
2500        let find = res.find((re) => re.cpu === it.cpu && re.itid === it.itid && re.ts === it.ts);
2501        if (find) {
2502          //@ts-ignore
2503          wake.priority = find.priority;
2504        }
2505        maxDuration = Math.max(maxDuration, it.dur!);
2506        maxPriority = Math.max(maxPriority, wake.priority);
2507        return wake;
2508      });
2509      if (this.selectWakeupBean) {
2510        // 点击第一层唤醒树时向数组头部添加当前点击信息
2511        if (data[0].schedulingLatency) {
2512          // @ts-ignore
2513          resource.unshift(this.selectWakeupBean);
2514        }
2515        // @ts-ignore
2516        maxDuration = Math.max(maxDuration, this.selectWakeupBean.dur);
2517        // @ts-ignore
2518        maxPriority = Math.max(maxPriority, this.selectWakeupBean.priority);
2519      }
2520      resource.forEach((it) => {
2521        if (it.priority === maxPriority) {
2522          maxPriorityDuration = Math.max(it.dur || 0, maxPriorityDuration);
2523        }
2524      });
2525      this.updateTableSettings(maxPriority, maxPriorityDuration, maxDuration);
2526      this.wakeupListTbl!.style.display = 'flex';
2527      this.wakeupListTbl!.recycleDataSource = resource;
2528    });
2529  }
2530
2531  private updateTableSettings(maxPriority: number, maxPriorityDuration: number, maxDuration: number): void {
2532    this.wakeupListTbl!.getItemTextColor = (data: unknown): string => {
2533      // @ts-ignore
2534      if ((data.priority === maxPriority && data.dur === maxPriorityDuration) || data.dur === maxDuration) {
2535        return '#f44336';
2536      } else {
2537        return '#262626';
2538      }
2539    };
2540  }
2541
2542  addTableObserver(): void {
2543    let leftTable = this.shadowRoot?.querySelector('.table-left');
2544    this.tableObserver?.observe(leftTable!, {
2545      attributes: true,
2546      attributeFilter: ['style'],
2547      attributeOldValue: true,
2548    });
2549  }
2550
2551  initHtml(): string {
2552    return TabPaneCurrentSelectionHtml;
2553  }
2554}
2555
2556export class JankTreeNode {
2557  name: string = '';
2558  pid: number = -1;
2559  frameType: string = '';
2560  type: number = 0;
2561
2562  constructor(name: string, pid: number, frameType: string) {
2563    this.name = name;
2564    this.pid = pid;
2565    this.frameType = frameType;
2566  }
2567
2568  children: Array<JankTreeNode> = [];
2569}
2570
2571export class ThreadTreeNode {
2572  tid: number = 0;
2573  pid: number = -1;
2574  startTime: number = 1;
2575  depth: number = 0;
2576
2577  constructor(tid: number, pid: number, startTime: number, depth: number = 0) {
2578    this.tid = tid;
2579    this.pid = pid;
2580    this.startTime = startTime;
2581    this.depth = depth;
2582  }
2583}
2584
2585class FunDetail {
2586  slice: string = '';
2587  CN: string = '';
2588  EN: string = '';
2589}
2590
2591class SortData {
2592  value: string = '';
2593  dur: number = 0;
2594  bytes: number = 0;
2595}
2596