• 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 { SelectionData, SelectionParam } from '../../../../bean/BoxSelection';
19import { initSort, resizeObserver } from '../SheetUtils';
20import { queryIrqDataBoxSelect, querySoftIrqDataBoxSelect, queryIrqSelectData, querySoftirqSelectData } from '../../../../database/sql/Irq.sql';
21import { FlagsConfig } from '../../../SpFlags';
22import { IrqAndSoftirqBean, byCallidGroupBean, finalResultBean } from './irqAndSoftirqBean';
23
24@element('tabpane-irq-counter')
25export class TabPaneIrqCounter extends BaseElement {
26  private irqCounterTbl: LitTable | null | undefined;
27  private irqRange: HTMLLabelElement | null | undefined;
28  private irqCounterSource: Array<SelectionData> = [];
29  private sortColumn: string = 'wallDurationFormat';
30  private sortType: number = 2;
31  private loadIrq: boolean = false;//flag开关
32  private irqAndSoftirqSource: Array<finalResultBean> = [];
33
34  set data(irqParam: SelectionParam | unknown) {
35    if (this.irqCounterTbl) {
36      //@ts-ignore
37      this.irqCounterTbl.shadowRoot.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 45}px`;
38    }
39    this.irqRange!.textContent = `Selected range: ${parseFloat(
40      // @ts-ignore
41      ((irqParam.rightNs - irqParam.leftNs) / 1000000.0).toFixed(5)
42    )} ms`;
43    this.irqCounterTbl!.loading = true;
44    let dataSource: Array<SelectionData> = [];
45    this.loadIrq = FlagsConfig.getFlagsConfigEnableStatus('CPU by Irq');//flag开关
46    if (this.loadIrq) {//@ts-ignore
47      let irqCallIds = irqParam.softIrqCallIds.length > 0 ? irqParam.softIrqCallIds : irqParam.irqCallIds;
48      Promise.all([//@ts-ignore
49        queryIrqSelectData(irqCallIds, irqParam.leftNs, irqParam.rightNs),//@ts-ignore
50        querySoftirqSelectData(irqParam.softIrqCallIds, irqParam.leftNs, irqParam.rightNs),
51      ]).then(([irqData, softirqData]) => {
52        this.irqCounterTbl!.loading = false;
53        const resArr = irqData.concat(softirqData);
54        if (resArr != null && resArr.length > 0) {//@ts-ignore
55          let isSelectIrq = irqParam.irqCallIds.length > 0 ? true : false;
56          const cutData: finalResultBean[] = this.groupByCallid(resArr);
57          this.aggregateData(cutData, isSelectIrq);//整合数据
58        } else {
59          this.irqAndSoftirqSource = [];
60          this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource;
61        }
62      });
63    } else {
64      Promise.all([
65        // @ts-ignore
66        queryIrqDataBoxSelect(irqParam.irqCallIds, irqParam.leftNs, irqParam.rightNs), // @ts-ignore
67        querySoftIrqDataBoxSelect(irqParam.softIrqCallIds, irqParam.leftNs, irqParam.rightNs),
68      ]).then((resArr) => {
69        this.irqCounterTbl!.loading = false;
70        resArr.forEach((res) => {
71          res.forEach((item) => {
72            let selectData = new SelectionData();
73            //@ts-ignore
74            selectData.name = item.irqName;
75            //@ts-ignore
76            selectData.cat = item.cat;
77            //@ts-ignore
78            selectData.count = item.count;
79            //@ts-ignore
80            selectData.wallDuration = item.wallDuration;
81            //@ts-ignore
82            selectData.wallDurationFormat = (item.wallDuration / 1000).toFixed(2);
83            //@ts-ignore
84            selectData.maxDuration = item.wallDuration;
85            //@ts-ignore
86            selectData.maxDurationFormat = (item.maxDuration / 1000).toFixed(2);
87            //@ts-ignore
88            selectData.avgDuration = (item.avgDuration / 1000).toFixed(2);
89            dataSource.push(selectData);
90          });
91        });
92        initSort(this.irqCounterTbl!, this.sortColumn, this.sortType);
93        this.irqCounterSource = dataSource;
94        this.irqCounterTbl!.recycleDataSource = dataSource;
95        this.sortByColumn(this.sortColumn, this.sortType);
96      });
97    }
98  }
99
100  initElements(): void {
101    this.irqCounterTbl = this.shadowRoot?.querySelector<LitTable>('#tb-irq-counter');
102    this.irqRange = this.shadowRoot?.querySelector('#time-range');
103    this.irqCounterTbl!.addEventListener('column-click', (event) => {
104      if (!this.loadIrq) {
105        // @ts-ignore
106        this.sortByColumn(event.detail.key, event.detail.sort);
107      } else {
108        // @ts-ignore
109        this.reSortByColum(event.detail.key, event.detail.sort);
110      }
111    });
112  }
113
114  connectedCallback(): void {
115    super.connectedCallback();
116    resizeObserver(this.parentElement!, this.irqCounterTbl!);
117  }
118
119  initHtml(): string {
120    return `
121        <style>
122        .irq-counter-label{
123            font-size: 10pt;
124        }
125        :host{
126            display: flex;
127            flex-direction: column;
128            padding: 10px 10px;
129        }
130        </style>
131        <label id="time-range" class="irq-counter-label" style="width: 100%;height: 20px;text-align: end;margin-bottom: 5px;">Selected range:0.0 ms</label>
132        <lit-table id="tb-irq-counter" style="height: auto">
133            <lit-table-column width="30%" title="Name" data-index="name" key="name"  align="flex-start" order>
134            </lit-table-column>
135            <lit-table-column width="10%" title="Type" data-index="cat" key="cat"  align="flex-start" order>
136            </lit-table-column>
137            <lit-table-column width="1fr" title="Duration(μs)" data-index="wallDurationFormat" key="wallDurationFormat"  align="flex-start" order >
138            </lit-table-column>
139            <lit-table-column width="1fr" title="Max Duration(μs)" data-index="maxDurationFormat" key="maxDurationFormat"  align="flex-start" order >
140            </lit-table-column>
141            <lit-table-column width="1fr" title="Average Duration(μs)" data-index="avgDuration" key="avgDuration"  align="flex-start" order >
142            </lit-table-column>
143            <lit-table-column width="1fr" title="Occurrences" data-index="count" key="count"  align="flex-start" order >
144            </lit-table-column>
145        </lit-table>
146        `;
147  }
148
149  sortByColumn(sortColumn: string, sortType: number): void {
150    let key = sortColumn;
151    let type = sortType;
152    let arr = Array.from(this.irqCounterSource);
153    arr.sort((irqCounterLeftData, irqCounterRightData): number => {
154      if (key === 'wallDurationFormat' || type === 0) {
155        return (type === 1 ? 1 : -1) * (irqCounterLeftData.wallDuration - irqCounterRightData.wallDuration);
156      } else if (key === 'count') {
157        return (type === 1 ? 1 : -1) * (parseInt(irqCounterLeftData.count) - parseInt(irqCounterRightData.count));
158      } else if (key === 'maxDurationFormat') {
159        return (type === 1 ? 1 : -1) * (irqCounterLeftData.maxDuration - irqCounterRightData.maxDuration);
160      } else if (key === 'avgDuration') {
161        const avgDiff =
162          irqCounterLeftData.wallDuration / parseInt(irqCounterLeftData.count) -
163          irqCounterRightData.wallDuration / parseInt(irqCounterRightData.count);
164        return (type === 1 ? 1 : -1) * avgDiff;
165      } else if (key === 'name') {
166        const nameDiff = irqCounterLeftData.name.localeCompare(irqCounterRightData.name);
167        return (type === 2 ? -1 : 1) * nameDiff;
168      } else {
169        return 0;
170      }
171    });
172    this.irqCounterTbl!.recycleDataSource = arr;
173  }
174
175    //将所有数据按callid重新分组
176    private groupByCallid(data: Array<IrqAndSoftirqBean>): finalResultBean[] {
177      const callidObject: { [callid: number]: byCallidGroupBean } =
178        data.reduce((groups, item) => {
179          const { callid, ...restProps } = item;
180          const newIrqAndSoftirqBean: IrqAndSoftirqBean = { callid, ...restProps };
181
182          if (!groups[callid]) {
183            groups[callid] = { Callid: [] };
184          }
185          groups[callid].Callid!.push(newIrqAndSoftirqBean);
186
187          return groups;
188        }, {} as { [callid: number]: byCallidGroupBean });
189      const cutObj: { [callid: number]: finalResultBean[] } = {};
190      Object.entries(callidObject).forEach(([callidStr, { Callid }]) => {
191        const callid = Number(callidStr);
192        cutObj[callid] = this.callidByIrq(Callid);
193      });
194      const cutList: finalResultBean[] = Object.values(cutObj).flat();
195      return cutList;
196    }
197
198    //具体切割方法
199    private callidByIrq(data: IrqAndSoftirqBean[]): finalResultBean[] {
200      let sourceData = data.sort((a, b) => a.startTime - b.startTime);
201      let waitArr: IrqAndSoftirqBean[] = [];
202      let completedArr: finalResultBean[] = [];
203      let globalTs: number = 0;
204      let index: number = 0;
205      while (index < sourceData.length || waitArr.length > 0) {
206        let minEndTs = Math.min(...waitArr.map((item: IrqAndSoftirqBean) => item.endTime));
207        let minIndex = waitArr.findIndex((item: IrqAndSoftirqBean) => item.endTime === minEndTs);
208        //当waitArr为空时
209        if (waitArr.length === 0) {
210          globalTs = sourceData[index].startTime;
211          waitArr.push(sourceData[index]);
212          index++;
213          continue;
214        }
215        //当全局Ts等于minEndTs时,只做删除处理
216        if (globalTs === minEndTs) {
217          if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
218          continue;
219        }
220        let obj: finalResultBean = {
221          cat: '',
222          name: '',
223          wallDuration: 0,
224          count: 0,
225        };
226        if (index < sourceData.length) {
227          if (sourceData[index].startTime < minEndTs) {
228            if (globalTs === sourceData[index].startTime) {
229              waitArr.push(sourceData[index]);
230              index++;
231              continue;
232            } else {
233              const maxPriorityItem = this.findMaxPriority(waitArr);
234              obj = {
235                cat: maxPriorityItem.cat,
236                name: maxPriorityItem.name,
237                wallDuration: sourceData[index].startTime - globalTs,
238                count: maxPriorityItem.isFirstObject === 1 ? 1 : 0
239              }
240              completedArr.push(obj);
241              maxPriorityItem.isFirstObject = 0;
242              waitArr.push(sourceData[index]);
243              globalTs = sourceData[index].startTime;
244              index++;
245            }
246          } else {
247            const maxPriorityItem = this.findMaxPriority(waitArr);
248            obj = {
249              cat: maxPriorityItem.cat,
250              name: maxPriorityItem.name,
251              wallDuration: minEndTs - globalTs,
252              count: maxPriorityItem.isFirstObject === 1 ? 1 : 0
253            }
254            completedArr.push(obj);
255            maxPriorityItem.isFirstObject = 0;
256            globalTs = minEndTs;
257            if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
258          }
259        } else {
260          const maxPriorityItem = this.findMaxPriority(waitArr);
261          obj = {
262            cat: maxPriorityItem.cat,
263            name: maxPriorityItem.name,
264            wallDuration: minEndTs - globalTs,
265            count: maxPriorityItem.isFirstObject === 1 ? 1 : 0
266          }
267          completedArr.push(obj);
268          maxPriorityItem.isFirstObject = 0;
269          globalTs = minEndTs;
270          if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
271        }
272      }
273      return completedArr;
274    }
275
276    private findMaxPriority(arr: IrqAndSoftirqBean[]): IrqAndSoftirqBean {
277      return arr.reduce((maxItem: IrqAndSoftirqBean, currentItem: IrqAndSoftirqBean) => {
278        return maxItem.priority > currentItem.priority ? maxItem : currentItem;
279      }, arr[0]);;
280    }
281
282    // 聚合数据
283    private aggregateData(data: finalResultBean[], isSelectIrq: boolean): void {
284      function groupAndSumDurations(items: finalResultBean[]): finalResultBean[] {
285        const grouped: Record<string, finalResultBean> = items.reduce((acc, item) => {
286          if (item.wallDuration !== 0) {
287            if (item.cat === 'irq' && !isSelectIrq) {//若没有框选irq,则不对其进行处理
288              return acc;
289            }
290            if (!acc[item.name]) {
291              acc[item.name] = {
292                wallDuration: 0,
293                maxDuration: 0,
294                name: item.name,
295                cat: item.cat,
296                count: 0,
297                avgDuration: 0
298              };
299            }
300            acc[item.name].wallDuration += item.wallDuration;
301            acc[item.name].wallDurationFormat = (acc[item.name].wallDuration / 1000).toFixed(2);
302            acc[item.name].count += item.count;
303            acc[item.name].avgDuration = (acc[item.name].wallDuration / acc[item.name].count / 1000).toFixed(2);
304            if (item.wallDuration > acc[item.name].maxDuration!) {
305              acc[item.name].maxDuration = item.wallDuration;
306              acc[item.name].maxDurationFormat = (acc[item.name].maxDuration! / 1000).toFixed(2);
307            }
308          }
309          return acc;
310        }, {} as Record<string, finalResultBean>);
311        return Object.values(grouped);
312      }
313      this.irqAndSoftirqSource = groupAndSumDurations(data);
314      this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource;
315    }
316
317    private reSortByColum(key: string, type: number): void {
318      // 如果数组为空,则直接返回
319      if (!this.irqAndSoftirqSource.length) return;
320      let sortObject: finalResultBean[] = JSON.parse(JSON.stringify(this.irqAndSoftirqSource));
321      let sortList: Array<finalResultBean> = [];
322      sortList.push(...sortObject);
323      if (type === 0) {
324        this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource;
325      } else {
326        sortList.sort((a, b) => {
327          let aValue: number | string, bValue: number | string;
328          if (key === 'name' || key === 'cat') {
329            aValue = a[key];
330            bValue = b[key];
331          } else {
332            // @ts-ignore
333            aValue = parseFloat(a[key]);
334            // @ts-ignore
335            bValue = parseFloat(b[key]);
336          }
337          if (typeof aValue === 'string' && typeof bValue === 'string') {
338            return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
339          } else if (typeof aValue === 'number' && typeof bValue === 'number') {
340            return type === 1 ? aValue - bValue : bValue - aValue;
341          } else {
342            return 0;
343          }
344        });
345        this.irqCounterTbl!.recycleDataSource = sortList;
346      }
347  }
348}
349