• 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) {
149          const item = waitArr[minIndex];
150          if (item.endTime > item.startTime) {
151            waitArr.splice(minIndex, 1);
152          } else {
153            // wallDuration为0,需要特别处理
154            const obj: finalResultBean = {
155              cat: item.cat,
156              cpu: item.cpu,
157              dur: 0,
158              pid: item.pid ? item.pid : '[NULL]',
159              tid: item.tid ? item.tid : '[NULL]',
160              occurrences: item.isFirstObject === 1 ? 1 : 0
161            };
162            completedArr.push(obj);
163            waitArr.splice(minIndex, 1);
164          }
165          continue;
166        }
167      }
168      let obj: finalResultBean = {
169        cat: '',
170        dur: 0,
171        cpu: 0,
172        pid: 0,
173        tid: 0,
174        occurrences: 0
175      };
176      if (index < sourceData.length) {
177        if (sourceData[index].startTime < minEndTs) {
178          if (globalTs === sourceData[index].startTime) {
179            waitArr.push(sourceData[index]);
180            index++;
181            continue;
182          } else {
183            const maxPriorityItem = this.findMaxPriority(waitArr);
184            obj = {
185              cat: maxPriorityItem.cat,
186              dur: sourceData[index].startTime - globalTs,
187              cpu: maxPriorityItem.cpu,
188              pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]',
189              tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]',
190              occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0
191            }
192            completedArr.push(obj);
193            maxPriorityItem.isFirstObject = 0;
194            waitArr.push(sourceData[index]);
195            globalTs = sourceData[index].startTime;
196            index++;
197          }
198        } else {
199          const maxPriorityItem = this.findMaxPriority(waitArr);
200          obj = {
201            cat: maxPriorityItem.cat,
202            dur: minEndTs - globalTs,
203            cpu: maxPriorityItem.cpu,
204            pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]',
205            tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]',
206            occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0
207          }
208          completedArr.push(obj);
209          maxPriorityItem.isFirstObject = 0;
210          globalTs = minEndTs;
211          if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
212        }
213      } else {
214        const maxPriorityItem = this.findMaxPriority(waitArr);
215        obj = {
216          cat: maxPriorityItem.cat,
217          dur: minEndTs - globalTs,
218          cpu: maxPriorityItem.cpu,
219          pid: maxPriorityItem.pid ? maxPriorityItem.pid : '[NULL]',
220          tid: maxPriorityItem.tid ? maxPriorityItem.tid : '[NULL]',
221          occurrences: maxPriorityItem.isFirstObject === 1 ? 1 : 0
222        }
223        completedArr.push(obj);
224        maxPriorityItem.isFirstObject = 0;
225        globalTs = minEndTs;
226        if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
227      }
228    }
229    return completedArr;
230  }
231
232  private findMaxPriority(arr: CpuAndIrqBean[]): CpuAndIrqBean {
233    return arr.reduce((maxItem: CpuAndIrqBean, currentItem: CpuAndIrqBean) => {
234      return maxItem.priority > currentItem.priority ? maxItem : currentItem;
235    }, arr[0]);
236  }
237
238  // 聚合数据
239  private aggregateData(data: any[], cpuByThreadValue: SelectionParam | any): void {
240    const cpuAggregations: { [tidPidKey: string]: softirqAndIrq } = {};
241    //@ts-ignore
242    let softirqAggregations: softirqAndIrq = {
243      occurrences: 0,
244      wallDuration: 0,
245      avgDuration: 0,
246      cpus: {}
247    };
248    //@ts-ignore
249    let irqAggregations: softirqAndIrq = {
250      occurrences: 0,
251      wallDuration: 0,
252      avgDuration: 0,
253      cpus: {}
254    };
255    data.forEach((obj) => {
256      // 聚合 cpu 数据
257      if (obj.cat === 'cpu') {
258        const tidPidKey = `${obj.tid}-${obj.pid}`;
259        const cpuDurationKey = `cpu${obj.cpu}`;
260        const cpuPercentKey = `cpu${obj.cpu}Ratio`;
261
262        if (!cpuAggregations[tidPidKey]) {
263          cpuAggregations[tidPidKey] = {
264            tid: obj.tid,
265            pid: obj.pid,
266            wallDuration: 0,
267            occurrences: 0,
268            avgDuration: 0,
269            cpus: {},
270            [cpuDurationKey]: 0,
271            [cpuPercentKey]: 100,
272          };
273        }
274
275        cpuAggregations[tidPidKey].wallDuration += obj.dur;
276        cpuAggregations[tidPidKey].occurrences += obj.occurrences;
277        cpuAggregations[tidPidKey].avgDuration = cpuAggregations[tidPidKey].wallDuration / cpuAggregations[tidPidKey].occurrences;
278        cpuAggregations[tidPidKey].cpus[obj.cpu] = (cpuAggregations[tidPidKey].cpus[obj.cpu] || 0) + obj.dur;
279        cpuAggregations[tidPidKey][cpuDurationKey] = cpuAggregations[tidPidKey].cpus[obj.cpu];
280        cpuAggregations[tidPidKey][cpuPercentKey] = (cpuAggregations[tidPidKey][cpuDurationKey] / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)) * 100;
281      }
282
283      // 聚合 softirq 数据
284      if (obj.cat === 'softirq') {
285        this.updateIrqAndSoftirq(softirqAggregations, obj, cpuByThreadValue);
286      }
287      // 聚合 irq 数据
288      if (obj.cat === 'irq') {
289        this.updateIrqAndSoftirq(irqAggregations, obj, cpuByThreadValue);
290      }
291
292    });
293
294    // 将聚合数据转换为最终结果格式
295    const result: Array<{ [key: string]: any }> = [];
296
297    // 添加 CPU 数据
298    for (const tidPidKey in cpuAggregations) {
299      const aggregation = cpuAggregations[tidPidKey];
300      const { tid, pid, occurrences, wallDuration, avgDuration, ...cpuDurations } = aggregation;
301      result.push({ tid, pid, occurrences, wallDuration, avgDuration, ...cpuDurations });
302    }
303
304    // 添加softirq
305    if (softirqAggregations.wallDuration >= 0) {
306      result.push({ process: 'softirq', thread: 'softirq', tid: '[NULL]', pid: '[NULL]', ...softirqAggregations, });
307    }
308
309    // 添加 irq 数据
310    if (irqAggregations.wallDuration >= 0) {
311      result.push({ process: 'irq', thread: 'irq', tid: '[NULL]', pid: '[NULL]', ...irqAggregations });
312    }
313    this.handleFunction(result, cpuByThreadValue);
314
315  }
316
317  //irq和softirq聚合方法
318  private updateIrqAndSoftirq(aggregation: softirqAndIrq, obj: CpuAndIrqBean, cpuByThreadValue: SelectionParam): void {
319    const callid = obj.cpu;
320    const callidDurKey = `cpu${callid}`;
321    const callidPercentKey = `cpu${callid}Ratio`;
322
323    aggregation.wallDuration += obj.dur;
324    aggregation.occurrences += obj.occurrences;
325    aggregation.avgDuration = aggregation.wallDuration / aggregation.occurrences;
326
327    if (!aggregation.cpus[callid]) {
328      aggregation.cpus[callid] = 0;
329    }
330    aggregation.cpus[callid] += obj.dur;
331
332    if (!(callidDurKey in aggregation)) {
333      aggregation[callidDurKey] = 0;
334    }
335    aggregation[callidDurKey] += obj.dur;
336
337    aggregation[callidPercentKey] = (aggregation[callidDurKey] / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)) * 100;
338  }
339
340  //最后将所有数据进行统一整理
341  private handleFunction(data: Array<{ [key: string]: any }>, cpuByThreadValue: SelectionParam): void {
342    let index = 0;
343    let totalWallDuration = 0;
344    let totalOccurrences = 0;
345    const finalData: Array<finalResultBean> = [];
346    while (index < data.length) {
347      const obj = data[index];
348      totalWallDuration += obj.wallDuration;
349      totalOccurrences += obj.occurrences;
350      if (obj.tid !== '[NULL]' && obj.pid !== '[NULL]') {
351        // @ts-ignore
352        let process = Utils.getInstance().getProcessMap(cpuByThreadValue.traceId).get(obj.pid);
353        // @ts-ignore
354        let thread = Utils.getInstance().getThreadMap(cpuByThreadValue.traceId).get(obj.tid);
355        obj.thread = thread == null || thread.length === 0 ? '[NULL]' : thread;
356        obj.process = process == null || process.length === 0 ? '[NULL]' : process;
357      }
358      obj.wallDuration /= 1000000;
359      obj.wallDuration = obj.wallDuration.toFixed(6);
360      obj.avgDuration /= 1000000;
361      obj.avgDuration = obj.avgDuration.toFixed(6);
362      for (const cpu in obj.cpus) {
363        if (obj.cpus.hasOwnProperty(cpu)) {
364          obj[`cpu${cpu}TimeStr`] = getProbablyTime(obj[`cpu${cpu}`]);
365          obj[`cpu${cpu}Ratio`] = obj[`cpu${cpu}Ratio`].toFixed(2);
366        }
367      }
368      for (const cpuNumber of cpuByThreadValue.cpus) {
369        const cpuKey = `cpu${cpuNumber}TimeStr`;
370        const percentKey = `cpu${cpuNumber}Ratio`;
371        if (!obj.hasOwnProperty(cpuKey)) {
372          obj[cpuKey] = "0.00";
373          obj[percentKey] = "0.00";
374        }
375      }
376      delete obj.cpus;
377      finalData.push(obj);
378      index++;
379    }
380    finalData.unshift({
381      wallDuration: (totalWallDuration / 1000000).toFixed(6),
382      occurrences: totalOccurrences,
383    });
384    this.cpuByIrqSource = finalData;
385    this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource;
386  }
387
388  //点击表头进行排序
389  private reSortByColum(key: string, type: number): void {
390    // 如果数组为空,则直接返回
391    if (!this.cpuByIrqSource.length) return;
392    let sortObject: finalResultBean[] = JSON.parse(JSON.stringify(this.cpuByIrqSource)).splice(1);
393    let sortList: Array<finalResultBean> = [];
394    sortList.push(...sortObject);
395    if (type === 0) {
396      this.cpuByThreadTbl!.recycleDataSource = this.cpuByIrqSource;
397    } else {
398      sortList.sort((a, b) => {
399        let aValue: number | string, bValue: number | string;
400        if (key === 'process' || key === 'thread') {
401          // @ts-ignore
402          aValue = a[key];
403          // @ts-ignore
404          bValue = b[key];
405        } else {
406          // @ts-ignore
407          aValue = parseFloat(a[key]);
408          // @ts-ignore
409          bValue = parseFloat(b[key]);
410        }
411        if (typeof aValue === 'string' && typeof bValue === 'string') {
412          return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
413        } else if (typeof aValue === 'number' && typeof bValue === 'number') {
414          return type === 1 ? aValue - bValue : bValue - aValue;
415        } else {
416          return 0;
417        }
418      });
419      this.cpuByThreadTbl!.recycleDataSource = [this.cpuByIrqSource[0]].concat(sortList);
420    }
421  }
422
423  private processResult(result: Array<unknown>, cpuByThreadValue: unknown): void {
424    let sumWall = 0.0;
425    let sumOcc = 0;
426    let map: Map<string, unknown> = new Map<string, unknown>();
427    for (let e of result) {
428      // @ts-ignore
429      sumWall += e.wallDuration;
430      // @ts-ignore
431      sumOcc += e.occurrences;
432      this.updateThreadMap(e, cpuByThreadValue, map);
433    }
434    this.calculateCount(map, sumWall, sumOcc);
435  }
436
437  private updateThreadMap(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void {
438    // @ts-ignore
439    if (map.has(`${e.tid}`)) {
440      this.updateExistingThread(e, cpuByThreadValue, map);
441    } else {
442      this.createThread(e, cpuByThreadValue, map);
443    }
444  }
445
446  private updateExistingThread(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void {
447    // @ts-ignore
448    let thread = map.get(`${e.tid}`)!;
449    // @ts-ignore
450    thread.wallDuration += e.wallDuration;
451    // @ts-ignore
452    thread.occurrences += e.occurrences;
453    this.updateCpuValues(e, cpuByThreadValue, thread);
454  }
455
456  private createThread(e: unknown, cpuByThreadValue: unknown, map: Map<string, unknown>): void {
457    // @ts-ignore
458    let process = Utils.getInstance().getProcessMap(cpuByThreadValue.traceId).get(e.pid);
459    // @ts-ignore
460    let thread = Utils.getInstance().getThreadMap(cpuByThreadValue.traceId).get(e.tid);
461    let cpuByThreadObject: unknown = {
462      // @ts-ignore
463      tid: e.tid,
464      // @ts-ignore
465      pid: e.pid,
466      thread: !thread || thread.length === 0 ? '[NULL]' : thread,
467      process: !process || process.length === 0 ? '[NULL]' : process,
468      // @ts-ignore
469      wallDuration: e.wallDuration || 0,
470      // @ts-ignore
471      occurrences: e.occurrences || 0,
472      avgDuration: 0,
473    };
474    this.initializeCpuValues(cpuByThreadValue, cpuByThreadObject);
475    this.updateCpuValues(e, cpuByThreadValue, cpuByThreadObject);
476    // @ts-ignore
477    map.set(`${e.tid}`, cpuByThreadObject);
478  }
479
480  private initializeCpuValues(cpuByThreadValue: unknown, cpuByThreadObject: unknown): void {
481    // @ts-ignore
482    for (let i of cpuByThreadValue.cpus) {
483      // @ts-ignore
484      cpuByThreadObject[`cpu${i}`] = 0;
485      // @ts-ignore
486      cpuByThreadObject[`cpu${i}TimeStr`] = '0';
487      // @ts-ignore
488      cpuByThreadObject[`cpu${i}Ratio`] = '0';
489    }
490  }
491
492  private updateCpuValues(e: unknown, cpuByThreadValue: unknown, cpuByThreadObject: unknown): void {
493    // @ts-ignore
494    cpuByThreadObject[`cpu${e.cpu}`] = e.wallDuration || 0;
495    // @ts-ignore
496    cpuByThreadObject[`cpu${e.cpu}TimeStr`] = getProbablyTime(e.wallDuration || 0);
497    // @ts-ignore
498    let ratio = ((100.0 * (e.wallDuration || 0)) / (cpuByThreadValue.rightNs - cpuByThreadValue.leftNs)).toFixed(2);
499    if (ratio === '0.00') {
500      ratio = '0';
501    }
502    // @ts-ignore
503    cpuByThreadObject[`cpu${e.cpu}Ratio`] = ratio;
504  }
505
506  private calculateCount(map: Map<string, unknown>, sumWall: number, sumOcc: number): void {
507    // @ts-ignore
508    let arr = Array.from(map.values()).sort((a, b) => b.wallDuration - a.wallDuration);
509    for (let e of arr) {
510      // @ts-ignore
511      e.avgDuration = (e.wallDuration / (e.occurrences || 1.0) / 1000000.0).toFixed(5);
512      // @ts-ignore
513      e.wallDuration = parseFloat((e.wallDuration / 1000000.0).toFixed(5));
514    }
515    let count: unknown = {};
516    // @ts-ignore
517    count.process = ' ';
518    // @ts-ignore
519    count.wallDuration = parseFloat((sumWall / 1000000.0).toFixed(7));
520    // @ts-ignore
521    count.occurrences = sumOcc;
522    // @ts-ignore
523    arr.splice(0, 0, count);
524    // @ts-ignore
525    this.cpuByThreadSource = arr;
526    this.cpuByThreadTbl!.recycleDataSource = arr;
527  }
528
529  getTableColumns(cpus: Array<number>): string {
530    let cpuByThreadTblHtml = `${this.pubColumns}`;
531    let cpuByThreadList = cpus.sort((cpuByThreadA, cpuByThreadB) => cpuByThreadA - cpuByThreadB);
532    for (let index of cpuByThreadList) {
533      cpuByThreadTblHtml = `${cpuByThreadTblHtml}
534            <lit-table-column width="100px" title="cpu${index}" data-index="cpu${index}TimeStr" key="cpu${index}TimeStr"  align="flex-start" order>
535            </lit-table-column>
536            <lit-table-column width="100px" title="%" data-index="cpu${index}Ratio" key="cpu${index}Ratio"  align="flex-start" order>
537            </lit-table-column>
538            `;
539    }
540    return cpuByThreadTblHtml;
541  }
542
543  initElements(): void {
544    this.cpuByThreadTbl = this.shadowRoot?.querySelector<LitTable>('#tb-cpu-thread');
545    this.range = this.shadowRoot?.querySelector('#time-range');
546    this.cpuByThreadTbl!.addEventListener('column-click', (evt): void => {
547      if (!this.loadIrq) {
548        // @ts-ignore
549        this.sortByColumn(evt.detail);
550      } else {
551        // @ts-ignore
552        this.reSortByColum(evt.detail.key, evt.detail.sort);
553      }
554    });
555    this.cpuByThreadTbl!.addEventListener('row-click', (evt: unknown): void => {
556      // @ts-ignore
557      let data = evt.detail.data;
558      data.isSelected = true;
559      this.cpuByThreadTbl?.clearAllSelection(data);
560      this.cpuByThreadTbl?.setCurrentSelection(data);
561    });
562  }
563
564  connectedCallback(): void {
565    super.connectedCallback();
566    resizeObserver(this.parentElement!, this.cpuByThreadTbl!);
567  }
568
569  initHtml(): string {
570    return `
571        <style>
572        .cpu-by-thread-label{
573            width: 100%;
574            height: 20px;
575        }
576        :host{
577            width: auto;
578            display: flex;
579            flex-direction: column;
580            padding: 10px 10px;
581        }
582        </style>
583        <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>
584        <lit-table id="tb-cpu-thread" style="height:calc( 30vh - 25px )" >
585
586        </lit-table>
587        `;
588  }
589  compare(property: unknown, sort: unknown, type: string) {
590    return function (cpuByThreadLeftData: SelectionData, cpuByThreadRightData: SelectionData): number {
591      if (cpuByThreadLeftData.process === ' ' || cpuByThreadRightData.process === ' ') {
592        return 0;
593      }
594      if (type === 'number') {
595        return sort === 2 // @ts-ignore
596          ? parseFloat(cpuByThreadRightData[property]) - parseFloat(cpuByThreadLeftData[property]) // @ts-ignore
597          : parseFloat(cpuByThreadLeftData[property]) - parseFloat(cpuByThreadRightData[property]);
598      } else {
599        // @ts-ignore
600        if (cpuByThreadRightData[property] > cpuByThreadLeftData[property]) {
601          return sort === 2 ? 1 : -1;
602        } else {
603          // @ts-ignore
604          if (cpuByThreadRightData[property] === cpuByThreadLeftData[property]) {
605            return 0;
606          } else {
607            return sort === 2 ? -1 : 1;
608          }
609        }
610      }
611    };
612  }
613  sortByColumn(detail: unknown): void {
614    // @ts-ignore
615    if ((detail.key as string).includes('cpu')) {
616      // @ts-ignore
617      if ((detail.key as string).includes('Ratio')) {
618        // @ts-ignore
619        this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'string'));
620      } else {
621        // @ts-ignore
622        this.cpuByThreadSource.sort(this.compare((detail.key as string).replace('TimeStr', ''), detail.sort, 'number'));
623      }
624    } else {
625      if (
626        // @ts-ignore
627        detail.key === 'pid' ||
628        // @ts-ignore
629        detail.key === 'tid' ||
630        // @ts-ignore
631        detail.key === 'wallDuration' ||
632        // @ts-ignore
633        detail.key === 'avgDuration' ||
634        // @ts-ignore
635        detail.key === 'occurrences'
636      ) {
637        // @ts-ignore
638        this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'number'));
639      } else {
640        // @ts-ignore
641        this.cpuByThreadSource.sort(this.compare(detail.key, detail.sort, 'string'));
642      }
643    }
644
645    this.cpuByThreadTbl!.recycleDataSource = this.cpuByThreadSource;
646  }
647}
648