• 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 { ColorUtils } from '../base/ColorUtils';
30import { IrqStruct } from '../../../database/ui-worker/ProcedureWorkerIrq';
31import { BinderArgBean } from '../../../bean/BinderArgBean';
32import { JankStruct } from '../../../database/ui-worker/ProcedureWorkerJank';
33import { Utils } from '../base/Utils';
34import { SpSystemTrace } from '../../SpSystemTrace';
35import { AppStartupStruct } from '../../../database/ui-worker/ProcedureWorkerAppStartup';
36import { SoStruct } from '../../../database/ui-worker/ProcedureWorkerSoInit';
37import { type SelectionParam } from '../../../bean/BoxSelection';
38import { type FrameAnimationStruct } from '../../../database/ui-worker/ProcedureWorkerFrameAnimation';
39import {
40  queryBinderByArgsId,
41  queryBinderBySliceId,
42  queryFlowsData,
43  queryPrecedingData,
44  queryThreadByItid,
45  queryFpsSourceList,
46  queryStateFreqList,
47} from '../../../database/sql/SqlLite.sql';
48import {
49  queryBinderArgsByArgset,
50  queryRunnableTimeByRunning,
51  queryThreadNearData,
52  queryThreadStateArgs,
53  queryThreadWakeUp,
54  queryThreadWakeUpFrom,
55} from '../../../database/sql/ProcessThread.sql';
56import { queryGpuDur } from '../../../database/sql/Gpu.sql';
57import { queryWakeupListPriority } from '../../../database/sql/Cpu.sql';
58import { TabPaneCurrentSelectionHtml } from './TabPaneCurrentSelection.html';
59import { queryRealTime } from '../../../database/sql/Clock.sql';
60import { PerfToolStruct } from '../../../database/ui-worker/ProcedureWorkerPerfTool';
61
62const INPUT_WORD =
63  '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.';
64
65const CLOCK_STARTTIME_ABSALUTED_ID: string = 'clockStartTimeAbsaluteId';
66const CLOCK_TRANSF_BTN_ID: string = 'clockTransfBtnId';
67const CPU_STARTTIME_ABSALUTED_ID: string = 'cpuStartTimeAbsaluteId';
68const CPU_TRANSF_BTN_ID: string = 'cpuTransfBtnId';
69const THREAD_STARTTIME_ABSALUTED_ID: string = 'threadStartTimeAbsaluteId';
70const THREAD_TRANSF_BTN_ID: string = 'threadTransfBtnId';
71const FUN_STARTTIME_ABSALUTED_ID: string = 'funStartTimeAbsaluteId';
72const FUN_TRANSF_BTN_ID: string = 'funTransfBtnId';
73
74export function getTimeString(ns: number): string {
75  if (ns === 0) {
76    return '0';
77  }
78  let currentTimeNs = ns;
79  let hour1 = 3600_000_000_000;
80  let minute1 = 60_000_000_000;
81  let second1 = 1_000_000_000; // 1 second
82  let millisecond1 = 1_000_000; // 1 millisecond
83  let microsecond1 = 1_000; // 1 microsecond
84  let res = '';
85  if (currentTimeNs >= hour1) {
86    res += Math.floor(currentTimeNs / hour1) + 'h ';
87    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / hour1) * hour1;
88  }
89  if (currentTimeNs >= minute1) {
90    res += Math.floor(currentTimeNs / minute1) + 'm ';
91    currentTimeNs = currentTimeNs - Math.floor(ns / minute1) * minute1;
92  }
93  if (currentTimeNs >= second1) {
94    res += Math.floor(currentTimeNs / second1) + 's ';
95    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / second1) * second1;
96  }
97  if (currentTimeNs >= millisecond1) {
98    res += Math.floor(currentTimeNs / millisecond1) + 'ms ';
99    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / millisecond1) * millisecond1;
100  }
101  if (currentTimeNs >= microsecond1) {
102    res += Math.floor(currentTimeNs / microsecond1) + 'μs ';
103    currentTimeNs = currentTimeNs - Math.floor(currentTimeNs / microsecond1) * microsecond1;
104  }
105  if (currentTimeNs > 0) {
106    res += currentTimeNs.toFixed(0) + 'ns ';
107  }
108  return res;
109}
110
111@element('tabpane-current-selection')
112export class TabPaneCurrentSelection extends BaseElement {
113  weakUpBean: WakeupBean | null | undefined;
114  selectWakeupBean: unknown;
115  private currentSelectionTbl: LitTable | null | undefined;
116  private tableObserver: MutationObserver | undefined;
117  private wakeupListTbl: LitTable | undefined | null;
118  private scrollView: HTMLDivElement | null | undefined;
119  // @ts-ignore
120  private dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
121  private wakeUp: string = '';
122  private isFpsAvailable: boolean = true;
123  private realTime: number = 0;
124  private bootTime: number = 0;
125
126  set data(selection: unknown) {
127    // @ts-ignore
128    if (selection !== undefined && selection.constructor && selection.constructor.name !== 'SelectionParam') {
129      // @ts-ignore
130      this.setCpuData(selection);
131    }
132  }
133
134  /**
135   * 创建StartTime的Dom节点
136   * @param selectTable面板的dom树对象
137   * @param startTs 开始时间
138   * @param transfBtnId 转换按钮id
139   * @param startTimeAbsaluteId 开始时间的id
140   */
141  createStartTimeNode(list: unknown[], startTs: number, transfBtnId: string, startTimeAbsaluteId: string): void {
142    let timeStr: string = '';
143    let startTimeValue: string = '';
144    // @ts-ignore
145    let startTimeAbsolute = startTs + (window as unknown).recordStartNS;
146    if (this.realTime > 0) {
147      if (Utils.isTransformed) {
148        timeStr = this.getRealTimeStr(startTimeAbsolute);
149      } else {
150        timeStr = startTimeAbsolute / 1000000000 + 's';
151      }
152      startTimeValue = `<div style="white-space: nowrap;display: flex;align-items: center">
153                            <div id="${startTimeAbsaluteId}" style="white-space:pre-wrap" >${timeStr}</div>
154                            <lit-icon id="${transfBtnId}" class="temp-icon" title="Convert to realtime" name="restore" size="30"
155                                  style="position: relative; top: 5px; left: 10px;"></lit-icon>
156                        </div>`;
157    } else {
158      startTimeValue = startTimeAbsolute / 1000000000 + 's';
159    }
160    list.push({
161      name: 'StartTime(Absolute)',
162      value: startTimeValue,
163    });
164  }
165
166  /**
167   * 给转换按钮添加点击事件
168   * @param startTimeAbsolute 开始时间
169   * @param transfBtnId 转换按钮id
170   * @param startTimeAbsaluteId 开始时间ID
171   */
172  addClickToTransfBtn(startTimeAbsolute: number, transfBtnId: string, startTimeAbsaluteId: string): void {
173    let transfBtn = this.currentSelectionTbl?.shadowRoot?.querySelector(`#${transfBtnId}`);
174    transfBtn?.addEventListener('click', () => {
175      let startTimeAbsalute = this.currentSelectionTbl?.shadowRoot?.querySelector(`#${startTimeAbsaluteId}`);
176      if (startTimeAbsalute) {
177        if (Utils.isTransformed) {
178          startTimeAbsalute!.innerHTML = startTimeAbsolute / 1000000000 + 's';
179          Utils.isTransformed = false;
180        } else {
181          startTimeAbsalute!.innerHTML = this.getRealTimeStr(startTimeAbsolute);
182          Utils.isTransformed = true;
183        }
184      }
185    });
186  }
187
188  async setCpuData(
189    data: CpuStruct,
190    callback: ((data: WakeupBean | null) => void) | undefined = undefined,
191    scrollCallback?: (data: CpuStruct) => void
192  ): Promise<void> {
193    await this.setRealTime();
194    this.setTableHeight('650px');
195    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
196    if (leftTitle) {
197      leftTitle.innerText = 'Slice Details';
198    }
199    let list: unknown[] = [];
200    this.updateUI(data, list);
201    Promise.all([this.queryThreadStateDArgs(data.argSetID), this.queryCPUWakeUpFromData(data)]).then((resArr) => {
202      let args = resArr[0];
203      let bean = resArr[1];
204      if (callback) {
205        callback(bean);
206      }
207      if (args.length > 0) {
208        args.forEach((arg) => {
209          list.push({ name: arg.keyName, value: arg.strValue });
210        });
211      }
212      this.currentSelectionTbl!.dataSource = list;
213      // @ts-ignore
214      let startTimeAbsolute = (data.startTime || 0) + (window as unknown).recordStartNS;
215      this.addClickToTransfBtn(startTimeAbsolute, CPU_TRANSF_BTN_ID, CPU_STARTTIME_ABSALUTED_ID);
216
217      let rightArea: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#table-right');
218      let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
219      let rightButton: HTMLElement | null | undefined = this?.shadowRoot
220        ?.querySelector('#rightButton')
221        ?.shadowRoot?.querySelector('#custom-button');
222      let rightStar: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#right-star');
223      this.threadClickEvent(scrollCallback, data);
224      let canvas = this.initCanvas();
225      if (bean !== null) {
226        this.selectWakeupBean = {
227          process: `${this.transferString(data.processName || 'Process')}(${data.processId})`,
228          thread: `${this.transferString(data.name || 'Thread')}(${data.tid})`,
229          cpu: data.cpu,
230          dur: data.dur,
231          priority: data.priority,
232          isSelected: false,
233        };
234
235        this.weakUpBean = bean;
236        this.updateRightTitleUI(rightArea!, rightTitle!, rightButton!, rightStar!);
237        this.drawRight(canvas, bean);
238      } else {
239        this.handleNullBeanUI(rightArea!, rightTitle!, rightButton!, rightStar!);
240      }
241    });
242  }
243
244  private threadClickEvent(scrollCallback: ((data: CpuStruct) => void) | undefined, data: CpuStruct): void {
245    let threadClick = this.currentSelectionTbl?.shadowRoot?.querySelector('#thread-id');
246    threadClick?.addEventListener('click', () => {
247      //cpu点击
248      if (scrollCallback) {
249        data.state = 'Running';
250        scrollCallback(data);
251      }
252    });
253  }
254
255  private updateRightTitleUI(
256    rightArea: HTMLElement,
257    rightTitle: HTMLElement,
258    rightButton: HTMLElement,
259    rightStar: HTMLElement
260  ): void {
261    if (rightArea !== null && rightArea) {
262      rightArea.style.visibility = 'visible';
263    }
264    if (rightTitle !== null && rightTitle) {
265      rightTitle.style.visibility = 'visible';
266      rightButton!.style.visibility = 'visible';
267      rightStar!.style.visibility = 'hidden';
268      SpSystemTrace.btnTimer = null;
269    }
270  }
271
272  private handleNullBeanUI(
273    rightArea: HTMLElement,
274    rightTitle: HTMLElement,
275    rightButton: HTMLElement,
276    rightStar: HTMLElement
277  ): void {
278    this.weakUpBean = null;
279    if (rightArea !== null && rightArea) {
280      rightArea.style.visibility = 'hidden';
281    }
282    if (rightTitle !== null && rightTitle) {
283      rightTitle.style.visibility = 'hidden';
284      rightButton!.style.visibility = 'hidden';
285      rightStar!.style.visibility = 'hidden';
286    }
287  }
288
289  private updateUI(data: CpuStruct, list: unknown[]): void {
290    let process = this.transferString(data.processName || 'Process');
291    let processId = data.processId || data.tid;
292    let state = '';
293    if (data.end_state) {
294      state = Utils.getEndState(data.end_state);
295    } else if (data.end_state === '' || data.end_state === null) {
296      state = '';
297    } else {
298      state = 'Unknown State';
299    }
300    list.push({
301      name: 'Process',
302      value: `${process || 'Process'} [${processId}]`,
303    });
304    let name = this.transferString(data.name ?? '');
305    if (data.processId) {
306      list.push({
307        name: 'Thread',
308        value: `<div style="white-space: nowrap;display: flex;align-items: center">
309<div style="white-space:pre-wrap">${name || 'Process'} [${data.tid}]</div>
310<lit-icon style="cursor:pointer;margin-left: 5px" id="thread-id" name="select" color="#7fa1e7" size="20"></lit-icon>
311</div>`,
312      });
313    } else {
314      list.push({
315        name: 'Thread',
316        value: `<div style="white-space: nowrap;display: flex;align-items: center">
317<div style="white-space:pre-wrap">${name || 'Process'} [${data.tid}]</div>
318</div>`,
319      });
320    }
321
322    list.push({ name: 'StartTime(Relative)', value: getTimeString(data.startTime || 0) });
323    this.createStartTimeNode(list, data.startTime || 0, CPU_TRANSF_BTN_ID, CPU_STARTTIME_ABSALUTED_ID);
324    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
325    list.push({ name: 'Prio', value: data.priority || 0 });
326    list.push({ name: 'End State', value: state });
327  }
328  // 设置真实时间和启动时间的值
329  private async setRealTime(): Promise<unknown> {
330    return queryRealTime().then((result) => {
331      if (result && result.length > 0) {
332        result.forEach((item) => {
333          if (item.name === 'realtime') {
334            this.realTime = item.ts;
335          } else {
336            this.bootTime = item.ts;
337          }
338        });
339      }
340    });
341  }
342
343  async setFunctionData(data: FuncStruct, scrollCallback: Function): Promise<void> {
344    //方法信息
345    await this.setRealTime();
346    this.tabCurrentSelectionInit('Slice Details');
347    let list: unknown[] = [];
348    let name = this.transferString(data.funName ?? '');
349    let isBinder = FuncStruct.isBinder(data);
350    let isAsyncBinder = isBinder && FuncStruct.isBinderAsync(data);
351    if (data.argsetid !== undefined && data.argsetid !== null && data.argsetid >= 0) {
352      this.setTableHeight('700px');
353      if (isAsyncBinder) {
354        this.handleAsyncBinder(data, list, name, scrollCallback);
355      } else if (isBinder) {
356        this.handleBinder(data, list, name, scrollCallback);
357      } else {
358        this.handleNonBinder(data, list, name);
359      }
360    } else {
361      this.setTableHeight('auto');
362      list.push({ name: 'Name', value: name });
363      list.push({
364        name: 'StartTime(Relative)',
365        value: getTimeString(data.startTs || 0),
366      });
367      this.createStartTimeNode(list, data.startTs || 0, FUN_TRANSF_BTN_ID, FUN_STARTTIME_ABSALUTED_ID);
368      list.push({
369        name: 'Duration',
370        value: getTimeString(data.dur || 0),
371      });
372      list.push({ name: 'depth', value: data.depth });
373      this.currentSelectionTbl!.dataSource = list;
374      // @ts-ignore
375      let startTimeAbsolute = (data.startTs || 0) + (window as unknown).recordStartNS;
376      this.addClickToTransfBtn(startTimeAbsolute, FUN_TRANSF_BTN_ID, FUN_STARTTIME_ABSALUTED_ID);
377    }
378  }
379
380  // 计算真实时间
381  private getRealTimeStr(startTs: number): string {
382    // @ts-ignore
383    let time = (startTs || 0) + (window as unknown).recordStartNS - this.bootTime + this.realTime;
384    const formateDateStr =
385      this.getDate(parseInt(time.toString().substring(0, 13))) + '.' + time.toString().substring(10);
386    return formateDateStr;
387  }
388
389  // 格式化时间戳为字符串格式 yyyy/mm/dd hh:mi:ss
390  private getDate(timestamp: number): string {
391    let date = new Date(timestamp);
392    let gmt = date.toLocaleString();
393    return gmt;
394  }
395
396  private handleNonBinder(data: FuncStruct, list: unknown[], name: string): void {
397    queryBinderArgsByArgset(data.argsetid!).then((argset) => {
398      list.push({ name: 'Name', value: name });
399      argset.forEach((item) => {
400        list.push({ name: item.keyName, value: item.strValue });
401      });
402      this.addTabPanelContent(list, data);
403      this.currentSelectionTbl!.dataSource = list;
404    });
405  }
406
407  private handleBinder(data: FuncStruct, list: unknown[], name: string, scrollCallback: Function): void {
408    queryBinderArgsByArgset(data.argsetid!).then((argset) => {
409      let binderSliceId = -1;
410      argset.forEach((item) => {
411        if (item.keyName === 'destination slice id') {
412          binderSliceId = Number(item.strValue);
413          list.unshift({
414            name: 'Name',
415            value: `<div style="white-space: nowrap;display: flex;align-items: center">
416<div style="white-space:pre-wrap">${name || 'binder'}</div>
417<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="function-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
418</div>`,
419          });
420        }
421        list.push({ name: item.keyName, value: item.strValue });
422      });
423      if (binderSliceId === -1) {
424        list.unshift({ name: 'Name', value: name });
425      }
426      this.addTabPanelContent(list, data);
427      this.currentSelectionTbl!.dataSource = list;
428      let funcClick = this.currentSelectionTbl?.shadowRoot?.querySelector('#function-jump');
429      funcClick?.addEventListener('click', () => {
430        if (!Number.isNaN(binderSliceId) && binderSliceId !== -1) {
431          queryBinderBySliceId(binderSliceId).then((result: unknown[]) => {
432            if (result.length > 0) {
433              // @ts-ignore
434              result[0].type = TraceRow.ROW_TYPE_FUNC;
435              scrollCallback(result[0]);
436            }
437          });
438        }
439      });
440    });
441  }
442
443  private handleAsyncBinder(data: FuncStruct, list: unknown[], name: string, scrollCallback: Function): void {
444    Promise.all([
445      queryBinderByArgsId(data.argsetid!, data.startTs!, !data.funName!.endsWith('rcv')),
446      queryBinderArgsByArgset(data.argsetid!),
447    ]).then((result) => {
448      let asyncBinderRes = result[0];
449      let argsBinderRes = result[1];
450      let asyncBinderStract: unknown;
451      if (asyncBinderRes.length > 0) {
452        //@ts-ignore
453        asyncBinderRes[0].type = TraceRow.ROW_TYPE_FUNC;
454        asyncBinderStract = asyncBinderRes[0];
455      }
456      if (argsBinderRes.length > 0) {
457        argsBinderRes.forEach((item) => {
458          list.push({
459            name: item.keyName,
460            value: item.strValue,
461          });
462        });
463      }
464      if (asyncBinderStract !== undefined) {
465        list.unshift({
466          name: 'Name',
467          value: `<div style="white-space: nowrap;display: flex;align-items: center">
468<div style="white-space:pre-wrap">${name || 'binder'}</div>
469<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="function-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
470</div>`,
471        });
472      } else {
473        list.unshift({ name: 'Name', value: name });
474      }
475      this.addTabPanelContent(list, data);
476      this.currentSelectionTbl!.dataSource = list;
477      let funcClick = this.currentSelectionTbl?.shadowRoot?.querySelector('#function-jump');
478      funcClick?.addEventListener('click', () => {
479        scrollCallback(asyncBinderStract);
480      });
481    });
482  }
483
484  private addTabPanelContent(contentList: unknown[], data: FuncStruct): void {
485    contentList.push({
486      name: 'StartTime(Relative)',
487      value: getTimeString(data.startTs || 0),
488    });
489    contentList.push({
490      name: 'StartTime(Absolute)',
491      // @ts-ignore
492      value: ((data.startTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
493    });
494    contentList.push({
495      name: 'Duration',
496      value: getTimeString(data.dur || 0),
497    });
498    contentList.push({ name: 'depth', value: data.depth });
499    if (data.argsetid && data.argsetid > -1) {
500      contentList.push({ name: 'arg_set_id', value: data.argsetid });
501    }
502  }
503
504  private tabCurrentSelectionInit(leftTitleStr: string): void {
505    this.initCanvas();
506    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
507    this.setTitleAndButtonStyle();
508    if (leftTitle) {
509      leftTitle.innerText = leftTitleStr;
510    }
511  }
512
513  private setTitleAndButtonStyle(): void {
514    let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
515    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
516      ?.querySelector('#rightButton')
517      ?.shadowRoot?.querySelector('#custom-button');
518    let rightStar: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#right-star');
519    if (rightTitle) {
520      rightTitle.style.visibility = 'hidden';
521      rightButton!.style.visibility = 'hidden';
522      rightStar!.style.visibility = 'hidden';
523    }
524  }
525
526  async setClockData(data: ClockStruct): Promise<void> {
527    await this.setRealTime();
528    this.setTableHeight('auto');
529    //时钟信息
530    this.tabCurrentSelectionInit('Counter Details');
531    let list: unknown[] = [];
532    list.push({
533      name: 'StartTime(Relative)',
534      value: getTimeString(data.startNS || 0),
535    });
536    this.createStartTimeNode(list, data.startNS || 0, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
537    list.push({
538      name: 'Value',
539      value: ColorUtils.formatNumberComma(data.value || 0),
540    });
541    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
542    this.currentSelectionTbl!.dataSource = list;
543    // @ts-ignore
544    let startTimeAbsolute = (data.startNS || 0) + (window as unknown).recordStartNS;
545    this.addClickToTransfBtn(startTimeAbsolute, CLOCK_TRANSF_BTN_ID, CLOCK_STARTTIME_ABSALUTED_ID);
546  }
547
548  setPerfToolsData(data: PerfToolStruct): void {
549    this.setTableHeight('auto');
550    //Perf Tools info
551    this.tabCurrentSelectionInit('Slice Details');
552    let list: unknown[] = [];
553    list.push({
554      name: 'Name',
555      value: data.name,
556    });
557    list.push({
558      name: 'StartTime(Relative)',
559      value: getTimeString(data.startNS || 0),
560    });
561    list.push({
562      name: 'StartTime(Absolute)',
563      // @ts-ignore
564      value: ((data.startNS || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
565    });
566    list.push({
567      name: 'Value',
568      value: Number(data.count),
569    });
570    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
571    this.currentSelectionTbl!.dataSource = list;
572  }
573
574  setMemData(data: ProcessMemStruct): void {
575    this.setTableHeight('auto');
576    //时钟信息
577    this.initCanvas();
578    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
579    if (leftTitle) {
580      leftTitle.innerText = 'Counter Details';
581    }
582    let list: object[] = [];
583    list.push({
584      name: 'StartTime(Relative)',
585      value: getTimeString(data.startTime || 0),
586    });
587    list.push({
588      name: 'StartTime(Absolute)',
589      // @ts-ignore
590      value: ((data.startTime || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
591    });
592    list.push({ name: 'Value', value: data.value });
593    list.push({ name: 'Delta', value: data.delta });
594    list.push({
595      name: 'Duration',
596      value: getTimeString(data.duration || 0),
597    });
598    this.currentSelectionTbl!.dataSource = list;
599  }
600
601  setIrqData(data: IrqStruct): void {
602    this.setTableHeight('550px');
603    this.initCanvas();
604    this.setTitleAndButtonStyle();
605    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
606    if (leftTitle) {
607      leftTitle.innerText = 'Counter Details';
608    }
609    let list: object[] = [];
610    list.push({
611      name: 'StartTime(Relative)',
612      value: getTimeString(data.startNS || 0),
613    });
614    list.push({
615      name: 'StartTime(Absolute)',
616      // @ts-ignore
617      value: ((data.startNS || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
618    });
619    list.push({ name: 'Name', value: data.name });
620    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
621    queryBinderArgsByArgset(data.argSetId || 0).then((argsBinderRes) => {
622      if (argsBinderRes.length > 0) {
623        argsBinderRes.forEach((item) => {
624          list.push({ name: item.keyName, value: item.strValue });
625        });
626      }
627      this.currentSelectionTbl!.dataSource = list;
628    });
629  }
630
631  async setThreadData(
632    data: ThreadStruct,
633    scrollCallback: ((d: unknown) => void) | undefined,
634    scrollWakeUp: (d: unknown) => void | undefined,
635    callback?: (data: Array<unknown>, str: string) => void
636  ): Promise<void> {
637    //线程信息
638    await this.setRealTime();
639    this.setTableHeight('550px');
640    this.initCanvas();
641    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
642    this.setTitleAndButtonStyle();
643    if (leftTitle) {
644      leftTitle.innerText = 'Thread State';
645    }
646    let list: unknown[] = [];
647    let jankJumperList: Array<ThreadTreeNode> = [];
648    this.prepareThreadInfo(list, data);
649    let cpu = new CpuStruct();
650    cpu.id = data.id;
651    cpu.startTime = data.startTime;
652    this.queryThreadDetails(data, list, jankJumperList, callback, scrollWakeUp, scrollCallback);
653  }
654
655  private sortByNearData(nearData: unknown[], data: ThreadStruct, list: unknown[]): unknown[] {
656    let preData: unknown = undefined;
657    let nextData: unknown = undefined;
658
659    nearData
660      // @ts-ignore
661      .sort((near1, near2) => near1.startTime - near2.startTime)
662      .forEach((near) => {
663        // @ts-ignore
664        if (near.itid === data.id) {
665          // @ts-ignore
666          if (near.startTime < data.startTime!) {
667            preData = near;
668            list.push({
669              name: 'Previous State',
670              value: `<div style="white-space: nowrap;display: flex;align-items: center">
671              <div style="white-space:pre-wrap">${
672                // @ts-ignore
673                Utils.getEndState(near.state)
674              }</div>
675              <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="previous-state-click" name="select" color="#7fa1e7" size="20"></lit-icon>
676              </div>`,
677            });
678          } else {
679            nextData = near;
680            list.push({
681              name: 'Next State',
682              value: `<div style="white-space: nowrap;display: flex;align-items: center">
683              <div style="white-space:pre-wrap">${
684                // @ts-ignore
685                Utils.getEndState(near.state)
686              }</div>
687              <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="next-state-click" name="select" color="#7fa1e7" size="20"></lit-icon>
688              </div>`,
689            });
690          }
691        }
692      });
693    return [preData, nextData];
694  }
695
696  private setWakeupData(fromBean: WakeupBean | undefined, wakeUps: WakeupBean[], list: unknown[]): void {
697    if (fromBean !== null && fromBean !== undefined && fromBean.pid !== 0 && fromBean.tid !== 0) {
698      list.push({
699        name: 'wakeup from tid',
700        value: `<div style="white-space: nowrap;display: flex;align-items: center">
701            <div style="white-space:pre-wrap">${fromBean.tid}</div>
702            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="wakeup-from"
703            class="wakeup-click"  name="select" color="#7fa1e7" size="20"></lit-icon>
704            </div>`,
705      });
706    }
707    if (wakeUps !== null) {
708      wakeUps.map((e) => {
709        list.push({
710          name: 'wakeup tid',
711          value: `<div style="white-space: nowrap;display: flex;align-items: center">
712            <div style="white-space:pre-wrap">${e.tid}</div>
713            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="wakeup-${e.tid}"
714            class="wakeup-click" name="select" color="#7fa1e7" size="20"></lit-icon>
715            </div>`,
716        });
717      });
718    }
719  }
720
721  private queryThreadDetails(
722    data: ThreadStruct,
723    list: unknown[],
724    jankJumperList: ThreadTreeNode[],
725    callback: ((data: Array<unknown>, str: string) => void) | undefined,
726    scrollWakeUp: (d: unknown) => void | undefined,
727    scrollCallback: ((d: unknown) => void) | undefined
728  ): void {
729    Promise.all([
730      this.queryThreadWakeUpFromData(data.id!, data.startTime!, data.dur!),
731      this.queryThreadWakeUpData(data.id!, data.startTime!, data.dur!),
732      this.queryThreadStateDArgs(data.argSetID),
733      queryThreadNearData(data.id!, data.startTime!),
734    ]).then((result) => {
735      let fromBean = result[0] as WakeupBean;
736      let wakeUps = result[1] as WakeupBean[];
737      let args = result[2];
738      let [preData, nextData] = this.sortByNearData(result[3], data, list);
739      this.setWakeupData(fromBean, wakeUps, list);
740      if (args.length > 0) {
741        args.forEach((arg) => {
742          list.push({ name: arg.keyName, value: arg.strValue });
743        });
744      }
745      this.currentSelectionTbl!.dataSource = list;
746      // @ts-ignore
747      let startTimeAbsolute = (data.startTime || 0) + (window as unknown).recordStartNS;
748      this.addClickToTransfBtn(startTimeAbsolute, THREAD_TRANSF_BTN_ID, THREAD_STARTTIME_ABSALUTED_ID);
749      let timeLineNode = new ThreadTreeNode(data.tid!, data.pid!, data.startTime!);
750      jankJumperList.push(timeLineNode);
751      if (callback) {
752        callback(jankJumperList, this.wakeUp);
753        this.wakeUp = '';
754      }
755      this.stateClickHandler(preData, nextData, data, scrollWakeUp, scrollCallback);
756      this.wakeupClickHandler(wakeUps, fromBean, scrollWakeUp);
757    });
758  }
759
760  private wakeupClickHandler(
761    wakeUps: WakeupBean[],
762    fromBean: WakeupBean | undefined,
763    scrollWakeUp: (d: unknown) => void | undefined
764  ): void {
765    this.currentSelectionTbl?.shadowRoot?.querySelector('#wakeup-from')?.addEventListener('click', () => {
766      //点击跳转,唤醒和被唤醒的 线程
767      if (fromBean && scrollWakeUp) {
768        scrollWakeUp({
769          processId: fromBean.pid,
770          tid: fromBean.tid,
771          startTime: fromBean.ts,
772          dur: fromBean.dur,
773          cpu: fromBean.cpu,
774          id: fromBean.itid,
775          state: 'Running',
776          argSetID: fromBean.argSetID,
777        });
778      }
779      this.wakeUp = 'wakeup tid';
780    });
781    if (wakeUps) {
782      wakeUps.map((up) => {
783        this.currentSelectionTbl?.shadowRoot?.querySelector(`#wakeup-${up.tid}`)?.addEventListener('click', () => {
784          //点击跳转,唤醒和被唤醒的 线程
785          if (up && scrollWakeUp !== undefined) {
786            scrollWakeUp({
787              processId: up.pid,
788              tid: up.tid,
789              startTime: up.ts,
790              dur: up.dur,
791              cpu: up.cpu,
792              id: up.itid,
793              state: up.state,
794              argSetID: up.argSetID,
795            });
796          }
797          this.wakeUp = 'wakeup tid';
798        });
799      });
800    }
801  }
802
803  private stateClickHandler(
804    preData: unknown,
805    nextData: unknown,
806    data: ThreadStruct,
807    scrollWakeUp: (d: unknown) => void | undefined,
808    scrollCallback: ((d: unknown) => void) | undefined
809  ): void {
810    this.currentSelectionTbl?.shadowRoot?.querySelector('#next-state-click')?.addEventListener('click', () => {
811      if (nextData && scrollWakeUp !== undefined) {
812        scrollWakeUp({
813          // @ts-ignore
814          processId: nextData.pid,
815          // @ts-ignore
816          tid: nextData.tid,
817          // @ts-ignore
818          startTime: nextData.startTime,
819          // @ts-ignore
820          dur: nextData.dur,
821          // @ts-ignore
822          cpu: nextData.cpu,
823          // @ts-ignore
824          id: nextData.itid,
825          // @ts-ignore
826          state: nextData.state,
827          // @ts-ignore
828          argSetID: nextData.argSetID,
829        });
830      }
831    });
832
833    this.currentSelectionTbl?.shadowRoot?.querySelector('#previous-state-click')?.addEventListener('click', () => {
834      if (preData && scrollWakeUp !== undefined) {
835        scrollWakeUp({
836          // @ts-ignore
837          processId: preData.pid,
838          // @ts-ignore
839          tid: preData.tid,
840          // @ts-ignore
841          startTime: preData.startTime,
842          // @ts-ignore
843          dur: preData.dur,
844          // @ts-ignore
845          cpu: preData.cpu,
846          // @ts-ignore
847          id: preData.itid,
848          // @ts-ignore
849          state: preData.state,
850          // @ts-ignore
851          argSetID: preData.argSetID,
852        });
853      }
854    });
855
856    this.currentSelectionTbl?.shadowRoot?.querySelector('#state-click')?.addEventListener('click', () => {
857      //线程点击
858      if (scrollCallback) {
859        scrollCallback(data);
860      }
861    });
862  }
863
864  private async prepareThreadInfo(list: unknown[], data: ThreadStruct): Promise<void> {
865    list.push({
866      name: 'StartTime(Relative)',
867      value: getTimeString(data.startTime || 0),
868    });
869    this.createStartTimeNode(list, data.startTime || 0, THREAD_TRANSF_BTN_ID, THREAD_STARTTIME_ABSALUTED_ID);
870    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
871    let state;
872    if (data.state) {
873      state = Utils.getEndState(data.state);
874    } else if (data.state === '' || data.state === null) {
875      state = '';
876    } else {
877      state = 'Unknown State';
878    }
879    if ('Running' === state) {
880      state = state + ' on CPU ' + data.cpu;
881      list.push({
882        name: 'State',
883        value: `<div style="white-space: nowrap;display: flex;align-items: center">
884            <div style="white-space:pre-wrap">${state}</div>
885            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="state-click" name="select" color="#7fa1e7" size="20"></lit-icon>
886            </div>`,
887      });
888    } else {
889      list.push({ name: 'State', value: `${state}` });
890    }
891    if (state.includes('Running')) {
892      let startTime: number = data.startTime || 0;
893      let endTime: number = (data.startTime || 0) + (data.dur || 0);
894      let freqList: Array<unknown> = [];
895      let str = '';
896      freqList = await queryStateFreqList(startTime, endTime, data.cpu || 0);
897      freqList.forEach((it) => {
898        // @ts-ignore
899        if (it.startTime < startTime! && it.endTime > endTime!) {
900          // @ts-ignore
901          it.stateDur = data.dur;
902          // @ts-ignore
903        } else if (it.startTime < startTime! && startTime! < it.endTime && it.endTime < endTime!) {
904          // @ts-ignore
905          it.stateDur = it.endTime - startTime!;
906          // @ts-ignore
907        } else if (it.startTime > startTime! && startTime! < it.endTime && it.endTime < endTime!) {
908          // @ts-ignore
909          it.stateDur = it.dur;
910          // @ts-ignore
911        } else if (it.startTime > startTime! && endTime! > it.startTime && it.endTime > endTime!) {
912          // @ts-ignore
913          it.stateDur = endTime! - it.startTime;
914        }
915        // @ts-ignore
916        str += '[' + it.value + ': ' + (it.stateDur || 0) / 1000 + ']' + ',';
917      });
918      list.push({ name: 'Freq [KHz,μs]', value: str.substring(0, str.length - 1) });
919    }
920    let slice = Utils.SCHED_SLICE_MAP.get(`${data.id}-${data.startTime}`);
921    if (slice) {
922      list.push({ name: 'Prio', value: `${slice.priority}` });
923    }
924    let processName = Utils.PROCESS_MAP.get(data.pid!);
925    if (
926      processName === null ||
927      processName === undefined ||
928      processName === '' ||
929      processName.toLowerCase() === 'null'
930    ) {
931      processName = Utils.THREAD_MAP.get(data.tid!) || 'null';
932    }
933    list.push({
934      name: 'Process',
935      value: this.transferString(processName ?? '') + ' [' + data.pid + '] ',
936    });
937  }
938
939  setJankData(
940    data: JankStruct,
941    callback: ((data: Array<unknown>) => void) | undefined = undefined,
942    scrollCallback: ((d: unknown) => void) | undefined
943  ): void {
944    //线程信息
945    this.setTableHeight('750px');
946    this.tabCurrentSelectionInit('Slice Details');
947    let list: unknown[] = [];
948    this.setJankCommonMessage(list, data);
949    if (data.type === '0') {
950      this.handleTypeJank(data, list, scrollCallback, callback);
951    } else {
952      this.currentSelectionTbl!.dataSource = list;
953    }
954  }
955
956  private handleTypeJank(
957    data: JankStruct,
958    list: unknown[],
959    scrollCallback: ((d: unknown) => void) | undefined,
960    callback: ((data: Array<unknown>) => void) | undefined
961  ): void {
962    this.setJankType(data, list);
963    let jankJumperList: Array<JankTreeNode> = [];
964    if (data.frame_type === 'render_service') {
965      queryGpuDur(data.id!).then((it) => {
966        if (it.length > 0) {
967          //@ts-ignore
968          list.push({ name: 'Gpu Duration', value: getTimeString(it[0].gpu_dur) });
969        }
970      });
971      this.handleRenderServiceJank(data, list, jankJumperList, scrollCallback, callback);
972    } else if (data.frame_type === 'app') {
973      this.handleAppJank(list, data, jankJumperList, scrollCallback, callback);
974    } else if (data.frame_type === 'frameTime') {
975      this.handleFrameTimeJank(data, list, jankJumperList, scrollCallback, callback);
976    }
977  }
978
979  private handleFrameTimeJank(
980    data: JankStruct,
981    list: unknown[],
982    jankJumperList: JankTreeNode[],
983    scrollCallback: ((d: unknown) => void) | undefined,
984    callback: ((data: Array<unknown>) => void) | undefined
985  ): void {
986    queryGpuDur(data.id!).then((it) => {
987      if (it.length > 0) {
988        list.push({
989          name: 'Gpu Duration',
990          //@ts-ignore
991          value: getTimeString(it[0].gpu_dur),
992        });
993      }
994      this.addAppFrameDetails(data, list);
995      this.addRenderServiceFrameDetails(data, list);
996      this.addFollowingDetails(list, data);
997      let appNode = new JankTreeNode(data.name!, data.pid!, 'app');
998      let rsNode = new JankTreeNode(data.rs_vsync!, data.rs_pid!, 'render_service');
999      appNode.children.push(rsNode);
1000      jankJumperList.push(appNode);
1001      this.currentSelectionTbl!.dataSource = list;
1002      this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1003    });
1004  }
1005
1006  private addRenderServiceFrameDetails(data: JankStruct, list: unknown[]): void {
1007    if (data.rs_name) {
1008      list.push({
1009        name: 'RenderService Frame',
1010        value: '',
1011      });
1012      list.push({
1013        name: 'Process',
1014        value: 'render_service ' + data.rs_pid,
1015      });
1016      list.push({
1017        name: 'StartTime(Relative)',
1018        value: getTimeString(data.rs_ts || 0),
1019      });
1020      list.push({
1021        name: 'StartTime(Absolute)',
1022        // @ts-ignore
1023        value: ((data.rs_ts || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1024      });
1025      list.push({
1026        name: 'end time',
1027        value: getTimeString(data.rs_ts! + data.rs_dur! || 0),
1028      });
1029    }
1030  }
1031
1032  private addFollowingDetails(list: unknown[], data: JankStruct): void {
1033    list.push({
1034      name: 'Following',
1035      value: '',
1036    });
1037    list.push({
1038      name: 'Slice',
1039      value:
1040        data.cmdline +
1041        ' [' +
1042        data.name +
1043        ']' +
1044        `<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>`,
1045    });
1046  }
1047
1048  private addAppFrameDetails(data: JankStruct, list: unknown[]): void {
1049    if (data.name) {
1050      list.push({
1051        name: 'App Frame',
1052        value: '',
1053      });
1054      list.push({
1055        name: 'Process',
1056        value: data.cmdline + ' ' + data.pid,
1057      });
1058      list.push({
1059        name: 'StartTime(Relative)',
1060        value: getTimeString(data.ts || 0),
1061      });
1062      list.push({
1063        name: 'StartTime(Absolute)',
1064        // @ts-ignore
1065        value: ((data.ts || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1066      });
1067      list.push({
1068        name: 'end time',
1069        value: getTimeString(data!.ts! + data.dur! || 0),
1070      });
1071    }
1072  }
1073
1074  private handleAppJank(
1075    list: unknown[],
1076    data: JankStruct,
1077    jankJumperList: JankTreeNode[],
1078    scrollCallback: ((d: unknown) => void) | undefined,
1079    callback: ((data: Array<unknown>) => void) | undefined
1080  ): void {
1081    list.push({
1082      name: 'FrameTimeLine flows',
1083      value: '',
1084    });
1085    list.push({
1086      name: 'Slice',
1087      value:
1088        data.cmdline +
1089        ' [' +
1090        data.name +
1091        ']' +
1092        `<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>`,
1093    });
1094    let timeLineNode = new JankTreeNode(data.name!, data.pid!, 'frameTime');
1095    jankJumperList.push(timeLineNode);
1096    if (data.dst_slice) {
1097      queryPrecedingData(data.dst_slice).then((it) => {
1098        if (it.length > 0) {
1099          list.push({
1100            name: 'Preceding flows',
1101            value: '',
1102          });
1103          it.forEach((a: unknown) => {
1104            // @ts-ignore
1105            let rsNode = new JankTreeNode(a.name, a.pid, 'render_service');
1106            jankJumperList.push(rsNode);
1107            list.push({
1108              name: 'Slice',
1109              value:
1110                // @ts-ignore
1111                a.cmdline +
1112                ' [' +
1113                // @ts-ignore
1114                a.name +
1115                ']' +
1116                // @ts-ignore
1117                `<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>`,
1118            });
1119          });
1120          this.currentSelectionTbl!.dataSource = list;
1121          this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1122        }
1123      });
1124    } else {
1125      this.currentSelectionTbl!.dataSource = list;
1126      this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1127    }
1128  }
1129
1130  private handleRenderServiceJank(
1131    data: JankStruct,
1132    list: unknown[],
1133    jankJumperList: JankTreeNode[],
1134    scrollCallback: ((d: unknown) => void) | undefined,
1135    callback: ((data: Array<unknown>) => void) | undefined
1136  ): void {
1137    if (data.src_slice) {
1138      queryFlowsData(data.src_slice!.split(',')).then((it) => {
1139        if (it.length > 0) {
1140          list.push({
1141            name: 'FrameTimeLine flows',
1142            value: '',
1143          });
1144          it.forEach((a: unknown) => {
1145            // @ts-ignore
1146            let appNode = new JankTreeNode(a.name, a.pid, 'app');
1147            // @ts-ignore
1148            appNode.children.push(new JankTreeNode(a.name, a.pid, 'frameTime'));
1149            jankJumperList.push(appNode);
1150            list.push({
1151              name: 'Slice',
1152              value:
1153                // @ts-ignore
1154                a.cmdline +
1155                ' [' +
1156                // @ts-ignore
1157                a.name +
1158                ']' +
1159                // @ts-ignore
1160                `<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>`,
1161            });
1162          });
1163          list.push({
1164            name: 'Following flows',
1165            value: '',
1166          });
1167          it.forEach((a: unknown) => {
1168            list.push({
1169              name: 'Slice',
1170              value:
1171                // @ts-ignore
1172                a.cmdline +
1173                ' [' +
1174                // @ts-ignore
1175                a.name +
1176                ']' +
1177                // @ts-ignore
1178                `<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>`,
1179            });
1180          });
1181          this.currentSelectionTbl!.dataSource = list;
1182          this.addJankScrollCallBackEvent(scrollCallback, callback, jankJumperList);
1183        }
1184      });
1185    } else {
1186      this.currentSelectionTbl!.dataSource = list;
1187    }
1188  }
1189
1190  setAllStartupData(data: AllAppStartupStruct, scrollCallback: Function): void {
1191    this.setTableHeight('550px');
1192    this.initCanvas();
1193    let allStartUpLeftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1194    let allStartUpmiddleTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightText');
1195    let allStartUpRightButton: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightButton');
1196    if (allStartUpmiddleTitle) {
1197      allStartUpmiddleTitle.style.visibility = 'hidden';
1198    }
1199    if (allStartUpRightButton) {
1200      allStartUpRightButton.style.visibility = 'hidden';
1201    }
1202    if (allStartUpLeftTitle) {
1203      allStartUpLeftTitle.innerText = 'Details';
1204    }
1205    let list: unknown[] = [];
1206    list.push({ name: 'Name', value: data.stepName! });
1207    list.push({
1208      name: 'StartTime(Relative)',
1209      value: getTimeString(data.startTs || 0),
1210    });
1211    list.push({
1212      name: 'StartTime(Absolute)',
1213      // @ts-ignore
1214      value: ((data.startTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1215    });
1216    list.push({
1217      name: 'EndTime(Relative)',
1218      value: getTimeString((data.startTs || 0) + (data.dur || 0)),
1219    });
1220    list.push({
1221      name: 'EndTime(Abslute)',
1222      // @ts-ignore
1223      value: ((data.startTs || 0) + (data.dur || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1224    });
1225    list.push({
1226      name: 'Dur',
1227      value: getTimeString(data.dur || 0),
1228    });
1229    this.currentSelectionTbl!.dataSource = list;
1230  }
1231
1232  setStartupData(data: AppStartupStruct, scrollCallback: Function, rowData: unknown): void {
1233    this.setTableHeight('550px');
1234    this.initCanvas();
1235    this.setStartUpStyle();
1236    let list: unknown[] = [];
1237    list.push({ name: 'Name', value: AppStartupStruct.getStartupName(data.startName) });
1238    list.push({
1239      name: 'StartTime(Relative)',
1240      value: `
1241      <div style="display: flex;white-space: nowrap;align-items: center">
1242<div style="white-space:pre-wrap">${getTimeString(data.startTs || 0)}</div>
1243<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="start-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
1244</div>`,
1245    });
1246    list.push({
1247      name: 'StartTime(Absolute)',
1248      // @ts-ignore
1249      value: ((data.startTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1250    });
1251    if (data.dur && data.dur > 0) {
1252      list.push({
1253        name: 'EndTime(Relative)',
1254        value: `<div style="white-space: nowrap;display: flex;align-items: center">
1255<div style="white-space:pre-wrap">${getTimeString((data.startTs || 0) + (data.dur || 0))}</div>
1256<lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="end-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
1257</div>`,
1258      });
1259      list.push({
1260        name: 'EndTime(Absolute)',
1261        // @ts-ignore
1262        value: ((data.startTs || 0) + (data.dur || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1263      });
1264    } else {
1265      list.push({
1266        name: 'EndTime(Relative)',
1267        value: 'Unknown Time',
1268      });
1269      list.push({
1270        name: 'EndTime(Absolute)',
1271        value: 'Unknown Time',
1272      });
1273    }
1274    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1275    // @ts-ignore
1276    let sortedArray = rowData.slice().sort(function (a: { startTs: number }, b: { startTs: number }) {
1277      return a.startTs - b.startTs;
1278    });
1279    sortedArray.forEach((item: unknown, index: number) => {
1280      // @ts-ignore
1281      if (item.startName === data.startName) {
1282        list.push({
1283          name: 'StartSlice',
1284          value:
1285            index === 0
1286              ? 'NULL'
1287              : `${AppStartupStruct.getStartupName(sortedArray[index - 1].startName)}     ${getTimeString(
1288                  sortedArray[index - 1].startTs + sortedArray[index - 1].dur
1289                )}`,
1290        });
1291        list.push({
1292          name: 'EndSlice',
1293          value:
1294            index === sortedArray.length - 1
1295              ? 'NULL'
1296              : `${AppStartupStruct.getStartupName(sortedArray[index + 1].startName)}      ${getTimeString(
1297                  sortedArray[index + 1].startTs
1298                )}`,
1299        });
1300      }
1301    });
1302    this.currentSelectionTbl!.dataSource = list;
1303    this.attachScrollHandlers(data, scrollCallback);
1304  }
1305
1306  private setStartUpStyle(): void {
1307    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
1308      ?.querySelector('#rightButton')
1309      ?.shadowRoot?.querySelector('#custom-button');
1310    let startUpRightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
1311    if (startUpRightTitle) {
1312      startUpRightTitle.style.visibility = 'hidden';
1313      rightButton!.style.visibility = 'hidden';
1314    }
1315    let startUpLeftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1316    if (startUpLeftTitle) {
1317      startUpLeftTitle.innerText = 'Details';
1318    }
1319  }
1320
1321  private attachScrollHandlers(data: AppStartupStruct, scrollCallback: Function): void {
1322    let startIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#start-jump');
1323    let endIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#end-jump');
1324    let scrollClick = (type: number): void => {
1325      // @ts-ignore
1326      let recordNs: number = (window as unknown).recordStartNS;
1327      let useEnd = type === 1 && data.startName! < 6;
1328      queryThreadByItid(
1329        useEnd ? data.endItid! : data.itid!,
1330        useEnd ? recordNs + data.startTs! + data.dur! : recordNs + data.startTs!
1331      ).then((result) => {
1332        if (result.length > 0) {
1333          //@ts-ignore
1334          let pt: {
1335            pid: number;
1336            tid: number;
1337            dur: number;
1338            name: string;
1339            depth: number;
1340          } = result[0];
1341          scrollCallback({
1342            pid: pt.pid,
1343            tid: pt.tid,
1344            type: 'func',
1345            dur: pt.dur,
1346            depth: pt.depth,
1347            funName: pt.name,
1348            startTs: useEnd ? (data.startTs || 0) + (data.dur || 0) : data.startTs,
1349            keepOpen: true,
1350          });
1351        }
1352      });
1353    };
1354    if (startIcon) {
1355      startIcon.addEventListener('click', () => scrollClick(0));
1356    }
1357    if (endIcon) {
1358      endIcon.addEventListener('click', () => scrollClick(1));
1359    }
1360  }
1361
1362  setStaticInitData(data: SoStruct, scrollCallback: Function): void {
1363    this.setTableHeight('550px');
1364    this.initCanvas();
1365    this.setStaticInitStyle();
1366    let list: unknown[] = [];
1367    list.push({ name: 'Name', value: data.soName });
1368    list.push({
1369      name: 'StartTime(Relative)',
1370      value: `<div style="white-space: nowrap;display: flex;align-items: center">
1371<div style="white-space:pre-wrap">${getTimeString(data.startTs || 0)}</div>
1372<lit-icon id="start-jump" style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" name="select" color="#7fa1e7" size="20"></lit-icon>
1373</div>`,
1374    });
1375    list.push({
1376      name: 'StartTime(Absolute)',
1377      // @ts-ignore
1378      value: ((data.startTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1379    });
1380    list.push({ name: 'Duration', value: getTimeString(data.dur || 0) });
1381    this.currentSelectionTbl!.dataSource = list;
1382    this.startIconClickEvent(data, scrollCallback);
1383  }
1384
1385  private setStaticInitStyle(): void {
1386    let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#rightTitle');
1387    let rightButton: HTMLElement | null | undefined = this?.shadowRoot
1388      ?.querySelector('#rightButton')
1389      ?.shadowRoot?.querySelector('#custom-button');
1390    if (rightTitle) {
1391      rightTitle.style.visibility = 'hidden';
1392      rightButton!.style.visibility = 'hidden';
1393    }
1394    let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector('#leftTitle');
1395    if (leftTitle) {
1396      leftTitle.innerText = 'Details';
1397    }
1398  }
1399
1400  private startIconClickEvent(data: SoStruct, scrollCallback: Function): void {
1401    let startIcon = this.currentSelectionTbl?.shadowRoot?.querySelector('#start-jump');
1402    if (startIcon) {
1403      startIcon.addEventListener('click', () => {
1404        // @ts-ignore
1405        let recordNs: number = (window as unknown).recordStartNS;
1406        queryThreadByItid(data.itid!, recordNs + data.startTs!).then((result) => {
1407          if (result.length > 0) {
1408            //@ts-ignore
1409            let pt: {
1410              pid: number;
1411              tid: number;
1412              dur: number;
1413              name: string;
1414              depth: number;
1415            } = result[0];
1416            scrollCallback({
1417              pid: pt.pid,
1418              tid: pt.tid,
1419              type: 'func',
1420              dur: pt.dur,
1421              depth: pt.depth,
1422              funName: pt.name,
1423              startTs: data.startTs,
1424              keepOpen: true,
1425            });
1426          }
1427        });
1428      });
1429    }
1430  }
1431
1432  async setFrameAnimationData(data: FrameAnimationStruct, scrollCallback: Function): Promise<void> {
1433    this.setTableHeight('550px');
1434    this.tabCurrentSelectionInit('Animation Details');
1435    let list = [];
1436    let dataTs: number = data.startTs < 0 ? 0 : data.startTs;
1437    list.push({ name: 'Name', value: data.name });
1438    list.push({ name: 'Start time(Relative)', value: `${Utils.getTimeString(dataTs)}` });
1439    list.push({
1440      name: 'Start time(Absolute)',
1441      // @ts-ignore
1442      value: ((dataTs || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1443    });
1444    list.push({
1445      name: 'End time(Relative)',
1446      value: `${Utils.getTimeString(dataTs + (data.dur || 0))}`,
1447    });
1448    list.push({
1449      name: 'End time(Absolute)',
1450      // @ts-ignore
1451      value: (dataTs + (data.dur || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1452    });
1453    list.push({ name: 'Duration', value: `${Utils.getTimeString(data.dur || 0)}` });
1454    if (data.status === 'Completion delay') {
1455      let frameFpsMessage = data.frameInfo?.split(':');
1456      if (frameFpsMessage) {
1457        if (frameFpsMessage[1] !== '0') {
1458          if (this.isFpsAvailable) {
1459            list.push({
1460              name: 'FPS',
1461              value: `<div style="white-space: nowrap;display: flex;align-items: center">
1462            <div style="white-space:pre-wrap">${frameFpsMessage[1]}</div>
1463            <lit-icon style="cursor:pointer;transform: scaleX(-1);margin-left: 5px" id="fps-jump" name="select" color="#7fa1e7" size="20"></lit-icon>
1464            </div>`,
1465            });
1466          } else {
1467            list.push({ name: 'FPS', value: `${frameFpsMessage[1]}` });
1468          }
1469        } else {
1470          let fixedNumber: number = 2;
1471          let fpsValue: number = Number(frameFpsMessage[0]) / (data.dur / 1000_000_000);
1472          list.push({ name: 'FPS', value: `${fpsValue.toFixed(fixedNumber) || 0}` });
1473        }
1474      }
1475    }
1476    this.currentSelectionTbl!.dataSource = list;
1477    this.fpsClickEvent(data, scrollCallback);
1478  }
1479
1480  private fpsClickEvent(data: FrameAnimationStruct, scrollCallback: Function): void {
1481    let queryJoinName = `${data.frameInfo?.split(':')[1]}: ${data.name?.split(':')![1]}`;
1482    // @ts-ignore
1483    let recordNs: number = (window as unknown).recordStartNS;
1484    this.currentSelectionTbl?.shadowRoot?.querySelector('#fps-jump')?.addEventListener('click', () => {
1485      queryFpsSourceList(data.inputTime, data.endTime, queryJoinName).then((result) => {
1486        if (result.length > 0) {
1487          this.isFpsAvailable = true;
1488          let pt: {
1489            pid: number;
1490            tid: number;
1491            name: string;
1492            ts: number;
1493            dur: number;
1494            depth: number;
1495          } = result[0];
1496          scrollCallback({
1497            pid: pt.tid,
1498            tid: pt.tid,
1499            dur: pt.dur,
1500            type: 'func',
1501            depth: pt.depth,
1502            funName: pt.name,
1503            startTs: pt.ts - recordNs,
1504            keepOpen: true,
1505          });
1506        } else {
1507          this.isFpsAvailable = false;
1508        }
1509      });
1510    });
1511  }
1512
1513  private setJankType(data: JankStruct, list: unknown[]): void {
1514    if (data.jank_tag === 1) {
1515      if (data.frame_type === 'render_service') {
1516        list.push({ name: 'Jank Type', value: 'RenderService Deadline Missed' });
1517      } else if (data.frame_type === 'app') {
1518        list.push({ name: 'Jank Type', value: 'APP Deadline Missed' });
1519      } else if (data.frame_type === 'frameTime') {
1520        list.push({ name: 'Jank Type', value: 'Deadline Missed' });
1521      }
1522    } else if (data.jank_tag === 3) {
1523      list.push({ name: 'Jank Type', value: 'Deadline Missed' });
1524    } else {
1525      list.push({ name: 'Jank Type', value: 'NONE' });
1526    }
1527  }
1528
1529  private setJankCommonMessage(list: unknown[], data: JankStruct): void {
1530    list.push({ name: 'Name', value: data.name });
1531    list.push({ name: 'StartTime(Relative)', value: getTimeString(data.ts || 0) });
1532    list.push({
1533      name: 'StartTime(Absolute)',
1534      // @ts-ignore
1535      value: ((data.ts || 0) + (window as unknown).recordStartNS) / 1000000000 + 's',
1536    });
1537    list.push({ name: 'Duration', value: data.dur ? getTimeString(data.dur) : ' ' });
1538    if (data.frame_type !== 'frameTime') {
1539      list.push({ name: 'Process', value: data.cmdline + ' ' + data.pid });
1540    }
1541  }
1542
1543  private setTableHeight(height: string): void {
1544    this.scrollView!.scrollTop = 0;
1545    this.currentSelectionTbl!.style.height = height;
1546    this.wakeupListTbl!.style.display = 'none';
1547  }
1548
1549  private addJankScrollCallBackEvent(
1550    scrollCallback: ((d: unknown) => void) | undefined,
1551    callback: ((data: Array<unknown>) => void) | undefined,
1552    jankJumperList: JankTreeNode[]
1553  ): void {
1554    let all = this.currentSelectionTbl?.shadowRoot?.querySelectorAll('.jank_cla');
1555    all!.forEach((a) => {
1556      a.addEventListener('click', () => {
1557        if (scrollCallback) {
1558          scrollCallback({
1559            rowId: a.id,
1560            name: a.getAttribute('slice_name'),
1561            pid: a.getAttribute('pid'),
1562          });
1563        }
1564      });
1565    });
1566    if (callback) {
1567      callback(jankJumperList);
1568    }
1569  }
1570
1571  async queryThreadStateDArgs(argSetID: number | undefined): Promise<BinderArgBean[]> {
1572    let list: Array<BinderArgBean> = [];
1573    if (argSetID !== undefined && argSetID > 0) {
1574      list = await queryThreadStateArgs(argSetID);
1575    }
1576    return list;
1577  }
1578
1579  /**
1580   * 查询出 线程被唤醒的 线程信息
1581   * @param data
1582   */
1583  async queryCPUWakeUpFromData(data: CpuStruct): Promise<WakeupBean | null> {
1584    let wb: WakeupBean | null = null;
1585    if (data.id === undefined || data.startTime === undefined) {
1586      return null;
1587    }
1588    let wakeup = await queryRunnableTimeByRunning(data.tid!, data.startTime);
1589    if (wakeup && wakeup[0]) {
1590      let wakeupTs = wakeup[0].ts as number;
1591      let recordStartTs = window.recordStartNS;
1592      let wf = await queryThreadWakeUpFrom(data.id, wakeupTs);
1593      if (wf && wf[0]) {
1594        wb = wf[0];
1595        if (wb !== null) {
1596          wb.wakeupTime = wakeupTs - recordStartTs;
1597          wb.process = Utils.PROCESS_MAP.get(wb.pid!) || 'Process';
1598          wb.thread = Utils.THREAD_MAP.get(wb.tid!) || 'Thread';
1599          wb.schedulingLatency = (data.startTime || 0) - (wb.wakeupTime || 0);
1600          wb.schedulingDesc = INPUT_WORD;
1601        }
1602      }
1603    }
1604    return wb;
1605  }
1606
1607  /**
1608   * 查询出 线程被唤醒的 线程链信息
1609   * @param data
1610   */
1611  static async queryCPUWakeUpListFromBean(data: WakeupBean): Promise<WakeupBean | null> {
1612    let wb: WakeupBean | null = null;
1613    let wakeup = await queryRunnableTimeByRunning(data.tid!, data.ts!);
1614    if (wakeup && wakeup[0]) {
1615      let wakeupTs = wakeup[0].ts as number;
1616      // @ts-ignore
1617      let recordStartTs = (window as unknown).recordStartNS;
1618      let wf = await queryThreadWakeUpFrom(data.itid!, wakeupTs);
1619      if (wf && wf[0]) {
1620        wb = wf[0];
1621        if (wb !== null) {
1622          wb.wakeupTime = wakeupTs - recordStartTs;
1623          wb.process = Utils.PROCESS_MAP.get(wb.pid!) || 'Process';
1624          wb.thread = Utils.THREAD_MAP.get(wb.tid!) || 'Thread';
1625          wb.schedulingLatency = (data.ts || 0) - (wb.wakeupTime || 0);
1626          wb.schedulingDesc = INPUT_WORD;
1627        }
1628      }
1629    }
1630    return wb;
1631  }
1632
1633  /**
1634   * 查询出 线程唤醒了哪些线程信息
1635   */
1636  async queryThreadWakeUpFromData(itid: number, startTime: number, dur: number): Promise<unknown> {
1637    // @ts-ignore
1638    let wakeUps = await queryThreadWakeUpFrom(itid, startTime + (window as unknown).recordStartNS);
1639    if (wakeUps !== undefined && wakeUps.length > 0) {
1640      return wakeUps[0];
1641    } else {
1642      return;
1643    }
1644  }
1645
1646  /**
1647   * 查询出 线程唤醒了哪些线程信息
1648   */
1649  async queryThreadWakeUpData(itid: number, startTime: number, dur: number): Promise<Array<WakeupBean>> {
1650    let list: Array<WakeupBean> = [];
1651    if (itid === undefined || startTime === undefined) {
1652      return list;
1653    }
1654    let wakeUps = await queryThreadWakeUp(itid, startTime, dur); //  3,4835380000
1655    if (wakeUps !== undefined && wakeUps.length > 0) {
1656      list.push(...wakeUps);
1657    }
1658    return list;
1659  }
1660
1661  initCanvas(): HTMLCanvasElement | null {
1662    let canvas = this.shadowRoot!.querySelector<HTMLCanvasElement>('#rightDraw');
1663    let width = getComputedStyle(this.currentSelectionTbl!).getPropertyValue('width');
1664    if (canvas !== null) {
1665      canvas.width = Math.round(Number(width.replace('px', '')) * this.dpr);
1666      canvas.height = Math.round(Number(200 * this.dpr));
1667      canvas.style.width = width;
1668      canvas.style.height = '200px';
1669      canvas.getContext('2d')!.scale(this.dpr, this.dpr);
1670    }
1671    SpApplication.skinChange = (val: boolean): void => {
1672      this.drawRight(canvas, this.weakUpBean!);
1673    };
1674    return canvas;
1675  }
1676
1677  drawRight(cavs: HTMLCanvasElement | null, wakeupBean: WakeupBean | null): void {
1678    if (cavs === null) {
1679      return;
1680    }
1681    let context = cavs.getContext('2d');
1682    if (context !== null) {
1683      //绘制竖线
1684      this.drawVerticalLine(context);
1685      //绘制菱形
1686      context.lineWidth = 1;
1687      context.beginPath();
1688      context.moveTo(10, 30);
1689      context.lineTo(4, 40);
1690      context.lineTo(10, 50);
1691      context.lineTo(16, 40);
1692      context.lineTo(10, 30);
1693      context.closePath();
1694      context.fill();
1695      context.font = 12 + 'px sans-serif';
1696      //绘制wake up 文字
1697      let strList = [];
1698      strList.push('wakeup @ ' + getTimeString(wakeupBean?.wakeupTime || 0) + ' on CPU ' + wakeupBean?.cpu + ' by');
1699      strList.push('P:' + wakeupBean?.process + ' [ ' + wakeupBean?.pid + ' ]');
1700      strList.push('T:' + wakeupBean?.thread + ' [ ' + wakeupBean?.tid + ' ]');
1701      strList.forEach((str, index) => {
1702        if (context !== null) {
1703          context.fillText(str, 40, 40 + 16 * index);
1704        }
1705      });
1706      context.lineWidth = 2;
1707      context.lineJoin = 'bevel';
1708      context.moveTo(10, 95);
1709      context.lineTo(20, 90);
1710      context.moveTo(10, 95);
1711      context.lineTo(20, 100);
1712      context.moveTo(10, 95);
1713      context.lineTo(80, 95);
1714      context.lineTo(70, 90);
1715      context.moveTo(80, 95);
1716      context.lineTo(70, 100);
1717      context.stroke();
1718      //绘制latency
1719      context.font = 12 + 'px sans-serif';
1720      context.fillText('Scheduling latency:' + getTimeString(wakeupBean?.schedulingLatency || 0), 90, 100);
1721      //绘制最下方提示语句
1722      context.font = 10 + 'px sans-serif';
1723      INPUT_WORD.split('\n').forEach((str, index) => {
1724        context?.fillText(str, 90, 120 + 12 * index);
1725      });
1726    }
1727  }
1728
1729  private drawVerticalLine(context: CanvasRenderingContext2D): void {
1730    if (document.querySelector<SpApplication>('sp-application')!.dark) {
1731      context.strokeStyle = '#ffffff';
1732      context.fillStyle = '#ffffff';
1733    } else {
1734      context.strokeStyle = '#000000';
1735      context.fillStyle = '#000000';
1736    }
1737    context.lineWidth = 2;
1738    context.moveTo(10, 15);
1739    context.lineTo(10, 125);
1740    context.stroke();
1741  }
1742
1743  transferString(str: string): string {
1744    let s = '';
1745    if (str.length === 0) {
1746      return '';
1747    }
1748    s = str.replace(/&/g, '&amp;');
1749    s = s.replace(/</g, '&lt;');
1750    s = s.replace(/>/g, '&gt;');
1751    s = s.replace(/\'/g, '&#39;');
1752    s = s.replace(/\"/g, '&#quat;');
1753    return s;
1754  }
1755
1756  initElements(): void {
1757    this.currentSelectionTbl = this.shadowRoot?.querySelector<LitTable>('#selectionTbl');
1758    this.wakeupListTbl = this.shadowRoot?.querySelector<LitTable>('#wakeupListTbl');
1759    this.scrollView = this.shadowRoot?.querySelector<HTMLDivElement>('#scroll_view');
1760    this.currentSelectionTbl?.addEventListener('column-click', (ev: unknown): void => {}); //@ts-ignore
1761    window.subscribe(window.SmartEvent.UI.WakeupList, (data: Array<WakeupBean>) => this.showWakeupListTableData(data));
1762  }
1763
1764  showWakeupListTableData(data: Array<WakeupBean>): void {
1765    this.wakeupListTbl!.style.display = 'flex';
1766    let cpus: number[] = [];
1767    let itids: number[] = [];
1768    let ts: number[] = [];
1769    let maxPriority = 0;
1770    let maxPriorityDuration = 0;
1771    let maxDuration = 0;
1772    data.forEach((it) => {
1773      cpus.push(it.cpu!);
1774      itids.push(it.itid!);
1775      ts.push(it.ts!);
1776    });
1777    queryWakeupListPriority(itids, ts, cpus).then((res) => {
1778      let resource = data.map((it) => {
1779        let wake = {
1780          process: `${it.process}(${it.pid})`,
1781          thread: `${it.thread}(${it.tid})`,
1782          cpu: it.cpu,
1783          dur: it.dur,
1784          priority: 0,
1785          isSelected: false,
1786        };
1787        //@ts-ignore
1788        let find = res.find((re) => re.cpu === it.cpu && re.itid === it.itid && re.ts === it.ts);
1789        if (find) {
1790          //@ts-ignore
1791          wake.priority = find.priority;
1792        }
1793        maxDuration = Math.max(maxDuration, it.dur!);
1794        maxPriority = Math.max(maxPriority, wake.priority);
1795        return wake;
1796      });
1797      if (this.selectWakeupBean) {
1798        // 点击第一层唤醒树时向数组头部添加当前点击信息
1799        if (data[0].schedulingLatency) {
1800          // @ts-ignore
1801          resource.unshift(this.selectWakeupBean);
1802        }
1803        // @ts-ignore
1804        maxDuration = Math.max(maxDuration, this.selectWakeupBean.dur);
1805        // @ts-ignore
1806        maxPriority = Math.max(maxPriority, this.selectWakeupBean.priority);
1807      }
1808      resource.forEach((it) => {
1809        if (it.priority === maxPriority) {
1810          maxPriorityDuration = Math.max(it.dur || 0, maxPriorityDuration);
1811        }
1812      });
1813      this.updateTableSettings(maxPriority, maxPriorityDuration, maxDuration);
1814      this.wakeupListTbl!.recycleDataSource = resource;
1815    });
1816  }
1817
1818  private updateTableSettings(maxPriority: number, maxPriorityDuration: number, maxDuration: number): void {
1819    this.wakeupListTbl!.getItemTextColor = (data: unknown): string => {
1820      // @ts-ignore
1821      if ((data.priority === maxPriority && data.dur === maxPriorityDuration) || data.dur === maxDuration) {
1822        return '#f44336';
1823      } else {
1824        return '#262626';
1825      }
1826    };
1827  }
1828
1829  addTableObserver(): void {
1830    let leftTable = this.shadowRoot?.querySelector('.table-left');
1831    this.tableObserver?.observe(leftTable!, {
1832      attributes: true,
1833      attributeFilter: ['style'],
1834      attributeOldValue: true,
1835    });
1836  }
1837
1838  initHtml(): string {
1839    return TabPaneCurrentSelectionHtml;
1840  }
1841}
1842
1843export class JankTreeNode {
1844  name: string = '';
1845  pid: number = -1;
1846  frameType: string = '';
1847  type: number = 0;
1848
1849  constructor(name: string, pid: number, frameType: string) {
1850    this.name = name;
1851    this.pid = pid;
1852    this.frameType = frameType;
1853  }
1854
1855  children: Array<JankTreeNode> = [];
1856}
1857
1858export class ThreadTreeNode {
1859  tid: number = 0;
1860  pid: number = -1;
1861  startTime: number = 1;
1862
1863  constructor(tid: number, pid: number, startTime: number) {
1864    this.tid = tid;
1865    this.pid = pid;
1866    this.startTime = startTime;
1867  }
1868}
1869