• 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 { LitChartColumn } from '../../../base-ui/chart/column/LitChartColumn';
19import '../../../base-ui/chart/column/LitChartColumn';
20import './CheckCpuSetting';
21import '../../../base-ui/icon/LitIcon';
22import { CheckCpuSetting } from './CheckCpuSetting';
23import { procedurePool } from '../../database/Procedure';
24import { info } from '../../../log/Log';
25import '../../../base-ui/progress-bar/LitProgressBar';
26import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar';
27import './TableNoData';
28import { TableNoData } from './TableNoData';
29import { getProbablyTime } from '../../database/logic-worker/ProcedureLogicWorkerCommon';
30import { SpSchedulingAnalysis } from './SpSchedulingAnalysis';
31import { Top20ThreadCpuUsageHtml } from './Top20ThreadCpuUsage.html';
32
33@element('top20-thread-cpu-usage')
34export class Top20ThreadCpuUsage extends BaseElement {
35  traceChange: boolean = false;
36  private table: LitTable | null | undefined;
37  private tableBig: LitTable | null | undefined;
38  private tableMid: LitTable | null | undefined;
39  private tableSmall: LitTable | null | undefined;
40  private chartTotal: LitChartColumn | null | undefined;
41  private chart2: LitChartColumn | null | undefined;
42  private chart3: LitChartColumn | null | undefined;
43  private chart4: LitChartColumn | null | undefined;
44  private cpuSetting: CheckCpuSetting | undefined | null;
45  private setting: HTMLDivElement | null | undefined;
46  private progress: LitProgressBar | null | undefined;
47  private nodata: TableNoData | null | undefined;
48  private map: Map<string, { chart: LitChartColumn; table: LitTable }> | undefined;
49  private data: Array<any> = [];
50  private dataBig: Array<any> = [];
51  private dataMid: Array<any> = [];
52  private dataSmall: Array<any> = [];
53  private sort: any = {
54    total: { key: '', sort: 0 },
55    small: { key: '', sort: 0 },
56    mid: { key: '', sort: 0 },
57    big: { key: '', sort: 0 },
58  };
59
60  private publicColumns = `
61                <lit-table-column width="50px" title=" " data-index="no" key="no" align="flex-start"></lit-table-column>
62                <lit-table-column width="50px" title="" data-index="visible" key="visible" align="flex-start">
63                    <template>
64                        <lit-icon name="{{ visible === 1 ? 'eye':'eye-close' }}" onclick="{
65                            let data = this.parentElement.parentElement.data;
66                            data.visible = data.visible === 1 ? 0 : 1
67                            this.name = data.visible === 1 ? 'eye':'eye-close'
68                            data.hideHandler()
69                        }" size="20"></lit-icon>
70                    </template>
71                </lit-table-column>
72                <lit-table-column width="100px" title="tid" data-index="tid" key="tid" align="flex-start" order></lit-table-column>
73                <lit-table-column width="200px" title="t_name" data-index="tName" key="tName" align="flex-start" order></lit-table-column>
74                <lit-table-column width="100px" title="pid" data-index="pid" key="pid" align="flex-start" order></lit-table-column>
75                <lit-table-column width="200px" title="p_name" data-index="pName" key="pName" align="flex-start" order></lit-table-column>
76        `;
77  private bigColumn = `
78                <lit-table-column width="100px" title="big core" data-index="bigTimeStr" key="bigTimeStr" align="flex-start" order></lit-table-column>
79                <lit-table-column width="100px" title="%" data-index="bigPercent" key="bigPercent" align="flex-start" order></lit-table-column>
80        `;
81  private midColumn = `
82                <lit-table-column width="100px" title="middle core" data-index="midTimeStr" key="midTimeStr" align="flex-start" order></lit-table-column>
83                <lit-table-column width="100px" title="%" data-index="midPercent" key="midPercent" align="flex-start" order></lit-table-column>
84        `;
85  private smallColumn = `
86                <lit-table-column width="100px" title="small core" data-index="smallTimeStr" key="smallTimeStr" align="flex-start" order></lit-table-column>
87                <lit-table-column width="100px" title="%" data-index="smallPercent" key="smallPercent" align="flex-start" order></lit-table-column>
88        `;
89
90  initElements(): void {
91    this.nodata = this.shadowRoot!.querySelector<TableNoData>('#nodata');
92    this.progress = this.shadowRoot!.querySelector<LitProgressBar>('#loading');
93    this.table = this.shadowRoot!.querySelector<LitTable>('#tb-thread-usage');
94    this.tableBig = this.shadowRoot!.querySelector<LitTable>('#tb-thread-big');
95    this.tableMid = this.shadowRoot!.querySelector<LitTable>('#tb-thread-mid');
96    this.tableSmall = this.shadowRoot!.querySelector<LitTable>('#tb-thread-small');
97    this.chartTotal = this.shadowRoot!.querySelector<LitChartColumn>('#chart_total');
98    this.chart2 = this.shadowRoot!.querySelector<LitChartColumn>('#chart_2');
99    this.chart3 = this.shadowRoot!.querySelector<LitChartColumn>('#chart_3');
100    this.chart4 = this.shadowRoot!.querySelector<LitChartColumn>('#chart_4');
101    this.map = new Map<string, { chart: LitChartColumn; table: LitTable }>();
102    this.map.set('total', { chart: this.chartTotal!, table: this.table! });
103    this.map.set('small', { chart: this.chart2!, table: this.tableSmall! });
104    this.map.set('mid', { chart: this.chart3!, table: this.tableMid! });
105    this.map.set('big', { chart: this.chart4!, table: this.tableBig! });
106    this.setting = this.shadowRoot!.querySelector<HTMLDivElement>('#setting');
107    this.cpuSetting = this.shadowRoot!.querySelector<CheckCpuSetting>('#cpu_setting');
108    this.cpuSetting!.cpuSetListener = () => {
109      this.cpuSetting!.style.display = 'none';
110      (this.shadowRoot!.querySelector('#total')! as any).style.display = 'grid';
111      (this.shadowRoot!.querySelector('#small')! as any).style.display =
112        CheckCpuSetting.small_cores.length > 0 ? 'grid' : 'none';
113      (this.shadowRoot!.querySelector('#mid')! as any).style.display =
114        CheckCpuSetting.mid_cores.length > 0 ? 'grid' : 'none';
115      (this.shadowRoot!.querySelector('#big')! as any).style.display =
116        CheckCpuSetting.big_cores.length > 0 ? 'grid' : 'none';
117      this.queryData();
118    };
119    this.setting?.addEventListener('click', (event) => {
120      for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) {
121        (node as any).style.display = 'none';
122      }
123      this.cpuSetting!.style.display = 'inline';
124      this.cpuSetting?.init();
125    });
126    this.tabListener();
127  }
128
129  private tabListener(): void {
130    for (let key of this.map!.keys()) {
131      let tab = this.map!.get(key)!.table;
132      let chart = this.map!.get(key)!.chart;
133      tab!.addEventListener('row-click', (evt: any) => {
134        let data = evt.detail.data;
135        data.isSelected = true;
136        // @ts-ignore
137        if ((evt.detail as any).callBack) {
138          // @ts-ignore
139          (evt.detail as any).callBack(true);
140        }
141      });
142      tab!.addEventListener('column-click', (evt: any) => {
143        this.sort[key].key = evt.detail.key;
144        this.sort[key].sort = evt.detail.sort;
145        if (key == 'total') {
146          this.sortByColumn(evt.detail, tab, this.data);
147        } else if (key == 'small') {
148          this.sortByColumn(evt.detail, tab, this.dataSmall);
149        } else if (key == 'mid') {
150          this.sortByColumn(evt.detail, tab, this.dataMid);
151        } else if (key == 'big') {
152          this.sortByColumn(evt.detail, tab, this.dataBig);
153        }
154      });
155      tab!.addEventListener('row-hover', (evt: any) => {
156        if (evt.detail.data) {
157          let data = evt.detail.data;
158          data.isHover = true;
159          if ((evt.detail as any).callBack) {
160            (evt.detail as any).callBack(true);
161          }
162          chart.showHoverColumn(data.no);
163        }
164      });
165    }
166  }
167
168  sortByColumn(detail: any, table: LitTable | null | undefined, data: Array<any>) {
169    // @ts-ignore
170    function compare(threadCpuUsageProperty, sort, type) {
171      return function (a: any, b: any) {
172        if (type === 'number') {
173          // @ts-ignore
174          return sort === 2
175            ? parseFloat(b[threadCpuUsageProperty]) - parseFloat(a[threadCpuUsageProperty])
176            : parseFloat(a[threadCpuUsageProperty]) - parseFloat(b[threadCpuUsageProperty]);
177        } else {
178          if (sort === 2) {
179            return b[threadCpuUsageProperty].toString().localeCompare(a[threadCpuUsageProperty].toString());
180          } else {
181            return a[threadCpuUsageProperty].toString().localeCompare(b[threadCpuUsageProperty].toString());
182          }
183        }
184      };
185    }
186
187    let type = 'number';
188
189    if (detail.key === 'bigTimeStr') {
190      detail.key = 'big';
191    } else if (detail.key === 'midTimeStr') {
192      detail.key = 'mid';
193    } else if (detail.key === 'smallTimeStr') {
194      detail.key = 'small';
195    } else if (
196      detail.key === 'bigPercent' ||
197      detail.key === 'ratio' ||
198      detail.key === 'tid' ||
199      detail.key === 'pid' ||
200      detail.key === 'midPercent' ||
201      detail.key.includes('cpu')
202    ) {
203    } else {
204      type = 'string';
205    }
206    data.sort(compare(detail.key, detail.sort, type));
207    table!.recycleDataSource = data;
208  }
209
210  init() {
211    if (!this.traceChange) {
212      for (let key of this.map!.keys()) {
213        this.map!.get(key)!.table.reMeauseHeight();
214      }
215      return;
216    }
217    this.traceChange = false;
218    for (let key of this.map!.keys()) {
219      let table = this.map!.get(key)!.table;
220      table.innerHTML = '';
221      let columns = this.getTableColumns(key);
222      for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) {
223        columns = `
224                ${columns}
225                <lit-table-column width="120px" title="cpu${i}(us)" data-index="cpu${i}" key="cpu${i}" align="flex-start" order></lit-table-column>
226            `;
227      }
228      table.innerHTML = columns;
229    }
230
231    if (!CheckCpuSetting.init_setting) {
232      for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) {
233        (node as any).style.display = 'none';
234      }
235      this.cpuSetting!.style.display = 'inline';
236      this.cpuSetting?.init();
237    } else {
238      this.queryData();
239    }
240  }
241
242  clearData() {
243    this.traceChange = true;
244    for (let key of this.map!.keys()) {
245      this.map!.get(key)!.chart.dataSource = [];
246      this.map!.get(key)!.table.recycleDataSource = [];
247    }
248  }
249
250  queryData(): void {
251    this.progress!.loading = true;
252    this.queryLogicWorker(`scheduling-Thread CpuUsage`, `query Thread Cpu Usage Analysis Time:`, (res) => {
253      this.nodata!.noData = res.keys().length === 0;
254      for (let key of this.map!.keys()) {
255        let obj = this.map!.get(key)!;
256        let source: any[] = res.get(key) || [];
257        source = source.map((it: any, index: number) => {
258          let data: any = {
259            pid: it.pid,
260            pName: it.pName,
261            tid: it.tid,
262            tName: it.tName,
263            total: it.total,
264            big: it.big,
265            mid: it.mid,
266            small: it.small,
267            no: index + 1,
268            visible: 1,
269            bigPercent: it.bigPercent,
270            midPercent: it.midPercent,
271            smallPercent: it.smallPercent,
272            bigTimeStr: it.bigTimeStr,
273            midTimeStr: it.midTimeStr,
274            smallTimeStr: it.smallTimeStr,
275            hideHandler: () => {
276              let arr = source.filter((o) => o.visible === 1);
277              obj.chart.dataSource = this.getArrayDataBySize(key, arr);
278            },
279          };
280          for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) {
281            data[`cpu${i}`] = (it[`cpu${i}`] || 0) / 1000;
282          }
283          return data;
284        });
285        this.setChartConfig(obj, key, source);
286        this.assignmentData(key, source, obj);
287      }
288      this.progress!.loading = false;
289    });
290  }
291
292  private assignmentData(key: string, source: any[], obj: { chart: LitChartColumn; table: LitTable }): void {
293    if (key == 'total') {
294      this.data = source;
295    } else if (key == 'small') {
296      this.dataSmall = source;
297    } else if (key == 'mid') {
298      this.dataMid = source;
299    } else if (key == 'big') {
300      this.dataBig = source;
301    }
302    if (this.sort[key].key != '') {
303      this.sortByColumn(this.sort[key], obj.table, source);
304    } else {
305      obj.table.recycleDataSource = source;
306    }
307  }
308
309  private setChartConfig(obj: { chart: LitChartColumn; table: LitTable }, key: string, source: any[]): void {
310    obj.chart.config = {
311      data: this.getArrayDataBySize(key, source),
312      appendPadding: 10,
313      xField: 'tid',
314      yField: 'total',
315      seriesField: key === 'total' ? 'size' : '',
316      color: (a) => {
317        if (a.size === 'big core') {
318          return '#2f72f8';
319        } else if (a.size === 'middle core') {
320          return '#ffab67';
321        } else if (a.size === 'small core') {
322          return '#a285d2';
323        } else {
324          return '#0a59f7';
325        }
326      },
327      hoverHandler: (no) => {
328        this.setHover(source, no, obj);
329      },
330      tip: (a) => {
331        if (a && a[0]) {
332          let tip = '';
333          let total = 0;
334          for (let obj of a) {
335            total += obj.obj.total;
336            tip = `${tip}
337                                <div style="display:flex;flex-direction: row;align-items: center;">
338                                    <div style="width: 10px;height: 5px;background-color: ${
339                                      obj.color
340                                    };margin-right: 5px"></div>
341                                    <div>${obj.type || key}:${obj.obj.timeStr}</div>
342                                </div>
343                            `;
344          }
345          tip = `<div>
346                                        <div>tid:${a[0].obj.tid}</div>
347                                        ${tip}
348                                        ${a.length > 1 ? `<div>total:${getProbablyTime(total)}</div>` : ''}
349                                    </div>`;
350          return tip;
351        } else {
352          return '';
353        }
354      },
355      label: null,
356    };
357  }
358
359  private setHover(source: any[], no: number, obj: { chart: LitChartColumn; table: LitTable }): void {
360    let data = source.find((it) => it.no === no);
361    if (data) {
362      data.isHover = true;
363      obj.table!.setCurrentHover(data);
364    } else {
365      obj.table!.mouseOut();
366    }
367  }
368
369  getArrayDataBySize(type: string, arr: Array<any>) {
370    let data: any[] = [];
371    for (let obj of arr) {
372      if (type === 'total') {
373        data.push({
374          pid: obj.pid,
375          pName: obj.pName,
376          tid: obj.tid,
377          tName: obj.tName,
378          total: obj.big,
379          size: 'big core',
380          no: obj.no,
381          timeStr: obj.bigTimeStr,
382        });
383        data.push({
384          pid: obj.pid,
385          pName: obj.pName,
386          tid: obj.tid,
387          tName: obj.tName,
388          total: obj.mid,
389          size: 'middle core',
390          no: obj.no,
391          timeStr: obj.midTimeStr,
392        });
393        data.push({
394          pid: obj.pid,
395          pName: obj.pName,
396          tid: obj.tid,
397          tName: obj.tName,
398          total: obj.small,
399          size: 'small core',
400          no: obj.no,
401          timeStr: obj.smallTimeStr,
402        });
403      } else {
404        data.push({
405          pid: obj.pid,
406          pName: obj.pName,
407          tid: obj.tid,
408          tName: obj.tName,
409          total: obj[type],
410          no: obj.no,
411          timeStr: obj[`${type}TimeStr`],
412        });
413      }
414    }
415    return data;
416  }
417
418  queryLogicWorker(option: string, log: string, handler: (res: any) => void) {
419    let time = new Date().getTime();
420    procedurePool.submitWithName(
421      'logic0',
422      option,
423      {
424        bigCores: CheckCpuSetting.big_cores,
425        midCores: CheckCpuSetting.mid_cores,
426        smallCores: CheckCpuSetting.small_cores,
427      },
428      undefined,
429      handler
430    );
431    let durTime = new Date().getTime() - time;
432    info(log, durTime);
433  }
434
435  getTableColumns(type: string) {
436    if (type === 'total') {
437      return `${this.publicColumns}${this.bigColumn}${this.midColumn}${this.smallColumn}`;
438    } else if (type === 'big') {
439      return `${this.publicColumns}${this.bigColumn}`;
440    } else if (type === 'mid') {
441      return `${this.publicColumns}${this.midColumn}`;
442    } else if (type === 'small') {
443      return `${this.publicColumns}${this.smallColumn}`;
444    } else {
445      return '';
446    }
447  }
448
449  initHtml(): string {
450    return Top20ThreadCpuUsageHtml;
451  }
452}
453