• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { BaseElement, element } from '../../../base-ui/BaseElement';
17import { LitTable } from '../../../base-ui/table/lit-table';
18import { procedurePool } from '../../database/Procedure';
19import { info } from '../../../log/Log';
20import '../../../base-ui/chart/pie/LitChartPie';
21import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie';
22import { LitSelect } from '../../../base-ui/select/LitSelect';
23import { LitSelectOption } from '../../../base-ui/select/LitSelectOption';
24import '../../../base-ui/progress-bar/LitProgressBar';
25import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar';
26import './TableNoData';
27import { TableNoData } from './TableNoData';
28import { getProbablyTime } from '../../database/logic-worker/ProcedureLogicWorkerCommon';
29import {queryThreads} from "../../database/sql/ProcessThread.sql";
30import { Top20FrequencyThreadHtml } from './Top20FrequencyThread.html';
31
32@element('top20-frequency-thread')
33export class Top20FrequencyThread extends BaseElement {
34  static threads: { id: number; tid: number; name: string }[] | undefined;
35  traceChange: boolean = false;
36  private frequencyThreadTbl: LitTable | null | undefined;
37  private threadSelect: LitSelect | null | undefined;
38  private frequencyThreadPie: LitChartPie | null | undefined;
39  private currentThread: HTMLDivElement | null | undefined;
40  private frequencyThreadProgress: LitProgressBar | null | undefined;
41  private nodata: TableNoData | null | undefined;
42  private currentTid: number = 0;
43  private frequencyThreadData: Array<any> = [];
44  private sortColumn: string = '';
45  private sortType: number = 0;
46
47  initElements(): void {
48    this.nodata = this.shadowRoot!.querySelector<TableNoData>('#nodata');
49    this.frequencyThreadProgress = this.shadowRoot!.querySelector<LitProgressBar>('#loading');
50    this.frequencyThreadTbl = this.shadowRoot!.querySelector<LitTable>('#tb-process-thread-count');
51    this.currentThread = this.shadowRoot!.querySelector<HTMLDivElement>('#current_thread');
52    this.threadSelect = this.shadowRoot!.querySelector<LitSelect>('#thread_select');
53    this.frequencyThreadPie = this.shadowRoot!.querySelector<LitChartPie>('#pie');
54
55    this.threadSelect!.onchange = (e) => {
56      this.currentThread!.textContent = (e as any).detail.text;
57      this.currentTid = parseInt((e as any).detail.value);
58      this.frequencyThreadProgress!.loading = true;
59      this.queryData();
60    };
61
62    this.frequencyThreadTbl!.addEventListener('row-click', (evt: any) => {
63      let data = evt.detail.data;
64      data.isSelected = true;
65      if ((evt.detail as any).callBack) {
66        (evt.detail as any).callBack(true);
67      }
68    });
69
70    this.frequencyThreadTbl!.addEventListener('column-click', (evt: any) => {
71      this.sortColumn = evt.detail.key;
72      this.sortType = evt.detail.sort;
73      // @ts-ignore
74      this.sortByColumn(evt.detail);
75    });
76    this.frequencyThreadTbl!.addEventListener('row-hover', (evt: any) => {
77      if (evt.detail.data) {
78        let data = evt.detail.data;
79        data.isHover = true;
80        if ((evt.detail as any).callBack) {
81          (evt.detail as any).callBack(true);
82        }
83      }
84      this.frequencyThreadPie?.showHover();
85    });
86    this.frequencyThreadTbl!.itemTextHandleMap.set('freq', (value) => (value === -1 ? 'unknown' : value));
87  }
88
89  sortByColumn(detail: any) {
90    // @ts-ignore
91    function compare(frequencyThreadProperty, sort, type) {
92      return function (a: any, b: any) {
93        if (type === 'number') {
94          // @ts-ignore
95          return sort === 2
96            ? parseFloat(b[frequencyThreadProperty]) - parseFloat(a[frequencyThreadProperty])
97            : parseFloat(a[frequencyThreadProperty]) - parseFloat(b[frequencyThreadProperty]);
98        } else {
99          if (sort === 2) {
100            return b[frequencyThreadProperty].toString().localeCompare(a[frequencyThreadProperty].toString());
101          } else {
102            return a[frequencyThreadProperty].toString().localeCompare(b[frequencyThreadProperty].toString());
103          }
104        }
105      };
106    }
107
108    if (detail.key === 'timeStr') {
109      detail.key = 'time';
110      this.frequencyThreadData.sort(compare(detail.key, detail.sort, 'number'));
111    } else if (detail.key === 'no' || detail.key === 'cpu' || detail.key === 'freq' || detail.key === 'ratio') {
112      this.frequencyThreadData.sort(compare(detail.key, detail.sort, 'number'));
113    } else {
114      this.frequencyThreadData.sort(compare(detail.key, detail.sort, 'string'));
115    }
116    this.frequencyThreadTbl!.recycleDataSource = this.frequencyThreadData;
117  }
118
119  async init() {
120    if (!this.traceChange) {
121      if (this.frequencyThreadTbl!.recycleDataSource.length > 0) {
122        this.frequencyThreadTbl?.reMeauseHeight();
123      }
124      return;
125    }
126    this.traceChange = false;
127    this.frequencyThreadProgress!.loading = true;
128    if (Top20FrequencyThread.threads === undefined) {
129      Top20FrequencyThread.threads = (await queryThreads()) || [];
130      this.nodata!.noData = Top20FrequencyThread.threads === undefined || Top20FrequencyThread.threads.length === 0;
131      this.threadSelect!.innerHTML = '';
132      let threads = Top20FrequencyThread.threads.map((it) => {
133        let option = new LitSelectOption();
134        option.setAttribute('value', it.tid + '');
135        option.textContent = it.name;
136        return option;
137      });
138      this.threadSelect!.append(...threads);
139      this.threadSelect?.initOptions();
140      this.threadSelect!.value = Top20FrequencyThread.threads[0].tid + '';
141      this.currentThread!.textContent = Top20FrequencyThread.threads[0].name;
142      this.currentTid = Top20FrequencyThread.threads[0].tid;
143      this.queryData();
144    }
145  }
146
147  queryData() {
148    this.queryLogicWorker('scheduling-Thread Freq', 'query Thread Top 20 Frequency Time:', (res) => {
149      this.nodata!.noData =
150        Top20FrequencyThread.threads === undefined ||
151        Top20FrequencyThread.threads.length === 0 ||
152        res === undefined ||
153        res.length === 0;
154      (res as any[]).map((it: any, index: number) => {
155        it.no = index + 1;
156      });
157      this.frequencyThreadData = res;
158      if (this.sortColumn != '') {
159        this.sortByColumn({
160          key: this.sortColumn,
161          sort: this.sortType,
162        });
163      } else {
164        this.frequencyThreadTbl!.recycleDataSource = res;
165      }
166      this.frequencyThreadTbl!.reMeauseHeight();
167      this.setThreadPieConfig(res);
168      this.frequencyThreadProgress!.loading = false;
169      this.shadowRoot!.querySelector('#tb_vessel')!.scrollTop = 0;
170    });
171  }
172
173  private setThreadPieConfig(res: any): void {
174    this.frequencyThreadPie!.config = {
175      appendPadding: 10,
176      data: this.getPieChartData(res),
177      angleField: 'time',
178      colorField: 'freq',
179      colorFieldTransferHandler: (value) => (value === -1 ? 'unknown' : value),
180      radius: 0.8,
181      label: {
182        type: 'outer',
183      },
184      tip: (obj) => {
185        return `<div>
186                             <div>freq:${obj.obj.freq === -1 ? 'unknown' : obj.obj.freq}</div>
187                             <div>cpu:${obj.obj.cpu}</div>
188                             <div>time:${obj.obj.timeStr}</div>
189                             <div>ratio:${obj.obj.ratio}%</div>
190                        </div>
191                `;
192      },
193      hoverHandler: (data) => {
194        if (data) {
195          this.frequencyThreadTbl!.setCurrentHover(data);
196        } else {
197          this.frequencyThreadTbl!.mouseOut();
198        }
199      },
200      interactions: [
201        {
202          type: 'element-active',
203        },
204      ],
205    };
206  }
207
208  getPieChartData(res: any[]) {
209    if (res.length > 20) {
210      let pieChartArr: any[] = [];
211      let other: any = {
212        cpu: '-',
213        freq: 'other',
214        time: 0,
215        ratio: '0',
216        totalDur: 0,
217      };
218      for (let i = 0; i < res.length; i++) {
219        if (i < 19) {
220          pieChartArr.push(res[i]);
221        } else {
222          other.time += res[i].time;
223          other.timeStr = getProbablyTime(other.time);
224          other.totalDur = res[i].totalDur;
225          other.ratio = ((other.time / other.totalDur) * 100).toFixed(2);
226        }
227      }
228      pieChartArr.push(other);
229      return pieChartArr;
230    }
231    return res;
232  }
233
234  clearData() {
235    this.traceChange = true;
236    this.threadSelect!.innerHTML = '';
237    this.frequencyThreadPie!.dataSource = [];
238    this.frequencyThreadTbl!.recycleDataSource = [];
239  }
240
241  queryLogicWorker(option: string, log: string, handler: (res: any) => void) {
242    let frequencyThreadTime = new Date().getTime();
243    procedurePool.submitWithName('logic0', option, { tid: this.currentTid }, undefined, handler);
244    let durTime = new Date().getTime() - frequencyThreadTime;
245    info(log, durTime);
246  }
247
248  initHtml(): string {
249    return Top20FrequencyThreadHtml;
250  }
251}
252