• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2023 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 { getTabPaneFrequencySampleData } from '../../../../database/sql/SqlLite.sql';
20import { getTabPaneCounterSampleData } from '../../../../database/sql/Cpu.sql';
21import { ColorUtils } from '../../base/ColorUtils';
22import { resizeObserver } from '../SheetUtils';
23import { CpuFreqStruct } from '../../../../database/ui-worker/ProcedureWorkerFreq';
24import { SpSystemTrace } from '../../../SpSystemTrace';
25import { TraceRow } from '../../base/TraceRow';
26import { drawLines } from '../../../../database/ui-worker/ProcedureWorkerCommon';
27
28@element('tabpane-frequency-sample')
29export class TabPaneFrequencySample extends BaseElement {
30  private frequencySampleTbl: LitTable | null | undefined;
31  private selectionParam: SelectionParam | null | undefined;
32  private frequencyLoadingPage: unknown;
33  private frequencySampleSource: unknown[] = [];
34  private frequencySampleSortKey: string = 'counter';
35  private frequencySampleSortType: number = 0;
36  private systemTrace: SpSystemTrace | undefined | null; // @ts-ignore
37  private _rangeRow: Array<TraceRow<unknown>> | undefined | null;
38  private frequencySampleClickType: boolean = false;
39  private busyTimeLoadingHide: boolean = false;
40  private freqBusyDataList: Array<unknown> = [];
41  private worker: Worker | undefined;
42  private freqResult: Array<unknown> = [];
43
44  set data(frequencySampleValue: SelectionParam | unknown) {
45    if (frequencySampleValue === this.selectionParam) {
46      return;
47    }
48    // @ts-ignore
49    this.selectionParam = frequencySampleValue;
50    if (this.frequencySampleTbl) {
51      // @ts-ignore
52      this.frequencySampleTbl.shadowRoot.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 25}px`;
53    }
54    this.queryDataByDB(frequencySampleValue);
55  }
56  // @ts-ignore
57  set rangeTraceRow(rangeRow: Array<TraceRow<unknown>> | undefined) {
58    this._rangeRow = rangeRow;
59  }
60
61  initElements(): void {
62    this.frequencyLoadingPage = this.shadowRoot!.querySelector('.loadingFre');
63    this.frequencySampleTbl = this.shadowRoot!.querySelector<LitTable>('#tb-states');
64    this.systemTrace = document
65      .querySelector('body > sp-application')
66      ?.shadowRoot!.querySelector<SpSystemTrace>('#sp-system-trace');
67    this.frequencySampleTbl!.addEventListener('column-click', (evt): void => {
68      // @ts-ignore
69      this.frequencySampleSortKey = evt.detail.key;
70      // @ts-ignore
71      this.frequencySampleSortType = evt.detail.sort;
72      // @ts-ignore
73      this.sortTable(evt.detail.key, evt.detail.sort);
74    });
75    this.frequencySampleTbl!.addEventListener('row-click', (evt): void => {
76      this.clickTblRowEvent(evt);
77    });
78    this.frequencySampleTbl!.addEventListener('button-click', (evt): void => {
79      //@ts-ignore
80      this.frequencySampleClickKey = evt.detail.key;
81      this.frequencySampleClickType = !this.frequencySampleClickType;
82      //@ts-ignore
83      this.handleClick(evt.detail.key, this.frequencySampleClickType);
84    });
85    //开启一个线程计算busyTime
86    this.worker = new Worker(new URL('../../../../database/StateBusyTimeWorker', import.meta.url));
87  }
88  clickTblRowEvent(evt: Event): void {
89    // @ts-ignore
90    let data = evt.detail.data;
91    if (this._rangeRow && this._rangeRow!.length > 0) {
92      let rangeTraceRow = this._rangeRow!.filter(function (item) {
93        return item.name.includes('Frequency');
94      });
95      let freqFilter = [];
96      for (let row of rangeTraceRow!) {
97        let context = row.collect ? this.systemTrace!.canvasFavoritePanelCtx! : this.systemTrace!.canvasPanelCtx!;
98        freqFilter.push(...row.dataListCache);
99        row.canvasSave(context); // @ts-ignore
100        context.clearRect(row.frame.x, row.frame.y, row.frame.width, row.frame.height); // @ts-ignore
101        drawLines(context!, TraceRow.range?.xs || [], row.frame.height, this.systemTrace!.timerShaftEL!.lineColor());
102        if (row.name.includes('Frequency') && parseInt(row.name.replace(/[^\d]/g, ' ')) === data.cpu) {
103          CpuFreqStruct.hoverCpuFreqStruct = undefined;
104          for (let i = 0; i < freqFilter!.length; i++) {
105            if (
106              // @ts-ignore
107              freqFilter[i].value === data.value && // @ts-ignore
108              freqFilter[i].cpu === data.cpu && // @ts-ignore
109              Math.max(TraceRow.rangeSelectObject?.startNS!, freqFilter[i].startNS!) < // @ts-ignore
110              Math.min(TraceRow.rangeSelectObject?.endNS!, freqFilter[i].startNS! + freqFilter[i].dur!)
111            ) {
112              // @ts-ignore
113              CpuFreqStruct.hoverCpuFreqStruct = freqFilter[i];
114            } // @ts-ignore
115            if (freqFilter[i].cpu === data.cpu) {
116              // @ts-ignore
117              CpuFreqStruct.draw(context, freqFilter[i]);
118            }
119          }
120        } else {
121          for (let i = 0; i < freqFilter!.length; i++) {
122            if (
123              row.name.includes('Frequency') && // @ts-ignore
124              freqFilter[i].cpu !== data.cpu && // @ts-ignore
125              freqFilter[i].cpu === parseInt(row.name.replace(/[^\d]/g, ' '))
126            ) {
127              // @ts-ignore
128              CpuFreqStruct.draw(context, freqFilter[i]);
129            }
130          }
131        }
132        this.metricsText(context, row);
133      }
134    }
135  }
136  // @ts-ignore
137  private metricsText(context: CanvasRenderingContext2D, row: TraceRow<unknown>): void {
138    let s = CpuFreqStruct.maxFreqName;
139    let textMetrics = context.measureText(s);
140    context.globalAlpha = 0.8;
141    context.fillStyle = '#f0f0f0';
142    context.fillRect(0, 5, textMetrics.width + 8, 18);
143    context.globalAlpha = 1;
144    context.fillStyle = '#333';
145    context.textBaseline = 'middle';
146    context.fillText(s, 4, 5 + 9);
147    row.canvasRestore(context, this.systemTrace);
148  }
149
150  connectedCallback(): void {
151    super.connectedCallback();
152    // @ts-ignore
153    resizeObserver(this.parentElement!, this.frequencySampleTbl!, 25, this.frequencyLoadingPage, 24);
154  }
155
156  async queryDataByDB(frqSampleParam: SelectionParam | unknown): Promise<void> {
157    let sampleMap = new Map<unknown, unknown>();
158    let weightMap = new Map<unknown, unknown>();
159    let frqSampleList: unknown[] = [];
160    this.frequencySampleTbl!.loading = true;
161    if (this.frequencySampleClickType) {
162      this.frequencySampleClickType = !this.frequencySampleClickType;
163    }
164    if (this.busyTimeLoadingHide) {
165      this.busyTimeLoadingHide = !this.busyTimeLoadingHide;
166    }
167    let result = await getTabPaneFrequencySampleData(
168      // @ts-ignore
169      frqSampleParam.leftNs + frqSampleParam.recordStartNs,
170      // @ts-ignore
171      frqSampleParam.rightNs + frqSampleParam.recordStartNs,
172      // @ts-ignore
173      frqSampleParam.cpuFreqFilterIds
174    );
175    this.freqResult = result;
176    // @ts-ignore
177    frqSampleParam.cpuFreqFilterIds.forEach((a: number): void => {
178      weightMap.set(`${a}`, { counter: '', filterId: a });
179      this.getInitTime(
180        //@ts-ignore
181        result.filter((f) => f.filterId === a),
182        sampleMap,
183        // @ts-ignore
184        frqSampleParam
185      );
186    });
187    let tmpCpuArr = Array.from(sampleMap.entries());
188    let weightMapArr = Array.from(weightMap.entries());
189    for (let j = 0; j < weightMapArr.length; j++) {
190      // @ts-ignore
191      let singleCpuArr = tmpCpuArr.filter((item) => item[1].filterId && item[1].filterId === Number(weightMapArr[j][1].filterId));
192      let tmpTotalTime = 0;
193      let tmpTotalCount = 0;
194      for (let i = 0; i < singleCpuArr.length; i++) {
195        // @ts-ignore
196        tmpTotalTime += singleCpuArr[i][1].time;
197        // @ts-ignore
198        tmpTotalCount += singleCpuArr[i][1].time / 1000000 * singleCpuArr[i][1].value;
199      }
200      // @ts-ignore
201      let tmpPosition = tmpCpuArr.findIndex(item => item[1].filterId === weightMapArr[j][1].filterId);
202      if (singleCpuArr[0] && singleCpuArr[0].length >= 2) {
203      // @ts-ignore
204        tmpCpuArr.splice(tmpPosition, 0, [`${weightMapArr[j][1].filterId}-0`, { counter: `${singleCpuArr[0][1].counter}:( WA )`, time: tmpTotalTime, valueStr: ColorUtils.formatNumberComma(Math.round(tmpTotalCount / (tmpTotalTime / 1000000))) }]);
205      }
206    };
207    sampleMap = new Map(tmpCpuArr);
208    sampleMap.forEach((a): void => {
209      // @ts-ignore
210      if (a.time) {
211        // @ts-ignore
212        a.timeStr = parseFloat((a.time / 1000000.0).toFixed(6));
213      }
214      frqSampleList.push(a);
215    });
216    this.frequencySampleSource = frqSampleList;
217    this.frequencySampleTbl!.loading = false;
218    this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType);
219    // @ts-ignore
220    this.getBusyTimeData(frqSampleParam, sampleMap, result);
221  }
222
223  async getBusyTimeData(
224    frqSampleParam: SelectionParam,
225    sampleMap: Map<unknown, unknown>,
226    result: Array<unknown>
227  ): Promise<void> {
228    let stateFiliterIds: Array<unknown> = [];
229    let cpuFiliterOrder: Array<unknown> = [];
230    //找出框选的cpu fre所对应的cpu state
231    this.freqBusyDataList = [];
232    if (!frqSampleParam.cpuStateRowsId.length) {
233      sampleMap.forEach((value: unknown): void => {
234        // @ts-ignore
235        value.busyTime = 'NULL';
236        this.freqBusyDataList.push(value);
237      });
238    } else {
239      frqSampleParam.cpuFreqFilterNames.forEach((item: string): void => {
240        let cpuStateIds: unknown = frqSampleParam.cpuStateRowsId.filter(
241          // @ts-ignore
242          (it: unknown) => it.cpu === Number(item.replace(/[^\d]/g, ' ').trim())
243        );
244        // @ts-ignore
245        stateFiliterIds.push(cpuStateIds[0].filterId);
246        // @ts-ignore
247        cpuFiliterOrder.push(cpuStateIds[0].cpu);
248      });
249      let res = await getTabPaneCounterSampleData(
250        frqSampleParam.leftNs + frqSampleParam.recordStartNs,
251        frqSampleParam.rightNs + frqSampleParam.recordStartNs,
252        // @ts-ignore
253        stateFiliterIds
254      );
255      let msg = {
256        timeParam: {
257          leftNs: frqSampleParam.leftNs,
258          rightNs: frqSampleParam.rightNs,
259          recordStartNs: frqSampleParam.recordStartNs,
260        },
261        result,
262        sampleMap,
263        res,
264        cpuFiliterOrder,
265      };
266      this.worker!.postMessage(msg);
267      this.worker!.onmessage = (event: MessageEvent): void => {
268        sampleMap = event.data;
269        this.freqBusyDataList = [...sampleMap.values()];
270        this.busyTimeLoadingHide = true;
271        //当busyTimebutton的状态为true但busyTime的计算未完成时
272        if (this.frequencySampleClickType) {
273          this.handleClick(this.frequencySampleSortKey, this.frequencySampleClickType);
274        }
275      };
276    }
277  }
278  getInitTime(initFreqResult: Array<unknown>, sampleMap: Map<unknown, unknown>, selectionParam: SelectionParam): void {
279    let leftStartNs = selectionParam.leftNs + selectionParam.recordStartNs;
280    let rightEndNs = selectionParam.rightNs + selectionParam.recordStartNs;
281    if (initFreqResult.length === 0) {
282      return;
283    }
284    // @ts-ignore
285    let includeData = initFreqResult.findIndex((a) => a.ts > leftStartNs);
286    if (includeData !== 0) {
287      initFreqResult = initFreqResult.slice(
288        includeData === -1 ? initFreqResult.length - 1 : includeData - 1,
289        initFreqResult.length
290      );
291    }
292    // @ts-ignore
293    if (initFreqResult[0].ts < leftStartNs && includeData !== 0) {
294      // @ts-ignore
295      initFreqResult[0].ts = leftStartNs;
296    }
297    initFreqResult.forEach((item, idx): void => {
298      if (idx + 1 === initFreqResult.length) {
299        // @ts-ignore
300        item.time = rightEndNs - item.ts;
301      } else {
302        // @ts-ignore
303        item.time = initFreqResult[idx + 1].ts - item.ts;
304      }
305      // @ts-ignore
306      if (sampleMap.has(`${item.filterId}-${item.value}`)) {
307        // @ts-ignore
308        let obj = sampleMap.get(`${item.filterId}-${item.value}`);
309        // @ts-ignore
310        obj.time += item.time;
311      } else {
312        // @ts-ignore
313        sampleMap.set(`${item.filterId}-${item.value}`, {
314          // @ts-ignore
315          ...item,
316          // @ts-ignore
317          counter: `Cpu ${item.cpu}`,
318          // @ts-ignore
319          valueStr: ColorUtils.formatNumberComma(item.value),
320          busyTimeStr: '-',
321          busyTime: 0,
322        });
323      }
324    });
325  }
326
327  //点击按钮控制busyTime显示与否
328  handleClick(key: string, type: boolean): void {
329    let res: unknown[] = [];
330    if (this.freqResult.length === 0) {
331      return;
332    }
333    //当busyTime的值计算完毕后进入if判断
334    if (this.busyTimeLoadingHide) {
335      this.busyTimeLoadingHide = false;
336      this.frequencySampleSource = this.freqBusyDataList;
337      this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType);
338    }
339    this.frequencySampleTbl!.loading = this.freqBusyDataList.length <= 0;
340    if (this.freqBusyDataList.length > 0) {
341      this.frequencySampleTbl!.recycleDataSource.forEach((value): void => {
342        // @ts-ignore
343        if (value.counter.includes('( WA )')) {
344          // @ts-ignore
345          value.busyTimeStr = '-';
346        } else {
347          // @ts-ignore
348          value.busyTimeStr = type ? value.busyTime : '-';
349        }
350        res.push(value);
351      });
352      this.frequencySampleTbl!.recycleDataSource = res;
353    }
354  }
355
356  sortTable(key: string, type: number): void {
357    if (type === 0) {
358      this.frequencySampleTbl!.recycleDataSource = this.frequencySampleSource;
359    } else {
360      let arr = Array.from(this.frequencySampleSource);
361      arr.sort((frequencySampleLeftData, frequencySampleRightData): number => {
362        if (key === 'timeStr') {
363          if (type === 1) {
364            // @ts-ignore
365            return frequencySampleLeftData.time - frequencySampleRightData.time;
366          } else {
367            // @ts-ignore
368            return frequencySampleRightData.time - frequencySampleLeftData.time;
369          }
370        } else if (key === 'counter') {
371          if (type === 1) {
372            // @ts-ignore
373            return frequencySampleLeftData.cpu - frequencySampleRightData.cpu;
374          } else {
375            // @ts-ignore
376            return frequencySampleRightData.cpu - frequencySampleLeftData.cpu;
377          }
378        } else if (key === 'valueStr') {
379          if (type === 1) {
380            // @ts-ignore
381            return frequencySampleLeftData.value - frequencySampleRightData.value;
382          } else {
383            // @ts-ignore
384            return frequencySampleRightData.value - frequencySampleLeftData.value;
385          }
386        } else if (key === 'busyTimeStr') {
387          if (type === 1) {
388            // @ts-ignore
389            return frequencySampleLeftData.busyTimeStr - frequencySampleRightData.busyTimeStr;
390          } else {
391            // @ts-ignore
392            return frequencySampleRightData.busyTimeStr - frequencySampleLeftData.busyTimeStr;
393          }
394        } else {
395          return 0;
396        }
397      });
398      this.frequencySampleTbl!.recycleDataSource = arr;
399    }
400  }
401
402  initHtml(): string {
403    return `
404        <style>
405        :host{
406            display: flex;
407            padding: 10px 10px;
408            flex-direction: column;
409        }
410        </style>
411        <lit-table id="tb-states" style="height: auto" >
412            <lit-table-column class="freq-sample-column" width="20%" title="Cpu" data-index="counter" key="counter" align="flex-start" order>
413            </lit-table-column>
414            <lit-table-column class="freq-sample-column" width="1fr" title="Time(ms)" data-index="timeStr" key="timeStr" align="flex-start" order>
415            </lit-table-column>
416            <lit-table-column class="freq-sample-column" width="1fr" title="Value(kHz)" data-index="valueStr" key="valueStr" align="flex-start" order>
417            </lit-table-column>
418            <lit-table-column class="freq-sample-column" width="1fr" title="" data-index="busyTimeStr" key="busyTimeStr" align="flex-start" order button>
419            </lit-table-column>
420        </lit-table>
421        `;
422  }
423}
424