• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../../../../../base-ui/BaseElement';
17import { LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table';
18import { Utils } from '../../base/Utils';
19import { SelectionParam } from '../../../../bean/BoxSelection';
20import { BinderGroup, DataSource } from '../../../../bean/BinderProcessThread';
21import {
22  querySingleFuncNameCycleStates,
23  queryStatesCut,
24  queryLoopFuncNameCycle,
25} from '../../../../database/sql/Func.sql';
26import { FuncNameCycle } from '../../../../bean/BinderProcessThread';
27import { resizeObserver } from '../SheetUtils';
28import { LitChartColumn } from '../../../../../base-ui/chart/column/LitChartColumn';
29import '../../../../../base-ui/chart/column/LitChartColumn';
30import { SpSegmentationChart } from '../../../chart/SpSegmentationChart';
31import { StateGroup } from '../../../../bean/StateModle';
32import { TraceSheet } from '../../base/TraceSheet';
33import { Flag } from '../../timer-shaft/Flag';
34import { TraceRow } from '../../base/TraceRow';
35import { Rect, ns2x } from '../../../../database/ui-worker/ProcedureWorkerCommon';
36import { SpSystemTrace } from '../../../SpSystemTrace';
37
38@element('tabpane-states-datacut')
39export class TabPaneFreqStatesDataCut extends BaseElement {
40  private threadBindersTbl: LitTable | null | undefined;
41  private currentSelectionParam: SelectionParam | any;
42  private threadStatesDIV: Element | null | undefined;
43  private cycleARangeArr: StateGroup[] | undefined;
44  private cycleBRangeArr: StateGroup[] | undefined;
45  private cycleAStartRangeDIV: HTMLInputElement | null | undefined;
46  private cycleAEndRangeDIV: HTMLInputElement | null | undefined;
47  private cycleBStartRangeDIV: HTMLInputElement | null | undefined;
48  private cycleBEndRangeDIV: HTMLInputElement | null | undefined;
49  private chartTotal: LitChartColumn | null | undefined;
50  private dataSource: DataSource[] | undefined;
51  private rowCycleData: StateGroup[] | undefined;
52  private funcNameCycleArr: FuncNameCycle[] | undefined;
53  private currentThreadId: string | undefined;
54  private cycleStartTime: number | undefined;
55  private cycleEndTime: number | undefined;
56  private filterState: Array<StateGroup> = [];
57  private traceSheetEl: TraceSheet | undefined | null;
58  private spSystemTrace: SpSystemTrace | undefined | null;
59  private lineCycleNum: number = -1;
60  private cycleIsClick: Boolean = false;
61  static isStateTabHover: boolean = false;
62
63  // tab页入口函数
64  set data(threadStatesParam: SelectionParam | any) {
65    // 获取输入框
66    let threadIdDIV = this.shadowRoot!.querySelector('.thread-id-input') as HTMLElement;
67    threadIdDIV.style.border = '1px solid rgb(151,151,151)';
68    let cycleNameDIV = this.shadowRoot!.querySelector('.cycle-name-input') as HTMLElement;
69    cycleNameDIV.style.border = '1px solid rgb(151,151,151)';
70    if (this.currentSelectionParam === threadStatesParam) {
71      return;
72    }
73    // 隐藏右半边区域
74    this.dispalyQueryArea(true);
75    // 清空切割按钮状态
76    this.clickLoop(false);
77    this.clickSingle(false);
78    this.currentSelectionParam = threadStatesParam;
79    // 清空表格数据
80    this.threadBindersTbl!.recycleDataSource = [];
81    this.theadClick(this.threadBindersTbl!.recycleDataSource as Array<BinderGroup>);
82  }
83
84  initTabSheetEl(traceSheet: TraceSheet): void {
85    this.traceSheetEl = traceSheet;
86  }
87
88  dispalyQueryArea(b: boolean) {
89    if (b) {
90      this.setAttribute('dispalyQueryArea', '');
91    } else {
92      this.removeAttribute('dispalyQueryArea');
93    }
94  }
95
96  clickSingle(b: boolean) {
97    if (b) {
98      this.setAttribute('clickSingle', '');
99    } else {
100      this.removeAttribute('clickSingle');
101    }
102  }
103
104  clickLoop(b: boolean) {
105    if (b) {
106      this.setAttribute('clickLoop', '');
107    } else {
108      this.removeAttribute('clickLoop');
109    }
110  }
111
112  // LOOP切割方法
113  async dataLoopCut(threadId: HTMLInputElement, threadFunc: HTMLInputElement): Promise<void> {
114    // 清除表格数据
115    SpSegmentationChart.setStateChartData([]);
116    // 获取框选范围内包含的进程和线程ID
117    let threadIds: number[] = this.currentSelectionParam.threadIds;
118    let processIds: number[] = this.currentSelectionParam.processIds;
119    // 获取输入的进程号和方法名
120    let threadIdValue: string = threadId.value.trim();
121    let threadFuncName: string = threadFunc.value.trim();
122    // 获取框选的左右边界
123    let leftNS: number = this.currentSelectionParam.leftNs;
124    let rightNS: number = this.currentSelectionParam.rightNs;
125    // 判断进程号和方法名是否都输入了内容
126    if (threadIdValue !== '' && threadFuncName !== '') {
127      // 修改按钮样式
128      this.clickLoop(true);
129      this.clickSingle(false);
130      threadId.style.border = '1px solid rgb(151,151,151)';
131      threadFunc.style.border = '1px solid rgb(151,151,151)';
132      this.threadBindersTbl!.loading = true;
133      this.funcNameCycleArr = await queryLoopFuncNameCycle(threadFuncName, threadIdValue, leftNS, rightNS);
134      this.cycleStartTime = this.funcNameCycleArr!.length > 0 ? this.funcNameCycleArr![0].cycleStartTime : undefined;
135      this.cycleEndTime =
136        this.funcNameCycleArr!.length > 1
137          ? this.funcNameCycleArr![this.funcNameCycleArr!.length - 1].cycleStartTime
138          : undefined;
139      // 遍历设置周期的起始时间
140      for (let i = 0; i < this.funcNameCycleArr!.length - 1; i++) {
141        this.funcNameCycleArr![i].endTime = this.funcNameCycleArr![i + 1].cycleStartTime;
142      }
143      // 框选范围内的状态数据
144      let stateItemArr = await queryStatesCut(threadIds, leftNS, rightNS);
145      // 周期数组里的最后一项不满足loop要求,直接删除
146      this.funcNameCycleArr!.pop();
147      if (this.funcNameCycleArr!.length !== 0) {
148        let stateCutArr: StateGroup[] = [];
149        // pid数组去重
150        processIds = Array.from(new Set(processIds));
151        // 去除切割范围以外的数据
152        this.filterState = new Array<StateGroup>();
153        stateItemArr.map((stateItem) => {
154          for (let i = 0; i < this.funcNameCycleArr!.length; i++) {
155            if (
156              ((stateItem.ts > this.funcNameCycleArr![i].cycleStartTime && stateItem.ts < this.funcNameCycleArr![i].endTime) ||
157                (stateItem.ts + stateItem.dur! > this.funcNameCycleArr![i].cycleStartTime &&
158                  stateItem.ts + stateItem.dur! < this.funcNameCycleArr![i].endTime) ||
159                (this.funcNameCycleArr![i].cycleStartTime > stateItem.ts && this.funcNameCycleArr![i].endTime < stateItem.ts + stateItem.dur!)) &&
160              (stateItem.state === 'S' ||
161                stateItem.state === 'R' ||
162                stateItem.state === 'D' ||
163                stateItem.state === 'Running')
164            ) {
165              stateItem.startTs = stateItem.ts;
166              stateItem.chartDur = stateItem.dur;
167              this.filterState!.push(stateItem);
168            }
169          }
170        });
171        this.filterState = Array.from(new Set(this.filterState));
172        // 周期内有数据
173        if (this.filterState.length !== 0) {
174          for (let i = 0; i < processIds.length; i++) {
175            this.setProcessData(this.filterState, processIds[i], stateCutArr);
176          }
177        }
178        this.threadBindersTbl!.recycleDataSource = stateCutArr;
179        this.threadBindersTbl!.loading = false;
180        // 表格添加点击事件
181        this.theadClick(this.threadBindersTbl!.recycleDataSource as Array<BinderGroup>);
182      } else {
183        this.threadBindersTbl!.recycleDataSource = [];
184        this.threadBindersTbl!.loading = false;
185        this.theadClick(this.threadBindersTbl!.recycleDataSource as Array<BinderGroup>);
186      }
187    } else {
188      this.verifyInputIsEmpty(threadIdValue, threadFuncName, threadId, threadFunc);
189    }
190  }
191
192  async dataSingleCut(threadId: HTMLInputElement, threadFunc: HTMLInputElement): Promise<void> {
193    SpSegmentationChart.setStateChartData([]);
194    this.currentThreadId = '';
195    let threadIds: number[] = this.currentSelectionParam.threadIds;
196    let processIds: number[] = this.currentSelectionParam.processIds;
197    let threadIdValue: string = threadId.value.trim();
198    let threadFuncName: string = threadFunc.value.trim();
199    let leftNS: number = this.currentSelectionParam.leftNs;
200    let rightNS: number = this.currentSelectionParam.rightNs;
201    if (threadIdValue !== '' && threadFuncName !== '') {
202      this.clickLoop(false);
203      this.clickSingle(true);
204      threadId.style.border = '1px solid rgb(151,151,151)';
205      threadFunc.style.border = '1px solid rgb(151,151,151)';
206      this.threadBindersTbl!.loading = true;
207      this.funcNameCycleArr = await querySingleFuncNameCycleStates(threadFuncName, threadIdValue, leftNS, rightNS);
208      this.cycleStartTime = this.funcNameCycleArr!.length > 0 ? this.funcNameCycleArr![0].cycleStartTime : undefined;
209      this.cycleEndTime =
210        this.funcNameCycleArr!.length > 0
211          ? this.funcNameCycleArr![this.funcNameCycleArr!.length - 1].endTime
212          : undefined;
213      let stateItemArr = await queryStatesCut(threadIds, leftNS, rightNS);
214      if (this.funcNameCycleArr!.length !== 0) {
215        let stateCutArr: StateGroup[] = [];
216        // pid数组去重
217        processIds = Array.from(new Set(processIds));
218        // 去除切割范围以外的数据
219        this.filterState = new Array<StateGroup>();
220        stateItemArr.map((stateItem) => {
221          for (let i = 0; i < this.funcNameCycleArr!.length; i++) {
222            if (
223              ((stateItem.ts > this.funcNameCycleArr![i].cycleStartTime && stateItem.ts < this.funcNameCycleArr![i].endTime) ||
224                (stateItem.ts + stateItem.dur! > this.funcNameCycleArr![i].cycleStartTime &&
225                  stateItem.ts + stateItem.dur! < this.funcNameCycleArr![i].endTime) ||
226                (this.funcNameCycleArr![i].cycleStartTime > stateItem.ts && this.funcNameCycleArr![i].endTime < stateItem.ts + stateItem.dur!)) &&
227              (stateItem.state === 'S' ||
228                stateItem.state === 'R' ||
229                stateItem.state === 'D' ||
230                stateItem.state === 'Running')
231            ) {
232              stateItem.startTs = stateItem.ts;
233              stateItem.chartDur = stateItem.dur;
234              // @ts-ignore 周期第一条数据开始时间设置为周期开始时间
235              if (stateItem.ts + stateItem.dur > this.funcNameCycleArr[i].cycleStartTime && stateItem.ts < this.funcNameCycleArr[i].cycleStartTime) {
236                stateItem.dur = stateItem.ts + stateItem.dur! - this.funcNameCycleArr![i].cycleStartTime;
237                stateItem.ts = this.funcNameCycleArr![i].cycleStartTime;
238              }
239              this.filterState!.push(stateItem);
240            }
241          }
242        });
243        if (this.filterState.length > 0) {
244          for (let i = 0; i < processIds.length; i++) {
245            this.setProcessData(this.filterState, processIds[i], stateCutArr);
246          }
247        }
248        this.threadBindersTbl!.recycleDataSource = stateCutArr;
249        this.threadBindersTbl!.loading = false;
250        this.theadClick(this.threadBindersTbl!.recycleDataSource as BinderGroup[]);
251      } else {
252        this.threadBindersTbl!.recycleDataSource = [];
253        this.threadBindersTbl!.loading = false;
254        this.theadClick(this.threadBindersTbl!.recycleDataSource as BinderGroup[]);
255      }
256    } else {
257      this.verifyInputIsEmpty(threadIdValue, threadFuncName, threadId, threadFunc);
258    }
259  }
260
261  // 处理进程数据
262  setProcessData(filterState: StateGroup[], processId: number, stateCutArr: StateGroup[]): void {
263    // 当前进程级别的数据
264    let filterObj = new StateGroup();
265    // 筛选出当前进程下的所有数据
266    let processArr = new Array<StateGroup>();
267    filterState.map((filterItem) => {
268      if (filterItem.pid === processId) {
269        processArr.push(filterItem);
270        filterObj.totalCount! += 1;
271        filterItem.state === 'R'
272          ? (filterObj.RunnableCount += 1, filterObj.RunnableDur += filterItem.dur!)
273          : filterItem.state === 'Running'
274            ? (filterObj.RunningCount += 1, filterObj.RunningDur += filterItem.dur!)
275            : filterItem.state === 'D'
276              ? (filterObj.DCount += 1, filterObj.DDur += filterItem.dur!)
277              : (filterObj.SleepingCount += 1, filterObj.SleepingDur += filterItem.dur!);
278        filterObj.title = (Utils.getInstance().getProcessMap().get(processId) || 'Process') + processId;
279        filterObj.pid = processId;
280        filterObj.type = 'process';
281        // @ts-ignore
282        filterObj.cycleDur! += filterItem.dur!;
283      }
284    });
285    // @ts-ignore
286    filterObj.RunningDur = this.formatNumber(filterObj.RunningDur / 1000000);
287    // @ts-ignore
288    filterObj.RunnableDur = this.formatNumber(filterObj.RunnableDur / 1000000);
289    // @ts-ignore
290    filterObj.DDur = this.formatNumber(filterObj.DDur / 1000000);
291    // @ts-ignore
292    filterObj.SleepingDur = this.formatNumber(filterObj.SleepingDur / 1000000);
293    // @ts-ignore
294    filterObj.cycleDur = this.formatNumber(filterObj.cycleDur! / 1000000);
295    if (processArr.length > 0) {
296      filterObj.children = this.setThreadData(processArr);
297    }
298    stateCutArr.push(filterObj);
299  }
300
301  // 是0为0,非0保留三位小数
302  formatNumber(num: number): string | 0 {
303    return num === 0 ? 0 : num.toFixed(3);
304  }
305
306  // 处理线程数据
307  setThreadData(threadData: Array<StateGroup>) {
308    // 进程下面的线程,相当于process的children
309    let threadArr = new Array<StateGroup>();
310    let threads = this.currentSelectionParam.threadIds;
311    for (let i = 0; i < threads.length; i++) {
312      // 单个线程
313      let threadObj = new StateGroup();
314      threadObj.tid = threads[i];
315      threadObj.pid = threadData[0].pid;
316      threadObj.children = new Array<StateGroup>();
317      threadObj.type = 'thread';
318      (threadObj.title = (Utils.getInstance().getProcessMap().get(threads[i]) || 'Process') + threads[i]),
319        threadArr.push(threadObj);
320    }
321    for (let i = 0; i < threadArr.length; i++) {
322      let threadList = new Array<StateGroup>();
323      threadData.map((threadItem) => {
324        if (threadItem.tid === threadArr[i].tid) {
325          threadList.push(threadItem);
326          threadArr[i].totalCount! += 1;
327          threadItem.state === 'R'
328            ? ((threadArr[i].RunnableCount += 1), (threadArr[i].RunnableDur += threadItem.dur!))
329            : threadItem.state === 'Running'
330              ? ((threadArr[i].RunningCount += 1), (threadArr[i].RunningDur += threadItem.dur!))
331              : threadItem.state === 'S'
332                ? ((threadArr[i].SleepingCount += 1), (threadArr[i].SleepingDur += threadItem.dur!))
333                : ((threadArr[i].DCount += 1), (threadArr[i].DDur += threadItem.dur!));
334          // @ts-ignore
335          threadArr[i].cycleDur! += threadItem.dur!;
336        }
337      });
338      // @ts-ignore
339      threadArr[i].SleepingDur = this.formatNumber(threadArr[i].SleepingDur / 1000000);
340      // @ts-ignore
341      threadArr[i].RunnableDur = this.formatNumber(threadArr[i].RunnableDur / 1000000);
342      // @ts-ignore
343      threadArr[i].RunningDur = this.formatNumber(threadArr[i].RunningDur / 1000000);
344      // @ts-ignore
345      threadArr[i].DDur = this.formatNumber(threadArr[i].DDur / 1000000);
346      // @ts-ignore
347      threadArr[i].cycleDur = this.formatNumber(threadArr[i].cycleDur / 1000000);
348      if (threadList.length > 0) {
349        threadArr[i].children = this.setCycleData(threadList);
350      }
351    }
352    threadArr = threadArr.filter((V) => {
353      return V.totalCount! > 0;
354    });
355    return threadArr;
356  }
357
358  // 处理周期数据
359  setCycleData(threadData: Array<StateGroup>): Array<StateGroup> {
360    let cycleArr = new Array<StateGroup>();
361    if (this.funcNameCycleArr !== undefined && this.funcNameCycleArr.length > 0) {
362      for (let i = 0; i < this.funcNameCycleArr!.length; i++) {
363        let cycleItem = new StateGroup();
364        cycleItem.title = `cycle-${i + 1}`;
365        cycleItem.cycle = i;
366        threadData.map((v) => {
367          if (
368            (v.ts > this.funcNameCycleArr![i].cycleStartTime && v.ts < this.funcNameCycleArr![i].endTime) ||
369            (v.ts + v.dur! > this.funcNameCycleArr![i].cycleStartTime && v.ts + v.dur! < this.funcNameCycleArr![i].endTime) ||
370            (this.funcNameCycleArr![i].cycleStartTime > v.ts && this.funcNameCycleArr![i].endTime < v.ts + v.dur!)
371          ) {
372            cycleItem.totalCount! += 1;
373            v.state === 'R'
374              ? ((cycleItem.RunnableCount += 1), (cycleItem.RunnableDur += v.dur!))
375              : v.state === 'Running'
376                ? ((cycleItem.RunningCount += 1), (cycleItem.RunningDur += v.dur!))
377                : v.state === 'S'
378                  ? ((cycleItem.SleepingCount += 1), (cycleItem.SleepingDur += v.dur!))
379                  : ((cycleItem.DCount += 1), (cycleItem.DDur += v.dur!));
380          }
381        });
382        // @ts-ignore
383        cycleItem.SleepingDur = this.formatNumber(cycleItem.SleepingDur / 1000000);
384        // @ts-ignore
385        cycleItem.RunningDur = this.formatNumber(cycleItem.RunningDur / 1000000);
386        // @ts-ignore
387        cycleItem.RunnableDur = this.formatNumber(cycleItem.RunnableDur / 1000000);
388        // @ts-ignore
389        cycleItem.DDur = this.formatNumber(cycleItem.DDur / 1000000);
390        cycleItem.cycleDur! = this.formatNumber((this.funcNameCycleArr[i].endTime - this.funcNameCycleArr[i].cycleStartTime) / 1000000);
391        cycleItem.type = 'cycle';
392        cycleArr.push(cycleItem);
393      }
394    }
395    return cycleArr;
396  }
397
398  // 输入框为空点击按钮之后的样式
399  verifyInputIsEmpty(
400    threadIdValue: string,
401    threadFuncName: string,
402    threadId: HTMLInputElement,
403    threadFunc: HTMLInputElement
404  ): void {
405    if (threadIdValue === '') {
406      threadId.style.border = '1px solid rgb(255,0,0)';
407      threadId.setAttribute('placeholder', 'Please input thread id');
408    } else {
409      threadId.style.border = '1px solid rgb(151,151,151)';
410    }
411
412    if (threadFuncName === '') {
413      threadFunc.style.border = '1px solid rgb(255,0,0)';
414      threadFunc.setAttribute('placeholder', 'Please input function name');
415    } else {
416      threadFunc.style.border = '1px solid rgb(151,151,151)';
417    }
418  }
419
420  // 线程点击
421  private theadClick(data: Array<BinderGroup>): void {
422    let labels = this.threadBindersTbl?.shadowRoot?.querySelector('.th > .td')?.querySelectorAll('label');
423    if (labels) {
424      for (let i = 0; i < labels.length; i++) {
425        let label = labels[i].innerHTML;
426        labels[i].addEventListener('click', (e) => {
427          if (label.includes('Process') && i === 0) {
428            // 数据递归设置status
429            this.threadBindersTbl!.setStatus(data, false);
430            this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(
431              data,
432              RedrawTreeForm.Retract
433            );
434          } else if (label.includes('Thread') && i === 1) {
435            for (let item of data) {
436              item.status = true;
437              if (item.children != undefined && item.children.length > 0) {
438                this.threadBindersTbl!.setStatus(item.children, false);
439              }
440            }
441            this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(
442              data,
443              RedrawTreeForm.Retract
444            );
445          } else if (label.includes('Cycle') && i === 2) {
446            this.threadBindersTbl!.setStatus(data, true);
447            this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand);
448          }
449        });
450      }
451    }
452  }
453
454  initElements(): void {
455    this.threadBindersTbl = this.shadowRoot?.querySelector<LitTable>('#tb-binder-count');
456    this.chartTotal = this.shadowRoot!.querySelector<LitChartColumn>('#chart_cycle');
457    this.cycleAStartRangeDIV = this.shadowRoot?.querySelector('#cycle-a-start-range');
458    this.cycleAEndRangeDIV = this.shadowRoot?.querySelector('#cycle-a-end-range');
459    this.cycleBStartRangeDIV = this.shadowRoot?.querySelector('#cycle-b-start-range');
460    this.cycleBEndRangeDIV = this.shadowRoot?.querySelector('#cycle-b-end-range');
461
462    this.threadStatesDIV = this.shadowRoot!.querySelector('#dataCut');
463    this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => {
464      this.dispalyQueryArea(true);
465      this.dataSource = [];
466      // @ts-ignore
467      this.dataSingleCut(this.threadStatesDIV!.children[0], this.threadStatesDIV?.children[1]);
468    });
469    this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => {
470      this.dispalyQueryArea(true);
471      this.dataSource = [];
472      // @ts-ignore
473      this.dataLoopCut(this.threadStatesDIV?.children[0], this.threadStatesDIV?.children[1]);
474    });
475
476    this.threadBindersTbl!.addEventListener('mouseout', (): void => {
477      this.cycleIsClick = false;
478      this.lineCycleNum = -1;
479      this.traceSheetEl!.systemLogFlag = undefined;
480      SpSegmentationChart.tabHoverObj = { key: '', cycle: -1 };
481      TabPaneFreqStatesDataCut.isStateTabHover = false;
482      this.spSystemTrace?.refreshCanvas(false);
483    });
484
485    this.threadBindersTbl!.addEventListener('row-click', (evt: any) => {
486      let currentData: StateGroup = evt.detail.data;
487      if (currentData.type === 'thread') {
488        this.currentThreadId = currentData.tid + '' + currentData.pid;
489        this.clearCycleRange();
490        currentData.isSelected = true;
491        this.threadBindersTbl!.clearAllSelection(currentData);
492        this.threadBindersTbl!.setCurrentSelection(currentData);
493        this.rowCycleData = currentData.children;
494        this.dispalyQueryArea(false);
495        let totalCount =
496          currentData.SleepingCount + currentData.RunnableCount + currentData.DCount + currentData.RunningCount;
497        this.dataSource = [];
498        this.dataSource.push({
499          xName: 'Total',
500          yAverage: totalCount !== 0 ? Math.ceil(totalCount! / this.rowCycleData!.length) : 0,
501        });
502        if (this.dataSource!.length !== 0) {
503          this.drawColumn();
504        }
505        let statesChartData = this.filCycleData(currentData.pid, currentData.tid);
506        SpSegmentationChart.setStateChartData(statesChartData);
507      }
508      if (currentData.type === 'cycle') {
509        currentData.isSelected = true;
510        this.threadBindersTbl!.clearAllSelection(currentData);
511        this.threadBindersTbl!.setCurrentSelection(currentData);
512        if (currentData.cycle === this.lineCycleNum && this.cycleIsClick === true) {
513          this.traceSheetEl!.systemLogFlag = undefined;
514          SpSegmentationChart.tabHoverObj = { key: '', cycle: -1 };
515          TabPaneFreqStatesDataCut.isStateTabHover = false;
516          this.cycleIsClick = false;
517        } else {
518          SpSegmentationChart.tabHoverObj = { key: '', cycle: -1 };
519          let pointX: number = ns2x(
520            this.funcNameCycleArr![currentData.cycle].cycleStartTime || 0,
521            TraceRow.range!.startNS,
522            TraceRow.range!.endNS,
523            TraceRow.range!.totalNS,
524            new Rect(0, 0, TraceRow.FRAME_WIDTH, 0)
525          );
526          SpSegmentationChart.tabHoverObj.key = 'STATES';
527          SpSegmentationChart.trace.traceSheetEL!.systemLogFlag = new Flag(
528            Math.floor(pointX),
529            0,
530            0,
531            0,
532            this.funcNameCycleArr![currentData.cycle].cycleStartTime!,
533            '#000000',
534            '',
535            true,
536            ''
537          );
538          TabPaneFreqStatesDataCut.isStateTabHover = true;
539          this.lineCycleNum = currentData.cycle;
540          this.cycleIsClick = true;
541        }
542        SpSegmentationChart.trace.refreshCanvas(false);
543      }
544    });
545
546    // 筛选柱状图数据
547    this.shadowRoot?.querySelector('#query-btn')?.addEventListener('click', () => {
548      this.cycleARangeArr = this.rowCycleData?.filter((it: StateGroup) => {
549        return (
550          // @ts-ignore
551          it.cycleDur! >= Number(this.cycleAStartRangeDIV!.value) &&
552          // @ts-ignore
553          it.cycleDur! < Number(this.cycleAEndRangeDIV!.value)
554        );
555      });
556      this.cycleBRangeArr = this.rowCycleData?.filter((it: StateGroup) => {
557        return (
558          // @ts-ignore
559          it.cycleDur! >= Number(this.cycleBStartRangeDIV!.value) &&
560          // @ts-ignore
561          it.cycleDur! < Number(this.cycleBEndRangeDIV!.value)
562        );
563      });
564      let cycleACount: number = 0;
565      this.cycleARangeArr?.forEach((it: StateGroup) => {
566        cycleACount += it.totalCount!;
567      });
568      let cycleBCount: number = 0;
569      this.cycleBRangeArr?.forEach((it: StateGroup) => {
570        cycleBCount += it.totalCount!;
571      });
572      this.dataSource!.length > 1 && this.dataSource?.splice(1);
573      this.dataSource!.push({
574        xName: 'cycleA',
575        yAverage: cycleACount !== 0 ? Math.ceil(cycleACount / this.cycleARangeArr!.length) : 0,
576      });
577      this.dataSource!.push({
578        xName: 'cycleB',
579        yAverage: cycleBCount !== 0 ? Math.ceil(cycleBCount / this.cycleBRangeArr!.length) : 0,
580      });
581      if (this.dataSource!.length !== 0) {
582        this.drawColumn();
583      }
584    });
585  }
586
587  // 筛选出点击的线程数据
588  filCycleData(pid: number, tid: number): Array<StateGroup> {
589    return this.filterState?.filter((v: StateGroup) => {
590      return v.pid === pid && v.tid === tid && (
591        (v.ts > this.cycleStartTime! && v.ts < this.cycleEndTime!) ||
592        (v.ts + v.dur! > this.cycleStartTime! && v.ts + v.dur! < this.cycleEndTime!) ||
593        (this.cycleStartTime! > v.ts && this.cycleEndTime! < v.ts + v.dur!));
594    })
595  };
596
597  // 清空dur筛选输入框内容
598  clearCycleRange(): void {
599    this.cycleAStartRangeDIV!.value = '';
600    this.cycleAEndRangeDIV!.value = '';
601    this.cycleBStartRangeDIV!.value = '';
602    this.cycleBEndRangeDIV!.value = '';
603  }
604
605  // 画柱状图
606  drawColumn(): void {
607    this.chartTotal!.dataSource = this.dataSource!;
608    this.chartTotal!.config = {
609      data: this.dataSource!,
610      appendPadding: 10,
611      xField: 'xName',
612      yField: 'yAverage',
613      seriesField: '',
614      removeUnit: true,
615      notSort: true,
616      color: (a) => {
617        //@ts-ignore
618        const xName = a.xName;
619        if (xName === 'Total') {
620          return '#2f72f8';
621        } else if (xName === 'cycleA') {
622          return '#ffab67';
623        } else if (xName === 'cycleB') {
624          return '#a285d2';
625        } else {
626          return '#0a59f7';
627        }
628      },
629      tip: (a) => {
630        //@ts-ignore
631        if (a && a[0]) {
632          //@ts-ignore
633          const obj = a[0];
634          let tip: string = '';
635          tip = `<div>
636                    <div>Average count: ${obj.obj.yAverage}</div>
637                </div>`;
638          return tip;
639        } else {
640          return '';
641        }
642      },
643      label: null,
644    };
645  }
646
647  connectedCallback(): void {
648    super.connectedCallback();
649    resizeObserver(this.parentElement!, this.threadBindersTbl!);
650  }
651
652  // 页面结构
653
654  initHtml(): string {
655    return `
656        <style>
657        :host{
658            padding: 10px 10px;
659            display: flex;
660            flex-direction: column;
661        }
662        #dataCut{
663            display: flex;
664            justify-content: space-between;
665            width:100%;
666            height:20px;
667            padding:auto;
668            align-items:center;
669        }
670        button{
671            width:40%;
672            height:100%;
673            border: solid 1px #666666;
674            background-color: rgba(0,0,0,0);
675            border-radius:10px;
676            cursor: pointer;
677        }
678        button:hover{
679            background-color:#666666;
680            color:white;
681        }
682        :host([clickSingle]) .click_single{
683            background-color:#666666;
684            color:white;
685        }
686        :host([clickLoop]) .click_loop{
687            background-color:#666666;
688            color:white;
689        }
690        .thread-id-input{
691            width: 15%;
692            height:90%;
693            border-radius:10px;
694            border:solid 1px #979797;
695            font-size:15px;
696            text-indent:3%
697        }
698        .cycle-name-input{
699            width: 20%;
700            height:90%;
701            border-radius:10px;
702            border:solid 1px #979797;
703            font-size:15px;
704            text-indent:3%
705        }
706        .data-cut-area{
707            width:20%;
708            height: 100%;
709            display:flex;
710            justify-content: space-around;
711        }
712        .main-area{
713            width:100%;
714            display:flex;
715            margin-top:5px;
716        }
717        lit-table{
718            height: auto;
719            overflow-x:auto;
720            width:100%
721        }
722        #query-btn{
723            width:90px;
724        }
725        .cycle-range-input {
726            width: 120px;
727            height: 18px;
728            padding: 1px 5px;
729            border-radius: 12px;
730            border: solid 1px #979797;
731            font-size: 15px;
732            text-indent: 3%
733        }
734        :host([dispalyQueryArea]) .query-cycle-area{
735            display: none;
736        }
737        #chart_cycle{
738            width:100%;
739            height:300px;
740        }
741        .chart_labels{
742            height: 30px;
743            width: 100%;
744            display: flex;
745            flex-direction: row;
746            align-items: center;
747            justify-content: center;
748            margin-top:12px;
749        }
750        .labels{
751            display: flex;
752            flex-direction: row;
753            align-items: center;
754            justify-content: center;
755            font-size: 9pt;
756            padding-right: 15px;
757        }
758        .labels_item{
759            width: 20px;
760            height: 10px;
761            background-color: #2f72f8;
762            margin-right: 5px;
763        }
764        .chart_area{
765            margin-top:40px;
766            height:0;
767        }
768        .chart_title{
769            line-height: 40px;
770            height: 40px;
771            width: 100%;
772            text-align: center;
773        }
774        </style>
775        <div id='dataCut'>
776            <input id="dataCutThreadId" type="text" class="thread-id-input" placeholder="Please input thread id" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" />
777            <input id="dataCutThreadFunc" type="text" class="cycle-name-input" placeholder="Please input function name" value='' />
778            <div class="data-cut-area">
779                <button id="single-btn" class="click_single">Single</button>
780                <button id="loop-btn" class="click_loop">Loop</button>
781            </div>
782        </div>
783        <div class="main-area">
784            <lit-slicer style="width:100%">
785                <div style="width:70%;">
786                    <lit-table id="tb-binder-count" style="height: auto; overflow-x:auto;width:100%;" tree>
787                        <lit-table-column width="250px" title="Process/Thread/Cycle" data-index="title" key="title"  align="flex-start" retract>
788                        </lit-table-column>
789                        <lit-table-column width="80px" title="Running count" data-index="RunningCount" key="RunningCoung" align="center">
790                        </lit-table-column>
791                        <lit-table-column width="80px" title="Running dur(ms)" data-index="RunningDur" key="RunningDur" align="center">
792                        </lit-table-column>
793                        <lit-table-column width="80px" title="Runnable count" data-index="RunnableCount" key="RunnableCount" align="center">
794                        </lit-table-column>
795                        <lit-table-column width="80px" title="Runnable dur(ms)" data-index="RunnableDur" key="RunnableDur" align="center">
796                        </lit-table-column>
797                        <lit-table-column width="80px" title="Sleeping count" data-index="SleepingCount" key="SleepingCount" align="center">
798                        </lit-table-column>
799                        <lit-table-column width="80px" title="Sleeping dur(ms)" data-index="SleepingDur" key="SleepingDur" align="center">
800                        </lit-table-column>
801                        <lit-table-column width="80px" title="D count" data-index="DCount" key="DCount" align="center">
802                        </lit-table-column>
803                        <lit-table-column width="80px" title="D dur(ms)" data-index="DDur" key="DDUR" align="center">
804                        </lit-table-column>
805                        <lit-table-column width="80px" title="Duration(ms)" data-index="cycleDur" key="cycleDur" align="center">
806                        </lit-table-column>
807                        <lit-table-column width="80px"  title="Total" data-index="totalCount" key="totalCount" align="center">
808                        </lit-table-column>
809                    </lit-table>
810                </div>
811                <lit-slicer-track ></lit-slicer-track>
812                <div style="width:30%;padding: 16px;height:auto;overflow:auto;" class="query-cycle-area">
813                    <div >
814                        <div id="cycle-a">
815                            <span>Cycle A: </span>
816                            <input id="cycle-a-start-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" />
817                            <span>~</span>
818                            <input id="cycle-a-end-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" />
819                        </div>
820                        <div style="margin-top: 10px; display:flex; flex-derection:row; justify-content:space-between">
821                            <div id="cycle-b">
822                                <span>Cycle B: </span>
823                                <input id="cycle-b-start-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" />
824                                <span>~</span>
825                                <input id="cycle-b-end-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" />
826                            </div>
827                            <div>
828                                <button id="query-btn">Query</button>
829                            </div>
830                        </div>
831                    </div>
832                    <div class="chart_area">
833                        <div class="chart_title">Average State Count</div>
834                        <lit-chart-column id="chart_cycle"></lit-chart-column>
835                        <div class="chart_labels">
836                            <div class="labels"><div class="labels_item"></div>Total</div>
837                            <div class="labels"><div class="labels_item" style="background-color: #ffab67;"></div>CycleA</div>
838                            <div class="labels"><div class="labels_item" style="background-color: #a285d2;"></div>CycleB</div>
839                        </div>
840                    </div>
841                </div>
842            </lit-slicer>
843        </div>
844        `;
845  }
846}
847