• 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
46  set data(threadStatesParam: SelectionParam) {
47    if (this.currentSelectionParam === threadStatesParam) {
48      return;
49    }
50    this.currentSelectionParam = threadStatesParam;
51    this.threadStatesTbl!.recycleDataSource = [];
52    // @ts-ignore
53    this.threadStatesTbl.value = [];
54    this.queryAllData(threadStatesParam);
55  }
56
57  static refresh(): void {
58    this.prototype.queryAllData(TabPaneFreqUsage.element.currentSelectionParam!);
59  }
60
61  async queryAllData(threadStatesParam: SelectionParam): Promise<void> {
62    TabPaneFreqUsage.element.threadStatesTbl!.loading = true;
63    let runningResult: Array<RunningData> = await getTabRunningPercent(
64      threadStatesParam.threadIds,
65      threadStatesParam.processIds,
66      threadStatesParam.leftNs,
67      threadStatesParam.rightNs
68    );
69    // 查询cpu及id信息
70    let cpuIdResult: Array<{ id: number; cpu: number }> =
71      await queryCpuFreqFilterId();
72    // 以键值对形式将cpu及id进行对应,后续会将频点数据与其对应cpu进行整合
73    let IdMap: Map<number, number> = new Map();
74    let queryId: Array<number> = [];
75    let cpuArray: Array<number> = [];
76    for (let i = 0; i < cpuIdResult.length; i++) {
77      queryId.push(cpuIdResult[i].id);
78      IdMap.set(cpuIdResult[i].id, cpuIdResult[i].cpu);
79      cpuArray.push(cpuIdResult[i].cpu);
80    }
81    // 通过id去查询频点数据
82    let cpuFreqResult: Array<CpuFreqTd> = await queryCpuFreqUsageData(queryId);
83    let cpuFreqData: Array<CpuFreqData> = [];
84    for (let i of cpuFreqResult) {
85      cpuFreqData.push({
86        ts: i.startNS + threadStatesParam.recordStartNs,
87        cpu: IdMap.get(i.filter_id)!,
88        value: i.value,
89        dur: i.dur,
90      });
91    }
92    const cpuData = await getCpuData(cpuArray, threadStatesParam.leftNs, threadStatesParam.rightNs);
93    const LEFT_TIME: number = threadStatesParam.leftNs + threadStatesParam.recordStartNs;
94    const RIGHT_TIME: number = threadStatesParam.rightNs + threadStatesParam.recordStartNs;
95    const comPower =
96      SpSegmentationChart.freqInfoMapData.size > 0
97        ? SpSegmentationChart.freqInfoMapData
98        : undefined;
99    const args = {
100      runData: runningResult,
101      cpuFreqData: cpuFreqData,
102      leftNs: LEFT_TIME,
103      rightNs: RIGHT_TIME,
104      cpuArray: cpuArray,
105      comPower: comPower,
106      broCpuData: cpuData,
107      // @ts-ignore
108      recordStartNS: (window as unknown).recordStartNS
109    };
110    TabPaneFreqUsage.element.worker!.postMessage(args);
111    TabPaneFreqUsage.element.worker!.onmessage = (event: MessageEvent): void => {
112      let resultArr: Array<RunningFreqData> = event.data;
113      TabPaneFreqUsage.element.fixedDeal(resultArr, threadStatesParam.traceId);
114      TabPaneFreqUsage.element.threadClick(resultArr);
115      TabPaneFreqUsage.element.threadStatesTbl!.recycleDataSource = resultArr;
116      TabPaneFreqUsage.element.threadStatesTbl!.loading = false;
117    };
118  }
119
120  /**
121   * 表头点击事件
122   */
123  private threadClick(data: Array<RunningFreqData>): void {
124    let labels = this.threadStatesTbl?.shadowRoot
125      ?.querySelector('.th > .td')!
126      .querySelectorAll('label');
127    if (labels) {
128      for (let i = 0; i < labels.length; i++) {
129        let label = labels[i].innerHTML;
130        labels[i].addEventListener('click', (e) => {
131          if (label.includes('Process') && i === 0) {
132            this.threadStatesTbl!.setStatus(data, false);
133            this.threadStatesTbl!.recycleDs =
134              this.threadStatesTbl!.meauseTreeRowElement(
135                data,
136                RedrawTreeForm.Retract
137              );
138          } else if (label.includes('Thread') && i === 1) {
139            for (let item of data) {
140              // @ts-ignore
141              item.status = true;
142              if (item.children !== undefined && item.children.length > 0) {
143                this.threadStatesTbl!.setStatus(item.children, false);
144              }
145            }
146            this.threadStatesTbl!.recycleDs =
147              this.threadStatesTbl!.meauseTreeRowElement(
148                data,
149                RedrawTreeForm.Retract
150              );
151          } else if (label.includes('CPU') && i === 2) {
152            this.threadStatesTbl!.setStatus(data, true);
153            this.threadStatesTbl!.recycleDs =
154              this.threadStatesTbl!.meauseTreeRowElement(
155                data,
156                RedrawTreeForm.Expand
157              );
158          }
159        });
160      }
161    }
162  }
163
164
165  initElements(): void {
166    this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>(
167      '#tb-running-percent'
168    );
169    //开启一个线程计算busyTime
170    this.worker = new Worker(
171      new URL('../../../../database/TabPaneFreqUsageWorker', import.meta.url)
172    );
173    TabPaneFreqUsage.element = this;
174  }
175
176  connectedCallback(): void {
177    super.connectedCallback();
178    resizeObserver(this.parentElement!, this.threadStatesTbl!, 20);
179  }
180
181  initHtml(): string {
182    return `
183        <style>
184        :host{
185            padding: 10px 10px;
186            display: flex;
187            flex-direction: column;
188        }
189        </style>
190        <lit-table id="tb-running-percent" style="height: auto; overflow-x:auto;" tree>
191          <lit-table-column class="running-percent-column" width="320px" title="Process/Thread/CPU" data-index="thread" key="thread" align="flex-start" retract>
192          </lit-table-column>
193          <lit-table-column class="running-percent-column" width="100px" title="CPU" data-index="cpu" key="cpu" align="flex-start">
194          </lit-table-column>
195          <lit-table-column class="running-percent-column" width="240px" title="Consume(MHz*ms)" data-index="consumption" key="consumption" align="flex-start">
196          </lit-table-column>
197          <lit-table-column class="running-percent-column" width="200px" title="Freq(MHz:Cap)" data-index="frequency" key="frequency" align="flex-start">
198          </lit-table-column>
199          <lit-table-column class="running-percent-column" width="240px" title="Consume(cap*ms)" data-index="consumpower" key="consumpower" align="flex-start">
200          </lit-table-column>
201          <lit-table-column class="running-percent-column" width="100px" title="TaskUtil(%)" data-index="cpuload" key="cpuload" align="flex-start">
202          </lit-table-column>
203          <lit-table-column class="running-percent-column" width="200px" title="Dur(ms)" data-index="dur" key="dur" align="flex-start">
204          </lit-table-column>
205          <lit-table-column class="running-percent-column" width="140px" title="Dur/All_Dur(%)" data-index="percent" key="percent" align="flex-start">
206          </lit-table-column>
207        </lit-table>
208        `;
209  }
210
211  /**
212   * 递归整理数据小数位
213   */
214  fixedDeal(arr: Array<RunningFreqData>, traceId?: string | null): void {
215    if (arr == undefined) {
216      return;
217    }
218    const TIME_MUTIPLE: number = 1000000;
219    // KHz->MHz  *  ns->ms
220    const CONS_MUTIPLE: number = 1000000000;
221    const MIN_PERCENT: number = 2;
222    const MIN_FREQ: number = 3;
223    const MIN_POWER: number = 6;
224    for (let i = 0; i < arr.length; i++) {
225      let trackId: number;
226      // 若存在空位元素则进行删除处理
227      if (arr[i] === undefined) {
228        arr.splice(i, 1);
229        i--;
230        continue;
231      }
232      if (arr[i].thread?.indexOf('P') !== -1) {
233        trackId = Number(arr[i].thread?.slice(1)!);
234        arr[i].thread = `${Utils.getInstance().getProcessMap(traceId).get(trackId) || 'Process'} ${trackId}`;
235      } else if (arr[i].thread === 'summary data') {
236      } else {
237        trackId = Number(arr[i].thread!.split('_')[1]);
238        arr[i].thread = `${Utils.getInstance().getThreadMap(traceId).get(trackId) || 'Thread'} ${trackId}`;
239      }
240      if (arr[i].cpu < 0) {
241        // @ts-ignore
242        arr[i].cpu = '';
243      }
244      // @ts-ignore
245      if (arr[i].frequency < 0) {
246        arr[i].frequency = '';
247      }
248      if (!arr[i].cpuload) {
249        // @ts-ignore
250        arr[i].cpuload = '0.000000';
251      } else {
252        // @ts-ignore
253        arr[i].cpuload = arr[i].cpuload.toFixed(MIN_POWER);
254      }
255      // @ts-ignore
256      arr[i].percent = arr[i].percent.toFixed(MIN_PERCENT);
257      // @ts-ignore
258      arr[i].dur = (arr[i].dur / TIME_MUTIPLE).toFixed(MIN_FREQ);
259      // @ts-ignore
260      arr[i].consumption = (arr[i].consumption / CONS_MUTIPLE).toFixed(MIN_FREQ);
261      // @ts-ignore
262      arr[i].consumpower = (arr[i].consumpower / TIME_MUTIPLE).toFixed(MIN_FREQ);
263      if (arr[i].frequency !== '') {
264        if (arr[i].frequency === 'unknown') {
265          arr[i].frequency = 'unknown';
266        } else {
267          arr[i].frequency = arr[i].frequency;
268        }
269      }
270      this.fixedDeal(arr[i].children!, traceId);
271    }
272  }
273}