• 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) {
218            const item = waitArr[minIndex];
219            if (item.endTime > item.startTime) {
220              waitArr.splice(minIndex, 1);
221            } else {
222              // wallDuration为0,需要特别处理
223              const obj: finalResultBean = {
224                cat: item.cat,
225                name: item.name,
226                wallDuration: 0,
227                count: item.isFirstObject === 1 ? 1 : 0
228              };
229              completedArr.push(obj);
230              waitArr.splice(minIndex, 1);
231            }
232            continue;
233          }
234        }
235        let obj: finalResultBean = {
236          cat: '',
237          name: '',
238          wallDuration: 0,
239          count: 0,
240        };
241        if (index < sourceData.length) {
242          if (sourceData[index].startTime < minEndTs) {
243            if (globalTs === sourceData[index].startTime) {
244              waitArr.push(sourceData[index]);
245              index++;
246              continue;
247            } else {
248              const maxPriorityItem = this.findMaxPriority(waitArr);
249              obj = {
250                cat: maxPriorityItem.cat,
251                name: maxPriorityItem.name,
252                wallDuration: sourceData[index].startTime - globalTs,
253                count: maxPriorityItem.isFirstObject === 1 ? 1 : 0
254              }
255              completedArr.push(obj);
256              maxPriorityItem.isFirstObject = 0;
257              waitArr.push(sourceData[index]);
258              globalTs = sourceData[index].startTime;
259              index++;
260            }
261          } else {
262            const maxPriorityItem = this.findMaxPriority(waitArr);
263            obj = {
264              cat: maxPriorityItem.cat,
265              name: maxPriorityItem.name,
266              wallDuration: minEndTs - globalTs,
267              count: maxPriorityItem.isFirstObject === 1 ? 1 : 0
268            }
269            completedArr.push(obj);
270            maxPriorityItem.isFirstObject = 0;
271            globalTs = minEndTs;
272            if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
273          }
274        } else {
275          const maxPriorityItem = this.findMaxPriority(waitArr);
276          obj = {
277            cat: maxPriorityItem.cat,
278            name: maxPriorityItem.name,
279            wallDuration: minEndTs - globalTs,
280            count: maxPriorityItem.isFirstObject === 1 ? 1 : 0
281          }
282          completedArr.push(obj);
283          maxPriorityItem.isFirstObject = 0;
284          globalTs = minEndTs;
285          if (minIndex !== -1) { waitArr.splice(minIndex, 1) };
286        }
287      }
288      return completedArr;
289    }
290
291    private findMaxPriority(arr: IrqAndSoftirqBean[]): IrqAndSoftirqBean {
292      return arr.reduce((maxItem: IrqAndSoftirqBean, currentItem: IrqAndSoftirqBean) => {
293        return maxItem.priority > currentItem.priority ? maxItem : currentItem;
294      }, arr[0]);;
295    }
296
297    // 聚合数据
298    private aggregateData(data: finalResultBean[], isSelectIrq: boolean): void {
299      function groupAndSumDurations(items: finalResultBean[]): finalResultBean[] {
300        const grouped: Record<string, finalResultBean> = items.reduce((acc, item) => {
301            if (item.cat === 'irq' && !isSelectIrq) {//若没有框选irq,则不对其进行处理
302              return acc;
303            }
304            if (!acc[item.name]) {
305              acc[item.name] = {
306                wallDuration: 0,
307                maxDuration: 0,
308                name: item.name,
309                cat: item.cat,
310                count: 0,
311                avgDuration: 0
312              };
313            }
314            acc[item.name].wallDuration += item.wallDuration;
315            acc[item.name].wallDurationFormat = (acc[item.name].wallDuration / 1000).toFixed(2);
316            acc[item.name].count += item.count;
317            acc[item.name].avgDuration = (acc[item.name].wallDuration / acc[item.name].count / 1000).toFixed(2);
318            if (item.wallDuration > acc[item.name].maxDuration!) {
319              acc[item.name].maxDuration = item.wallDuration;
320              acc[item.name].maxDurationFormat = (acc[item.name].maxDuration! / 1000).toFixed(2);
321            }
322          return acc;
323        }, {} as Record<string, finalResultBean>);
324        return Object.values(grouped);
325      }
326      this.irqAndSoftirqSource = groupAndSumDurations(data);
327      this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource;
328    }
329
330    private reSortByColum(key: string, type: number): void {
331      // 如果数组为空,则直接返回
332      if (!this.irqAndSoftirqSource.length) return;
333      let sortObject: finalResultBean[] = JSON.parse(JSON.stringify(this.irqAndSoftirqSource));
334      let sortList: Array<finalResultBean> = [];
335      sortList.push(...sortObject);
336      if (type === 0) {
337        this.irqCounterTbl!.recycleDataSource = this.irqAndSoftirqSource;
338      } else {
339        sortList.sort((a, b) => {
340          let aValue: number | string, bValue: number | string;
341          if (key === 'name' || key === 'cat') {
342            aValue = a[key];
343            bValue = b[key];
344          } else {
345            // @ts-ignore
346            aValue = parseFloat(a[key]);
347            // @ts-ignore
348            bValue = parseFloat(b[key]);
349          }
350          if (typeof aValue === 'string' && typeof bValue === 'string') {
351            return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
352          } else if (typeof aValue === 'number' && typeof bValue === 'number') {
353            return type === 1 ? aValue - bValue : bValue - aValue;
354          } else {
355            return 0;
356          }
357        });
358        this.irqCounterTbl!.recycleDataSource = sortList;
359      }
360  }
361}
362