• 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        SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu));
528      // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容
529      const consumption: number = Number(
530        consumptionMap && consumptionMap.get(Number(value[j].freq))
531          ? consumptionMap.get(Number(value[j].freq))
532          : value[j].freq === 'unknown'
533          ? 0
534          : value[j].freq
535      );
536      if (!constant.cpuArr.includes(Number(value[j].cpu))) {
537        constant.cpuArr.push(Number(value[j].cpu));
538        constant.cpuMap
539          .get(constant.key)
540          ?.push(
541            new TabPaneFreqUsageConfig(
542              'cycle' + (constant.i + 1) + '—' + value[j].thread,
543              '',
544              value[j].pid,
545              value[j].tid,
546              0,
547              value[j].cpu,
548              '',
549              0,
550              '',
551              0,
552              'cpu',
553              -1,
554              []
555            )
556          );
557      }
558      // 以下为频点数据按Single周期切割数据如何取舍的判断条件,dealArr为周期切割依据,value为某一线程下的频点汇总数据
559      // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间小于周期结束时间的情况
560      if (
561        funData.ts < startTime &&
562        funData.ts + funData.dur > startTime &&
563        funData.ts + funData.dur > startTime + value[j].dur
564      ) {
565        resList.push(
566          this.returnSingleObj(
567            'cycle' + (constant.i + 1) + '—' + value[j].thread,
568            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
569            value[j],
570            funData,
571            1
572          )!
573        );
574        totalList
575          .get(constant.key)
576          ?.push(
577            this.returnSingleObj(
578              value[j].thread,
579              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
580              value[j],
581              funData,
582              1
583            )!
584          );
585      }
586      // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间大于等于周期结束时间的情况
587      if (
588        funData.ts < startTime &&
589        funData.ts + funData.dur > startTime &&
590        funData.ts + funData.dur <= startTime + value[j].dur
591      ) {
592        resList.push(
593          this.returnSingleObj(
594            'cycle' + (constant.i + 1) + '—' + value[j].thread,
595            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
596            value[j],
597            funData,
598            2
599          )!
600        );
601        totalList
602          .get(constant.key)
603          ?.push(
604            this.returnSingleObj(
605              value[j].thread,
606              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
607              value[j],
608              funData,
609              2
610            )!
611          );
612        break;
613      }
614      // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间大于周期结束时间的情况
615      if (
616        funData.ts > startTime &&
617        startTime + value[j].dur > funData.ts &&
618        startTime + value[j].dur > funData.ts + funData.dur
619      ) {
620        resList.push(
621          this.returnSingleObj(
622            'cycle' + (constant.i + 1) + '—' + value[j].thread,
623            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
624            value[j],
625            funData,
626            3
627          )!
628        );
629        totalList
630          .get(constant.key)
631          ?.push(
632            this.returnSingleObj(
633              value[j].thread,
634              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
635              value[j],
636              funData,
637              3
638            )!
639          );
640        break;
641      }
642      // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间小于等于周期结束时间的情况
643      if (
644        funData.ts > startTime &&
645        startTime + value[j].dur > funData.ts &&
646        startTime + value[j].dur <= funData.ts + funData.dur
647      ) {
648        resList.push(
649          this.returnSingleObj(
650            'cycle' + (constant.i + 1) + '—' + value[j].thread,
651            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
652            value[j],
653            funData,
654            4
655          )!
656        );
657        totalList
658          .get(constant.key)
659          ?.push(
660            this.returnSingleObj(
661              value[j].thread,
662              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
663              value[j],
664              funData,
665              4
666            )!
667          );
668      }
669    }
670  }
671  /**
672   *
673   * @param str 周期列头
674   * @param arg 常量参数
675   * @param value 频点数据对象
676   * @param funData 方法对象
677   * @param flag 标志位
678   * @returns 频点数据对象
679   */
680  returnSingleObj(
681    str: string,
682    arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number },
683    value: TabPaneFreqUsageConfig,
684    funData: { ts: number; dur: number },
685    flag: number
686  ): TabPaneFreqUsageConfig | undefined {
687    switch (flag) {
688      case 1:
689        return new TabPaneFreqUsageConfig(
690          str,
691          '',
692          value.pid,
693          value.tid,
694          (arg.consumption * value.dur) / arg.countMutiple,
695          value.cpu,
696          value.freq,
697          value.dur,
698          '',
699          arg.percent,
700          'freqdata',
701          arg.i,
702          undefined
703        );
704      case 2:
705        return new TabPaneFreqUsageConfig(
706          str,
707          '',
708          value.pid,
709          value.tid,
710          ((funData.ts + funData.dur - arg.startTime) * arg.consumption) / arg.countMutiple,
711          value.cpu,
712          value.freq,
713          funData.ts + funData.dur - arg.startTime,
714          '',
715          ((funData.ts + funData.dur - arg.startTime) / value.dur) * arg.percent,
716          'freqdata',
717          arg.i,
718          undefined
719        );
720      case 3:
721        return new TabPaneFreqUsageConfig(
722          str,
723          '',
724          value.pid,
725          value.tid,
726          (funData.dur * arg.consumption) / arg.countMutiple,
727          value.cpu,
728          value.freq,
729          funData.dur,
730          '',
731          (funData.dur / value.dur) * arg.percent,
732          'freqdata',
733          arg.i,
734          undefined
735        );
736      case 4:
737        return new TabPaneFreqUsageConfig(
738          str,
739          '',
740          value.pid,
741          value.tid,
742          ((arg.startTime + value.dur - funData.ts) * arg.consumption) / arg.countMutiple,
743          value.cpu,
744          value.freq,
745          arg.startTime + value.dur - funData.ts,
746          '',
747          ((arg.startTime + value.dur - funData.ts) / value.dur) * arg.percent,
748          'freqdata',
749          arg.i,
750          undefined
751        );
752      default:
753        break;
754    }
755  }
756  /**
757   * Loop方式切割数据功能
758   */
759  dataLoopCut(
760    threadId: HTMLInputElement,
761    threadFunc: HTMLInputElement,
762    resultList: Map<string, Array<TabPaneFreqUsageConfig>>
763  ): void {
764    let threadIdValue: string = threadId.value.trim();
765    let threadFuncName: string = threadFunc.value.trim();
766    let rightNS: number = this.currentSelectionParam.rightNs;
767    let recordStartNs: number = this.currentSelectionParam.recordStartNs;
768    // @ts-ignore
769    this.threadStatesTbl.value = [];
770    if (threadIdValue !== '' && threadFuncName !== '') {
771      querySearchFuncData(threadFuncName, Number(threadIdValue), this.currentSelectionParam.leftNs, rightNS).then(
772        (res) => {
773          if (res !== null && res.length > 0) {
774            // targetMap为全局initData的拷贝对象,cutArr数组用来存放周期切割依据数据
775            let targetMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
776            let cutArr: Array<{ ts: number; dur?: number }> = [];
777            // 新创建map对象接收传过来的实参map
778            resultList.forEach((item: Array<TabPaneFreqUsageConfig>, key: string) => {
779              targetMap.set(key, JSON.parse(JSON.stringify(item)));
780            });
781            // 根据线程id及方法名获取的数据,处理后用作切割时间依据,时间跨度为整个方法开始时间到末个方法开始时间
782            for (let i of res) {
783              cutArr[cutArr.length - 1] &&
784                (cutArr[cutArr.length - 1].dur = i.startTime
785                  ? i.startTime + recordStartNs - cutArr[cutArr.length - 1].ts
786                  : 0);
787              cutArr.push({ ts: i.startTime! + recordStartNs });
788            }
789            let cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
790            let totalList: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
791            this.mergeLoopData(cutArr, targetMap, cycleMap, totalList);
792            let threadArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.threadArr));
793            let processArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.processArr));
794            this.mergeThreadData(threadArr, cycleMap);
795            this.mergeTotalData(threadArr, this.merge(totalList));
796            this.mergePidData(processArr, threadArr);
797            this.fixedDeal(processArr);
798            this.threadStatesTblSource = processArr;
799            this.threadStatesTbl!.recycleDataSource = processArr;
800            this.threadClick(processArr);
801          } else {
802            this.threadStatesTblSource = [];
803            this.threadStatesTbl!.recycleDataSource = [];
804          }
805        }
806      );
807      this.threadStatesTbl!.loading = false;
808    } else {
809      this.threadStatesTbl!.loading = false;
810      if (threadIdValue === '') {
811        threadId.style.border = '2px solid rgb(255,0,0)';
812      }
813      if (threadFuncName === '') {
814        threadFunc.style.border = '2px solid rgb(255,0,0)';
815      }
816    }
817  }
818  /**
819   * 整合Loop切割方式中的频点数据与方法周期数据
820   */
821  mergeLoopData(
822    cutArr: Array<{ ts: number; dur?: number }>,
823    targetMap: Map<string, Array<TabPaneFreqUsageConfig>>,
824    cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>,
825    totalList: Map<string, Array<TabPaneFreqUsageConfig>>
826  ): void {
827    let timeDur: number = this.currentSelectionParam.recordStartNs;
828    targetMap.forEach((value: any, key) => {
829      cycleMap.set(key, new Array());
830      totalList.set(key, new Array());
831      for (let i = 0; i < cutArr.length - 1; i++) {
832        let cpuArr: Array<number> = [];
833        let resList: Array<TabPaneFreqUsageConfig> = [];
834        let cpuMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map();
835        // 时间倍数值
836        const countMutiple: number = 1000000;
837        const MIN_NUM: number = 3;
838        cpuMap.set(key, new Array());
839        // 创建周期层级数据
840        cycleMap
841          .get(key)
842          ?.push(
843            new TabPaneFreqUsageConfig(
844              'cycle' + (i + 1) + '—' + value[0].thread,
845              ((cutArr[i].ts - timeDur) / countMutiple).toFixed(MIN_NUM),
846              key.split('_')[0],
847              key.split('_')[1],
848              0,
849              '',
850              '',
851              0,
852              (cutArr[i].dur! / countMutiple).toFixed(MIN_NUM),
853              0,
854              'cycle',
855              i + 1,
856              []
857            )
858          );
859        this.dismantlingLoop(
860          value,
861          cutArr,
862          {
863            i: i,
864            key: key,
865            countMutiple: countMutiple,
866            cpuArr,
867            cpuMap,
868          },
869          resList,
870          totalList
871        );
872        // 合并相同周期内的数据
873        this.mergeData(resList);
874        // 整理排序相同周期下的数据
875        this.mergeCpuData(cpuMap.get(key)!, resList);
876        // 将cpu数据放置到对应周期层级下
877        this.mergeCycleData(cycleMap.get(key)![i], cpuMap.get(key)!);
878      }
879    });
880  }
881  /**
882   * 拆解Loop大函数
883   * @param value 频点数据数组
884   * @param funData 方法对象
885   * @param constant 常量
886   * @param resList 周期数组
887   * @param totalList total数组
888   */
889  dismantlingLoop(
890    value: Array<TabPaneFreqUsageConfig>,
891    cutArr: Array<{ ts: number; dur?: number }>,
892    constant: {
893      i: number;
894      key: string;
895      countMutiple: number;
896      cpuArr: Array<number>;
897      cpuMap: Map<string, Array<TabPaneFreqUsageConfig>>;
898    },
899    resList: Array<TabPaneFreqUsageConfig>,
900    totalList: Map<string, Array<TabPaneFreqUsageConfig>>
901  ): void {
902    for (let j = 0; j < value.length; j++) {
903      // 判断若用户导入json文件,则替换为对应cpu下的对应频点的算力值进行算力消耗计算
904      let startTime = Number(value[j].ts);
905      let percent = Number(value[j].percent);
906      // @ts-ignore
907      let consumptionMap: Map<number, number> =
908        SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu));
909      // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容
910      const consumption: number = Number(
911        consumptionMap && consumptionMap.get(Number(value[j].freq))
912          ? consumptionMap.get(Number(value[j].freq))
913          : value[j].freq === 'unknown'
914          ? 0
915          : value[j].freq
916      );
917      if (!constant.cpuArr.includes(Number(value[j].cpu))) {
918        constant.cpuArr.push(Number(value[j].cpu));
919        // 创建cpu层级数据,以便后续生成树结构
920        constant.cpuMap
921          .get(constant.key)
922          ?.push(
923            new TabPaneFreqUsageConfig(
924              'cycle' + (constant.i + 1) + '—' + value[j].thread,
925              '',
926              value[j].pid,
927              value[j].tid,
928              0,
929              value[j].cpu,
930              '',
931              0,
932              '',
933              0,
934              'cpu',
935              -1,
936              []
937            )
938          );
939      }
940      // 以下为频点数据按Loop周期切割数据如何取舍的判断条件,cutArr为周期切割依据,value为某一线程下的频点汇总数据
941      // 如果频点数据开始时间大于某一周期起始时间,且结束时间小于等于下一同名方法开始时间的情况
942      if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur <= cutArr[constant.i + 1].ts) {
943        resList.push(
944          this.returnLoopObj(
945            'cycle' + (constant.i + 1) + '—' + value[j].thread,
946            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
947            value[j],
948            cutArr,
949            1
950          )!
951        );
952        totalList
953          .get(constant.key)
954          ?.push(
955            this.returnLoopObj(
956              value[j].thread,
957              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
958              value[j],
959              cutArr,
960              1
961            )!
962          );
963      }
964      // 如果频点数据开始时间大于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况
965      if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) {
966        if (cutArr[constant.i + 1].ts - startTime > 0) {
967          resList.push(
968            this.returnLoopObj(
969              'cycle' + (constant.i + 1) + '—' + value[j].thread,
970              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
971              value[j],
972              cutArr,
973              2
974            )!
975          );
976          totalList
977            .get(constant.key)
978            ?.push(
979              this.returnLoopObj(
980                value[j].thread,
981                { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
982                value[j],
983                cutArr,
984                2
985              )!
986            );
987          break;
988        }
989      }
990      // 如果频点数据开始时间小于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况
991      if (startTime < cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) {
992        resList.push(
993          this.returnLoopObj(
994            'cycle' + (constant.i + 1) + '—' + value[j].thread,
995            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
996            value[j],
997            cutArr,
998            3
999          )!
1000        );
1001        totalList
1002          .get(constant.key)
1003          ?.push(
1004            this.returnLoopObj(
1005              value[j].thread,
1006              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
1007              value[j],
1008              cutArr,
1009              3
1010            )!
1011          );
1012      }
1013      // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该方法开始时间。且频点数据结束时间小于下一同名方法开始时间
1014      if (
1015        startTime < cutArr[constant.i].ts &&
1016        startTime + value[j].dur > cutArr[constant.i].ts &&
1017        startTime + value[j].dur < cutArr[constant.i + 1].ts
1018      ) {
1019        resList.push(
1020          this.returnLoopObj(
1021            'cycle' + (constant.i + 1) + '—' + value[j].thread,
1022            { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
1023            value[j],
1024            cutArr,
1025            4
1026          )!
1027        );
1028        totalList
1029          .get(constant.key)
1030          ?.push(
1031            this.returnLoopObj(
1032              value[j].thread,
1033              { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple },
1034              value[j],
1035              cutArr,
1036              4
1037            )!
1038          );
1039      }
1040    }
1041  }
1042  /**
1043   *
1044   * @param str 周期列头
1045   * @param arg 常量参数
1046   * @param value 频点数据对象
1047   * @param funData 方法对象
1048   * @param flag 标志位
1049   * @returns 频点数据对象
1050   */
1051  returnLoopObj(
1052    str: string,
1053    arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number },
1054    value: TabPaneFreqUsageConfig,
1055    cutArr: Array<{ ts: number; dur?: number }>,
1056    flag: number
1057  ): TabPaneFreqUsageConfig | undefined {
1058    switch (flag) {
1059      case 1:
1060        return new TabPaneFreqUsageConfig(
1061          str,
1062          '',
1063          value.pid,
1064          value.tid,
1065          (arg.consumption * value.dur) / arg.countMutiple,
1066          value.cpu,
1067          value.freq,
1068          value.dur,
1069          '',
1070          value.percent,
1071          'freqdata',
1072          arg.i,
1073          undefined
1074        );
1075      case 2:
1076        return new TabPaneFreqUsageConfig(
1077          str,
1078          '',
1079          value.pid,
1080          value.tid,
1081          (arg.consumption * (cutArr[arg.i + 1].ts - arg.startTime)) / arg.countMutiple,
1082          value.cpu,
1083          value.freq,
1084          cutArr[arg.i + 1].ts - arg.startTime,
1085          '',
1086          arg.percent * ((cutArr[arg.i + 1].ts - arg.startTime) / value.dur),
1087          'freqdata',
1088          arg.i,
1089          undefined
1090        );
1091      case 3:
1092        return new TabPaneFreqUsageConfig(
1093          str,
1094          '',
1095          value.pid,
1096          value.tid,
1097          (arg.consumption * (cutArr[arg.i + 1].ts - cutArr[arg.i].ts)) / arg.countMutiple,
1098          value.cpu,
1099          value.freq,
1100          cutArr[arg.i + 1].ts - cutArr[arg.i].ts,
1101          '',
1102          arg.percent * ((cutArr[arg.i + 1].ts - cutArr[arg.i].ts) / value.dur),
1103          'freqdata',
1104          arg.i,
1105          undefined
1106        );
1107      case 4:
1108        return new TabPaneFreqUsageConfig(
1109          str,
1110          '',
1111          value.pid,
1112          value.tid,
1113          (arg.consumption * (value.dur + arg.startTime - cutArr[arg.i].ts)) / arg.countMutiple,
1114          value.cpu,
1115          value.freq,
1116          value.dur + arg.startTime - cutArr[arg.i].ts,
1117          '',
1118          arg.percent * ((value.dur + arg.startTime - cutArr[arg.i].ts) / value.dur),
1119          'freqdata',
1120          arg.i,
1121          undefined
1122        );
1123      default:
1124        break;
1125    }
1126  }
1127  /**
1128   * 切割后整合好的周期频点数据放置到对应的线程下
1129   */
1130  mergeThreadData(
1131    threadArr: Array<TabPaneFreqUsageConfig>,
1132    cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>
1133  ): void {
1134    for (let i = 0; i < threadArr.length; i++) {
1135      let cycleMapData: Array<TabPaneFreqUsageConfig> = cycleMap.get(threadArr[i].pid + '_' + threadArr[i].tid)!;
1136      for (let j = 0; j < cycleMapData!.length; j++) {
1137        threadArr[i].children?.push(cycleMapData![j]);
1138        threadArr[i].count += cycleMapData![j].count;
1139        threadArr[i].dur += cycleMapData![j].dur;
1140        // @ts-ignore
1141        threadArr[i].percent += cycleMapData![j].percent;
1142      }
1143    }
1144  }
1145  /**
1146   * 切割后整合好的线程级频点数据放置到对应的进程
1147   */
1148  mergePidData(pidArr: Array<TabPaneFreqUsageConfig>, threadArr: Array<TabPaneFreqUsageConfig>): void {
1149    for (let i = 0; i < pidArr.length; i++) {
1150      for (let j = 0; j < threadArr.length; j++) {
1151        if (pidArr[i].pid === threadArr[j].pid) {
1152          pidArr[i].children?.push(threadArr[j]);
1153          pidArr[i].count += threadArr[j].count;
1154          pidArr[i].dur += threadArr[j].dur;
1155          // @ts-ignore
1156          pidArr[i].percent += threadArr[j].percent;
1157        }
1158      }
1159    }
1160  }
1161  /**
1162   * 合并相同周期内运行所在cpu相同、频点相同的数据
1163   */
1164  mergeData(resList: Array<TabPaneFreqUsageConfig>): void {
1165    // 合并相同周期内的数据
1166    for (let i = 0; i < resList.length; i++) {
1167      for (let j = i + 1; j < resList.length; j++) {
1168        if (
1169          resList[i].cpu === resList[j].cpu &&
1170          resList[i].freq === resList[j].freq &&
1171          resList[i].id === resList[j].id
1172        ) {
1173          resList[i].dur += resList[j].dur;
1174          // @ts-ignore
1175          resList[i].percent += resList[j].percent;
1176          resList[i].count += resList[j].count;
1177          resList.splice(j, 1);
1178          j--;
1179        }
1180      }
1181    }
1182  }
1183  /**
1184   * 将cpu层级数据放到对应的周期层级下
1185   */
1186  mergeCycleData(obj: TabPaneFreqUsageConfig, arr: Array<TabPaneFreqUsageConfig>): void {
1187    for (let i = 0; i < arr!.length; i++) {
1188      if (arr![i].count === 0 && arr![i].dur === 0) {
1189        continue;
1190      }
1191      obj.children?.push(arr![i]);
1192      obj.count += arr![i].count;
1193      obj.dur += arr![i].dur;
1194      // @ts-ignore
1195      obj.percent += arr![i].percent;
1196    }
1197  }
1198  /**
1199   * 将切割好的不区分周期的数据作为total数据放到对应的线程层级下,周期数据前
1200   */
1201  mergeTotalData(threadArr: Array<TabPaneFreqUsageConfig>, totalData: Array<TabPaneFreqUsageConfig>): void {
1202    for (let i = 0; i < threadArr.length; i++) {
1203      for (let j = 0; j < totalData.length; j++) {
1204        if (
1205          Number(threadArr[i].pid) === Number(totalData[j].pid) &&
1206          Number(threadArr[i].tid) === Number(totalData[j].tid)
1207        ) {
1208          totalData[j].thread = 'TotalData';
1209          totalData[j].flag = 't_cycle';
1210          // @ts-ignore
1211          threadArr[i].children.unshift(totalData[j]);
1212        }
1213      }
1214    }
1215  }
1216  /**
1217   * 整理排序相同周期下的数据
1218   */
1219  mergeCpuData(cpuArray: Array<TabPaneFreqUsageConfig>, resList: Array<TabPaneFreqUsageConfig>): void {
1220    // 以算力消耗降序排列
1221    resList.sort((a, b) => b.count - a.count);
1222    // 以cpu升序排列
1223    cpuArray.sort((a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu));
1224    cpuArray.forEach((item: TabPaneFreqUsageConfig) => {
1225      for (let s = 0; s < resList.length; s++) {
1226        if (item.cpu === resList[s].cpu) {
1227          item.children?.push(resList[s]);
1228          item.count += resList[s].count;
1229          item.dur += resList[s].dur;
1230          // @ts-ignore
1231          item.percent += resList[s].percent;
1232        }
1233      }
1234    });
1235  }
1236  /**
1237   * 切割好的不区分周期的数据,以相同cpu相同频点的进行整合
1238   */
1239  merge(totalList: Map<string, Array<TabPaneFreqUsageConfig>>): Array<TabPaneFreqUsageConfig> {
1240    let result: Array<TabPaneFreqUsageConfig> = new Array();
1241    totalList.forEach((value: Array<TabPaneFreqUsageConfig>, key: string) => {
1242      let countNum = result.push(
1243        new TabPaneFreqUsageConfig('', '', key.split('_')[0], key.split('_')[1], 0, '', '', 0, '', 0, 'cycle', 0, [])
1244      );
1245      let cpuArr: Array<TabPaneFreqUsageConfig> = [];
1246      let flagArr: Array<number | string> = [];
1247      for (let i = 0; i < value.length; i++) {
1248        if (!flagArr.includes(value[i].cpu)) {
1249          flagArr.push(value[i].cpu);
1250          let flag = cpuArr.push(
1251            new TabPaneFreqUsageConfig(
1252              value[i].thread,
1253              '',
1254              value[i].pid,
1255              value[i].tid,
1256              0,
1257              value[i].cpu,
1258              '',
1259              0,
1260              '',
1261              0,
1262              'cpu',
1263              -1,
1264              []
1265            )
1266          );
1267          result[countNum - 1].children?.push(cpuArr[flag - 1]);
1268        }
1269        for (let j = i + 1; j < value.length; j++) {
1270          if (value[i].cpu === value[j].cpu && value[i].freq === value[j].freq) {
1271            value[i].dur += value[j].dur;
1272            // @ts-ignore
1273            value[i].percent += value[j].percent;
1274            value[i].count += value[j].count;
1275            value.splice(j, 1);
1276            j--;
1277          }
1278        }
1279      }
1280      result[countNum - 1].children?.sort(
1281        (a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu)
1282      );
1283      for (let i = 0; i < cpuArr.length; i++) {
1284        for (let j = 0; j < value.length; j++) {
1285          if (cpuArr[i].cpu === value[j].cpu) {
1286            cpuArr[i].children?.push(value[j]);
1287            cpuArr[i].dur += value[j].dur;
1288            cpuArr[i].count += value[j].count;
1289            // @ts-ignore
1290            cpuArr[i].percent += value[j].percent;
1291          }
1292        }
1293        result[countNum - 1].dur += cpuArr[i].dur;
1294        result[countNum - 1].count += cpuArr[i].count;
1295        // @ts-ignore
1296        result[countNum - 1].percent += cpuArr[i].percent;
1297      }
1298    });
1299    return result;
1300  }
1301  /**
1302   * 递归整理数据,取小数位数,转换单位
1303   */
1304  fixedDeal(arr: Array<TabPaneFreqUsageConfig>): void {
1305    if (arr === undefined) {
1306      return;
1307    }
1308    for (let i = 0; i < arr.length; i++) {
1309      // @ts-ignore
1310      arr[i].percent = arr[i].percent.toFixed(2);
1311      // @ts-ignore
1312      arr[i].dur = (arr[i].dur / 1000000).toFixed(3);
1313      if (arr[i].freq !== '') {
1314        if (arr[i].freq === 'unknown') {
1315          arr[i].freq = 'unknown';
1316        } else {
1317          // @ts-ignore
1318          arr[i].freq = arr[i].freq / 1000;
1319        }
1320      }
1321      if (!(SpSegmentationChart.freqInfoMapData.size > 0)) {
1322        // @ts-ignore
1323        arr[i].count = (arr[i].count / 1000).toFixed(3);
1324      } else {
1325        // @ts-ignore
1326        arr[i].count = arr[i].count.toFixed(3);
1327      }
1328      // @ts-ignore
1329      this.fixedDeal(arr[i].children);
1330    }
1331  }
1332  /**
1333   * 绑定表格点击事件
1334   */
1335  private threadClick(data: Array<TabPaneFreqUsageConfig>): void {
1336    let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label');
1337    if (labels) {
1338      for (let i = 0; i < labels.length; i++) {
1339        let label = labels[i].innerHTML;
1340        labels[i].addEventListener('click', (e) => {
1341          if (!this.threadStatesTblSource.length && !this.threadStatesTbl!.recycleDataSource.length) {
1342            data = [];
1343          }
1344          if (label.includes('Process') && i === 0) {
1345            this.threadStatesTbl!.setStatus(data, false);
1346            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
1347          } else if (label.includes('Thread') && i === 1) {
1348            for (let item of data) {
1349              // @ts-ignore
1350              item.status = true;
1351              if (item.children !== undefined && item.children.length > 0) {
1352                this.threadStatesTbl!.setStatus(item.children, false);
1353              }
1354            }
1355            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
1356          } else if (label.includes('Cycle') && i === 2) {
1357            for (let item of data) {
1358              // @ts-ignore
1359              item.status = true;
1360              for (let value of item.children ? item.children : []) {
1361                // @ts-ignore
1362                value.status = true;
1363                if (value.children !== undefined && value.children.length > 0) {
1364                  this.threadStatesTbl!.setStatus(value.children, false);
1365                }
1366              }
1367            }
1368            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
1369          } else if (label.includes('CPU') && i === 3) {
1370            this.threadStatesTbl!.setStatus(data, true);
1371            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand);
1372          }
1373        });
1374      }
1375    }
1376  }
1377  /**
1378   * 散点图渲染数据整理
1379   */
1380  render(res: Array<TabPaneFreqUsageConfig>, str: string, queryCycleScatter: Array<number>): void {
1381    let maxFreq: HTMLInputElement = this.scatterInput!.querySelector('#maxFreq')!;
1382    let maxHz: HTMLInputElement = this.scatterInput!.querySelector('#maxHz')!;
1383    if (maxFreq.value && maxHz.value) {
1384      if (/^[0-9]*$/.test(maxFreq.value) && /^[0-9]*$/.test(maxHz.value)) {
1385        this.organizeData(res, str, queryCycleScatter, maxFreq.value, maxHz.value);
1386      } else {
1387        if (!/^[0-9]*$/.test(maxFreq.value)) {
1388          maxFreq.style.border = '2px solid rgb(255,0,0)';
1389        }
1390        if (!/^[0-9]*$/.test(maxHz.value)) {
1391          maxHz.style.border = '2px solid rgb(255,0,0)';
1392        }
1393      }
1394    } else {
1395      if (maxFreq.value === '') {
1396        maxFreq.style.border = '2px solid rgb(255,0,0)';
1397      }
1398      if (maxHz.value === '') {
1399        maxHz.style.border = '2px solid rgb(255,0,0)';
1400      }
1401      SpSegmentationChart.setChartData('CPU-FREQ', []);
1402    }
1403  }
1404  /**
1405   * 数据整理
1406   */
1407  organizeData(
1408    res: Array<TabPaneFreqUsageConfig>,
1409    str: string,
1410    queryCycleScatter: Array<number>,
1411    maxFreqValue: string,
1412    maxHzValue: string
1413  ): void {
1414    // @ts-ignore
1415    this.shadowRoot?.querySelector('#cycleQuery')!.style.display = 'block';
1416    // @ts-ignore
1417    let freq: Map<number, number> =
1418      SpSegmentationChart.freqInfoMapData.size > 0 &&
1419      SpSegmentationChart.freqInfoMapData.get(SpSegmentationChart.freqInfoMapData.size - 1);
1420    // @ts-ignore
1421    let yAxis: number =
1422      freq && freq.get(Number(maxFreqValue) * 1000) ? freq.get(Number(maxFreqValue) * 1000) : Number(maxFreqValue);
1423    let xAxis: number = (yAxis * 1000) / Number(maxHzValue);
1424    // 需要做筛选时,会利用下面的cycleA、cycleB数组
1425    let scatterArr: Array<Array<number>> = [];
1426    let traceRowdata: Array<{
1427      dur: number;
1428      startNS: number;
1429      value: number;
1430      cycle: number;
1431    }> = [];
1432    let cycleA: Array<Array<number>> = [];
1433    let cycleB: Array<Array<number>> = [];
1434    let cycleAStart: number = queryCycleScatter[0] || 0;
1435    let cycleAEnd: number = queryCycleScatter[1] || 0;
1436    let cycleBStart: number = queryCycleScatter[2] || 0;
1437    let cycleBEnd: number = queryCycleScatter[3] || 0;
1438    for (let i = 1; i < res.length; i++) {
1439      const count: number = Number(res[i].count);
1440      const dur: number = Number(res[i].cdur);
1441      const rdur: number = Number(res[i].dur); //MHz·ms   ms   ms
1442      scatterArr.push([count, count / dur, i, dur, rdur]);
1443      traceRowdata.push({
1444        dur: dur * 1000000,
1445        value: count,
1446        startNS: Number(res[i].ts) * 1000000,
1447        cycle: i - 1,
1448      });
1449      if (dur >= cycleAStart && dur < cycleAEnd) {
1450        cycleA.push([count, count / dur, i, dur, rdur]);
1451      }
1452      if (dur >= cycleBStart && dur < cycleBEnd) {
1453        cycleB.push([count, count / dur, i, dur, rdur]);
1454      }
1455    }
1456    this.setConfig(Number(maxHzValue), str, scatterArr, yAxis, xAxis, cycleA, cycleB);
1457    SpSegmentationChart.setChartData('CPU-FREQ', traceRowdata);
1458  }
1459  /**
1460   * 配置散点图
1461   */
1462  setConfig(
1463    maxHz: number,
1464    str: string,
1465    scatterArr: Array<Array<number>>,
1466    yAxis: number,
1467    xAxis: number,
1468    cycleA: Array<Array<number>>,
1469    cycleB: Array<Array<number>>
1470  ): void {
1471    const DELTA: number = 5;
1472    this.statisticsScatter!.config = {
1473      // 纵轴坐标值
1474      yAxisLabel: [
1475        Math.round(yAxis / DELTA),
1476        Math.round((yAxis * 2) / DELTA),
1477        Math.round((yAxis * 3) / DELTA),
1478        Math.round((yAxis * 4) / DELTA),
1479        Math.round(yAxis),
1480      ],
1481      // 横轴坐标值
1482      xAxisLabel: [
1483        Math.round(xAxis / DELTA),
1484        Math.round((xAxis * 2) / DELTA),
1485        Math.round((xAxis * 3) / DELTA),
1486        Math.round((xAxis * 4) / DELTA),
1487        Math.round(xAxis),
1488        Math.round((xAxis * 6) / DELTA),
1489      ],
1490      // 横轴字段、纵轴字段
1491      axisLabel: ['负载', '算力供给'],
1492      // 是否加载最大负载线及均衡线
1493      drawload: true,
1494      // 最大负载线及均衡线值
1495      load: [xAxis, maxHz],
1496      // 绘制点数据信息存储数组
1497      paintingData: [],
1498      // 当前移入点坐标信息
1499      hoverData: {},
1500      // 颜色池
1501      colorPool: () => ['#2f72f8', '#ffab67', '#a285d2'],
1502      // 移入数据点时是否触发函数
1503      //@ts-ignore
1504      hoverEvent: SpSegmentationChart.tabHover,
1505      // 渐变色背景信息
1506      globalGradient: undefined,
1507      // 渲染数据点
1508      data: [scatterArr, cycleA, cycleB],
1509      // 散点图title
1510      title: str,
1511      colorPoolText: (): Array<string> => ['Total', 'CycleA', 'CycleB'],
1512      tip: (data: { c: Array<number> }): string => {
1513        return `
1514                <div>
1515                    <span>Cycle: ${data.c[2]};</span></br>
1516                    <span>Comsumption: ${data.c[0]};</span></br>
1517                    <span>Cycle_dur: ${data.c[3]} ms;</span></br>
1518                    <span>Running_dur: ${data.c[4]} ms;</span></br>
1519                </div>
1520                `;
1521      },
1522    };
1523  }
1524  initElements(): void {
1525    this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-running-datacut');
1526    // 绑定事件
1527    this.addListener();
1528    this.statisticsScatter = this.shadowRoot?.querySelector('#chart-scatter');
1529    // 增加表格thread层级点击更新散点图事件、周期层级点击高亮泳道图对应段事件
1530    let scatterData: Array<TabPaneFreqUsageConfig> = new Array();
1531    let str: string = '';
1532    this.threadStatesTbl!.addEventListener('row-click', (evt): void => {
1533      // @ts-ignore
1534      if (evt.detail.flag === 'thread') {
1535        // @ts-ignore
1536        scatterData = evt.detail.children;
1537        // @ts-ignore
1538        str = evt.detail.thread;
1539        this.render(scatterData, str, []);
1540      }
1541
1542      if (
1543        // @ts-ignore
1544        evt.detail.flag === 'cycle' &&
1545        // @ts-ignore
1546        evt.detail.pid === scatterData[evt.detail.id - 1].pid &&
1547        // @ts-ignore
1548        evt.detail.tid === scatterData[evt.detail.id - 1].tid &&
1549        // @ts-ignore
1550        evt.detail.id > 0
1551      ) {
1552        // @ts-ignore
1553        SpSegmentationChart.tabHover('CPU-FREQ', true, evt.detail.id - 1);
1554      }
1555    });
1556    this.scatterInput = this.shadowRoot?.querySelector('.chart-box');
1557    this.shadowRoot?.querySelector('#query-btn')!.addEventListener('click', (e) => {
1558      // @ts-ignore
1559      let cycleAStartValue = this.shadowRoot?.querySelector('#cycle-a-start-range')!.value;
1560      // @ts-ignore
1561      let cycleAEndValue = this.shadowRoot?.querySelector('#cycle-a-end-range')!.value;
1562      // @ts-ignore
1563      let cycleBStartValue = this.shadowRoot?.querySelector('#cycle-b-start-range')!.value;
1564      // @ts-ignore
1565      let cycleBEndValue = this.shadowRoot?.querySelector('#cycle-b-end-range')!.value;
1566      let queryCycleScatter = [
1567        Number(cycleAStartValue),
1568        Number(cycleAEndValue),
1569        Number(cycleBStartValue),
1570        Number(cycleBEndValue),
1571      ];
1572      this.render(scatterData, str, queryCycleScatter);
1573    });
1574  }
1575  /**
1576   * 配置监听事件
1577   */
1578  addListener(): void {
1579    // 绑定single、loop按钮点击事件
1580    this.threadStatesDIV = this.shadowRoot?.querySelector('#dataCut');
1581    this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => {
1582      this.threadStatesTbl!.loading = true;
1583      // @ts-ignore
1584        this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#666666';
1585        // @ts-ignore
1586        this.threadStatesDIV?.children[2].children[0].style.color = '#fff';
1587        // @ts-ignore
1588        this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#fff';
1589        // @ts-ignore
1590        this.threadStatesDIV?.children[2].children[1].style.color = '#000';
1591        // @ts-ignore
1592
1593      this.dataSingleCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData);
1594    });
1595    this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => {
1596      this.threadStatesTbl!.loading = true;
1597      // @ts-ignore
1598        this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#666666';
1599        // @ts-ignore
1600        this.threadStatesDIV?.children[2].children[1].style.color = '#fff';
1601        // @ts-ignore
1602        this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#fff';
1603        // @ts-ignore
1604        this.threadStatesDIV?.children[2].children[0].style.color = '#000';
1605        // @ts-ignore
1606      this.dataLoopCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData);
1607    });
1608    this.threadStatesDIV?.children[0].addEventListener('focus', (e) => {
1609      // @ts-ignore
1610      this.threadStatesDIV?.children[0]!.style.border = '1px solid rgb(151,151,151)';
1611    });
1612    this.threadStatesDIV?.children[1].addEventListener('focus', (e) => {
1613      // @ts-ignore
1614      this.threadStatesDIV?.children[1]!.style.border = '1px solid rgb(151,151,151)';
1615    });
1616    this.shadowRoot?.querySelector('#maxFreq')?.addEventListener('focus', (e) => {
1617      // @ts-ignore
1618      this.shadowRoot?.querySelector('#maxFreq')!.style.border = '1px solid rgb(151,151,151)';
1619    });
1620    this.shadowRoot?.querySelector('#maxHz')?.addEventListener('focus', (e) => {
1621      // @ts-ignore
1622      this.shadowRoot?.querySelector('#maxHz')!.style.border = '1px solid rgb(151,151,151)';
1623    });
1624  }
1625  connectedCallback(): void {
1626    super.connectedCallback();
1627    resizeObserver(this.parentElement!, this.threadStatesTbl!);
1628  }
1629  initHtml(): string {
1630    return (
1631      `
1632    <style>
1633    :host{
1634        padding: 10px 10px;
1635        display: flex;
1636        flex-direction: column;
1637        height: 100%;
1638    }
1639    #dataCut{
1640        display: flex;
1641        justify-content: space-between;
1642        width:100%;
1643        height:20px;
1644        margin-bottom:2px;
1645        align-items:center;
1646    }
1647    button{
1648        width:40%;
1649        height:100%;
1650        border: solid 1px #666666;
1651        background-color: rgba(0,0,0,0);
1652        border-radius:10px;
1653    }
1654    button:hover{
1655        background-color:#666666;
1656        color:white;
1657    }
1658    .d-box{
1659        display: flex;
1660        margin-left: 0;
1661        height: 100%;
1662    }
1663    .chart-box{
1664        width: 35%;
1665        min-width: 486px;
1666        overflow: auto;
1667        margin-bottom: 10px;
1668    }
1669    #chart-scatter{
1670        height: 100%;
1671        max-height: 390px;
1672    }
1673    #query-btn{
1674        width:90px;
1675    }
1676    </style>
1677    ` +
1678      this.htmlUp() +
1679      this.htmlDown()
1680    );
1681  }
1682  htmlUp(): string {
1683    return `
1684        <div id='dataCut'>
1685        <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='' />
1686        <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='' />
1687        <div style="width:20%;height: 100%;display:flex;justify-content: space-around;">
1688            <button>Single</button>
1689            <button>Loop</button>
1690        </div>
1691    </div>
1692    <selector class="d-box">
1693    <lit-slicer style="width:100%">
1694    <div class="table-box" style="width: 65%; max-width: calc(100%-495px); min-width: 60%">
1695        <lit-table id="tb-running-datacut" style="height: auto; overflow:auto;margin-top:5px" tree>
1696            <lit-table-column class="running-percent-column" width="250px" title="Process/Thread/Cycle/CPU" data-index="thread" key="thread" align="flex-start" retract>
1697            </lit-table-column>
1698            <lit-table-column class="running-percent-column" width="100px" title="Cycle_st(ms)" data-index="ts" key="ts" align="flex-start">
1699            </lit-table-column>
1700            <lit-table-column class="running-percent-column" width="110px"  title="Cycle_dur(ms)" data-index="cdur" key="cdur" align="flex-start">
1701            </lit-table-column>
1702            <lit-table-column class="running-percent-column"  width="50px" title="CPU" data-index="cpu" key="cpu" align="flex-start">
1703            </lit-table-column>
1704            <lit-table-column class="running-percent-column"  width="140px" title="Consumption" data-index="count" key="count" align="flex-start">
1705            </lit-table-column>
1706            <lit-table-column class="running-percent-column"  width="100px" title="Freq(MHz)" data-index="freq" key="freq" align="flex-start">
1707            </lit-table-column>
1708            <lit-table-column class="running-percent-column"  width="120px" title="Running_dur(ms)" data-index="dur" key="dur" align="flex-start">
1709            </lit-table-column>
1710            <lit-table-column class="running-percent-column"  width="100px" title="Percent(%)" data-index="percent" key="percent" align="flex-start">
1711            </lit-table-column>
1712        </lit-table>
1713        </div>
1714    `;
1715  }
1716  htmlDown(): string {
1717    return `
1718      <lit-slicer-track ></lit-slicer-track>
1719        <div class="chart-box">
1720        <div>
1721            <span>maxFreq: </span>
1722            <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='' />
1723            <span>Fps: </span>
1724            <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='' />
1725        </div>
1726        <div style="flex: 1;display: flex; flex-direction: row;">
1727        </div>
1728        <lit-chart-scatter id="chart-scatter"></lit-chart-scatter>
1729        <div id= "cycleQuery" style="margin-bottom:5px;margin-top:5px;display:none">
1730                <div id="cycle-a">
1731                    <span>Cycle A: </span>
1732                    <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='' />
1733                    <span>~</span>
1734                    <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='' />
1735                </div>
1736                <div style="margin-top: 5px; display:flex; flex-derection:row; justify-content:space-between">
1737                    <div id="cycle-b">
1738                        <span>Cycle B: </span>
1739                        <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='' />
1740                        <span>~</span>
1741                        <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='' />
1742                    </div>
1743                    <div>
1744                        <button id="query-btn">Query</button>
1745                    </div>
1746                </div>
1747        </div>
1748    </div>
1749    </lit-slicer>
1750    </selector>
1751    `;
1752  }
1753}
1754