• 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 { type LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table';
18import { type SelectionParam } from '../../../../bean/BoxSelection';
19import { getGpufreqData } from '../../../../database/sql/Perf.sql';
20import { resizeObserver } from '../SheetUtils';
21import { type GpuCountBean, TreeDataBean, TreeDataStringBean } from '../../../../bean/GpufreqBean';
22
23@element('tabpane-gpufreq')
24export class TabPaneGpufreq extends BaseElement {
25  private threadStatesTbl: LitTable | null | undefined;
26  private currentSelectionParam: SelectionParam | undefined;
27  private SUB_LENGTH: number = 3;
28  private PERCENT_SUB_LENGTH: number = 2;
29  private UNIT: number = 1000000;
30  private KUNIT: number = 1000000000000;
31
32  set data(clockCounterValue: SelectionParam) {
33    let finalGpufreqData: Array<TreeDataStringBean> = new Array();
34    if (this.currentSelectionParam === clockCounterValue) {
35      return;
36    }
37    this.currentSelectionParam = clockCounterValue;
38    this.threadStatesTbl!.recycleDataSource = [];
39    this.threadStatesTbl!.loading = true;
40    getGpufreqData(clockCounterValue.leftNs, clockCounterValue.rightNs, false).then(
41      (result: Array<GpuCountBean>): void => {
42        if (result !== null && result.length > 0) {
43          let resultList: Array<GpuCountBean> = JSON.parse(JSON.stringify(result));
44          resultList[0].dur = resultList[1]
45            ? resultList[1].startNS - clockCounterValue.leftNs
46            : clockCounterValue.rightNs - clockCounterValue.leftNs;
47          resultList[0].value = resultList[0].dur * resultList[0].val;
48          resultList[resultList.length - 1].dur =
49            resultList.length - 1 !== 0
50              ? clockCounterValue.rightNs - resultList[resultList.length - 1].startNS
51              : resultList[0].dur;
52          resultList[resultList.length - 1].value =
53            resultList.length - 1 !== 0
54              ? resultList[resultList.length - 1].dur * resultList[resultList.length - 1].val
55              : resultList[0].value;
56          // 将切割完成后的数据整理成树形
57          let tree: TreeDataStringBean = this.createTree(resultList);
58          finalGpufreqData.push(tree);
59          this.threadStatesTbl!.recycleDataSource = finalGpufreqData;
60          this.threadStatesTbl!.loading = false;
61          this.clickTableHeader(finalGpufreqData);
62        } else {
63          this.threadStatesTbl!.recycleDataSource = [];
64          this.threadStatesTbl!.loading = false;
65        }
66      }
67    );
68  }
69
70  initElements(): void {
71    this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-gpufreq-percent');
72  }
73
74  // 创建树形结构
75  private createTree(data: Array<GpuCountBean>): TreeDataStringBean {
76    if (data.length > 0) {
77      const root: {
78        thread: string;
79        value: number;
80        dur: number;
81        percent: number;
82        children: TreeDataBean[];
83      } = {
84        thread: 'gpufreq Frequency',
85        value: 0,
86        dur: 0,
87        percent: 100,
88        children: [],
89      };
90      const valueMap: { [freq: string]: TreeDataBean } = {};
91      data.forEach((item: GpuCountBean) => {
92        let freq: number = item.freq;
93        item.thread = `${item.thread} Frequency`;
94        this.updateValueMap(item, freq, valueMap);
95      });
96      Object.values(valueMap).forEach((node: TreeDataBean) => {
97        const parentNode: TreeDataBean = valueMap[node.freq! - 1];
98        if (parentNode) {
99          parentNode.children.push(node);
100          parentNode.dur += node.dur;
101          parentNode.value += node.value;
102        } else {
103          root.children.push(node);
104          root.dur += node.dur;
105          root.value += node.value;
106        }
107      });
108      this.flattenAndCalculate(root, root);
109      let _root = this.RetainDecimals(root);
110      return _root;
111    }
112    return new TreeDataStringBean('', '', '', '', '', '');
113  }
114  // 更新valueMap,用于整理相同频点的数据
115  private updateValueMap(item: GpuCountBean, freq: number, valueMap: { [freq: string]: TreeDataBean }): void {
116    if (!valueMap[freq]) {
117      valueMap[freq] = {
118        thread: 'gpufreq Frequency',
119        value: item.value,
120        freq: item.freq,
121        dur: item.dur,
122        percent: 100,
123        children: [],
124      };
125    } else {
126      valueMap[freq].dur += item.dur;
127      valueMap[freq].value += item.value;
128    }
129    valueMap[freq].children.push(item as unknown as TreeDataBean);
130  }
131  // 对树进行扁平化处理和计算
132  private flattenAndCalculate(node: TreeDataBean, root: TreeDataBean): void {
133    //处理百分比计算问题并保留两位小数
134    node.percent = (node.value / root.value) * 100;
135    if (node.children) {
136      node.children = node.children.flat();
137      node.children.forEach((childNode) => this.flattenAndCalculate(childNode, root));
138    }
139  }
140  // 将树形数据进行保留小数操作
141  private RetainDecimals(root: TreeDataBean): TreeDataStringBean {
142    const treeDataString: TreeDataStringBean = new TreeDataStringBean(
143      root.thread!,
144      (root.value / this.KUNIT).toFixed(this.SUB_LENGTH),
145      (root.dur / this.UNIT).toFixed(this.SUB_LENGTH),
146      root.percent!.toFixed(this.PERCENT_SUB_LENGTH),
147      String(root.level),
148      '',
149      0,
150      [],
151      '',
152      false
153    );
154    if (root.children) {
155      for (const child of root.children) {
156        treeDataString.children!.push(this.convertChildToString(child) as TreeDataStringBean);
157      }
158    }
159    return treeDataString;
160  }
161  // 将树形数据进行保留小数的具体操作
162  private convertChildToString(child: TreeDataBean | TreeDataBean[]): TreeDataStringBean | TreeDataStringBean[] {
163    if (Array.isArray(child)) {
164      if (child.length > 0) {
165        return child.map((c) => this.convertChildToString(c) as TreeDataStringBean);
166      } else {
167        return [];
168      }
169    } else if (child && child.children) {
170      return {
171        thread: child.thread as string,
172        value: (child.value / this.KUNIT).toFixed(this.SUB_LENGTH),
173        freq: '',
174        dur: (child.dur / this.UNIT).toFixed(this.SUB_LENGTH),
175        percent: child.percent ? child.percent.toFixed(this.PERCENT_SUB_LENGTH) : '',
176        children: this.convertChildToString(child.children) as unknown as TreeDataStringBean[],
177      };
178    } else {
179      return {
180        thread: child.thread as string,
181        value: (child.value / this.KUNIT).toFixed(this.SUB_LENGTH),
182        freq: child.freq ? child.freq!.toFixed(this.SUB_LENGTH) : '',
183        dur: (child.dur / this.UNIT).toFixed(this.SUB_LENGTH),
184        percent: child.percent ? child.percent.toFixed(this.PERCENT_SUB_LENGTH) : '',
185        level: String(child.level),
186      };
187    }
188  }
189  // 表头点击事件
190  private clickTableHeader(data: Array<TreeDataStringBean>): void {
191    let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label');
192    const THREAD_INDEX: number = 0;
193    const FREQ_INDEX: number = 1;
194
195    if (labels) {
196      for (let i = 0; i < labels.length; i++) {
197        let label = labels[i].innerHTML;
198        labels[i].addEventListener('click', (e) => {
199          if (label.includes('Thread') && i === THREAD_INDEX) {
200            this.threadStatesTbl!.setStatus(data, false);
201            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
202          } else if (label.includes('Freq') && i === FREQ_INDEX) {
203            for (let item of data) {
204              item.status = true;
205              if (item.children !== undefined && item.children.length > 0) {
206                this.threadStatesTbl!.setStatus(item.children, true);
207              }
208            }
209            this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand);
210          }
211        });
212      }
213    }
214  }
215  connectedCallback(): void {
216    super.connectedCallback();
217    resizeObserver(this.parentElement!, this.threadStatesTbl!);
218  }
219
220  initHtml(): string {
221    return `
222        <style>
223        :host{
224            padding: 10px 10px;
225            display: flex;
226            flex-direction: column;
227        }
228        </style>
229        <lit-table id="tb-gpufreq-percent" style="height: auto; overflow-x:auto;width:calc(100vw - 270px)" tree>
230            <lit-table-column class="gpufreq-percent-column" width='25%' title="Thread/Freq" data-index="thread" key="thread" align="flex-start" retract>
231            </lit-table-column>
232            <lit-table-column class="gpufreq-percent-column" width='1fr' title="consumption(MHz·ms)" data-index="value" key="value" align="flex-start">
233            </lit-table-column>
234            <lit-table-column class="gpufreq-percent-column" width='1fr' title="Freq(MHz)" data-index="freq" key="freq" align="flex-start">
235            </lit-table-column>
236            <lit-table-column class="gpufreq-percent-column" width='1fr' title="dur(ms)" data-index="dur" key="dur" align="flex-start">
237            </lit-table-column>
238            <lit-table-column class="gpufreq-percent-column" width='1fr' title="Percent(%)" data-index="percent" key="percent" align="flex-start">
239            </lit-table-column>
240        </lit-table>
241        `;
242  }
243}
244