• 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: any;
33  private frequencySampleSource: any[] = [];
34  private frequencySampleSortKey: string = 'counter';
35  private frequencySampleSortType: number = 0;
36  private systemTrace: SpSystemTrace | undefined | null;
37  private _rangeRow: Array<TraceRow<any>> | undefined | null;
38  private frequencySampleClickType: boolean = false;
39  private busyTimeLoadingHide: boolean = false;
40  private freqBusyDataList: Array<any> = [];
41  private worker: Worker | undefined;
42  private freqResult: Array<any> = [];
43
44  set data(frequencySampleValue: SelectionParam | any) {
45    if (frequencySampleValue === this.selectionParam) {
46      return;
47    }
48    this.selectionParam = frequencySampleValue;
49    if (this.frequencySampleTbl) {
50      // @ts-ignore
51      this.frequencySampleTbl.shadowRoot.querySelector('.table').style.height =
52        this.parentElement!.clientHeight - 25 + 'px';
53    }
54    this.queryDataByDB(frequencySampleValue);
55  }
56
57  set rangeTraceRow(rangeRow: Array<TraceRow<any>> | 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) => {
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) => {
76      this.clickTblRowEvent(evt);
77    });
78    this.frequencySampleTbl!.addEventListener('button-click', (evt) => {
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);
100        context.clearRect(row.frame.x, row.frame.y, row.frame.width, row.frame.height);
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              freqFilter[i].value === data.value &&
107              freqFilter[i].cpu === data.cpu &&
108              Math.max(TraceRow.rangeSelectObject?.startNS!, freqFilter[i].startNS!) <
109              Math.min(TraceRow.rangeSelectObject?.endNS!, freqFilter[i].startNS! + freqFilter[i].dur!)
110            ) {
111              CpuFreqStruct.hoverCpuFreqStruct = freqFilter[i];
112            }
113            if (freqFilter[i].cpu === data.cpu) {
114              CpuFreqStruct.draw(context, freqFilter[i]);
115            }
116          }
117        } else {
118          for (let i = 0; i < freqFilter!.length; i++) {
119            if (
120              row.name.includes('Frequency') &&
121              freqFilter[i].cpu !== data.cpu &&
122              freqFilter[i].cpu === parseInt(row.name.replace(/[^\d]/g, ' '))
123            ) {
124              CpuFreqStruct.draw(context, freqFilter[i]);
125            }
126          }
127        }
128        this.metricsText(context, row);
129      }
130    }
131  }
132
133  private metricsText(context: CanvasRenderingContext2D, row: TraceRow<any>): void {
134    let s = CpuFreqStruct.maxFreqName;
135    let textMetrics = context.measureText(s);
136    context.globalAlpha = 0.8;
137    context.fillStyle = '#f0f0f0';
138    context.fillRect(0, 5, textMetrics.width + 8, 18);
139    context.globalAlpha = 1;
140    context.fillStyle = '#333';
141    context.textBaseline = 'middle';
142    context.fillText(s, 4, 5 + 9);
143    row.canvasRestore(context, this.systemTrace);
144  }
145
146  connectedCallback() {
147    super.connectedCallback();
148    resizeObserver(this.parentElement!, this.frequencySampleTbl!, 25, this.frequencyLoadingPage, 24);
149  }
150
151  async queryDataByDB(frqSampleParam: SelectionParam | any) {
152    let sampleMap = new Map<any, any>();
153    let frqSampleList = new Array();
154    this.frequencySampleTbl!.loading = true;
155    if (this.frequencySampleClickType) this.frequencySampleClickType = !this.frequencySampleClickType;
156    if (this.busyTimeLoadingHide) this.busyTimeLoadingHide = !this.busyTimeLoadingHide;
157    let result = await getTabPaneFrequencySampleData(
158      frqSampleParam.leftNs + frqSampleParam.recordStartNs,
159      frqSampleParam.rightNs + frqSampleParam.recordStartNs,
160      frqSampleParam.cpuFreqFilterIds
161    );
162    this.freqResult = result;
163    frqSampleParam.cpuFreqFilterIds.forEach((a: number) => {
164      this.getInitTime(
165        result.filter((f) => f.filterId === a),
166        sampleMap,
167        frqSampleParam
168      );
169    });
170    sampleMap.forEach((a) => {
171      a.timeStr = parseFloat((a.time / 1000000.0).toFixed(6));
172      frqSampleList.push(a);
173    });
174    this.frequencySampleSource = frqSampleList;
175    this.frequencySampleTbl!.loading = false;
176    this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType);
177    this.getBusyTimeData(frqSampleParam, sampleMap, result);
178  }
179
180  async getBusyTimeData(frqSampleParam: SelectionParam, sampleMap: Map<any, any>, result: Array<any>) {
181    let stateFiliterIds: Array<any> = [];
182    let cpuFiliterOrder: Array<any> = [];
183    //找出框选的cpu fre所对应的cpu state
184    this.freqBusyDataList = [];
185    if (!frqSampleParam.cpuStateRowsId.length) {
186      sampleMap.forEach((value: any) => {
187        value.busyTime = 'NULL';
188        this.freqBusyDataList.push(value);
189      });
190    } else {
191      frqSampleParam.cpuFreqFilterNames.forEach((item: string) => {
192        let cpuStateIds:any = frqSampleParam.cpuStateRowsId.filter(
193          (it: any) => it.cpu === Number(item.replace(/[^\d]/g, ' ').trim())
194        );
195        stateFiliterIds.push(cpuStateIds[0].filterId);
196        cpuFiliterOrder.push(cpuStateIds[0].cpu);
197      });
198      let res = await getTabPaneCounterSampleData(
199        frqSampleParam.leftNs + frqSampleParam.recordStartNs,
200        frqSampleParam.rightNs + frqSampleParam.recordStartNs,
201        stateFiliterIds
202      );
203      let msg = {
204        frqSampleParam,
205        result,
206        sampleMap,
207        res,
208        cpuFiliterOrder,
209      };
210      this.worker!.postMessage(msg);
211      this.worker!.onmessage = (event: MessageEvent) => {
212        sampleMap = event.data;
213        sampleMap.forEach((value) => {
214          this.freqBusyDataList.push(value);
215        });
216        this.busyTimeLoadingHide = true;
217        //当busyTimebutton的状态为true但busyTime的计算未完成时
218        if (this.frequencySampleClickType) {
219          this.handleClick(this.frequencySampleSortKey, this.frequencySampleClickType);
220        }
221      };
222    }
223  }
224  getInitTime(initFreqResult: Array<any>, sampleMap: Map<any, any>, selectionParam: SelectionParam) {
225    let leftStartNs = selectionParam.leftNs + selectionParam.recordStartNs;
226    let rightEndNs = selectionParam.rightNs + selectionParam.recordStartNs;
227    if (initFreqResult.length === 0) { return };
228    let includeData = initFreqResult.findIndex((a) => a.ts >= leftStartNs);
229    if (includeData !== 0) {
230      initFreqResult = initFreqResult.slice(
231        includeData === -1 ? initFreqResult.length - 1 : includeData - 1,
232        initFreqResult.length
233      );
234    }
235    if (initFreqResult[0].ts < leftStartNs && includeData !== 0) { initFreqResult[0].ts = leftStartNs };
236    initFreqResult.forEach((item, idx) => {
237      if (idx + 1 === initFreqResult.length) {
238        item.time = rightEndNs - item.ts;
239      } else {
240        item.time = initFreqResult[idx + 1].ts - item.ts;
241      }
242      if (sampleMap.has(item.filterId + '-' + item.value)) {
243        let obj = sampleMap.get(item.filterId + '-' + item.value);
244        obj.time += item.time;
245      } else {
246        sampleMap.set(item.filterId + '-' + item.value, {
247          ...item,
248          counter: 'Cpu ' + item.cpu,
249          valueStr: ColorUtils.formatNumberComma(item.value),
250          busyTimeStr: '-',
251          busyTime: 0,
252        });
253      }
254    });
255  }
256
257  //点击按钮控制busyTime显示与否
258  handleClick(key: string, type: boolean) {
259    let res = new Array();
260    if (this.freqResult.length === 0) {
261      return;
262    }
263    //当busyTime的值计算完毕后进入if判断
264    if (this.busyTimeLoadingHide) {
265      this.busyTimeLoadingHide = false;
266      this.frequencySampleSource = this.freqBusyDataList;
267      this.sortTable(this.frequencySampleSortKey, this.frequencySampleSortType);
268    }
269    this.frequencySampleTbl!.loading = this.freqBusyDataList.length > 0 ? false : true;
270    if (this.freqBusyDataList.length > 0) {
271      this.frequencySampleTbl!.recycleDataSource.forEach((value) => {
272        value.busyTimeStr = type ? value.busyTime : '-';
273        res.push(value);
274      });
275      this.frequencySampleTbl!.recycleDataSource = res;
276    }
277  }
278
279  sortTable(key: string, type: number) {
280    if (type === 0) {
281      this.frequencySampleTbl!.recycleDataSource = this.frequencySampleSource;
282    } else {
283      let arr = Array.from(this.frequencySampleSource);
284      arr.sort((frequencySampleLeftData, frequencySampleRightData): number => {
285        if (key === 'timeStr') {
286          if (type === 1) {
287            return frequencySampleLeftData.time - frequencySampleRightData.time;
288          } else {
289            return frequencySampleRightData.time - frequencySampleLeftData.time;
290          }
291        } else if (key === 'counter') {
292          if (frequencySampleLeftData.counter > frequencySampleRightData.counter) {
293            return type === 2 ? -1 : 1;
294          } else if (frequencySampleLeftData.counter === frequencySampleRightData.counter) {
295            return 0;
296          } else {
297            return type === 2 ? 1 : -1;
298          }
299        } else if (key === 'valueStr') {
300          if (type === 1) {
301            return frequencySampleLeftData.value - frequencySampleRightData.value;
302          } else {
303            return frequencySampleRightData.value - frequencySampleLeftData.value;
304          }
305        } else if (key === 'busyTimeStr') {
306          if (type === 1) {
307            return frequencySampleLeftData.busyTimeStr - frequencySampleRightData.busyTimeStr;
308          } else {
309            return frequencySampleRightData.busyTimeStr - frequencySampleLeftData.busyTimeStr;
310          }
311        } else {
312          return 0;
313        }
314      });
315      this.frequencySampleTbl!.recycleDataSource = arr;
316    }
317  }
318
319  initHtml(): string {
320    return `
321        <style>
322        :host{
323            display: flex;
324            padding: 10px 10px;
325            flex-direction: column;
326        }
327        </style>
328        <lit-table id="tb-states" style="height: auto" >
329            <lit-table-column class="freq-sample-column" width="20%" title="Cpu" data-index="counter" key="counter" align="flex-start" order>
330            </lit-table-column>
331            <lit-table-column class="freq-sample-column" width="1fr" title="Time(ms)" data-index="timeStr" key="timeStr" align="flex-start" order>
332            </lit-table-column>
333            <lit-table-column class="freq-sample-column" width="1fr" title="Value(kHz)" data-index="valueStr" key="valueStr" align="flex-start" order>
334            </lit-table-column>
335            <lit-table-column class="freq-sample-column" width="1fr" title="" data-index="busyTimeStr" key="busyTimeStr" align="flex-start" order button>
336            </lit-table-column>
337        </lit-table>
338        `;
339  }
340}
341