• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2023 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 */
15import { BaseElement, element } from '../../../../../base-ui/BaseElement';
16import { LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table';
17import { SelectionParam } from '../../../../bean/BoxSelection';
18import '../../../StackBar';
19import { getTabRunningPercent } from '../../../../database/sql/ProcessThread.sql';
20import { queryCpuFreqUsageData, queryCpuFreqFilterId } from '../../../../database/sql/Cpu.sql';
21import { querySearchFuncData } from '../../../../database/sql/Func.sql';
22import { Utils } from '../../base/Utils';
23import { resizeObserver } from '../SheetUtils';
24import { LitChartScatter } from '../../../../../base-ui/chart/scatter/LitChartScatter';
25import { SpSegmentationChart } from '../../../chart/SpSegmentationChart';
26import { TabPaneFreqUsageConfig, type TabPaneRunningConfig, TabPaneCpuFreqConfig } from './TabPaneFreqUsageConfig';
27@element('tabpane-freqdatacut')
28export class TabPaneFreqDataCut extends BaseElement {
29  private threadStatesTbl: LitTable | null | undefined;
30  private threadStatesTblSource: Array<TabPaneFreqUsageConfig> = [];
31  private currentSelectionParam: SelectionParam | any;
32  private threadStatesDIV: HTMLDivElement | null | undefined;
33  private scatterInput: HTMLInputElement | null | undefined;
34  private initData: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
35  private processArr: Array<TabPaneFreqUsageConfig> = [];
36  private threadArr: Array<TabPaneFreqUsageConfig> = [];
37  private statisticsScatter: LitChartScatter | null | undefined;
38  set data(threadStatesParam: SelectionParam) {
39    if (this.currentSelectionParam === threadStatesParam) {
40      return;
41    }
42    this.currentSelectionParam = threadStatesParam;
43    this.initData = new Map();
44    this.threadArr = [];
45    this.initUI();
46    this.init(threadStatesParam);
47    let pidArr: Array<TabPaneFreqUsageConfig> = [];
48    // 整理进程级的数组信息
49    let processArr: Array<number> =
50      threadStatesParam.processIds.length > 1
51        ? [...new Set(threadStatesParam.processIds)]
52        : threadStatesParam.processIds;
53    for (let i of processArr) {
54      pidArr.push(
55        new TabPaneFreqUsageConfig(
56          Utils.getInstance().getProcessMap().get(i) === null
57            ? 'Process ' + i
58            : Utils.getInstance().getProcessMap().get(i) + ' ' + i,
59          '',
60          i,
61          '',
62          0,
63          '',
64          '',
65          0,
66          '',
67          0,
68          'process',
69          -1,
70          []
71        )
72      );
73    }
74    // 拷贝给私有属性,以便后续进行数据切割时免除整理进程层级数据
75    this.processArr = pidArr;
76  }
77  /**
78   * 初始化数据
79   */
80  async init(threadStatesParam: SelectionParam): Promise<void> {
81    let {
82      runningMap,
83      sum,
84    }: {
85      runningMap: Map<string, Array<TabPaneRunningConfig>>;
86      sum: number;
87    } = await this.queryRunningData(threadStatesParam);
88    let cpuFreqData: Array<TabPaneCpuFreqConfig> = await this.queryCpuFreqData(threadStatesParam);
89    if (runningMap.size > 0) {
90      // 将cpu频点数据与running状态数据整合,保证其上该段时长内有对应的cpu频点数据
91      this.mergeFreqData(runningMap, cpuFreqData, sum);
92      this.threadStatesTbl!.loading = false;
93    } else {
94      this.threadStatesTblSource = [];
95      this.threadStatesTbl!.recycleDataSource = [];
96      this.threadStatesTbl!.loading = false;
97    }
98  }
99  /**
100   * 重置UI输入框等组件为默认状态
101   */
102  initUI(): void {
103    this.threadStatesTblSource = [];
104    this.threadStatesTbl!.recycleDataSource = [];
105    this.threadStatesTbl!.loading = true;
106    // @ts-ignore
107    this.threadStatesTbl.value = [];
108    // @ts-ignore
109    this.shadowRoot?.querySelector('#dataCutThreadId').style.border = '1px solid rgb(151,151,151)';
110    // @ts-ignore
111    this.shadowRoot?.querySelector('#dataCutThreadFunc').style.border = '1px solid rgb(151,151,151)';
112    // @ts-ignore
113    this.shadowRoot?.querySelector('#maxFreq').style.border = '1px solid rgb(151,151,151)';
114    // @ts-ignore
115    this.shadowRoot?.querySelector('#maxHz').style.border = '1px solid rgb(151,151,151)';
116    // @ts-ignore
117    this.shadowRoot?.querySelector('#cycle-a-start-range').value = '';
118    // @ts-ignore
119    this.shadowRoot?.querySelector('#cycle-a-end-range').value = '';
120    // @ts-ignore
121    this.shadowRoot?.querySelector('#cycle-b-start-range').value = '';
122    // @ts-ignore
123    this.shadowRoot?.querySelector('#cycle-b-end-range').value = '';
124    // @ts-ignore
125    this.shadowRoot?.querySelector('#cycleQuery')!.style.display = 'none';
126    // @ts-ignore
127    this.shadowRoot?.querySelector('#dataCut')?.children[2].children[0].style.backgroundColor = '#fff';
128    // @ts-ignore
129    this.shadowRoot?.querySelector('#dataCut')?.children[2].children[0].style.color = '#000';
130    // @ts-ignore
131    this.shadowRoot?.querySelector('#dataCut')?.children[2].children[1].style.backgroundColor = '#fff';
132    // @ts-ignore
133    this.shadowRoot?.querySelector('#dataCut')?.children[2].children[1].style.color = '#000';
134    // @ts-ignore
135    this.statisticsScatter!.config = undefined;
136    this.parentElement!.style.overflow = 'hidden';
137  }
138  /**
139   * 查询cpu频点信息
140   */
141  async queryCpuFreqData(threadStatesParam: SelectionParam): Promise<Array<TabPaneCpuFreqConfig>> {
142    // 查询cpu及id信息
143    let result: Array<{ id: number; cpu: number }> = await queryCpuFreqFilterId();
144    // 以键值对形式将cpu及id进行对应,后续会将频点数据与其对应cpu进行整合
145    let idMap: Map<number, number> = new Map();
146    let queryId: Array<number> = [];
147    for (let i = 0; i < result.length; i++) {
148      queryId.push(result[i].id);
149      idMap.set(result[i].id, result[i].cpu);
150    }
151    let dealArr: Array<TabPaneCpuFreqConfig> = [];
152    // 通过id去查询频点数据
153    let res: Array<{
154      startNS: number;
155      filter_id: number;
156      value: number;
157      dur: number;
158    }> = await queryCpuFreqUsageData(queryId);
159    for (let i of res) {
160      dealArr.push(
161        new TabPaneCpuFreqConfig(i.startNS + threadStatesParam.recordStartNs, idMap.get(i.filter_id)!, i.value, i.dur)
162      );
163    }
164    return dealArr;
165  }
166  /**
167   * 查询框选区域内的所有running状态数据
168   */
169  async queryRunningData(
170    threadStatesParam: SelectionParam
171  ): Promise<{ runningMap: Map<string, Array<TabPaneRunningConfig>>; sum: number }> {
172    let result: Array<TabPaneRunningConfig> = await getTabRunningPercent(
173      threadStatesParam.threadIds,
174      threadStatesParam.processIds,
175      threadStatesParam.leftNs,
176      threadStatesParam.rightNs
177    );
178    let needDeal: Map<string, Array<TabPaneRunningConfig>> = new Map();
179    let sum: number = 0;
180    if (result !== null && result.length > 0) {
181      let processArr: Array<number> =
182        threadStatesParam.processIds.length > 1
183          ? [...new Set(threadStatesParam.processIds)]
184          : threadStatesParam.processIds;
185      for (let e of result) {
186        if (processArr.includes(e.pid)) {
187          if (needDeal.get(e.pid + '_' + e.tid) === undefined) {
188            this.threadArr.push(
189              new TabPaneFreqUsageConfig(
190                Utils.getInstance().getThreadMap().get(e.tid) + ' ' + e.tid,
191                '',
192                e.pid,
193                e.tid,
194                0,
195                '',
196                '',
197                0,
198                '',
199                0,
200                'thread',
201                -1,
202                []
203              )
204            );
205            needDeal.set(e.pid + '_' + e.tid, new Array());
206          }
207          if (
208            e.ts < threadStatesParam.leftNs + threadStatesParam.recordStartNs &&
209            e.ts + e.dur > threadStatesParam.leftNs + threadStatesParam.recordStartNs
210          ) {
211            const ts = e.ts;
212            e.ts = threadStatesParam.leftNs + threadStatesParam.recordStartNs;
213            e.dur = ts + e.dur - (threadStatesParam.leftNs + threadStatesParam.recordStartNs);
214          }
215          if (e.ts + e.dur > threadStatesParam.rightNs + threadStatesParam.recordStartNs) {
216            e.dur = threadStatesParam.rightNs + threadStatesParam.recordStartNs - e.ts;
217          }
218          e.process =
219            Utils.getInstance().getProcessMap().get(e.pid) === null
220              ? '[NULL]'
221              : Utils.getInstance().getProcessMap().get(e.pid)!;
222          e.thread =
223            Utils.getInstance().getThreadMap().get(e.tid) === null
224              ? '[NULL]'
225              : Utils.getInstance().getThreadMap().get(e.tid)!;
226          let arr: Array<TabPaneRunningConfig> | undefined = needDeal.get(e.pid + '_' + e.tid);
227          sum += e.dur;
228          arr?.push(e);
229        }
230      }
231    }
232    return { runningMap: needDeal, sum: sum };
233  }
234  /**
235   * 将cpu频点数据与running状态数据整合,保证其上该段时长内有对应的cpu频点数据
236   */
237  mergeFreqData(
238    needDeal: Map<string, Array<TabPaneRunningConfig>>,
239    dealArr: Array<TabPaneCpuFreqConfig>,
240    sum: number
241  ): void {
242    needDeal.forEach((value: Array<TabPaneRunningConfig>, key: string) => {
243      let resultList: Array<TabPaneFreqUsageConfig> = [];
244      for (let i = 0; i < value.length; i++) {
245        for (let j = 0; j < dealArr.length; j++) {
246          // 只需要判断running状态数据与频点数据cpu相同的情况
247          if (value[i].cpu === dealArr[j].cpu) {
248            // running状态数据的开始时间大于频点数据开始时间,小于频点结束时间。且running状态数据的持续时间小于频点结束时间减去running状态数据开始时间的情况
249            if (
250              value[i].ts > dealArr[j].startNS &&
251              value[i].ts < dealArr[j].startNS + dealArr[j].dur &&
252              value[i].dur < dealArr[j].startNS + dealArr[j].dur - value[i].ts
253            ) {
254              resultList.push(
255                new TabPaneFreqUsageConfig(
256                  value[i].thread,
257                  value[i].ts,
258                  value[i].pid,
259                  value[i].tid,
260                  0,
261                  value[i].cpu,
262                  dealArr[j].value,
263                  value[i].dur,
264                  '',
265                  (value[i].dur / sum) * 100,
266                  'freqdata',
267                  -1,
268                  undefined
269                )
270              );
271              break;
272            }
273            // running状态数据的开始时间大于频点数据开始时间,小于频点结束时间。且running状态数据的持续时间大于频点结束时间减去running状态数据开始时间的情况
274            if (
275              value[i].ts > dealArr[j].startNS &&
276              value[i].ts < dealArr[j].startNS + dealArr[j].dur &&
277              value[i].dur > dealArr[j].startNS + dealArr[j].dur - value[i].ts
278            ) {
279              resultList.push(
280                new TabPaneFreqUsageConfig(
281                  value[i].thread,
282                  value[i].ts,
283                  value[i].pid,
284                  value[i].tid,
285                  0,
286                  value[i].cpu,
287                  dealArr[j].value,
288                  dealArr[j].startNS + dealArr[j].dur - value[i].ts,
289                  '',
290                  ((dealArr[j].startNS + dealArr[j].dur - value[i].ts) / sum) * 100,
291                  'freqdata',
292                  -1,
293                  undefined
294                )
295              );
296            }
297            // running状态数据的开始时间小于频点数据开始时间,running状态数据的结束时间大于频点数据开始时间。且running状态数据在频点数据开始时间后的持续时间小于频点数据持续时间的情况
298            if (
299              value[i].ts < dealArr[j].startNS &&
300              value[i].ts + value[i].dur > dealArr[j].startNS &&
301              value[i].dur + value[i].ts - dealArr[j].startNS < dealArr[j].dur
302            ) {
303              resultList.push(
304                new TabPaneFreqUsageConfig(
305                  value[i].thread,
306                  dealArr[j].startNS,
307                  value[i].pid,
308                  value[i].tid,
309                  0,
310                  value[i].cpu,
311                  dealArr[j].value,
312                  value[i].dur + value[i].ts - dealArr[j].startNS,
313                  '',
314                  ((value[i].dur + value[i].ts - dealArr[j].startNS) / sum) * 100,
315                  'freqdata',
316                  -1,
317                  undefined
318                )
319              );
320              break;
321            }
322            // running状态数据的开始时间小于频点数据开始时间,running状态数据的结束时间大于频点数据开始时间。且running状态数据在频点数据开始时间后的持续时间大于频点数据持续时间的情况
323            if (
324              value[i].ts < dealArr[j].startNS &&
325              value[i].ts + value[i].dur > dealArr[j].startNS &&
326              value[i].dur + value[i].ts - dealArr[j].startNS > dealArr[j].dur
327            ) {
328              resultList.push(
329                new TabPaneFreqUsageConfig(
330                  value[i].thread,
331                  dealArr[j].startNS,
332                  value[i].pid,
333                  value[i].tid,
334                  0,
335                  value[i].cpu,
336                  dealArr[j].value,
337                  dealArr[j].dur,
338                  '',
339                  (dealArr[j].dur / sum) * 100,
340                  'freqdata',
341                  -1,
342                  undefined
343                )
344              );
345            }
346            // running状态数据的开始时间小于频点数据开始时间,running状态数据的持续时间小于频点数据开始时间的情况
347            if (value[i].ts < dealArr[j].startNS && value[i].ts + value[i].dur < dealArr[j].startNS) {
348              resultList.push(
349                new TabPaneFreqUsageConfig(
350                  value[i].thread,
351                  value[i].ts,
352                  value[i].pid,
353                  value[i].tid,
354                  0,
355                  value[i].cpu,
356                  'unknown',
357                  value[i].dur,
358                  '',
359                  (value[i].dur / sum) * 100,
360                  'freqdata',
361                  -1,
362                  undefined
363                )
364              );
365              break;
366            }
367          }
368        }
369      }
370      this.initData.set(key, resultList);
371    });
372  }
373  /**
374   * single方式切割数据功能
375   */
376  dataSingleCut(
377    threadId: HTMLInputElement,
378    threadFunc: HTMLInputElement,
379    resultList: Map<string, Array<TabPaneFreqUsageConfig>>
380  ): void {
381    let threadIdValue: string = threadId.value.trim();
382    let threadFuncName: string = threadFunc.value.trim();
383    let rightNS: number = this.currentSelectionParam.rightNs;
384    let recordStartNs: number = this.currentSelectionParam.recordStartNs;
385    // @ts-ignore
386    this.threadStatesTbl.value = [];
387    if (threadIdValue !== '' && threadFuncName !== '') {
388      // 根据用户输入的线程ID,方法名去查询数据库,得到对应的方法起始时间,持续时间等数据,以便作为依据进行后续数据切割
389      querySearchFuncData(threadFuncName, Number(threadIdValue), this.currentSelectionParam.leftNs, rightNS).then(
390        (result) => {
391          if (result !== null && result.length > 0) {
392            // targetMap为全局initData的拷贝对象,dealArr数组用来存放周期切割依据数据
393            let targetMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
394            let dealArr: Array<{ ts: number; dur: number }> = [];
395            // 新创建map对象接收传过来的实参map
396            resultList.forEach((item: Array<TabPaneFreqUsageConfig>, key: string) => {
397              targetMap.set(key, JSON.parse(JSON.stringify(item)));
398            });
399            // 整理周期切割依据的数据
400            for (let i of result) {
401              if (i.startTime! + recordStartNs + i.dur! < rightNS + recordStartNs) {
402                dealArr.push({ ts: i.startTime! + recordStartNs, dur: i.dur! });
403              }
404            }
405            let cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
406            let totalList: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
407            this.mergeSingleData(dealArr, targetMap, cycleMap, totalList);
408            // 拷贝线程数组,防止数据污染
409            let threadArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.threadArr));
410            // 拷贝进程数组,防止数据污染
411            let processArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.processArr));
412            // 将周期层级防止到线程层级下
413            this.mergeThreadData(threadArr, cycleMap);
414            // 将原始数据放置到对应的线程层级下,周期数据前
415            this.mergeTotalData(threadArr, this.merge(totalList));
416            // 合并数据到进程层级下
417            this.mergePidData(processArr, threadArr);
418            this.fixedDeal(processArr);
419            this.threadStatesTblSource = processArr;
420            this.threadStatesTbl!.recycleDataSource = processArr;
421            this.threadClick(processArr);
422          } else {
423            this.threadStatesTblSource = [];
424            this.threadStatesTbl!.recycleDataSource = [];
425          }
426          this.threadStatesTbl!.loading = false;
427        }
428      );
429    } else {
430      this.threadStatesTbl!.loading = false;
431      if (threadIdValue === '') {
432        threadId.style.border = '2px solid rgb(255,0,0)';
433      }
434      if (threadFuncName === '') {
435        threadFunc.style.border = '2px solid rgb(255,0,0)';
436      }
437    }
438  }
439  /**
440   * 整合Single切割方式中的频点数据与方法周期数据
441   */
442  mergeSingleData(
443    dealArr: Array<{ ts: number; dur: number }>,
444    targetMap: Map<string, Array<TabPaneFreqUsageConfig>>,
445    cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>,
446    totalList: Map<string, Array<TabPaneFreqUsageConfig>>
447  ): void {
448    let timeDur = this.currentSelectionParam.recordStartNs;
449    targetMap.forEach((value: any, key) => {
450      cycleMap.set(key, new Array());
451      totalList.set(key, new Array());
452      for (let i = 0; i < dealArr.length; i++) {
453        let cpuArr: Array<number> = [];
454        let resList: Array<TabPaneFreqUsageConfig> = [];
455        let cpuMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
456        // 时间倍数值
457        const countMutiple: number = 1000000;
458        const MIN_NUM: number = 3;
459        cpuMap.set(key, new Array());
460        cycleMap
461          .get(key)
462          ?.push(
463            new TabPaneFreqUsageConfig(
464              'cycle' + (i + 1) + '—' + value[0].thread,
465              ((dealArr[i].ts - timeDur) / countMutiple).toFixed(MIN_NUM),
466              key.split('_')[0],
467              key.split('_')[1],
468              0,
469              '',
470              '',
471              0,
472              (dealArr[i].dur / countMutiple).toFixed(MIN_NUM),
473              0,
474              'cycle',
475              i + 1,
476              []
477            )
478          );
479        this.dismantlingSingle(
480          value,
481          dealArr[i],
482          {
483            i: i,
484            key: key,
485            countMutiple: countMutiple,
486            cpuArr,
487            cpuMap,
488          },
489          resList,
490          totalList
491        );
492        this.mergeData(resList);
493        // 整理排序相同周期下的数据
494        this.mergeCpuData(cpuMap.get(key)!, resList);
495        // 将cpu数据放置到对应周期层级下
496        this.mergeCycleData(cycleMap.get(key)![i], cpuMap.get(key)!);
497      }
498    });
499  }
500  /**
501   * 拆解Single大函数
502   * @param value 频点数据数组
503   * @param funData 方法对象
504   * @param constant 常量
505   * @param resList 周期数组
506   * @param totalList total数组
507   */
508  dismantlingSingle(
509    value: Array<TabPaneFreqUsageConfig>,
510    funData: { ts: number; dur: number },
511    constant: {
512      i: number;
513      key: string;
514      countMutiple: number;
515      cpuArr: Array<number>;
516      cpuMap: Map<string, Array<TabPaneFreqUsageConfig>>;
517    },
518    resList: Array<TabPaneFreqUsageConfig>,
519    totalList: Map<string, Array<TabPaneFreqUsageConfig>>
520  ): void {
521    // 判断若用户导入json文件,则替换为对应cpu下的对应频点的算力值进行算力消耗计算
522    for (let j = 0; j < value.length; j++) {
523      let startTime = Number(value[j].ts);
524      let percent = Number(value[j].percent);
525      // @ts-ignore
526      let consumptionMap: Map<number, number> =
527      //@ts-ignore
528        SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu))?.mapData;
529      // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容
530      const consumption: number = Number(
531        consumptionMap && consumptionMap.get(Number(value[j].freq))
532          ? consumptionMap.get(Number(value[j].freq))
533          : value[j].freq === 'unknown'
534          ? 0
535          : value[j].freq
536      );
537      if (!constant.cpuArr.includes(Number(value[j].cpu))) {
538        constant.cpuArr.push(Number(value[j].cpu));
539        constant.cpuMap
540          .get(constant.key)
541          ?.push(
542            new TabPaneFreqUsageConfig(
543              'cycle' + (constant.i + 1) + '—' + value[j].thread,
544              '',
545              value[j].pid,
546              value[j].tid,
547              0,
548              value[j].cpu,
549              '',
550              0,
551              '',
552              0,
553              'cpu',
554              -1,
555              []
556            )
557          );
558      }
559      // 以下为频点数据按Single周期切割数据如何取舍的判断条件,dealArr为周期切割依据,value为某一线程下的频点汇总数据
560      // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间小于周期结束时间的情况
561      if (
562        funData.ts < startTime &&
563        funData.ts + funData.dur > startTime &&
564        funData.ts + funData.dur > startTime + value[j].dur
565      ) {
566        resList.push(
567          this.returnSingleObj(
568            'cycle' + (constant.i + 1) + '—' + value[j].thread,
569            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
570            value[j],
571            funData,
572            1
573          )!
574        );
575        totalList
576          .get(constant.key)
577          ?.push(
578            this.returnSingleObj(
579              value[j].thread,
580              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
581              value[j],
582              funData,
583              1
584            )!
585          );
586      }
587      // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间大于等于周期结束时间的情况
588      if (
589        funData.ts < startTime &&
590        funData.ts + funData.dur > startTime &&
591        funData.ts + funData.dur <= startTime + value[j].dur
592      ) {
593        resList.push(
594          this.returnSingleObj(
595            'cycle' + (constant.i + 1) + '—' + value[j].thread,
596            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
597            value[j],
598            funData,
599            2
600          )!
601        );
602        totalList
603          .get(constant.key)
604          ?.push(
605            this.returnSingleObj(
606              value[j].thread,
607              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
608              value[j],
609              funData,
610              2
611            )!
612          );
613        break;
614      }
615      // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间大于周期结束时间的情况
616      if (
617        funData.ts > startTime &&
618        startTime + value[j].dur > funData.ts &&
619        startTime + value[j].dur > funData.ts + funData.dur
620      ) {
621        resList.push(
622          this.returnSingleObj(
623            'cycle' + (constant.i + 1) + '—' + value[j].thread,
624            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
625            value[j],
626            funData,
627            3
628          )!
629        );
630        totalList
631          .get(constant.key)
632          ?.push(
633            this.returnSingleObj(
634              value[j].thread,
635              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
636              value[j],
637              funData,
638              3
639            )!
640          );
641        break;
642      }
643      // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间小于等于周期结束时间的情况
644      if (
645        funData.ts > startTime &&
646        startTime + value[j].dur > funData.ts &&
647        startTime + value[j].dur <= funData.ts + funData.dur
648      ) {
649        resList.push(
650          this.returnSingleObj(
651            'cycle' + (constant.i + 1) + '—' + value[j].thread,
652            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
653            value[j],
654            funData,
655            4
656          )!
657        );
658        totalList
659          .get(constant.key)
660          ?.push(
661            this.returnSingleObj(
662              value[j].thread,
663              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
664              value[j],
665              funData,
666              4
667            )!
668          );
669      }
670    }
671  }
672  /**
673   *
674   * @param str 周期列头
675   * @param arg 常量参数
676   * @param value 频点数据对象
677   * @param funData 方法对象
678   * @param flag 标志位
679   * @returns 频点数据对象
680   */
681  returnSingleObj(
682    str: string,
683    arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number },
684    value: TabPaneFreqUsageConfig,
685    funData: { ts: number; dur: number },
686    flag: number
687  ): TabPaneFreqUsageConfig | undefined {
688    switch (flag) {
689      case 1:
690        return new TabPaneFreqUsageConfig(
691          str,
692          '',
693          value.pid,
694          value.tid,
695          (arg.consumption * value.dur) / arg.countMutiple,
696          value.cpu,
697          value.freq,
698          value.dur,
699          '',
700          arg.percent,
701          'freqdata',
702          arg.i,
703          undefined
704        );
705      case 2:
706        return new TabPaneFreqUsageConfig(
707          str,
708          '',
709          value.pid,
710          value.tid,
711          ((funData.ts + funData.dur - arg.startTime) * arg.consumption) / arg.countMutiple,
712          value.cpu,
713          value.freq,
714          funData.ts + funData.dur - arg.startTime,
715          '',
716          ((funData.ts + funData.dur - arg.startTime) / value.dur) * arg.percent,
717          'freqdata',
718          arg.i,
719          undefined
720        );
721      case 3:
722        return new TabPaneFreqUsageConfig(
723          str,
724          '',
725          value.pid,
726          value.tid,
727          (funData.dur * arg.consumption) / arg.countMutiple,
728          value.cpu,
729          value.freq,
730          funData.dur,
731          '',
732          (funData.dur / value.dur) * arg.percent,
733          'freqdata',
734          arg.i,
735          undefined
736        );
737      case 4:
738        return new TabPaneFreqUsageConfig(
739          str,
740          '',
741          value.pid,
742          value.tid,
743          ((arg.startTime + value.dur - funData.ts) * arg.consumption) / arg.countMutiple,
744          value.cpu,
745          value.freq,
746          arg.startTime + value.dur - funData.ts,
747          '',
748          ((arg.startTime + value.dur - funData.ts) / value.dur) * arg.percent,
749          'freqdata',
750          arg.i,
751          undefined
752        );
753      default:
754        break;
755    }
756  }
757  /**
758   * Loop方式切割数据功能
759   */
760  dataLoopCut(
761    threadId: HTMLInputElement,
762    threadFunc: HTMLInputElement,
763    resultList: Map<string, Array<TabPaneFreqUsageConfig>>
764  ): void {
765    let threadIdValue: string = threadId.value.trim();
766    let threadFuncName: string = threadFunc.value.trim();
767    let rightNS: number = this.currentSelectionParam.rightNs;
768    let recordStartNs: number = this.currentSelectionParam.recordStartNs;
769    // @ts-ignore
770    this.threadStatesTbl.value = [];
771    if (threadIdValue !== '' && threadFuncName !== '') {
772      querySearchFuncData(threadFuncName, Number(threadIdValue), this.currentSelectionParam.leftNs, rightNS).then(
773        (res) => {
774          if (res !== null && res.length > 0) {
775            // targetMap为全局initData的拷贝对象,cutArr数组用来存放周期切割依据数据
776            let targetMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
777            let cutArr: Array<{ ts: number; dur?: number }> = [];
778            // 新创建map对象接收传过来的实参map
779            resultList.forEach((item: Array<TabPaneFreqUsageConfig>, key: string) => {
780              targetMap.set(key, JSON.parse(JSON.stringify(item)));
781            });
782            // 根据线程id及方法名获取的数据,处理后用作切割时间依据,时间跨度为整个方法开始时间到末个方法开始时间
783            for (let i of res) {
784              cutArr[cutArr.length - 1] &&
785                (cutArr[cutArr.length - 1].dur = i.startTime
786                  ? i.startTime + recordStartNs - cutArr[cutArr.length - 1].ts
787                  : 0);
788              cutArr.push({ ts: i.startTime! + recordStartNs });
789            }
790            let cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
791            let totalList: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
792            this.mergeLoopData(cutArr, targetMap, cycleMap, totalList);
793            let threadArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.threadArr));
794            let processArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.processArr));
795            this.mergeThreadData(threadArr, cycleMap);
796            this.mergeTotalData(threadArr, this.merge(totalList));
797            this.mergePidData(processArr, threadArr);
798            this.fixedDeal(processArr);
799            this.threadStatesTblSource = processArr;
800            this.threadStatesTbl!.recycleDataSource = processArr;
801            this.threadClick(processArr);
802          } else {
803            this.threadStatesTblSource = [];
804            this.threadStatesTbl!.recycleDataSource = [];
805          }
806        }
807      );
808      this.threadStatesTbl!.loading = false;
809    } else {
810      this.threadStatesTbl!.loading = false;
811      if (threadIdValue === '') {
812        threadId.style.border = '2px solid rgb(255,0,0)';
813      }
814      if (threadFuncName === '') {
815        threadFunc.style.border = '2px solid rgb(255,0,0)';
816      }
817    }
818  }
819  /**
820   * 整合Loop切割方式中的频点数据与方法周期数据
821   */
822  mergeLoopData(
823    cutArr: Array<{ ts: number; dur?: number }>,
824    targetMap: Map<string, Array<TabPaneFreqUsageConfig>>,
825    cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>,
826    totalList: Map<string, Array<TabPaneFreqUsageConfig>>
827  ): void {
828    let timeDur: number = this.currentSelectionParam.recordStartNs;
829    targetMap.forEach((value: any, key) => {
830      cycleMap.set(key, new Array());
831      totalList.set(key, new Array());
832      for (let i = 0; i < cutArr.length - 1; i++) {
833        let cpuArr: Array<number> = [];
834        let resList: Array<TabPaneFreqUsageConfig> = [];
835        let cpuMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
836        // 时间倍数值
837        const countMutiple: number = 1000000;
838        const MIN_NUM: number = 3;
839        cpuMap.set(key, new Array());
840        // 创建周期层级数据
841        cycleMap
842          .get(key)
843          ?.push(
844            new TabPaneFreqUsageConfig(
845              'cycle' + (i + 1) + '—' + value[0].thread,
846              ((cutArr[i].ts - timeDur) / countMutiple).toFixed(MIN_NUM),
847              key.split('_')[0],
848              key.split('_')[1],
849              0,
850              '',
851              '',
852              0,
853              (cutArr[i].dur! / countMutiple).toFixed(MIN_NUM),
854              0,
855              'cycle',
856              i + 1,
857              []
858            )
859          );
860        this.dismantlingLoop(
861          value,
862          cutArr,
863          {
864            i: i,
865            key: key,
866            countMutiple: countMutiple,
867            cpuArr,
868            cpuMap,
869          },
870          resList,
871          totalList
872        );
873        // 合并相同周期内的数据
874        this.mergeData(resList);
875        // 整理排序相同周期下的数据
876        this.mergeCpuData(cpuMap.get(key)!, resList);
877        // 将cpu数据放置到对应周期层级下
878        this.mergeCycleData(cycleMap.get(key)![i], cpuMap.get(key)!);
879      }
880    });
881  }
882  /**
883   * 拆解Loop大函数
884   * @param value 频点数据数组
885   * @param funData 方法对象
886   * @param constant 常量
887   * @param resList 周期数组
888   * @param totalList total数组
889   */
890  dismantlingLoop(
891    value: Array<TabPaneFreqUsageConfig>,
892    cutArr: Array<{ ts: number; dur?: number }>,
893    constant: {
894      i: number;
895      key: string;
896      countMutiple: number;
897      cpuArr: Array<number>;
898      cpuMap: Map<string, Array<TabPaneFreqUsageConfig>>;
899    },
900    resList: Array<TabPaneFreqUsageConfig>,
901    totalList: Map<string, Array<TabPaneFreqUsageConfig>>
902  ): void {
903    for (let j = 0; j < value.length; j++) {
904      // 判断若用户导入json文件,则替换为对应cpu下的对应频点的算力值进行算力消耗计算
905      let startTime = Number(value[j].ts);
906      let percent = Number(value[j].percent);
907      // @ts-ignore
908      let consumptionMap: Map<number, number> =
909      //@ts-ignore
910        SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu))?.mapData;
911      // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容
912      const consumption: number = Number(
913        consumptionMap && consumptionMap.get(Number(value[j].freq))
914          ? consumptionMap.get(Number(value[j].freq))
915          : value[j].freq === 'unknown'
916          ? 0
917          : value[j].freq
918      );
919      if (!constant.cpuArr.includes(Number(value[j].cpu))) {
920        constant.cpuArr.push(Number(value[j].cpu));
921        // 创建cpu层级数据,以便后续生成树结构
922        constant.cpuMap
923          .get(constant.key)
924          ?.push(
925            new TabPaneFreqUsageConfig(
926              'cycle' + (constant.i + 1) + '—' + value[j].thread,
927              '',
928              value[j].pid,
929              value[j].tid,
930              0,
931              value[j].cpu,
932              '',
933              0,
934              '',
935              0,
936              'cpu',
937              -1,
938              []
939            )
940          );
941      }
942      // 以下为频点数据按Loop周期切割数据如何取舍的判断条件,cutArr为周期切割依据,value为某一线程下的频点汇总数据
943      // 如果频点数据开始时间大于某一周期起始时间,且结束时间小于等于下一同名方法开始时间的情况
944      if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur <= cutArr[constant.i + 1].ts) {
945        resList.push(
946          this.returnLoopObj(
947            'cycle' + (constant.i + 1) + '—' + value[j].thread,
948            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
949            value[j],
950            cutArr,
951            1
952          )!
953        );
954        totalList
955          .get(constant.key)
956          ?.push(
957            this.returnLoopObj(
958              value[j].thread,
959              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
960              value[j],
961              cutArr,
962              1
963            )!
964          );
965      }
966      // 如果频点数据开始时间大于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况
967      if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) {
968        if (cutArr[constant.i + 1].ts - startTime > 0) {
969          resList.push(
970            this.returnLoopObj(
971              'cycle' + (constant.i + 1) + '—' + value[j].thread,
972              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
973              value[j],
974              cutArr,
975              2
976            )!
977          );
978          totalList
979            .get(constant.key)
980            ?.push(
981              this.returnLoopObj(
982                value[j].thread,
983                { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
984                value[j],
985                cutArr,
986                2
987              )!
988            );
989          break;
990        }
991      }
992      // 如果频点数据开始时间小于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况
993      if (startTime < cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) {
994        resList.push(
995          this.returnLoopObj(
996            'cycle' + (constant.i + 1) + '—' + value[j].thread,
997            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
998            value[j],
999            cutArr,
1000            3
1001          )!
1002        );
1003        totalList
1004          .get(constant.key)
1005          ?.push(
1006            this.returnLoopObj(
1007              value[j].thread,
1008              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
1009              value[j],
1010              cutArr,
1011              3
1012            )!
1013          );
1014      }
1015      // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该方法开始时间。且频点数据结束时间小于下一同名方法开始时间
1016      if (
1017        startTime < cutArr[constant.i].ts &&
1018        startTime + value[j].dur > cutArr[constant.i].ts &&
1019        startTime + value[j].dur < cutArr[constant.i + 1].ts
1020      ) {
1021        resList.push(
1022          this.returnLoopObj(
1023            'cycle' + (constant.i + 1) + '—' + value[j].thread,
1024            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
1025            value[j],
1026            cutArr,
1027            4
1028          )!
1029        );
1030        totalList
1031          .get(constant.key)
1032          ?.push(
1033            this.returnLoopObj(
1034              value[j].thread,
1035              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
1036              value[j],
1037              cutArr,
1038              4
1039            )!
1040          );
1041      }
1042    }
1043  }
1044  /**
1045   *
1046   * @param str 周期列头
1047   * @param arg 常量参数
1048   * @param value 频点数据对象
1049   * @param funData 方法对象
1050   * @param flag 标志位
1051   * @returns 频点数据对象
1052   */
1053  returnLoopObj(
1054    str: string,
1055    arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number },
1056    value: TabPaneFreqUsageConfig,
1057    cutArr: Array<{ ts: number; dur?: number }>,
1058    flag: number
1059  ): TabPaneFreqUsageConfig | undefined {
1060    switch (flag) {
1061      case 1:
1062        return new TabPaneFreqUsageConfig(
1063          str,
1064          '',
1065          value.pid,
1066          value.tid,
1067          (arg.consumption * value.dur) / arg.countMutiple,
1068          value.cpu,
1069          value.freq,
1070          value.dur,
1071          '',
1072          value.percent,
1073          'freqdata',
1074          arg.i,
1075          undefined
1076        );
1077      case 2:
1078        return new TabPaneFreqUsageConfig(
1079          str,
1080          '',
1081          value.pid,
1082          value.tid,
1083          (arg.consumption * (cutArr[arg.i + 1].ts - arg.startTime)) / arg.countMutiple,
1084          value.cpu,
1085          value.freq,
1086          cutArr[arg.i + 1].ts - arg.startTime,
1087          '',
1088          arg.percent * ((cutArr[arg.i + 1].ts - arg.startTime) / value.dur),
1089          'freqdata',
1090          arg.i,
1091          undefined
1092        );
1093      case 3:
1094        return new TabPaneFreqUsageConfig(
1095          str,
1096          '',
1097          value.pid,
1098          value.tid,
1099          (arg.consumption * (cutArr[arg.i + 1].ts - cutArr[arg.i].ts)) / arg.countMutiple,
1100          value.cpu,
1101          value.freq,
1102          cutArr[arg.i + 1].ts - cutArr[arg.i].ts,
1103          '',
1104          arg.percent * ((cutArr[arg.i + 1].ts - cutArr[arg.i].ts) / value.dur),
1105          'freqdata',
1106          arg.i,
1107          undefined
1108        );
1109      case 4:
1110        return new TabPaneFreqUsageConfig(
1111          str,
1112          '',
1113          value.pid,
1114          value.tid,
1115          (arg.consumption * (value.dur + arg.startTime - cutArr[arg.i].ts)) / arg.countMutiple,
1116          value.cpu,
1117          value.freq,
1118          value.dur + arg.startTime - cutArr[arg.i].ts,
1119          '',
1120          arg.percent * ((value.dur + arg.startTime - cutArr[arg.i].ts) / value.dur),
1121          'freqdata',
1122          arg.i,
1123          undefined
1124        );
1125      default:
1126        break;
1127    }
1128  }
1129  /**
1130   * 切割后整合好的周期频点数据放置到对应的线程下
1131   */
1132  mergeThreadData(
1133    threadArr: Array<TabPaneFreqUsageConfig>,
1134    cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>
1135  ): void {
1136    for (let i = 0; i < threadArr.length; i++) {
1137      let cycleMapData: Array<TabPaneFreqUsageConfig> = cycleMap.get(threadArr[i].pid + '_' + threadArr[i].tid)!;
1138      for (let j = 0; j < cycleMapData!.length; j++) {
1139        threadArr[i].children?.push(cycleMapData![j]);
1140        threadArr[i].count += cycleMapData![j].count;
1141        threadArr[i].dur += cycleMapData![j].dur;
1142        // @ts-ignore
1143        threadArr[i].percent += cycleMapData![j].percent;
1144      }
1145    }
1146  }
1147  /**
1148   * 切割后整合好的线程级频点数据放置到对应的进程
1149   */
1150  mergePidData(pidArr: Array<TabPaneFreqUsageConfig>, threadArr: Array<TabPaneFreqUsageConfig>): void {
1151    for (let i = 0; i < pidArr.length; i++) {
1152      for (let j = 0; j < threadArr.length; j++) {
1153        if (pidArr[i].pid === threadArr[j].pid) {
1154          pidArr[i].children?.push(threadArr[j]);
1155          pidArr[i].count += threadArr[j].count;
1156          pidArr[i].dur += threadArr[j].dur;
1157          // @ts-ignore
1158          pidArr[i].percent += threadArr[j].percent;
1159        }
1160      }
1161    }
1162  }
1163  /**
1164   * 合并相同周期内运行所在cpu相同、频点相同的数据
1165   */
1166  mergeData(resList: Array<TabPaneFreqUsageConfig>): void {
1167    // 合并相同周期内的数据
1168    for (let i = 0; i < resList.length; i++) {
1169      for (let j = i + 1; j < resList.length; j++) {
1170        if (
1171          resList[i].cpu === resList[j].cpu &&
1172          resList[i].freq === resList[j].freq &&
1173          resList[i].id === resList[j].id
1174        ) {
1175          resList[i].dur += resList[j].dur;
1176          // @ts-ignore
1177          resList[i].percent += resList[j].percent;
1178          resList[i].count += resList[j].count;
1179          resList.splice(j, 1);
1180          j--;
1181        }
1182      }
1183    }
1184  }
1185  /**
1186   * 将cpu层级数据放到对应的周期层级下
1187   */
1188  mergeCycleData(obj: TabPaneFreqUsageConfig, arr: Array<TabPaneFreqUsageConfig>): void {
1189    for (let i = 0; i < arr!.length; i++) {
1190      if (arr![i].count === 0 && arr![i].dur === 0) {
1191        continue;
1192      }
1193      obj.children?.push(arr![i]);
1194      obj.count += arr![i].count;
1195      obj.dur += arr![i].dur;
1196      // @ts-ignore
1197      obj.percent += arr![i].percent;
1198    }
1199  }
1200  /**
1201   * 将切割好的不区分周期的数据作为total数据放到对应的线程层级下,周期数据前
1202   */
1203  mergeTotalData(threadArr: Array<TabPaneFreqUsageConfig>, totalData: Array<TabPaneFreqUsageConfig>): void {
1204    for (let i = 0; i < threadArr.length; i++) {
1205      for (let j = 0; j < totalData.length; j++) {
1206        if (
1207          Number(threadArr[i].pid) === Number(totalData[j].pid) &&
1208          Number(threadArr[i].tid) === Number(totalData[j].tid)
1209        ) {
1210          totalData[j].thread = 'TotalData';
1211          totalData[j].flag = 't_cycle';
1212          // @ts-ignore
1213          threadArr[i].children.unshift(totalData[j]);
1214        }
1215      }
1216    }
1217  }
1218  /**
1219   * 整理排序相同周期下的数据
1220   */
1221  mergeCpuData(cpuArray: Array<TabPaneFreqUsageConfig>, resList: Array<TabPaneFreqUsageConfig>): void {
1222    // 以算力消耗降序排列
1223    resList.sort((a, b) => b.count - a.count);
1224    // 以cpu升序排列
1225    cpuArray.sort((a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu));
1226    cpuArray.forEach((item: TabPaneFreqUsageConfig) => {
1227      for (let s = 0; s < resList.length; s++) {
1228        if (item.cpu === resList[s].cpu) {
1229          item.children?.push(resList[s]);
1230          item.count += resList[s].count;
1231          item.dur += resList[s].dur;
1232          // @ts-ignore
1233          item.percent += resList[s].percent;
1234        }
1235      }
1236    });
1237  }
1238  /**
1239   * 切割好的不区分周期的数据,以相同cpu相同频点的进行整合
1240   */
1241  merge(totalList: Map<string, Array<TabPaneFreqUsageConfig>>): Array<TabPaneFreqUsageConfig> {
1242    let result: Array<TabPaneFreqUsageConfig> = new Array();
1243    totalList.forEach((value: Array<TabPaneFreqUsageConfig>, key: string) => {
1244      let countNum = result.push(
1245        new TabPaneFreqUsageConfig('', '', key.split('_')[0], key.split('_')[1], 0, '', '', 0, '', 0, 'cycle', 0, [])
1246      );
1247      let cpuArr: Array<TabPaneFreqUsageConfig> = [];
1248      let flagArr: Array<number | string> = [];
1249      for (let i = 0; i < value.length; i++) {
1250        if (!flagArr.includes(value[i].cpu)) {
1251          flagArr.push(value[i].cpu);
1252          let flag = cpuArr.push(
1253            new TabPaneFreqUsageConfig(
1254              value[i].thread,
1255              '',
1256              value[i].pid,
1257              value[i].tid,
1258              0,
1259              value[i].cpu,
1260              '',
1261              0,
1262              '',
1263              0,
1264              'cpu',
1265              -1,
1266              []
1267            )
1268          );
1269          result[countNum - 1].children?.push(cpuArr[flag - 1]);
1270        }
1271        for (let j = i + 1; j < value.length; j++) {
1272          if (value[i].cpu === value[j].cpu && value[i].freq === value[j].freq) {
1273            value[i].dur += value[j].dur;
1274            // @ts-ignore
1275            value[i].percent += value[j].percent;
1276            value[i].count += value[j].count;
1277            value.splice(j, 1);
1278            j--;
1279          }
1280        }
1281      }
1282      result[countNum - 1].children?.sort(
1283        (a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu)
1284      );
1285      for (let i = 0; i < cpuArr.length; i++) {
1286        for (let j = 0; j < value.length; j++) {
1287          if (cpuArr[i].cpu === value[j].cpu) {
1288            cpuArr[i].children?.push(value[j]);
1289            cpuArr[i].dur += value[j].dur;
1290            cpuArr[i].count += value[j].count;
1291            // @ts-ignore
1292            cpuArr[i].percent += value[j].percent;
1293          }
1294        }
1295        result[countNum - 1].dur += cpuArr[i].dur;
1296        result[countNum - 1].count += cpuArr[i].count;
1297        // @ts-ignore
1298        result[countNum - 1].percent += cpuArr[i].percent;
1299      }
1300    });
1301    return result;
1302  }
1303  /**
1304   * 递归整理数据,取小数位数,转换单位
1305   */
1306  fixedDeal(arr: Array<TabPaneFreqUsageConfig>): void {
1307    if (arr === undefined) {
1308      return;
1309    }
1310    for (let i = 0; i < arr.length; i++) {
1311      // @ts-ignore
1312      arr[i].percent = arr[i].percent.toFixed(2);
1313      // @ts-ignore
1314      arr[i].dur = (arr[i].dur / 1000000).toFixed(3);
1315      if (arr[i].freq !== '') {
1316        if (arr[i].freq === 'unknown') {
1317          arr[i].freq = 'unknown';
1318        } else {
1319          // @ts-ignore
1320          arr[i].freq = arr[i].freq / 1000;
1321        }
1322      }
1323      if (!(SpSegmentationChart.freqInfoMapData.size > 0)) {
1324        // @ts-ignore
1325        arr[i].count = (arr[i].count / 1000).toFixed(3);
1326      } else {
1327        // @ts-ignore
1328        arr[i].count = arr[i].count.toFixed(3);
1329      }
1330      // @ts-ignore
1331      this.fixedDeal(arr[i].children);
1332    }
1333  }
1334  /**
1335   * 绑定表格点击事件
1336   */
1337  private threadClick(data: Array<TabPaneFreqUsageConfig>): void {
1338    let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label');
1339    if (labels) {
1340      for (let i = 0; i < labels.length; i++) {
1341        let label = labels[i].innerHTML;
1342        labels[i].addEventListener('click', (e) => {
1343          if (!this.threadStatesTblSource.length && !this.threadStatesTbl!.recycleDataSource.length) {
1344            data = [];
1345          }
1346          if (label.includes('Process') && i === 0) {
1347            this.threadStatesTbl!.setStatus(data, false);
1348            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
1349          } else if (label.includes('Thread') && i === 1) {
1350            for (let item of data) {
1351              // @ts-ignore
1352              item.status = true;
1353              if (item.children !== undefined && item.children.length > 0) {
1354                this.threadStatesTbl!.setStatus(item.children, false);
1355              }
1356            }
1357            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
1358          } else if (label.includes('Cycle') && i === 2) {
1359            for (let item of data) {
1360              // @ts-ignore
1361              item.status = true;
1362              for (let value of item.children ? item.children : []) {
1363                // @ts-ignore
1364                value.status = true;
1365                if (value.children !== undefined && value.children.length > 0) {
1366                  this.threadStatesTbl!.setStatus(value.children, false);
1367                }
1368              }
1369            }
1370            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
1371          } else if (label.includes('CPU') && i === 3) {
1372            this.threadStatesTbl!.setStatus(data, true);
1373            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand);
1374          }
1375        });
1376      }
1377    }
1378  }
1379  /**
1380   * 散点图渲染数据整理
1381   */
1382  render(res: Array<TabPaneFreqUsageConfig>, str: string, queryCycleScatter: Array<number>): void {
1383    let maxFreq: HTMLInputElement = this.scatterInput!.querySelector('#maxFreq')!;
1384    let maxHz: HTMLInputElement = this.scatterInput!.querySelector('#maxHz')!;
1385    if (maxFreq.value && maxHz.value) {
1386      if (/^[0-9]*$/.test(maxFreq.value) && /^[0-9]*$/.test(maxHz.value)) {
1387        this.organizeData(res, str, queryCycleScatter, maxFreq.value, maxHz.value);
1388      } else {
1389        if (!/^[0-9]*$/.test(maxFreq.value)) {
1390          maxFreq.style.border = '2px solid rgb(255,0,0)';
1391        }
1392        if (!/^[0-9]*$/.test(maxHz.value)) {
1393          maxHz.style.border = '2px solid rgb(255,0,0)';
1394        }
1395      }
1396    } else {
1397      if (maxFreq.value === '') {
1398        maxFreq.style.border = '2px solid rgb(255,0,0)';
1399      }
1400      if (maxHz.value === '') {
1401        maxHz.style.border = '2px solid rgb(255,0,0)';
1402      }
1403      SpSegmentationChart.setChartData('CPU-FREQ', []);
1404    }
1405  }
1406  /**
1407   * 数据整理
1408   */
1409  organizeData(
1410    res: Array<TabPaneFreqUsageConfig>,
1411    str: string,
1412    queryCycleScatter: Array<number>,
1413    maxFreqValue: string,
1414    maxHzValue: string
1415  ): void {
1416    // @ts-ignore
1417    this.shadowRoot?.querySelector('#cycleQuery')!.style.display = 'block';
1418    // @ts-ignore
1419    let freq: Map<number, number> =
1420      SpSegmentationChart.freqInfoMapData.size > 0 &&
1421      //@ts-ignore
1422      SpSegmentationChart.freqInfoMapData.get(SpSegmentationChart.freqInfoMapData.size - 1)?.mapData;
1423    // @ts-ignore
1424    let yAxis: number =
1425      freq && freq.get(Number(maxFreqValue) * 1000) ? freq.get(Number(maxFreqValue) * 1000) : Number(maxFreqValue);
1426    let xAxis: number = (yAxis * 1000) / Number(maxHzValue);
1427    // 需要做筛选时,会利用下面的cycleA、cycleB数组
1428    let scatterArr: Array<Array<number>> = [];
1429    let traceRowdata: Array<{
1430      dur: number;
1431      startNS: number;
1432      value: number;
1433      cycle: number;
1434    }> = [];
1435    let cycleA: Array<Array<number>> = [];
1436    let cycleB: Array<Array<number>> = [];
1437    let cycleAStart: number = queryCycleScatter[0] || 0;
1438    let cycleAEnd: number = queryCycleScatter[1] || 0;
1439    let cycleBStart: number = queryCycleScatter[2] || 0;
1440    let cycleBEnd: number = queryCycleScatter[3] || 0;
1441    for (let i = 1; i < res.length; i++) {
1442      const count: number = Number(res[i].count);
1443      const dur: number = Number(res[i].cdur);
1444      const rdur: number = Number(res[i].dur); //MHz·ms   ms   ms
1445      scatterArr.push([count, count / dur, i, dur, rdur]);
1446      traceRowdata.push({
1447        dur: dur * 1000000,
1448        value: count,
1449        startNS: Number(res[i].ts) * 1000000,
1450        cycle: i - 1,
1451      });
1452      if (dur >= cycleAStart && dur < cycleAEnd) {
1453        cycleA.push([count, count / dur, i, dur, rdur]);
1454      }
1455      if (dur >= cycleBStart && dur < cycleBEnd) {
1456        cycleB.push([count, count / dur, i, dur, rdur]);
1457      }
1458    }
1459    this.setConfig(Number(maxHzValue), str, scatterArr, yAxis, xAxis, cycleA, cycleB);
1460    SpSegmentationChart.setChartData('CPU-FREQ', traceRowdata);
1461  }
1462  /**
1463   * 配置散点图
1464   */
1465  setConfig(
1466    maxHz: number,
1467    str: string,
1468    scatterArr: Array<Array<number>>,
1469    yAxis: number,
1470    xAxis: number,
1471    cycleA: Array<Array<number>>,
1472    cycleB: Array<Array<number>>
1473  ): void {
1474    const DELTA: number = 5;
1475    this.statisticsScatter!.config = {
1476      // 纵轴坐标值
1477      yAxisLabel: [
1478        Math.round(yAxis / DELTA),
1479        Math.round((yAxis * 2) / DELTA),
1480        Math.round((yAxis * 3) / DELTA),
1481        Math.round((yAxis * 4) / DELTA),
1482        Math.round(yAxis),
1483      ],
1484      // 横轴坐标值
1485      xAxisLabel: [
1486        Math.round(xAxis / DELTA),
1487        Math.round((xAxis * 2) / DELTA),
1488        Math.round((xAxis * 3) / DELTA),
1489        Math.round((xAxis * 4) / DELTA),
1490        Math.round(xAxis),
1491        Math.round((xAxis * 6) / DELTA),
1492      ],
1493      // 横轴字段、纵轴字段
1494      axisLabel: ['负载', '算力供给'],
1495      // 是否加载最大负载线及均衡线
1496      drawload: true,
1497      // 最大负载线及均衡线值
1498      load: [xAxis, maxHz],
1499      // 绘制点数据信息存储数组
1500      paintingData: [],
1501      // 当前移入点坐标信息
1502      hoverData: {},
1503      // 颜色池
1504      colorPool: () => ['#2f72f8', '#ffab67', '#a285d2'],
1505      // 移入数据点时是否触发函数
1506      //@ts-ignore
1507      hoverEvent: SpSegmentationChart.tabHover,
1508      // 渐变色背景信息
1509      globalGradient: undefined,
1510      // 渲染数据点
1511      data: [scatterArr, cycleA, cycleB],
1512      // 散点图title
1513      title: str,
1514      colorPoolText: (): Array<string> => ['Total', 'CycleA', 'CycleB'],
1515      tip: (data: { c: Array<number> }): string => {
1516        return `
1517                <div>
1518                    <span>Cycle: ${data.c[2]};</span></br>
1519                    <span>Comsumption: ${data.c[0]};</span></br>
1520                    <span>Cycle_dur: ${data.c[3]} ms;</span></br>
1521                    <span>Running_dur: ${data.c[4]} ms;</span></br>
1522                </div>
1523                `;
1524      },
1525    };
1526  }
1527  initElements(): void {
1528    this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-running-datacut');
1529    // 绑定事件
1530    this.addListener();
1531    this.statisticsScatter = this.shadowRoot?.querySelector('#chart-scatter');
1532    // 增加表格thread层级点击更新散点图事件、周期层级点击高亮泳道图对应段事件
1533    let scatterData: Array<TabPaneFreqUsageConfig> = new Array();
1534    let str: string = '';
1535    this.threadStatesTbl!.addEventListener('row-click', (evt): void => {
1536      // @ts-ignore
1537      if (evt.detail.flag === 'thread') {
1538        // @ts-ignore
1539        scatterData = evt.detail.children;
1540        // @ts-ignore
1541        str = evt.detail.thread;
1542        this.render(scatterData, str, []);
1543      }
1544
1545      if (
1546        // @ts-ignore
1547        evt.detail.flag === 'cycle' &&
1548        // @ts-ignore
1549        evt.detail.pid === scatterData[evt.detail.id - 1].pid &&
1550        // @ts-ignore
1551        evt.detail.tid === scatterData[evt.detail.id - 1].tid &&
1552        // @ts-ignore
1553        evt.detail.id > 0
1554      ) {
1555        // @ts-ignore
1556        SpSegmentationChart.tabHover('CPU-FREQ', true, evt.detail.id - 1);
1557      }
1558    });
1559    this.scatterInput = this.shadowRoot?.querySelector('.chart-box');
1560    this.shadowRoot?.querySelector('#query-btn')!.addEventListener('click', (e) => {
1561      // @ts-ignore
1562      let cycleAStartValue = this.shadowRoot?.querySelector('#cycle-a-start-range')!.value;
1563      // @ts-ignore
1564      let cycleAEndValue = this.shadowRoot?.querySelector('#cycle-a-end-range')!.value;
1565      // @ts-ignore
1566      let cycleBStartValue = this.shadowRoot?.querySelector('#cycle-b-start-range')!.value;
1567      // @ts-ignore
1568      let cycleBEndValue = this.shadowRoot?.querySelector('#cycle-b-end-range')!.value;
1569      let queryCycleScatter = [
1570        Number(cycleAStartValue),
1571        Number(cycleAEndValue),
1572        Number(cycleBStartValue),
1573        Number(cycleBEndValue),
1574      ];
1575      this.render(scatterData, str, queryCycleScatter);
1576    });
1577  }
1578  /**
1579   * 配置监听事件
1580   */
1581  addListener(): void {
1582    // 绑定single、loop按钮点击事件
1583    this.threadStatesDIV = this.shadowRoot?.querySelector('#dataCut');
1584    this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => {
1585      this.threadStatesTbl!.loading = true;
1586      // @ts-ignore
1587        this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#666666';
1588        // @ts-ignore
1589        this.threadStatesDIV?.children[2].children[0].style.color = '#fff';
1590        // @ts-ignore
1591        this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#fff';
1592        // @ts-ignore
1593        this.threadStatesDIV?.children[2].children[1].style.color = '#000';
1594        // @ts-ignore
1595
1596      this.dataSingleCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData);
1597    });
1598    this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => {
1599      this.threadStatesTbl!.loading = true;
1600      // @ts-ignore
1601        this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#666666';
1602        // @ts-ignore
1603        this.threadStatesDIV?.children[2].children[1].style.color = '#fff';
1604        // @ts-ignore
1605        this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#fff';
1606        // @ts-ignore
1607        this.threadStatesDIV?.children[2].children[0].style.color = '#000';
1608        // @ts-ignore
1609      this.dataLoopCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData);
1610    });
1611    this.threadStatesDIV?.children[0].addEventListener('focus', (e) => {
1612      // @ts-ignore
1613      this.threadStatesDIV?.children[0]!.style.border = '1px solid rgb(151,151,151)';
1614    });
1615    this.threadStatesDIV?.children[1].addEventListener('focus', (e) => {
1616      // @ts-ignore
1617      this.threadStatesDIV?.children[1]!.style.border = '1px solid rgb(151,151,151)';
1618    });
1619    this.shadowRoot?.querySelector('#maxFreq')?.addEventListener('focus', (e) => {
1620      // @ts-ignore
1621      this.shadowRoot?.querySelector('#maxFreq')!.style.border = '1px solid rgb(151,151,151)';
1622    });
1623    this.shadowRoot?.querySelector('#maxHz')?.addEventListener('focus', (e) => {
1624      // @ts-ignore
1625      this.shadowRoot?.querySelector('#maxHz')!.style.border = '1px solid rgb(151,151,151)';
1626    });
1627  }
1628  connectedCallback(): void {
1629    super.connectedCallback();
1630    resizeObserver(this.parentElement!, this.threadStatesTbl!);
1631  }
1632  initHtml(): string {
1633    return (
1634      `
1635    <style>
1636    :host{
1637        padding: 10px 10px;
1638        display: flex;
1639        flex-direction: column;
1640        height: 100%;
1641    }
1642    #dataCut{
1643        display: flex;
1644        justify-content: space-between;
1645        width:100%;
1646        height:20px;
1647        margin-bottom:2px;
1648        align-items:center;
1649    }
1650    button{
1651        width:40%;
1652        height:100%;
1653        border: solid 1px #666666;
1654        background-color: rgba(0,0,0,0);
1655        border-radius:10px;
1656    }
1657    button:hover{
1658        background-color:#666666;
1659        color:white;
1660    }
1661    .d-box{
1662        display: flex;
1663        margin-left: 0;
1664        height: 100%;
1665    }
1666    .chart-box{
1667        width: 35%;
1668        min-width: 486px;
1669        overflow: auto;
1670        margin-bottom: 10px;
1671    }
1672    #chart-scatter{
1673        height: 100%;
1674        max-height: 390px;
1675    }
1676    #query-btn{
1677        width:90px;
1678    }
1679    </style>
1680    ` +
1681      this.htmlUp() +
1682      this.htmlDown()
1683    );
1684  }
1685  htmlUp(): string {
1686    return `
1687        <div id='dataCut'>
1688        <input id="dataCutThreadId" type="text" style="width: 15%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%" placeholder="Please input thread id" value='' />
1689        <input id="dataCutThreadFunc" type="text" style="width: 20%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%" placeholder="Please input function name" value='' />
1690        <div style="width:20%;height: 100%;display:flex;justify-content: space-around;">
1691            <button>Single</button>
1692            <button>Loop</button>
1693        </div>
1694    </div>
1695    <selector class="d-box">
1696    <lit-slicer style="width:100%">
1697    <div class="table-box" style="width: 65%; max-width: calc(100%-495px); min-width: 60%">
1698        <lit-table id="tb-running-datacut" style="height: auto; overflow:auto;margin-top:5px" tree>
1699            <lit-table-column class="running-percent-column" width="250px" title="Process/Thread/Cycle/CPU" data-index="thread" key="thread" align="flex-start" retract>
1700            </lit-table-column>
1701            <lit-table-column class="running-percent-column" width="100px" title="Cycle_st(ms)" data-index="ts" key="ts" align="flex-start">
1702            </lit-table-column>
1703            <lit-table-column class="running-percent-column" width="110px"  title="Cycle_dur(ms)" data-index="cdur" key="cdur" align="flex-start">
1704            </lit-table-column>
1705            <lit-table-column class="running-percent-column"  width="50px" title="CPU" data-index="cpu" key="cpu" align="flex-start">
1706            </lit-table-column>
1707            <lit-table-column class="running-percent-column"  width="140px" title="Consumption" data-index="count" key="count" align="flex-start">
1708            </lit-table-column>
1709            <lit-table-column class="running-percent-column"  width="100px" title="Freq(MHz)" data-index="freq" key="freq" align="flex-start">
1710            </lit-table-column>
1711            <lit-table-column class="running-percent-column"  width="120px" title="Running_dur(ms)" data-index="dur" key="dur" align="flex-start">
1712            </lit-table-column>
1713            <lit-table-column class="running-percent-column"  width="100px" title="Percent(%)" data-index="percent" key="percent" align="flex-start">
1714            </lit-table-column>
1715        </lit-table>
1716        </div>
1717    `;
1718  }
1719  htmlDown(): string {
1720    return `
1721      <lit-slicer-track ></lit-slicer-track>
1722        <div class="chart-box">
1723        <div>
1724            <span>maxFreq: </span>
1725            <input id="maxFreq" type="text" style="width: 27%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Please input maxFreq" value='' />
1726            <span>Fps: </span>
1727            <input id="maxHz" type="text" style="width: 27%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Please input Fps" value='' />
1728        </div>
1729        <div style="flex: 1;display: flex; flex-direction: row;">
1730        </div>
1731        <lit-chart-scatter id="chart-scatter"></lit-chart-scatter>
1732        <div id= "cycleQuery" style="margin-bottom:5px;margin-top:5px;display:none">
1733                <div id="cycle-a">
1734                    <span>Cycle A: </span>
1735                    <input id="cycle-a-start-range" type="text" class="cycle-range-input" style="width: 15%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;"  placeholder="Time(ms)" value='' />
1736                    <span>~</span>
1737                    <input id="cycle-a-end-range" type="text" class="cycle-range-input" style="width: 15%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' />
1738                </div>
1739                <div style="margin-top: 5px; display:flex; flex-derection:row; justify-content:space-between">
1740                    <div id="cycle-b">
1741                        <span>Cycle B: </span>
1742                        <input id="cycle-b-start-range" type="text" class="cycle-range-input" style="width: 18%;height:77%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' />
1743                        <span>~</span>
1744                        <input id="cycle-b-end-range" type="text" class="cycle-range-input" style="width: 18%;height:77%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' />
1745                    </div>
1746                    <div>
1747                        <button id="query-btn">Query</button>
1748                    </div>
1749                </div>
1750        </div>
1751    </div>
1752    </lit-slicer>
1753    </selector>
1754    `;
1755  }
1756}
1757