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 { SelectionParam } from '../../../../bean/BoxSelection';
19import { Utils } from '../../base/Utils';
20import { ColorUtils } from '../../base/ColorUtils';
21import { CpuFreqLimitsStruct } from '../../../../database/ui-worker/cpu/ProcedureWorkerCpuFreqLimits';
22import { resizeObserver } from '../SheetUtils';
23import { getCpuLimitFreqBoxSelect } from '../../../../database/sql/Cpu.sql';
24
25@element('tabpane-cpu-freq-limits')
26export class TabPaneCpuFreqLimits extends BaseElement {
27  private cpuFreqLimitsTbl: LitTable | null | undefined;
28  private selectionParam: SelectionParam | null | undefined;
29  private cpuFreqLimitSource: CpuFreqLimit[] = [];
30  private cpuFreqLimitSortKey: string = 'cpu';
31  private cpuFreqLimitSortType: number = 0;
32
33  set data(cpuFreqLimitSelection: SelectionParam | unknown) {
34    if (cpuFreqLimitSelection === this.selectionParam) {
35      return;
36    }
37    // @ts-ignore
38    this.selectionParam = cpuFreqLimitSelection;
39    // @ts-ignore
40    this.cpuFreqLimitsTbl!.shadowRoot!.querySelector('.table').style.height =
41      this.parentElement!.clientHeight - 25 + 'px';
42    let list: unknown[] = [];
43    // @ts-ignore
44    getCpuLimitFreqBoxSelect(cpuFreqLimitSelection.cpuFreqLimit, cpuFreqLimitSelection.rightNs).then((res) => {
45      for (let it of res) {
46        //@ts-ignore
47        if (!it.dur || it.startNs + it.dur > cpuFreqLimitSelection.rightNs) {
48          //@ts-ignore
49          it.dur = (cpuFreqLimitSelection.rightNs || 0) - (it.startNs || 0);
50        }
51      }
52      //@ts-ignore
53      this.formatData(res, cpuFreqLimitSelection.leftNs, cpuFreqLimitSelection.rightNs);
54    });
55  }
56
57  initElements(): void {
58    this.cpuFreqLimitsTbl = this.shadowRoot!.querySelector<LitTable>('#tb-cpu-freq-limit');
59    this.cpuFreqLimitsTbl!.addEventListener('column-click', (evt) => {
60      // @ts-ignore
61      this.cpuFreqLimitSortKey = evt.detail.key;
62      // @ts-ignore
63      this.cpuFreqLimitSortType = evt.detail.sort;
64      // @ts-ignore
65      this.sortCpuFreqLimitTable(evt.detail.key, evt.detail.sort);
66    });
67  }
68
69  connectedCallback(): void {
70    super.connectedCallback();
71    resizeObserver(this.parentElement!, this.cpuFreqLimitsTbl!, 25);
72  }
73
74  formatData(list: CpuFreqLimitsStruct[], start: number, end: number): void {
75    let limitsMap = new Map<string, CpuFreqLimit>();
76    let groupMapData = (time: number, id: string, item: CpuFreqLimitsStruct): void => {
77      if (limitsMap.has(id)) {
78        limitsMap.get(id)!.time += time;
79      } else {
80        let isMax = id.endsWith('max');
81        let limit = new CpuFreqLimit();
82        limit.cpu = `Cpu ${item.cpu}`;
83        limit.time = time;
84        limit.type = isMax ? 'Max Freqency' : 'Min Frequency';
85        limit.value = isMax ? item.max! : item.min!;
86        limitsMap.set(id, limit);
87      }
88    };
89    list.forEach((item) => {
90      if (item.startNs! > end) {
91        return;
92      }
93      let max = Math.max(item.startNs || 0, start);
94      let min = Math.min((item.startNs || 0) + item.dur, end);
95      if (max < min) {
96        let maxId = `${item.cpu}-${item.max}-max`;
97        let minId = `${item.cpu}-${item.min}-min`;
98        groupMapData(min - max, maxId, item);
99        groupMapData(min - max, minId, item);
100      }
101    });
102    this.cpuFreqLimitSource = Array.from(limitsMap.values()).map((item) => {
103      item.timeStr = Utils.getProbablyTime(item.time);
104      item.valueStr = `${ColorUtils.formatNumberComma(item.value!)} kHz`;
105      return item;
106    });
107    this.cpuFreqLimitSource.sort((a, b): number => {
108      let cpuLeftData = Number(a.cpu.toString().replace('Cpu', ''));
109      let cpuRightData = Number(b.cpu.toString().replace('Cpu', ''));
110      if (cpuLeftData > cpuRightData) {
111        return 1;
112      } else {
113        return -1;
114      }
115    });
116    this.sortCpuFreqLimitTable(this.cpuFreqLimitSortKey, this.cpuFreqLimitSortType);
117  }
118
119  sortCpuFreqLimitTable(key: string, type: number): void {
120    if (type === 0) {
121      this.cpuFreqLimitsTbl!.recycleDataSource = this.cpuFreqLimitSource;
122    } else {
123      let cpuFreqLimitsArr = Array.from(this.cpuFreqLimitSource);
124      cpuFreqLimitsArr.sort((cpuFreqLimitA, cpuFreqLimitB): number => {
125        if (key === 'timeStr') {
126          return this.compareTime(cpuFreqLimitA, cpuFreqLimitB, type);
127        } else if (key === 'valueStr') {
128          return this.compareValue(cpuFreqLimitA, cpuFreqLimitB, type);
129        } else if (key === 'cpu') {
130          return this.compareCpu(cpuFreqLimitA, cpuFreqLimitB, type);
131        } else if (key === 'type') {
132          return this.compareType(cpuFreqLimitA, cpuFreqLimitB, type);
133        } else {
134          return 0;
135        }
136      });
137      this.cpuFreqLimitsTbl!.recycleDataSource = cpuFreqLimitsArr;
138    }
139  }
140
141  compareTime(cpuFreqLimitA: unknown, cpuFreqLimitB: unknown, type: number): number {
142    if (type === 1) {
143      // @ts-ignore
144      return cpuFreqLimitA.time - cpuFreqLimitB.time;
145    } else {
146      // @ts-ignore
147      return cpuFreqLimitB.time - cpuFreqLimitA.time;
148    }
149  }
150
151  compareValue(cpuFreqLimitA: unknown, cpuFreqLimitB: unknown, type: number): number {
152    if (type === 1) {
153      // @ts-ignore
154      return cpuFreqLimitA.value - cpuFreqLimitB.value;
155    } else {
156      // @ts-ignore
157      return cpuFreqLimitB.value - cpuFreqLimitA.value;
158    }
159  }
160
161  compareCpu(cpuFreqLimitA: unknown, cpuFreqLimitB: unknown, type: number): number {
162    // @ts-ignore
163    let cpuLeftData = Number(cpuFreqLimitA.cpu.toString().replace('Cpu', ''));
164    // @ts-ignore
165    let cpuRightData = Number(cpuFreqLimitB.cpu.toString().replace('Cpu', ''));
166    if (type === 1) {
167      return cpuLeftData - cpuRightData;
168    } else {
169      return cpuRightData - cpuLeftData;
170    }
171  }
172
173  compareType(cpuFreqLimitA: unknown, cpuFreqLimitB: unknown, type: number): number {
174    // @ts-ignore
175    if (cpuFreqLimitA.type > cpuFreqLimitB.type) {
176      return type === 2 ? 1 : -1; // @ts-ignore
177    } else if (cpuFreqLimitA.type === cpuFreqLimitB.type) {
178      return 0;
179    } else {
180      return type === 2 ? -1 : 1;
181    }
182  }
183
184  initHtml(): string {
185    return `
186        <style>
187        .cpu-freq-limit-tbl {
188            height: auto;
189        }
190        :host{
191            display: flex;
192            flex-direction: column;
193            padding: 10px 10px;
194        }
195        </style>
196        <lit-table id="tb-cpu-freq-limit" class="cpu-freq-limit-tbl">
197            <lit-table-column class="cpu-freq-limit-column" width="20%" title="Cpu" data-index="cpu" key="cpu" align="flex-start" order>
198            </lit-table-column>
199            <lit-table-column class="cpu-freq-limit-column" width="1fr" title="Type" data-index="type" key="type" align="flex-start" order>
200            </lit-table-column>
201            <lit-table-column class="cpu-freq-limit-column" width="1fr" title="Time" data-index="timeStr" key="timeStr" align="flex-start" order>
202            </lit-table-column>
203            <lit-table-column class="cpu-freq-limit-column" width="1fr" title="Value" data-index="valueStr" key="valueStr" align="flex-start" order>
204            </lit-table-column>
205        </lit-table>
206        `;
207  }
208}
209
210class CpuFreqLimit {
211  cpu: string = '';
212  type: string = '';
213  time: number = 0;
214  value: number = 0;
215  timeStr: string = '';
216  valueStr: string = '';
217}
218