• 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 {
18  LitTable,
19  RedrawTreeForm,
20} from '../../../../../base-ui/table/lit-table';
21import { SelectionParam } from '../../../../bean/BoxSelection';
22import '../../../StackBar';
23import { getTabRunningPercent } from '../../../../database/sql/ProcessThread.sql';
24import {
25  queryCpuFreqUsageData,
26  queryCpuFreqFilterId,
27} from '../../../../database/sql/Cpu.sql';
28import { Utils } from '../../base/Utils';
29import { resizeObserver } from '../SheetUtils';
30import { SpSegmentationChart } from '../../../chart/SpSegmentationChart';
31import {
32  type CpuFreqData,
33  type RunningFreqData,
34  type RunningData,
35  type CpuFreqTd,
36} from './TabPaneFreqUsageConfig';
37import { getCpuData } from '../../../../database/sql/CpuAndIrq.sql';
38
39@element('tabpane-frequsage')
40export class TabPaneFreqUsage extends BaseElement {
41  private threadStatesTbl: LitTable | null | undefined;
42  private currentSelectionParam: SelectionParam | undefined;
43  private worker: Worker | undefined;
44  static element: TabPaneFreqUsage;
45  private sortConsumpowerFlags: number = 0;
46  private sortConsumptionFlags: number = 0;
47  private sortCpuloadFlags: number = 0;
48  private sortDurFlags: number = 0;
49  private sortPercentFlags: number = 0;
50
51  set data(threadStatesParam: SelectionParam) {
52    if (this.currentSelectionParam === threadStatesParam) {
53      return;
54    }
55    this.currentSelectionParam = threadStatesParam;
56    this.threadStatesTbl!.recycleDataSource = [];
57    // @ts-ignore
58    this.threadStatesTbl.value = [];
59    this.queryAllData(threadStatesParam);
60  }
61
62  static refresh(): void {
63    this.prototype.queryAllData(TabPaneFreqUsage.element.currentSelectionParam!);
64  }
65
66  async queryAllData(threadStatesParam: SelectionParam): Promise<void> {
67    TabPaneFreqUsage.element.threadStatesTbl!.loading = true;
68    let runningResult: Array<RunningData> = await getTabRunningPercent(
69      threadStatesParam.threadIds,
70      threadStatesParam.processIds,
71      threadStatesParam.leftNs,
72      threadStatesParam.rightNs
73    );
74    // 查询cpu及id信息
75    let cpuIdResult: Array<{ id: number; cpu: number }> =
76      await queryCpuFreqFilterId();
77    // 以键值对形式将cpu及id进行对应,后续会将频点数据与其对应cpu进行整合
78    let IdMap: Map<number, number> = new Map();
79    let queryId: Array<number> = [];
80    let cpuArray: Array<number> = [];
81    for (let i = 0; i < cpuIdResult.length; i++) {
82      queryId.push(cpuIdResult[i].id);
83      IdMap.set(cpuIdResult[i].id, cpuIdResult[i].cpu);
84      cpuArray.push(cpuIdResult[i].cpu);
85    }
86    // 通过id去查询频点数据
87    let cpuFreqResult: Array<CpuFreqTd> = await queryCpuFreqUsageData(queryId);
88    let cpuFreqData: Array<CpuFreqData> = [];
89    for (let i of cpuFreqResult) {
90      cpuFreqData.push({
91        ts: i.startNS + threadStatesParam.recordStartNs,
92        cpu: IdMap.get(i.filter_id)!,
93        value: i.value,
94        dur: i.dur,
95      });
96    }
97    const cpuData = await getCpuData(cpuArray, threadStatesParam.leftNs, threadStatesParam.rightNs);
98    const LEFT_TIME: number = threadStatesParam.leftNs + threadStatesParam.recordStartNs;
99    const RIGHT_TIME: number = threadStatesParam.rightNs + threadStatesParam.recordStartNs;
100    const comPower =
101      SpSegmentationChart.freqInfoMapData.size > 0
102        ? SpSegmentationChart.freqInfoMapData
103        : undefined;
104    const args = {
105      runData: runningResult,
106      cpuFreqData: cpuFreqData,
107      leftNs: LEFT_TIME,
108      rightNs: RIGHT_TIME,
109      cpuArray: cpuArray,
110      comPower: comPower,
111      broCpuData: cpuData,
112      // @ts-ignore
113      recordStartNS: (window as unknown).recordStartNS
114    };
115    TabPaneFreqUsage.element.worker!.postMessage(args);
116    TabPaneFreqUsage.element.worker!.onmessage = (event: MessageEvent): void => {
117      let resultArr: Array<RunningFreqData> = event.data;
118      TabPaneFreqUsage.element.fixedDeal(resultArr, threadStatesParam.traceId);
119      TabPaneFreqUsage.element.threadClick(resultArr);
120      TabPaneFreqUsage.element.threadStatesTbl!.recycleDataSource = resultArr;
121      TabPaneFreqUsage.element.threadStatesTbl!.loading = false;
122    };
123  }
124
125  /**
126   * 表头点击事件
127   */
128  private threadClick(data: Array<RunningFreqData>): void {
129    let labels = this.threadStatesTbl?.shadowRoot
130      ?.querySelector('.th > .td')!
131      .querySelectorAll('label');
132    let tabHeads = this.threadStatesTbl?.shadowRoot
133      ?.querySelector('.th')!.querySelectorAll('.td');
134    if (labels) {
135      for (let i = 0; i < labels.length; i++) {
136        let label = labels[i].innerHTML;
137        labels[i].addEventListener('click', (e) => {
138          if (label.includes('Process') && i === 0) {
139            this.threadStatesTbl!.setStatus(data, false);
140            this.threadStatesTbl!.recycleDs =
141              this.threadStatesTbl!.meauseTreeRowElement(
142                data,
143                RedrawTreeForm.Retract
144              );
145          } else if (label.includes('Thread') && i === 1) {
146            for (let item of data) {
147              // @ts-ignore
148              item.status = true;
149              if (item.children !== undefined && item.children.length > 0) {
150                this.threadStatesTbl!.setStatus(item.children, false);
151              }
152            }
153            this.threadStatesTbl!.recycleDs =
154              this.threadStatesTbl!.meauseTreeRowElement(
155                data,
156                RedrawTreeForm.Retract
157              );
158          } else if (label.includes('CPU') && i === 2) {
159            this.threadStatesTbl!.setStatus(data, true);
160            this.threadStatesTbl!.recycleDs =
161              this.threadStatesTbl!.meauseTreeRowElement(
162                data,
163                RedrawTreeForm.Expand
164              );
165          }
166        });
167      }
168    }
169    if (tabHeads && tabHeads.length) {
170      this.restoreFlags();
171      tabHeads.forEach((item) => {
172        // @ts-ignore
173        switch (item.innerText) {
174          case 'Consume(cap*ms)':
175            item.addEventListener('click', () => { this.sortDataTree(data, 'Consume(cap*ms)') });
176            break;
177          case 'Consume(MHz*ms)':
178            item.addEventListener('click', () => { this.sortDataTree(data, 'Consume(MHz*ms)') });
179            break;
180          case 'TaskUtil(%)':
181            item.addEventListener('click', () => { this.sortDataTree(data, 'TaskUtil') });
182            break;
183          case 'Dur(ms)':
184            item.addEventListener('click', () => { this.sortDataTree(data, 'Dur') });
185            break;
186          case 'Dur\n/All_Dur(%)':
187            item.addEventListener('click', () => { this.sortDataTree(data, 'All_Dur') });
188            break;
189        }
190      })
191    }
192  }
193
194  sortDataTree(data: Array<RunningFreqData>, type: string) {
195    this.threadStatesTbl!.recycleDs = this.sortTree(data, type);
196    this.threadStatesTbl!.recycleDs =
197      this.threadStatesTbl!.meauseTreeRowElement(
198        data,
199        RedrawTreeForm.Expand
200      );
201    switch (type) {
202      case 'Consume(cap*ms)':
203        this.sortConsumptionFlags = 0;
204        this.sortCpuloadFlags = 0;
205        this.sortDurFlags = 0;
206        this.sortPercentFlags = 0;
207        if (this.sortConsumpowerFlags === 2) {
208          this.sortConsumpowerFlags = 0;
209        } else {
210          this.sortConsumpowerFlags++;
211        }
212        break;
213      case 'Consume(MHz*ms)':
214        this.sortConsumpowerFlags = 0;
215        this.sortCpuloadFlags = 0;
216        this.sortDurFlags = 0;
217        this.sortPercentFlags = 0;
218        if (this.sortConsumptionFlags === 2) {
219          this.sortConsumptionFlags = 0;
220        } else {
221          this.sortConsumptionFlags++;
222        }
223        break;
224      case 'TaskUtil':
225        this.sortConsumpowerFlags = 0;
226        this.sortConsumptionFlags = 0;
227        this.sortDurFlags = 0;
228        this.sortPercentFlags = 0;
229        if (this.sortCpuloadFlags === 2) {
230          this.sortCpuloadFlags = 0;
231        } else {
232          this.sortCpuloadFlags++;
233        }
234        break;
235      case 'Dur':
236        this.sortConsumpowerFlags = 0;
237        this.sortConsumptionFlags = 0;
238        this.sortCpuloadFlags = 0;
239        this.sortPercentFlags = 0;
240        if (this.sortDurFlags === 2) {
241          this.sortDurFlags = 0;
242        } else {
243          this.sortDurFlags++;
244        }
245        break;
246      case 'All_Dur':
247        this.sortConsumpowerFlags = 0;
248        this.sortConsumptionFlags = 0;
249        this.sortCpuloadFlags = 0;
250        this.sortDurFlags = 0;
251        if (this.sortPercentFlags === 2) {
252          this.sortPercentFlags = 0;
253        } else {
254          this.sortPercentFlags++;
255        }
256        break;
257    }
258  }
259
260  sortTree(arr: Array<unknown>, type: string): Array<unknown> {
261    if (arr.length > 1) {
262      // @ts-ignore
263      arr = arr.sort((sortArrA, sortArrB): number => {
264        // @ts-ignore
265        if (sortArrA.depth === sortArrB.depth) {
266          switch (type) {
267            case 'Consume(cap*ms)':
268              if (this.sortConsumpowerFlags === 0) {
269                //@ts-ignore
270                return Number(sortArrA.consumpower) - Number(sortArrB.consumpower);
271              } else if (this.sortConsumpowerFlags === 1) {
272                //@ts-ignore
273                return Number(sortArrB.consumpower) - Number(sortArrA.consumpower);
274              } else {
275                //@ts-ignore
276                return Number(sortArrA.cpu) - Number(sortArrB.cpu);
277              }
278              break;
279            case 'Consume(MHz*ms)':
280              if (this.sortConsumptionFlags === 0) {
281                //@ts-ignore
282                return Number(sortArrA.consumption) - Number(sortArrB.consumption);
283              } else if (this.sortConsumptionFlags === 1) {
284                //@ts-ignore
285                return Number(sortArrB.consumption) - Number(sortArrA.consumption);
286              } else {
287                //@ts-ignore
288                return Number(sortArrA.cpu) - Number(sortArrB.cpu);
289              }
290              break;
291            case 'TaskUtil':
292              if (this.sortCpuloadFlags === 0) {
293                //@ts-ignore
294                return Number(sortArrA.cpuload) - Number(sortArrB.cpuload);
295              } else if (this.sortCpuloadFlags === 1) {
296                //@ts-ignore
297                return Number(sortArrB.cpuload) - Number(sortArrA.cpuload);
298              } else {
299                //@ts-ignore
300                return Number(sortArrA.cpu) - Number(sortArrB.cpu);
301              }
302              break;
303            case 'Dur':
304              if (this.sortDurFlags === 0) {
305                //@ts-ignore
306                return Number(sortArrA.dur) - Number(sortArrB.dur);
307              } else if (this.sortDurFlags === 1) {
308                //@ts-ignore
309                return Number(sortArrB.dur) - Number(sortArrA.dur);
310              } else {
311                //@ts-ignore
312                return Number(sortArrA.cpu) - Number(sortArrB.cpu);
313              }
314              break;
315            case 'All_Dur':
316              if (this.sortPercentFlags === 0) {
317                //@ts-ignore
318                return Number(sortArrA.percent) - Number(sortArrB.percent);
319              } else if (this.sortPercentFlags === 1) {
320                //@ts-ignore
321                return Number(sortArrB.percent) - Number(sortArrA.percent);
322              } else {
323                //@ts-ignore
324                return Number(sortArrA.cpu) - Number(sortArrB.cpu);
325              }
326              break;
327          }
328        }
329      })
330    }
331    arr.map((call: unknown): void => {
332      // @ts-ignore
333      if (call.children && call.children.length > 1 && call.status) {
334        // @ts-ignore
335        call.children = this.sortTree(call.children, type);
336      }
337    })
338    return arr;
339  }
340
341  restoreFlags() {
342    this.sortConsumpowerFlags = 0;
343    this.sortConsumptionFlags = 0;
344    this.sortCpuloadFlags = 0;
345    this.sortDurFlags = 0;
346    this.sortPercentFlags = 0;
347  }
348
349
350  initElements(): void {
351    this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>(
352      '#tb-running-percent'
353    );
354    //开启一个线程计算busyTime
355    this.worker = new Worker(
356      new URL('../../../../database/TabPaneFreqUsageWorker', import.meta.url)
357    );
358    TabPaneFreqUsage.element = this;
359  }
360
361  connectedCallback(): void {
362    super.connectedCallback();
363    resizeObserver(this.parentElement!, this.threadStatesTbl!, 20);
364  }
365
366  initHtml(): string {
367    return `
368        <style>
369        :host{
370            padding: 10px 10px;
371            display: flex;
372            flex-direction: column;
373        }
374        </style>
375        <lit-table id="tb-running-percent" style="height: auto; overflow-x:auto;" tree>
376          <lit-table-column class="running-percent-column" width="320px" title="Process/Thread/CPU" data-index="thread" key="thread" align="flex-start" retract>
377          </lit-table-column>
378          <lit-table-column class="running-percent-column" width="100px" title="CPU" data-index="cpu" key="cpu" align="flex-start">
379          </lit-table-column>
380          <lit-table-column class="running-percent-column" width="240px" title="Consume(MHz*ms)" data-index="consumption" key="consumption" align="flex-start">
381          </lit-table-column>
382          <lit-table-column class="running-percent-column" width="200px" title="Freq(MHz:Cap)" data-index="frequency" key="frequency" align="flex-start">
383          </lit-table-column>
384          <lit-table-column class="running-percent-column" width="240px" title="Consume(cap*ms)" data-index="consumpower" key="consumpower" align="flex-start">
385          </lit-table-column>
386          <lit-table-column class="running-percent-column" width="100px" title="TaskUtil(%)" data-index="cpuload" key="cpuload" align="flex-start">
387          </lit-table-column>
388          <lit-table-column class="running-percent-column" width="200px" title="Dur(ms)" data-index="dur" key="dur" align="flex-start">
389          </lit-table-column>
390          <lit-table-column class="running-percent-column" width="140px" title="Dur/All_Dur(%)" data-index="percent" key="percent" align="flex-start">
391          </lit-table-column>
392        </lit-table>
393        `;
394  }
395
396  /**
397   * 递归整理数据小数位
398   */
399  fixedDeal(arr: Array<RunningFreqData>, traceId?: string | null): void {
400    if (arr == undefined) {
401      return;
402    }
403    const TIME_MUTIPLE: number = 1000000;
404    // KHz->MHz  *  ns->ms
405    const CONS_MUTIPLE: number = 1000000000;
406    const MIN_PERCENT: number = 2;
407    const MIN_FREQ: number = 3;
408    const MIN_POWER: number = 6;
409    for (let i = 0; i < arr.length; i++) {
410      let trackId: number;
411      // 若存在空位元素则进行删除处理
412      if (arr[i] === undefined) {
413        arr.splice(i, 1);
414        i--;
415        continue;
416      }
417      if (arr[i].thread?.indexOf('P') !== -1) {
418        trackId = Number(arr[i].thread?.slice(1)!);
419        arr[i].thread = `${Utils.getInstance().getProcessMap(traceId).get(trackId) || 'Process'} ${trackId}`;
420      } else if (arr[i].thread === 'summary data') {
421      } else {
422        trackId = Number(arr[i].thread!.split('_')[1]);
423        arr[i].thread = `${Utils.getInstance().getThreadMap(traceId).get(trackId) || 'Thread'} ${trackId}`;
424      }
425      if (arr[i].cpu < 0) {
426        // @ts-ignore
427        arr[i].cpu = '';
428      }
429      // @ts-ignore
430      if (arr[i].frequency < 0) {
431        arr[i].frequency = '';
432      }
433      if (!arr[i].cpuload) {
434        // @ts-ignore
435        arr[i].cpuload = '0.000000';
436      } else {
437        // @ts-ignore
438        arr[i].cpuload = arr[i].cpuload.toFixed(MIN_POWER);
439      }
440      // @ts-ignore
441      arr[i].percent = arr[i].percent.toFixed(MIN_PERCENT);
442      // @ts-ignore
443      arr[i].dur = (arr[i].dur / TIME_MUTIPLE).toFixed(MIN_FREQ);
444      // @ts-ignore
445      arr[i].consumption = (arr[i].consumption / CONS_MUTIPLE).toFixed(MIN_FREQ);
446      // @ts-ignore
447      arr[i].consumpower = (arr[i].consumpower / TIME_MUTIPLE).toFixed(MIN_FREQ);
448      if (arr[i].frequency !== '') {
449        if (arr[i].frequency === 'unknown') {
450          arr[i].frequency = 'unknown';
451        } else {
452          arr[i].frequency = arr[i].frequency;
453        }
454      }
455      this.fixedDeal(arr[i].children!, traceId);
456    }
457  }
458}