• 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 */
15import { BaseElement, element } from '../../../../../base-ui/BaseElement';
16import { type LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table';
17import { Utils } from '../../base/Utils';
18import { type SelectionParam } from '../../../../bean/BoxSelection';
19import {
20  type BinderItem,
21  type ProcessBinderItem,
22  type ThreadBinderItem,
23  type DataSource,
24  type FunctionItem,
25  type BinderDataStruct,
26  CycleBinderItem,
27} from '../../../../bean/BinderProcessThread';
28import { queryFuncNameCycle, queryLoopFuncNameCycle } from '../../../../../trace/database/sql/Func.sql';
29import { queryBinderByThreadId } from '../../../../../trace/database/sql/ProcessThread.sql';
30import { resizeObserver } from '../SheetUtils';
31import { type LitChartColumn } from '../../../../../base-ui/chart/column/LitChartColumn';
32import '../../../../../base-ui/chart/column/LitChartColumn';
33import { SpSegmentationChart } from '../../../chart/SpSegmentationChart';
34import { SliceGroup } from '../../../../bean/StateProcessThread';
35
36const MILLIONS: number = 1000000;
37const THREE: number = 3;
38@element('tabpane-binder-datacut')
39export class TabPaneBinderDataCut extends BaseElement {
40  private threadBindersTbl: LitTable | null | undefined;
41  private currentSelectionParam: SelectionParam | any;
42  private threadStatesDIV: Element | null | undefined;
43  private cycleColumnDiv: HTMLDivElement | null | undefined;
44  private cycleARangeArr: CycleBinderItem[] = [];
45  private cycleBRangeArr: CycleBinderItem[] = [];
46  private cycleAStartRangeDIV: HTMLInputElement | null | undefined;
47  private cycleAEndRangeDIV: HTMLInputElement | null | undefined;
48  private cycleBStartRangeDIV: HTMLInputElement | null | undefined;
49  private cycleBEndRangeDIV: HTMLInputElement | null | undefined;
50  private chartTotal: LitChartColumn | null | undefined;
51  private dataSource: DataSource[] = [];
52  private rowCycleData: CycleBinderItem[] = [];
53  private currentThreadId: string = '';
54  private threadArr: Array<ThreadBinderItem> = [];
55  private threadBinderMap: Map<string, Array<BinderItem>> = new Map();
56  private processIds: Array<number> = [];
57  private funcCycleArr: Array<FunctionItem> = [];
58
59  set data(threadStatesParam: SelectionParam) {
60    if (this.currentSelectionParam === threadStatesParam) {
61      return;
62    }
63    this.currentSelectionParam = threadStatesParam;
64    SpSegmentationChart.setBinderChartData([]);
65    SpSegmentationChart.tabHover('BINDER', false, -1);
66    // @ts-ignore
67    this.processIds = [...new Set(this.currentSelectionParam.processIds)];
68    this.threadArr = [];
69    this.threadBinderMap.clear();
70    this.hideQueryArea(true);
71    this.clickLoop(false);
72    this.clickSingle(false);
73    this.threadBindersTbl!.recycleDataSource = [];
74    // @ts-ignore
75    this.tHeadClick(this.threadBindersTbl!.recycleDataSource);
76    this.parentElement!.style.overflow = 'hidden';
77    new ResizeObserver(() => {
78      // @ts-ignore
79      let lastHeight: number = this.threadBindersTbl.tableElement!.offsetHeight;
80      this.cycleColumnDiv!.style.height = lastHeight + 'px';
81    }).observe(this.threadBindersTbl!);
82  }
83
84  hideQueryArea(b: boolean): void {
85    if (b) {
86      this.setAttribute('hideQueryArea', '');
87    } else {
88      this.removeAttribute('hideQueryArea');
89    }
90  }
91
92  clickSingle(b: boolean): void {
93    if (b) {
94      this.setAttribute('clickSingle', '');
95    } else {
96      this.removeAttribute('clickSingle');
97    }
98  }
99
100  clickLoop(b: boolean): void {
101    if (b) {
102      this.setAttribute('clickLoop', '');
103    } else {
104      this.removeAttribute('clickLoop');
105    }
106  }
107
108  // 查询数据库,binder和Function查询
109  async queryDataFromDb(
110    threadIdValue: string,
111    threadFuncName: string,
112    threadIds: Array<number>,
113    leftNS: number,
114    rightNS: number,
115    type: string
116  ): Promise<void> {
117    let binderArr: Array<BinderItem> = await queryBinderByThreadId(this.processIds, threadIds, leftNS, rightNS);
118    if (binderArr.length > 0) {
119      this.structureThreadBinderMap(binderArr);
120    }
121    if (type === 'loop') {
122      //@ts-ignore
123      this.funcCycleArr = await queryLoopFuncNameCycle(threadFuncName, threadIdValue, leftNS, rightNS);
124    } else {
125      this.funcCycleArr = await queryFuncNameCycle(threadFuncName, threadIdValue, leftNS, rightNS);
126    }
127  }
128
129  //点击single loop 切割按钮方法
130  async dataCutFunc(threadId: HTMLInputElement, threadFunc: HTMLInputElement, type: string): Promise<void> {
131    this.currentThreadId = '';
132    let threadIdValue = threadId.value.trim();
133    let threadFuncName = threadFunc.value.trim();
134
135    this.clickLoop(type === 'loop' ? true : false);
136    this.clickSingle(type === 'loop' ? false : true);
137    //清空泳道图
138    SpSegmentationChart.setBinderChartData([]);
139    SpSegmentationChart.tabHover('BINDER', false, -1);
140    if (threadIdValue !== '' && threadFuncName !== '') {
141      this.threadBindersTbl!.loading = true;
142      threadId.style.border = '1px solid rgb(151,151,151)';
143      threadFunc.style.border = '1px solid rgb(151,151,151)';
144      let threadIds = this.currentSelectionParam.threadIds;
145      let leftNS = this.currentSelectionParam.leftNs;
146      let rightNS = this.currentSelectionParam.rightNs;
147      this.threadArr = [];
148      this.threadBinderMap.clear();
149      await this.queryDataFromDb(threadIdValue, threadFuncName, threadIds, leftNS, rightNS, type);
150      if (this.funcCycleArr.length !== 0) {
151        let cycleMap: Map<string, Array<CycleBinderItem>> = type === 'loop'
152          ? this.loopDataCutCycleMap(this.funcCycleArr)
153          : this.singleDataCutCycleMap(this.funcCycleArr);
154        this.threadBindersTbl!.recycleDataSource = this.mergeData(cycleMap);
155        this.threadBindersTbl!.loading = false; // @ts-ignore
156        this.tHeadClick(this.threadBindersTbl!.recycleDataSource);
157      } else {
158        this.threadBindersTbl!.recycleDataSource = [];
159        this.threadBindersTbl!.loading = false; // @ts-ignore
160        this.tHeadClick(this.threadBindersTbl!.recycleDataSource);
161      }
162    } else {
163      this.verifyInputIsEmpty(threadIdValue, threadFuncName, threadId, threadFunc);
164    }
165  }
166
167  verifyInputIsEmpty(
168    threadIdValue: string,
169    threadFuncName: string,
170    threadId: HTMLInputElement,
171    threadFunc: HTMLInputElement
172  ): void {
173    if (threadIdValue === '') {
174      threadId.style.border = '1px solid rgb(255,0,0)';
175      threadId.setAttribute('placeholder', 'Please input thread id');
176      this.threadBindersTbl!.recycleDataSource = [];
177      this.threadBindersTbl!.loading = false; // @ts-ignore
178      this.tHeadClick(this.threadBindersTbl!.recycleDataSource);
179    } else {
180      threadId.style.border = '1px solid rgb(151,151,151)';
181    }
182    if (threadFuncName === '') {
183      threadFunc.style.border = '1px solid rgb(255,0,0)';
184      threadFunc.setAttribute('placeholder', 'Please input function name');
185      this.threadBindersTbl!.recycleDataSource = [];
186      this.threadBindersTbl!.loading = false; // @ts-ignore
187      this.tHeadClick(this.threadBindersTbl!.recycleDataSource);
188    } else {
189      threadFunc.style.border = '1px solid rgb(151,151,151)';
190    }
191  }
192
193  // 构建线程 binder Map数据
194  structureThreadBinderMap(binderArr: Array<BinderItem>): void {
195    for (let b of binderArr) {
196      if (!this.threadBinderMap.has(b.pid + '_' + b.tid)) {
197        this.threadArr.push({
198          title:
199            Utils.getInstance().getThreadMap().get(b.tid) === null
200              ? 'Thread' + ' ' + '[' + b.tid + ']'
201              : Utils.getInstance().getThreadMap().get(b.tid) + ' ' + '[' + b.tid + ']',
202          totalCount: 0,
203          tid: b.tid,
204          pid: b.pid,
205          children: [],
206          type: 'Thread',
207        });
208        this.threadBinderMap.set(b.pid + '_' + b.tid, new Array());
209      }
210      let arr: Array<BinderItem> | undefined = this.threadBinderMap.get(b.pid + '_' + b.tid);
211      arr?.push(b);
212    }
213  }
214
215  deepCloneThreadBinderMap(threadBinderMap: Map<string, Array<BinderItem>>): Map<string, Array<BinderItem>> {
216    let cloneThreadBinderMap: Map<string, Array<BinderItem>> = new Map();
217    if (cloneThreadBinderMap instanceof Map) {
218      threadBinderMap.forEach((val, key) => {
219        const k = key;
220        const v = JSON.parse(JSON.stringify(val));
221        cloneThreadBinderMap.set(k, v);
222      });
223    }
224    return cloneThreadBinderMap;
225  }
226
227  // 构建single切割cycle Map数据
228  singleDataCutCycleMap(funcNameArr: Array<FunctionItem>): Map<string, Array<CycleBinderItem>> {
229    let cloneThreadBinderMap: Map<string, Array<BinderItem>> = this.deepCloneThreadBinderMap(this.threadBinderMap);
230    let cycleMap: Map<string, Array<CycleBinderItem>> = new Map();
231    cloneThreadBinderMap.forEach((tBinder: Array<BinderItem>) => {
232      funcNameArr.forEach((func, idx) => {
233        let cycleArr: Array<CycleBinderItem> | undefined = [];
234        let countBinder: CycleBinderItem = new CycleBinderItem();
235        let cid = func.id;
236        for (let j: number = 0; j < tBinder.length; j++) {
237          if (!cycleMap.has(tBinder[j].tid + '_' + cid)) {
238            cycleMap.set(tBinder[j].tid + '_' + cid, new Array());
239          }
240          cycleArr = cycleMap.get(tBinder[j].tid + '_' + cid);
241          let thread: string = Utils.getInstance().getThreadMap().get(tBinder[j].tid) || 'Thread';
242          countBinder.title = 'cycle ' + (idx + 1) + '_' + thread;
243          countBinder.tid = tBinder[j].tid;
244          countBinder.pid = tBinder[j].pid;
245          countBinder.durNs = func.dur;
246          countBinder.tsNs = func.cycleStartTime;
247          countBinder.cycleDur = Number((func.dur / MILLIONS).toFixed(THREE));
248          countBinder.cycleStartTime = Number((func.cycleStartTime / MILLIONS).toFixed(THREE));
249          if (
250            tBinder[j].ts + tBinder[j].dur > func.cycleStartTime &&
251            tBinder[j].ts + tBinder[j].dur < func.cycleStartTime + func!.dur
252          ) {
253            countBinder.totalCount += 1;
254            countBinder.binderTransactionCount += tBinder[j].name === 'binder transaction' ? 1 : 0;
255            countBinder.binderAsyncRcvCount += tBinder[j].name === 'binder async rcv' ? 1 : 0;
256            countBinder.binderReplyCount += tBinder[j].name === 'binder reply' ? 1 : 0;
257            countBinder.binderTransactionAsyncCount += tBinder[j].name === 'binder transaction async' ? 1 : 0;
258            countBinder.idx = idx + 1;
259            tBinder.splice(j, 1);
260            j--;
261          }
262        }
263        cycleArr?.push(countBinder);
264      });
265    });
266    return cycleMap;
267  }
268
269  // 构建loop切割cycle Map数据
270  loopDataCutCycleMap(funcNameArr: Array<FunctionItem>): Map<string, Array<CycleBinderItem>> {
271    let cloneThreadBinderMap: Map<string, Array<BinderItem>> = this.deepCloneThreadBinderMap(this.threadBinderMap);
272    let cycleMap: Map<string, Array<CycleBinderItem>> = new Map();
273    cloneThreadBinderMap.forEach((tBinder: Array<BinderItem>) => {
274      for (let i: number = 0; i < funcNameArr.length - 1; i++) {
275        let cycleArr: Array<CycleBinderItem> | undefined = [];
276        let countBinder: CycleBinderItem = new CycleBinderItem();
277        let cid: number = funcNameArr[i].id;
278        for (let j: number = 0; j < tBinder.length; j++) {
279          if (!cycleMap.has(tBinder[j].tid + '_' + cid)) {
280            cycleMap.set(tBinder[j].tid + '_' + cid, new Array());
281          }
282          cycleArr = cycleMap.get(tBinder[j].tid + '_' + cid);
283          let thread: string = Utils.getInstance().getThreadMap().get(tBinder[j].tid) || 'Thread';
284          countBinder.title = 'cycle ' + (i + 1) + '_' + thread;
285          countBinder.tid = tBinder[j].tid;
286          countBinder.pid = tBinder[j].pid;
287          countBinder.durNs = funcNameArr[i + 1].cycleStartTime - funcNameArr[i].cycleStartTime;
288          countBinder.tsNs = funcNameArr[i].cycleStartTime;
289          countBinder.cycleDur = Number(
290            ((funcNameArr[i + 1].cycleStartTime - funcNameArr[i].cycleStartTime) / MILLIONS).toFixed(THREE)
291          );
292          countBinder.cycleStartTime = Number((funcNameArr[i].cycleStartTime / MILLIONS).toFixed(THREE));
293          if (
294            tBinder[j].ts + tBinder[j].dur > funcNameArr[i].cycleStartTime &&
295            tBinder[j].ts + tBinder[j].dur < funcNameArr[i + 1].cycleStartTime
296          ) {
297            countBinder.totalCount += 1;
298            countBinder!.binderTransactionCount += tBinder[j].name === 'binder transaction' ? 1 : 0;
299            countBinder!.binderAsyncRcvCount += tBinder[j].name === 'binder async rcv' ? 1 : 0;
300            countBinder.binderReplyCount += tBinder[j].name === 'binder reply' ? 1 : 0;
301            countBinder.binderTransactionAsyncCount += tBinder[j].name === 'binder transaction async' ? 1 : 0;
302            countBinder.idx = i + 1;
303            tBinder.splice(j, 1);
304            j--;
305          }
306        }
307        cycleArr?.push(countBinder);
308      }
309    });
310    return cycleMap;
311  }
312
313  //组成树结构数据
314  mergeData(cycleMap: Map<string, Array<CycleBinderItem>>): Array<ProcessBinderItem> {
315    let processArr: Array<ProcessBinderItem> = [];
316    let processIds: Array<number> = [];
317    // 将thread级下的周期数据放入对应的thread下。树结构的第二层thread数据
318    for (let thread of this.threadArr) {
319      if (!processIds.includes(thread.pid)) {
320        processIds.push(thread.pid);
321      }
322      thread.totalCount = 0;
323      thread.children = [];
324      for (let key of cycleMap!.keys()) {
325        let cycle: Array<CycleBinderItem> | undefined = cycleMap.get(key);
326        if (key.split('_')[0] === thread.tid + '') {
327          thread.totalCount += cycle![0].totalCount;
328          thread.children.push(cycle![0]);
329        }
330      }
331    }
332    // process级的数组数据,也就是树结构的根数据层
333    processIds.forEach((pid) => {
334      processArr.push({
335        pid: pid,
336        title:
337          Utils.getInstance().getProcessMap().get(pid) === null
338            ? 'Process' + ' ' + '[' + pid + ']'
339            : Utils.getInstance().getProcessMap().get(pid) + ' ' + '[' + pid + ']',
340        totalCount: 0,
341        type: 'Process',
342        children: [],
343      });
344    });
345    // 将process级下的thread数据放入对应的process下
346    for (let process of processArr) {
347      for (let thread of this.threadArr) {
348        if (thread.pid === process.pid) {
349          process.totalCount += thread.totalCount;
350          process.children.push(thread);
351        }
352      }
353    }
354    return processArr;
355  }
356
357  // 构建画泳道图的数据
358  structuredLaneChartData(rowCycleData: CycleBinderItem[]): Array<BinderDataStruct[]> {
359    let laneChartData: Array<BinderDataStruct[]> = [];
360    rowCycleData.forEach((it) => {
361      if (it.totalCount !== 0) {
362        let cycleDataArr: BinderDataStruct[] = [];
363        if (it.binderTransactionCount !== 0) {
364          cycleDataArr.push({
365            name: 'binder transaction',
366            value: it.binderTransactionCount!,
367            dur: it.durNs,
368            startNS: it.tsNs,
369            cycle: it.idx,
370          });
371        }
372        if (it.binderTransactionAsyncCount !== 0) {
373          cycleDataArr.push({
374            name: 'binder transaction async',
375            value: it.binderTransactionAsyncCount!,
376            dur: it.durNs,
377            startNS: it.tsNs,
378            cycle: it.idx,
379          });
380        }
381        if (it.binderReplyCount !== 0) {
382          cycleDataArr.push({
383            name: 'binder reply',
384            value: it.binderReplyCount!,
385            dur: it.durNs,
386            startNS: it.tsNs,
387            cycle: it.idx,
388          });
389        }
390        if (it.binderAsyncRcvCount !== 0) {
391          cycleDataArr.push({
392            name: 'binder async rcv',
393            value: it.binderAsyncRcvCount!,
394            dur: it.durNs,
395            startNS: it.tsNs,
396            cycle: it.idx,
397          });
398        }
399        laneChartData.push(cycleDataArr);
400      }
401    });
402    return laneChartData;
403  }
404
405  clearCycleRange(): void {
406    this.cycleAStartRangeDIV!.value = '';
407    this.cycleAEndRangeDIV!.value = '';
408    this.cycleBStartRangeDIV!.value = '';
409    this.cycleBEndRangeDIV!.value = '';
410  }
411
412  drawColumn(): void {
413    this.chartTotal!.dataSource = this.dataSource!;
414    this.chartTotal!.config = {
415      data: this.dataSource!,
416      appendPadding: 10,
417      xField: 'xName',
418      yField: 'yAverage',
419      seriesField: '',
420      removeUnit: true,
421      notSort: true,
422      color: (a) => {
423        //@ts-ignore
424        if (a.xName === 'Total') {
425          return '#2f72f8'; //@ts-ignore
426        } else if (a.xName === 'cycleA') {
427          return '#ffab67'; //@ts-ignore
428        } else if (a.xName === 'cycleB') {
429          return '#a285d2';
430        } else {
431          return '#0a59f7';
432        }
433      },
434      tip: (a) => {
435        //@ts-ignore
436        if (a && a[0]) {
437          let tip: string = '';
438          tip = `<div>
439                    <div>Average count: ${
440                      //@ts-ignore
441                      a[0].obj.yAverage
442                    }</div>
443                </div>`;
444          return tip;
445        } else {
446          return '';
447        }
448      },
449      label: null,
450    };
451  }
452
453  tHeadClick(data: Array<SliceGroup>): void {
454    let labels = this.threadBindersTbl?.shadowRoot?.querySelector('.th > .td')?.querySelectorAll('label');
455    if (labels) {
456      for (let i = 0; i < labels.length; i++) {
457        let label = labels[i].innerHTML;
458        labels[i].addEventListener('click', (e) => {
459          if (label.includes('Process')) {
460            this.threadBindersTbl!.setStatus(data, false);
461            this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(
462              data,
463              RedrawTreeForm.Retract
464            );
465          } else if (label.includes('Thread')) {
466            for (let item of data) {
467              item.status = true;
468              if (item.children !== undefined && item.children.length > 0) {
469                this.threadBindersTbl!.setStatus(item.children, false);
470              }
471            }
472            this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(
473              data,
474              RedrawTreeForm.Retract
475            );
476          } else if (label.includes('Cycle')) {
477            this.threadBindersTbl!.setStatus(data, true);
478            this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand);
479          }
480        });
481      }
482    }
483  }
484
485  //点击Thread行表格数据时
486  tableRowClickFunc(): void {
487    this.threadBindersTbl!.addEventListener('row-click', (evt: any) => {
488      let currentData = evt.detail.data;
489      if (currentData.type === 'Process') {
490        currentData.isSelected = true;
491        this.threadBindersTbl!.clearAllSelection(currentData);
492        this.threadBindersTbl!.setCurrentSelection(currentData);
493        this.hideQueryArea(true);
494        SpSegmentationChart.setBinderChartData([]);
495        SpSegmentationChart.tabHover('BINDER', false, -1);
496      }
497      if (currentData.type === 'Thread') {
498        SpSegmentationChart.tabHover('BINDER', false, -1);
499        this.currentThreadId = currentData.tid + '' + currentData.pid;
500        this.clearCycleRange();
501        currentData.isSelected = true;
502        this.threadBindersTbl!.clearAllSelection(currentData);
503        this.threadBindersTbl!.setCurrentSelection(currentData);
504        this.rowCycleData = currentData.children;
505        this.hideQueryArea(false);
506        let totalCount = currentData.totalCount;
507        this.dataSource = [];
508        this.dataSource.push({
509          xName: 'Total',
510          yAverage: totalCount > 0 ? Math.ceil(totalCount / this.rowCycleData!.length) : 0,
511        });
512        //绘制柱状图
513        this.drawColumn();
514        let laneChartData: Array<BinderDataStruct[]> = this.structuredLaneChartData(currentData.children!);
515        //绘制泳道图
516        SpSegmentationChart.setBinderChartData(laneChartData);
517      }
518
519      if (currentData.type === 'Cycle' && currentData.tid + '' + currentData.pid === this.currentThreadId) {
520        currentData.isSelected = true;
521        this.threadBindersTbl!.clearAllSelection(currentData);
522        this.threadBindersTbl!.setCurrentSelection(currentData);
523        //泳道图的鼠标悬浮
524        SpSegmentationChart.tabHover('BINDER', true, currentData.idx);
525      }
526    });
527  }
528
529  //点击query按钮绘制柱状图
530  queryBtnClick(): void {
531    this.shadowRoot?.querySelector('#query-btn')?.addEventListener('click', () => {
532      this.cycleARangeArr = this.rowCycleData?.filter((it: CycleBinderItem) => {
533        return (
534          it.cycleDur >= Number(this.cycleAStartRangeDIV!.value) && it.cycleDur < Number(this.cycleAEndRangeDIV!.value)
535        );
536      });
537      this.cycleBRangeArr = this.rowCycleData?.filter((it: CycleBinderItem) => {
538        return (
539          it.cycleDur >= Number(this.cycleBStartRangeDIV!.value) && it.cycleDur < Number(this.cycleBEndRangeDIV!.value)
540        );
541      });
542      let cycleACount: number = 0;
543      this.cycleARangeArr?.forEach((it: CycleBinderItem) => {
544        cycleACount += it.totalCount;
545      });
546      let cycleBCount: number = 0;
547      this.cycleBRangeArr?.forEach((it: CycleBinderItem) => {
548        cycleBCount += it.totalCount;
549      });
550      this.dataSource!.length > 1 && this.dataSource?.splice(1);
551      this.dataSource!.push({
552        xName: 'cycleA',
553        yAverage: cycleACount !== 0 ? Math.ceil(cycleACount / this.cycleARangeArr!.length) : 0,
554      });
555      this.dataSource!.push({
556        xName: 'cycleB',
557        yAverage: cycleBCount !== 0 ? Math.ceil(cycleBCount / this.cycleBRangeArr!.length) : 0,
558      });
559      this.drawColumn();
560    });
561  }
562
563  initElements(): void {
564    this.threadBindersTbl = this.shadowRoot?.querySelector<LitTable>('#tb-binder-count');
565    this.chartTotal = this.shadowRoot!.querySelector<LitChartColumn>('#chart_cycle');
566    this.cycleAStartRangeDIV = this.shadowRoot?.querySelector('#cycle-a-start-range');
567    this.cycleAEndRangeDIV = this.shadowRoot?.querySelector('#cycle-a-end-range');
568    this.cycleBStartRangeDIV = this.shadowRoot?.querySelector('#cycle-b-start-range');
569    this.cycleBEndRangeDIV = this.shadowRoot?.querySelector('#cycle-b-end-range');
570    this.cycleColumnDiv = this.shadowRoot?.querySelector('#cycleColumn');
571    this.threadStatesDIV = this.shadowRoot!.querySelector('#dataCut');
572    this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => {
573      this.hideQueryArea(true);
574      this.dataSource = [];
575      // @ts-ignore
576      this.dataCutFunc(this.threadStatesDIV!.children[0], this.threadStatesDIV?.children[1], 'single');
577    });
578    this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => {
579      this.hideQueryArea(true);
580      this.dataSource = [];
581      // @ts-ignore
582      this.dataCutFunc(this.threadStatesDIV?.children[0], this.threadStatesDIV?.children[1], 'loop');
583    });
584    this.tableRowClickFunc();
585    this.queryBtnClick();
586  }
587
588  connectedCallback(): void {
589    super.connectedCallback();
590    resizeObserver(this.parentElement!, this.threadBindersTbl!);
591  }
592
593  initHtml(): string {
594    return `
595        <style>
596        :host{
597            padding: 10px 10px;
598            display: flex;
599            flex-direction: column;
600        }
601        #dataCut{
602            display: flex;
603            justify-content: space-between;
604            width:100%;
605            height:20px;
606            padding:auto;
607            align-items:center;
608        }
609        button{
610            width:40%;
611            min-width:90px;
612            height:100%;
613            border: solid 1px #666666;
614            background-color: rgba(0,0,0,0);
615            border-radius:10px;
616            cursor: pointer;
617        }
618        button:hover{
619            background-color:#666666;
620            color:white;
621        }
622        :host([clickSingle]) .click_single{
623            background-color:#666666;
624            color:white;
625        }
626        :host([clickLoop]) .click_loop{
627            background-color:#666666;
628            color:white;
629        }
630        .thread-id-input{
631            width: 15%;
632            height:90%;
633            border-radius:10px;
634            border:solid 1px #979797;
635            font-size:15px;
636            text-indent:3%
637        }
638        .cycle-name-input{
639            width: 20%;
640            height:90%;
641            border-radius:10px;
642            border:solid 1px #979797;
643            font-size:15px;
644            text-indent:3%
645        }
646        .data-cut-area{
647            width:20%;
648            height: 100%;
649            display:flex;
650            justify-content: space-around;
651        }
652        .main-area{
653            width:100%;
654            display:flex;
655            margin-top:5px;
656        }
657        lit-table{
658            height: auto;
659            overflow-x:auto;
660            width:100%
661        }
662        #query-btn{
663            width:90px;
664        }
665        .cycle-range-input {
666            width: 24%;
667            height: 18px;
668            padding: 1px 5px;
669            border-radius: 12px;
670            border: solid 1px #979797;
671            font-size: 15px;
672            text-indent: 3%
673        }
674        :host([hideQueryArea]) .query-cycle-area{
675            display: none;
676        }
677        #chart_cycle{
678            width:100%;
679            height:300px;
680        }
681        .chart_labels{
682            height: 30px;
683            width: 100%;
684            display: flex;
685            flex-direction: row;
686            align-items: center;
687            justify-content: center;
688            margin-top:12px;
689            margin-bottom:20px;
690        }
691        .labels{
692            display: flex;
693            flex-direction: row;
694            align-items: center;
695            justify-content: center;
696            font-size: 9pt;
697            padding-right: 15px;
698        }
699        .labels_item{
700            width: 20px;
701            height: 10px;
702            background-color: #2f72f8;
703            margin-right: 5px;
704        }
705        .chart_area{
706            margin-top:20px;
707        }
708        .chart_title{
709            line-height: 40px;
710            height: 40px;
711            width: 100%;
712            text-align: center;
713        }
714        </style>
715        <div id='dataCut'>
716            <input id="dataCutThreadId" type="text" class="thread-id-input" placeholder="Please input thread id" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" />
717            <input id="dataCutThreadFunc" type="text" class="cycle-name-input" placeholder="Please input function name" value='' />
718            <div class="data-cut-area">
719                <button id="single-btn" class="click_single">Single</button>
720                <button id="loop-btn" class="click_loop">Loop</button>
721            </div>
722        </div>
723        <div class="main-area">
724            <lit-slicer style="width:100%">
725                <div style="width:65%;">
726                    <lit-table id="tb-binder-count" style="height: auto; overflow-x:auto;width:100%" tree>
727                        <lit-table-column width="250px" title="Process/Thread/Cycle" data-index="title" key="title"  align="flex-start" retract>
728                        </lit-table-column>
729                        <lit-table-column width="100px" title="Total count" data-index="totalCount" key="totalCount" align="center">
730                        </lit-table-column>
731                        <lit-table-column width="100px" title="Binder transaction count" data-index="binderTransactionCount" key="binderTransactionCount" align="center">
732                        </lit-table-column>
733                        <lit-table-column width="100px" title="Binder transaction async count" data-index="binderTransactionAsyncCount" key="binderTransactionAsyncCount" align="center">
734                        </lit-table-column>
735                        <lit-table-column width="100px" title="Binder reply count" data-index="binderReplyCount" key="binderReplyCount" align="center">
736                        </lit-table-column>
737                        <lit-table-column width="100px" title="Binder async rcv count" data-index="binderAsyncRcvCount" key="binderAsyncRcvCount" align="center">
738                        </lit-table-column>
739                        <lit-table-column width="100px" title="Cycle start time(ms)" data-index="cycleStartTime" key="cycleStartTime" align="flex-start">
740                        </lit-table-column>
741                        <lit-table-column width="110px" title="Duration(ms)" data-index="cycleDur" key="cycleDur" align="flex-start">
742                        </lit-table-column>
743                    </lit-table>
744                </div>
745                <lit-slicer-track ></lit-slicer-track>
746                <div style="width:35%;min-width:350px;padding:16px;overflow:auto;" id="cycleColumn" class="query-cycle-area">
747                    <div id="cycle-a"  style="width:84%">
748                        <span>Cycle A: </span>
749                        <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,'')" />
750                        <span>~</span>
751                        <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,'')" />
752                    </div>
753                    <div style="margin-top: 10px; display:flex; flex-derection:row; justify-content:space-between;width:100%">
754                        <div id="cycle-b" style="width:84%">
755                            <span>Cycle B: </span>
756                            <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,'')" />
757                            <span>~</span>
758                            <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,'')" />
759                        </div>
760                        <div>
761                            <button id="query-btn">Query</button>
762                        </div>
763                    </div>
764                    <div class="chart_area">
765                        <div class="chart_title">Average Binder Count</div>
766                        <lit-chart-column id="chart_cycle"></lit-chart-column>
767                        <div class="chart_labels">
768                            <div class="labels"><div class="labels_item"></div>Total</div>
769                            <div class="labels"><div class="labels_item" style="background-color: #ffab67;"></div>Cycle A</div>
770                            <div class="labels"><div class="labels_item" style="background-color: #a285d2;"></div>Cycle B</div>
771                        </div>
772                    </div>
773                </div>
774            </lit-slicer>
775        </div>
776        `;
777  }
778}
779