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