• 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 { LitTable } from '../../../../../base-ui/table/lit-table';
18import { SelectionData, SelectionParam } from '../../../../bean/BoxSelection';
19import { log } from '../../../../../log/Log';
20import { getProbablyTime } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon';
21import { Utils } from '../../base/Utils';
22import { resizeObserver } from '../SheetUtils';
23import { getTabCpuByThread } from '../../../../database/sql/Cpu.sql';
24import { getCpuData, getIrqAndSoftIrqData } from "../../../../database/sql/CpuAndIrq.sql";
25import { byCpuGroupBean, CpuAndIrqBean, softirqAndIrq, finalResultBean } from "./CpuAndIrqBean";
26import { FlagsConfig } from '../../../SpFlags';
27
28@element('tabpane-cpu-thread')
29export class TabPaneCpuByThread extends BaseElement {
30  private cpuByThreadTbl: LitTable | null | undefined;
31  private range: HTMLLabelElement | null | undefined;
32  private cpuByThreadSource: Array<SelectionData> = [];
33  private currentSelectionParam: SelectionParam | undefined;
34  private cpuByIrqSource: Array<finalResultBean> = [];
35  private loadIrq: boolean = false;//flag开关
36  private pubColumns = `
37            <lit-table-column order width="250px" title="Process" data-index="process" key="process" align="flex-start" order >
38            </lit-table-column>
39            <lit-table-column order width="120px" title="PID" data-index="pid" key="pid" align="flex-start" order >
40            </lit-table-column>
41            <lit-table-column order width="250px" title="Thread" data-index="thread" key="thread" align="flex-start" order >
42            </lit-table-column>
43            <lit-table-column order width="120px" title="TID" data-index="tid" key="tid" align="flex-start" order >
44            </lit-table-column>
45            <lit-table-column order width="200px" title="Wall duration(ms)" data-index="wallDuration" key="wallDuration" align="flex-start" order >
46            </lit-table-column>
47            <lit-table-column order width="200px" title="Avg Wall duration(ms)" data-index="avgDuration" key="avgDuration" align="flex-start" order >
48            </lit-table-column>
49            <lit-table-column order width="120px" title="Occurrences" data-index="occurrences" key="occurrences" align="flex-start" order >
50            </lit-table-column>
51    `;
52
53  set data(cpuByThreadValue: SelectionParam | unknown) {
54    if (this.currentSelectionParam === cpuByThreadValue) {
55      return;
56    }
57    // @ts-ignore
58    this.currentSelectionParam = cpuByThreadValue;
59    // @ts-ignore
60    this.cpuByThreadTbl!.innerHTML = this.getTableColumns(cpuByThreadValue.cpus);
61    this.cpuByThreadTbl!.injectColumns();
62    this.range!.textContent =
63      // @ts-ignore
64      `Selected range: ${parseFloat(((cpuByThreadValue.rightNs - cpuByThreadValue.leftNs) / 1000000.0).toFixed(5))} ms`;
65    this.cpuByThreadTbl!.loading = true;
66    this.loadIrq = FlagsConfig.getFlagsConfigEnableStatus('CPU by Irq');//flag开关
67    this.handleAsyncRequest(cpuByThreadValue, this.loadIrq);
68  }
69
70  private handleAsyncRequest(cpuByThreadValue: unknown, loadIrq: boolean): void {
71    if (loadIrq) {
72      //查询cpu数据和irq数据
73      Promise.all([
74        // @ts-ignore
75        getCpuData(cpuByThreadValue.cpus, cpuByThreadValue.leftNs, cpuByThreadValue.rightNs),
76        // @ts-ignore
77        getIrqAndSoftIrqData(cpuByThreadValue.cpus, cpuByThreadValue.leftNs, cpuByThreadValue.rightNs)
78      ]).then(([cpuData, interruptData]) => {
79        this.cpuByThreadTbl!.loading = false;
80        const resArr = cpuData.concat(interruptData);
81        if (resArr != null && resArr.length > 0) {
82          const cutData: finalResultBean[] = this.groupByCpu(resArr);//切割后数据
83          this.aggregateData(cutData, cpuByThreadValue);//整合数据
84        } else {
85          this.cpuByIrqSource = [];
86          this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource;
87        }
88      });
89    } else {
90      // @ts-ignore
91      getTabCpuByThread(cpuByThreadValue.cpus, cpuByThreadValue.leftNs, // @ts-ignore
92        cpuByThreadValue.rightNs, cpuByThreadValue.traceId).then((result): void => {
93          this.cpuByThreadTbl!.loading = false;
94          if (result !== null && result.length > 0) {
95            log(`getTabCpuByThread size :${result.length}`);
96            this.processResult(result, cpuByThreadValue);
97          } else {
98            this.cpuByThreadSource = [];
99            this.cpuByThreadTbl!.recycleDataSource = this.cpuByThreadSource;
100          }
101        });
102    }
103
104  }
105
106  //将所有数据按cpu重新分组
107  private groupByCpu(data: Array<CpuAndIrqBean>): finalResultBean[] {
108    const cpuObject: { [cpu: number]: byCpuGroupBean } =
109      data.reduce((groups, item) => {
110        const { cpu, ...restProps } = item;
111        const newCpuAndIrqBean: CpuAndIrqBean = { cpu, ...restProps };
112
113        if (!groups[cpu]) {
114          groups[cpu] = { CPU: [] };
115        }
116        groups[cpu].CPU!.push(newCpuAndIrqBean);
117
118        return groups;
119      }, {} as { [cpu: number]: byCpuGroupBean })
120    const cutObj: { [cpu: number]: finalResultBean[] } = {};
121    Object.entries(cpuObject).forEach(([cpuStr, { CPU }]) => {
122      const cpu = Number(cpuStr);
123      cutObj[cpu] = this.cpuByIrq(CPU);
124    })
125    const cutList: finalResultBean[] = Object.values(cutObj).flat();
126    return cutList;
127  }
128
129  //具体切割方法
130  private cpuByIrq(data: CpuAndIrqBean[]): finalResultBean[] {
131    let sourceData = data.sort((a, b) => a.startTime - b.startTime);
132    let waitArr: CpuAndIrqBean[] = [];
133    let completedArr: finalResultBean[] = [];
134    let globalTs: number = 0;
135    let index: number = 0;
136    while (index < sourceData.length || waitArr.length > 0) {
137      let minEndTs = Math.min(...waitArr.map((item: CpuAndIrqBean) => item.endTime));
138      let minIndex = waitArr.findIndex((item: CpuAndIrqBean) => item.endTime === minEndTs);
139      //当waitArr为空时
140      if (waitArr.length === 0) {
141        globalTs = sourceData[index].startTime;
142        waitArr.push(sourceData[index]);
143        index++;
144        continue;
145      }
146      //当全局Ts等于minEndTs时,只做删除处理
147      if (globalTs === minEndTs) {
148        if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
149        continue;
150      }
151      let obj: finalResultBean = {
152        cat: '',
153        dur: 0,
154        cpu: 0,
155        pid: 0,
156        tid: 0,
157        occurrences: 0
158      };
159      if (index < sourceData.length) {
160        if (sourceData[index].startTime < minEndTs) {
161          if (globalTs === sourceData[index].startTime) {
162            waitArr.push(sourceData[index]);
163            index++;
164            continue;
165          } else {
166            const maxPriorityItem = this.findMaxPriority(waitArr);
167            obj = {
168              cat: maxPriorityItem.cat,
169              dur: sourceData[index].startTime - globalTs,
170              cpu: maxPriorityItem.cpu,
171              pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]',
172              tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]',
173              occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0
174            }
175            completedArr.push(obj);
176            maxPriorityItem.isFirstObject = 0;
177            waitArr.push(sourceData[index]);
178            globalTs = sourceData[index].startTime;
179            index++;
180          }
181        } else {
182          const maxPriorityItem = this.findMaxPriority(waitArr);
183          obj = {
184            cat: maxPriorityItem.cat,
185            dur: minEndTs - globalTs,
186            cpu: maxPriorityItem.cpu,
187            pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]',
188            tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]',
189            occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0
190          }
191          completedArr.push(obj);
192          maxPriorityItem.isFirstObject = 0;
193          globalTs = minEndTs;
194          if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
195        }
196      } else {
197        const maxPriorityItem = this.findMaxPriority(waitArr);
198        obj = {
199          cat: maxPriorityItem.cat,
200          dur: minEndTs - globalTs,
201          cpu: maxPriorityItem.cpu,
202          pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]',
203          tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]',
204          occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0
205        }
206        completedArr.push(obj);
207        maxPriorityItem.isFirstObject = 0;
208        globalTs = minEndTs;
209        if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
210      }
211    }
212    return completedArr;
213  }
214
215  private findMaxPriority(arr: CpuAndIrqBean[]): CpuAndIrqBean {
216    return arr.reduce((maxItem: CpuAndIrqBean, currentItem: CpuAndIrqBean) => {
217      return maxItem.priority > currentItem.priority ? maxItem : currentItem;
218    }, arr[0]);
219  }
220
221  // 聚合数据
222  private aggregateData(data: any[], cpuByThreadValue: SelectionParam | any): void {
223    const cpuAggregations: { [tidPidKey: string]: softirqAndIrq } = {};
224    //@ts-ignore
225    let softirqAggregations: softirqAndIrq = {
226      occurrences: 0,
227      wallDuration: 0,
228      avgDuration: 0,
229      cpus: {}
230    };
231    //@ts-ignore
232    let irqAggregations: softirqAndIrq = {
233      occurrences: 0,
234      wallDuration: 0,
235      avgDuration: 0,
236      cpus: {}
237    };
238    data.forEach((obj) => {
239      // 聚合 cpu 数据
240      if (obj.cat === "cpu" && obj.dur !== 0) {
241        const tidPidKey = `${obj.tid}-${obj.pid}`;
242        const cpuDurationKey = `cpu${obj.cpu}`;
243        const cpuPercentKey = `cpu${obj.cpu}Ratio`;
244
245        if (!cpuAggregations[tidPidKey]) {
246          cpuAggregations[tidPidKey] = {
247            tid: obj.tid,
248            pid: obj.pid,
249            wallDuration: 0,
250            occurrences: 0,
251            avgDuration: 0,
252            cpus: {},
253            [cpuDurationKey]: 0,
254            [cpuPercentKey]: 100,
255          };
256        }
257
258        cpuAggregations[tidPidKey].wallDuration += obj.dur;
259        cpuAggregations[tidPidKey].occurrences += obj.occurrences;
260        cpuAggregations[tidPidKey].avgDuration = cpuAggregations[tidPidKey].wallDuration / cpuAggregations[tidPidKey].occurrences;
261        cpuAggregations[tidPidKey].cpus[obj.cpu] = (cpuAggregations[tidPidKey].cpus[obj.cpu] || 0) + obj.dur;
262        cpuAggregations[tidPidKey][cpuDurationKey] = cpuAggregations[tidPidKey].cpus[obj.cpu];
263        cpuAggregations[tidPidKey][cpuPercentKey] = (cpuAggregations[tidPidKey][cpuDurationKey] / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)) * 100;
264      }
265
266      // 聚合 softirq 数据
267      if (obj.cat === "softirq" && obj.dur !== 0) {
268        this.updateIrqAndSoftirq(softirqAggregations, obj, cpuByThreadValue);
269      }
270      // 聚合 irq 数据
271      if (obj.cat === "irq" && obj.dur !== 0) {
272        this.updateIrqAndSoftirq(irqAggregations, obj, cpuByThreadValue);
273      }
274
275    });
276
277    // 将聚合数据转换为最终结果格式
278    const result: Array<{ [key: string]: any }> = [];
279
280    // 添加 CPU 数据
281    for (const tidPidKey in cpuAggregations) {
282      const aggregation = cpuAggregations[tidPidKey];
283      const { tid, pid, occurrences, wallDuration, avgDuration, ...cpuDurations } = aggregation;
284      result.push({ tid, pid, occurrences, wallDuration, avgDuration, ...cpuDurations });
285    }
286
287    // 添加softirq
288    if (softirqAggregations.wallDuration > 0) {
289      result.push({ process: 'softirq', thread: 'softirq', tid: '[NULL]', pid: '[NULL]', ...softirqAggregations, });
290    }
291
292    // 添加 irq 数据
293    if (irqAggregations.wallDuration) {
294      result.push({ process: 'irq', thread: 'irq', tid: '[NULL]', pid: '[NULL]', ...irqAggregations });
295    }
296    this.handleFunction(result, cpuByThreadValue);
297
298  }
299
300  //irq和softirq聚合方法
301  private updateIrqAndSoftirq(aggregation: softirqAndIrq, obj: CpuAndIrqBean, cpuByThreadValue: SelectionParam): void {
302    const callid = obj.cpu;
303    const callidDurKey = `cpu${callid}`;
304    const callidPercentKey = `cpu${callid}Ratio`;
305
306    aggregation.wallDuration += obj.dur;
307    aggregation.occurrences += obj.occurrences;
308    aggregation.avgDuration = aggregation.wallDuration / aggregation.occurrences;
309
310    if (!aggregation.cpus[callid]) {
311      aggregation.cpus[callid] = 0;
312    }
313    aggregation.cpus[callid] += obj.dur;
314
315    if (!(callidDurKey in aggregation)) {
316      aggregation[callidDurKey] = 0;
317    }
318    aggregation[callidDurKey] += obj.dur;
319
320    aggregation[callidPercentKey] = (aggregation[callidDurKey] / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)) * 100;
321  }
322
323  //最后将所有数据进行统一整理
324  private handleFunction(data: Array<{ [key: string]: any }>, cpuByThreadValue: SelectionParam): void {
325    let index = 0;
326    let totalWallDuration = 0;
327    let totalOccurrences = 0;
328    const finalData: Array<finalResultBean> = [];
329    while (index < data.length) {
330      const obj = data[index];
331      totalWallDuration += obj.wallDuration;
332      totalOccurrences += obj.occurrences;
333      if (obj.tid !== '[NULL]' && obj.pid !== '[NULL]') {
334        // @ts-ignore
335        let process = Utils.getInstance().getProcessMap(cpuByThreadValue.traceId).get(obj.pid);
336        // @ts-ignore
337        let thread = Utils.getInstance().getThreadMap(cpuByThreadValue.traceId).get(obj.tid);
338        obj.thread = thread == null || thread.length === 0 ? '[NULL]' : thread;
339        obj.process = process == null || process.length === 0 ? '[NULL]' : process;
340      }
341      obj.wallDuration /= 1000000;
342      obj.wallDuration = obj.wallDuration.toFixed(6);
343      obj.avgDuration /= 1000000;
344      obj.avgDuration = obj.avgDuration.toFixed(6);
345      for (const cpu in obj.cpus) {
346        if (obj.cpus.hasOwnProperty(cpu)) {
347          obj[`cpu${cpu}TimeStr`] = getProbablyTime(obj[`cpu${cpu}`]);
348          obj[`cpu${cpu}Ratio`] = obj[`cpu${cpu}Ratio`].toFixed(2);
349        }
350      }
351      for (const cpuNumber of cpuByThreadValue.cpus) {
352        const cpuKey = `cpu${cpuNumber}TimeStr`;
353        const percentKey = `cpu${cpuNumber}Ratio`;
354        if (!obj.hasOwnProperty(cpuKey)) {
355          obj[cpuKey] = "0.00";
356          obj[percentKey] = "0.00";
357        }
358      }
359      delete obj.cpus;
360      finalData.push(obj);
361      index++;
362    }
363    finalData.unshift({
364      wallDuration: (totalWallDuration / 1000000).toFixed(6),
365      occurrences: totalOccurrences,
366    });
367    this.cpuByIrqSource = finalData;
368    this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource;
369  }
370
371  //点击表头进行排序
372  private reSortByColum(key: string, type: number): void {
373    // 如果数组为空,则直接返回
374    if (!this.cpuByIrqSource.length) return;
375    let sortObject: finalResultBean[] = JSON.parse(JSON.stringify(this.cpuByIrqSource)).splice(1);
376    let sortList: Array<finalResultBean> = [];
377    sortList.push(...sortObject);
378    if (type === 0) {
379      this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource;
380    } else {
381      sortList.sort((a, b) => {
382        let aValue: number | string, bValue: number | string;
383        if (key === 'process' || key === 'thread') {
384          // @ts-ignore
385          aValue = a[key];
386          // @ts-ignore
387          bValue = b[key];
388        } else {
389          // @ts-ignore
390          aValue = parseFloat(a[key]);
391          // @ts-ignore
392          bValue = parseFloat(b[key]);
393        }
394        if (typeof aValue === 'string' && typeof bValue === 'string') {
395          return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
396        } else if (typeof aValue === 'number' && typeof bValue === 'number') {
397          return type === 1 ? aValue - bValue : bValue - aValue;
398        } else {
399          return 0;
400        }
401      });
402      this.cpuByThreadTbl!.recycleDataSource = [this.cpuByIrqSource[0]].concat(sortList);
403    }
404  }
405
406  private processResult(result: Array<unknown>, cpuByThreadValue: unknown): void {
407    let sumWall = 0.0;
408    let sumOcc = 0;
409    let map: Map<string, unknown> = new Map<string, unknown>();
410    for (let e of result) {
411      // @ts-ignore
412      sumWall += e.wallDuration;
413      // @ts-ignore
414      sumOcc += e.occurrences;
415      this.updateThreadMap(e, cpuByThreadValue, map);
416    }
417    this.calculateCount(map, sumWall, sumOcc);
418  }
419
420  private updateThreadMap(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void {
421    // @ts-ignore
422    if (map.has(`${e.tid}`)) {
423      this.updateExistingThread(e, cpuByThreadValue, map);
424    } else {
425      this.createThread(e, cpuByThreadValue, map);
426    }
427  }
428
429  private updateExistingThread(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void {
430    // @ts-ignore
431    let thread = map.get(`${e.tid}`)!;
432    // @ts-ignore
433    thread.wallDuration += e.wallDuration;
434    // @ts-ignore
435    thread.occurrences += e.occurrences;
436    this.updateCpuValues(e, cpuByThreadValue, thread);
437  }
438
439  private createThread(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void {
440    // @ts-ignore
441    let process = Utils.getInstance().getProcessMap(cpuByThreadValue.traceId).get(e.pid);
442    // @ts-ignore
443    let thread = Utils.getInstance().getThreadMap(cpuByThreadValue.traceId).get(e.tid);
444    let cpuByThreadObject: unknown = {
445      // @ts-ignore
446      tid: e.tid,
447      // @ts-ignore
448      pid: e.pid,
449      thread: !thread || thread.length === 0 ? '[NULL]' : thread,
450      process: !process || process.length === 0 ? '[NULL]' : process,
451      // @ts-ignore
452      wallDuration: e.wallDuration || 0,
453      // @ts-ignore
454      occurrences: e.occurrences || 0,
455      avgDuration: 0,
456    };
457    this.initializeCpuValues(cpuByThreadValue, cpuByThreadObject);
458    this.updateCpuValues(e, cpuByThreadValue, cpuByThreadObject);
459    // @ts-ignore
460    map.set(`${e.tid}`, cpuByThreadObject);
461  }
462
463  private initializeCpuValues(cpuByThreadValue: unknown, cpuByThreadObject: unknown): void {
464    // @ts-ignore
465    for (let i of cpuByThreadValue.cpus) {
466      // @ts-ignore
467      cpuByThreadObject[`cpu${i}`] = 0;
468      // @ts-ignore
469      cpuByThreadObject[`cpu${i}TimeStr`] = '0';
470      // @ts-ignore
471      cpuByThreadObject[`cpu${i}Ratio`] = '0';
472    }
473  }
474
475  private updateCpuValues(e: unknown, cpuByThreadValue: unknown, cpuByThreadObject: unknown): void {
476    // @ts-ignore
477    cpuByThreadObject[`cpu${e.cpu}`] = e.wallDuration || 0;
478    // @ts-ignore
479    cpuByThreadObject[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0);
480    // @ts-ignore
481    let ratio = ((100.0 * (e.wallDuration || 0)) / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)).toFixed(2);
482    if (ratio === '0.00') {
483      ratio = '0';
484    }
485    // @ts-ignore
486    cpuByThreadObject[`cpu${e.cpu}Ratio`] = ratio;
487  }
488
489  private calculateCount(map: Map<string, unknown>, sumWall: number, sumOcc: number): void {
490    // @ts-ignore
491    let arr = Array.from(map.values()).sort((a, b) => b.wallDuration - a.wallDuration);
492    for (let e of arr) {
493      // @ts-ignore
494      e.avgDuration = (e.wallDuration / (e.occurrences || 1.0) / 1000000.0).toFixed(5);
495      // @ts-ignore
496      e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5));
497    }
498    let count: unknown = {};
499    // @ts-ignore
500    count.process = ' ';
501    // @ts-ignore
502    count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(7));
503    // @ts-ignore
504    count.occurrences = sumOcc;
505    // @ts-ignore
506    arr.splice(0, 0, count);
507    // @ts-ignore
508    this.cpuByThreadSource = arr;
509    this.cpuByThreadTbl!.recycleDataSource = arr;
510  }
511
512  getTableColumns(cpus: Array<number>): string {
513    let cpuByThreadTblHtml = `${this.pubColumns}`;
514    let cpuByThreadList = cpus.sort((cpuByThreadA, cpuByThreadB) => cpuByThreadA - cpuByThreadB);
515    for (let index of cpuByThreadList) {
516      cpuByThreadTblHtml = `${cpuByThreadTblHtml}
517            <lit-table-column width="100px" title="cpu${index}" data-index="cpu${index}TimeStr" key="cpu${index}TimeStr"  align="flex-start" order>
518            </lit-table-column>
519            <lit-table-column width="100px" title="%" data-index="cpu${index}Ratio" key="cpu${index}Ratio"  align="flex-start" order>
520            </lit-table-column>
521            `;
522    }
523    return cpuByThreadTblHtml;
524  }
525
526  initElements(): void {
527    this.cpuByThreadTbl = this.shadowRoot?.querySelector<LitTable>('#tb-cpu-thread');
528    this.range = this.shadowRoot?.querySelector('#time-range');
529    this.cpuByThreadTbl!.addEventListener('column-click', (evt): void => {
530      if (!this.loadIrq) {
531        // @ts-ignore
532        this.sortByColumn(evt.detail);
533      } else {
534        // @ts-ignore
535        this.reSortByColum(evt.detail.key, evt.detail.sort);
536      }
537    });
538    this.cpuByThreadTbl!.addEventListener('row-click', (evt: unknown): void => {
539      // @ts-ignore
540      let data = evt.detail.data;
541      data.isSelected = true;
542      this.cpuByThreadTbl?.clearAllSelection(data);
543      this.cpuByThreadTbl?.setCurrentSelection(data);
544    });
545  }
546
547  connectedCallback(): void {
548    super.connectedCallback();
549    resizeObserver(this.parentElement!, this.cpuByThreadTbl!);
550  }
551
552  initHtml(): string {
553    return `
554        <style>
555        .cpu-by-thread-label{
556            width: 100%;
557            height: 20px;
558        }
559        :host{
560            width: auto;
561            display: flex;
562            flex-direction: column;
563            padding: 10px 10px;
564        }
565        </style>
566        <label id="time-range" class="cpu-by-thread-label" style="text-align: end;font-size: 10pt;margin-bottom: 5px">Selected range:0.0 ms</label>
567        <lit-table id="tb-cpu-thread" style="height:calc( 30vh - 25px )" >
568
569        </lit-table>
570        `;
571  }
572  compare(property: unknown, sort: unknown, type: string) {
573    return function (cpuByThreadLeftData: SelectionData, cpuByThreadRightData: SelectionData): number {
574      if (cpuByThreadLeftData.process === ' ' || cpuByThreadRightData.process === ' ') {
575        return 0;
576      }
577      if (type === 'number') {
578        return sort === 2 // @ts-ignore
579          ? parseFloat(cpuByThreadRightData[property]) - parseFloat(cpuByThreadLeftData[property]) // @ts-ignore
580          : parseFloat(cpuByThreadLeftData[property]) - parseFloat(cpuByThreadRightData[property]);
581      } else {
582        // @ts-ignore
583        if (cpuByThreadRightData[property] > cpuByThreadLeftData[property]) {
584          return sort === 2 ? 1 : -1;
585        } else {
586          // @ts-ignore
587          if (cpuByThreadRightData[property] === cpuByThreadLeftData[property]) {
588            return 0;
589          } else {
590            return sort === 2 ? -1 : 1;
591          }
592        }
593      }
594    };
595  }
596  sortByColumn(detail: unknown): void {
597    // @ts-ignore
598    if ((detail.key as string).includes('cpu')) {
599      // @ts-ignore
600      if ((detail.key as string).includes('Ratio')) {
601        // @ts-ignore
602        this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'string'));
603      } else {
604        // @ts-ignore
605        this.cpuByThreadSource.sort(this.compare((detail.key as string).replace('TimeStr', ''), detail.sort, 'number'));
606      }
607    } else {
608      if (
609        // @ts-ignore
610        detail.key === 'pid' ||
611        // @ts-ignore
612        detail.key === 'tid' ||
613        // @ts-ignore
614        detail.key === 'wallDuration' ||
615        // @ts-ignore
616        detail.key === 'avgDuration' ||
617        // @ts-ignore
618        detail.key === 'occurrences'
619      ) {
620        // @ts-ignore
621        this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'number'));
622      } else {
623        // @ts-ignore
624        this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'string'));
625      }
626    }
627
628    this.cpuByThreadTbl!.recycleDataSource = this.cpuByThreadSource;
629  }
630}
631