• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2022 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, RedrawTreeForm } from '../../../../../base-ui/table/lit-table';
18import { SelectionParam } from '../../../../bean/BoxSelection';
19import { resizeObserver } from '../SheetUtils';
20import { Utils } from '../../base/Utils';
21import { Priority } from '../../../../bean/StateProcessThread';
22import { queryThreadStateArgsByName } from '../../../../database/sql/ProcessThread.sql';
23import { FlagsConfig } from '../../../SpFlags';
24import { sliceSPTSender } from '../../../../database/data-trafic/SliceSender';
25
26@element('tabpane-sched-priority')
27export class TabPaneSchedPriority extends BaseElement {
28  private priorityTbl: LitTable | null | undefined;
29  private range: HTMLLabelElement | null | undefined;
30  private selectionParam: SelectionParam | null | undefined;
31  private strValueMap: Map<number, string> = new Map<number, string>();
32
33  set data(sptValue: SelectionParam) {
34    if (sptValue === this.selectionParam) {
35      return;
36    }
37    this.selectionParam = sptValue;
38    if (this.priorityTbl) {
39      // @ts-ignore
40      this.priorityTbl.shadowRoot.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 45}px`;
41    }
42    this.range!.textContent = `Selected range: ${parseFloat(
43      ((sptValue.rightNs - sptValue.leftNs) / 1000000.0).toFixed(5)
44    )} ms`;
45    this.queryDataByDB(sptValue);
46  }
47
48  public initElements(): void {
49    this.priorityTbl = this.shadowRoot?.querySelector<LitTable>('#priority-tbl');
50    this.range = this.shadowRoot?.querySelector('#priority-time-range');
51  }
52
53  public connectedCallback(): void {
54    super.connectedCallback();
55    resizeObserver(this.parentElement!, this.priorityTbl!);
56  }
57
58  private async queryDataByDB(sptParam: SelectionParam | unknown): Promise<void> {
59    this.priorityTbl!.loading = true;
60    const resultData: Array<Priority> = [];
61    await this.fetchAndProcessData();
62
63    const filterList = ['0', '0x0']; //next_info第2字段不为0 || next_info第3字段不为0
64    // 通过priority与next_info结合判断优先级等级
65    function setPriority(item: Priority, strArg: string[]): void {
66      let flagsItem = window.localStorage.getItem(FlagsConfig.FLAGS_CONFIG_KEY);
67      let flagsItemJson = JSON.parse(flagsItem!);
68      let hmKernel = flagsItemJson.HMKernel;
69      if (hmKernel === 'Enabled') {
70        if (item.priority >= 0 && item.priority <= 40) {
71          item.priorityType = 'CFS';
72        } else {
73          item.priorityType = 'RT';
74        }
75      } else {
76        if (item.priority >= 0 && item.priority <= 88) {
77          item.priorityType = 'RT';
78        } else if (item.priority >= 89 && item.priority <= 99) {
79          item.priorityType = 'VIP2.0';
80        } else if (
81          item.priority >= 100 &&
82          strArg.length > 1 &&
83          (!filterList.includes(strArg[1]) || !filterList.includes(strArg[2]))
84        ) {
85          item.priorityType = 'STATIC_VIP';
86        } else {
87          item.priorityType = 'CFS';
88        }
89      }
90    }
91    // thread_state表中runnable数据的Map
92    const runnableMap = new Map<string, Priority>();
93    // @ts-ignore
94    sliceSPTSender(sptParam.leftNs, sptParam.rightNs, [], 'spt-getCpuPriorityByTime', sptParam.traceId).then(res => {
95      for (const item of res) {
96        //@ts-ignore
97        if (['R', 'R+'].includes(item.state)) {
98          //@ts-ignore
99          runnableMap.set(`${item.id}_${item.startTime + item.dur}`, item);
100        }
101        // @ts-ignore
102        if (item.cpu === null || !sptParam.cpus.includes(item.cpu)) {
103          continue;
104        }
105        this.fetchData(item, setPriority, resultData, runnableMap);
106      }
107      this.getDataByPriority(resultData);
108    });
109  }
110
111  private fetchData(
112    item: any,
113    setPriority: (item: Priority, strArg: string[]) => void,
114    resultData: Array<Priority>,
115    runnableMap: Map<string, Priority>
116  ): void {
117    let strArg: string[] = [];
118    const args = this.strValueMap.get(item.argSetId);
119    if (args) {
120      strArg = args!.split(',');
121    }
122    const slice = Utils.getInstance().getSchedSliceMap(Utils.currentSelectTrace).get(`${item.id}-${item.startTime}`);
123    if (slice) {
124      const runningPriority = new Priority();
125      runningPriority.priority = slice.priority;
126      runningPriority.state = 'Running';
127      runningPriority.dur = item.dur;
128      setPriority(runningPriority, strArg);
129      resultData.push(runningPriority);
130
131      const runnableItem = runnableMap.get(`${item.id}_${item.startTime}`);
132      if (runnableItem) {
133        const runnablePriority = new Priority();
134        runnablePriority.priority = slice.priority;
135        runnablePriority.state = 'Runnable';
136        runnablePriority.dur = runnableItem.dur;
137        setPriority(runnablePriority, strArg);
138        resultData.push(runnablePriority);
139      }
140    }
141  }
142
143  private async fetchAndProcessData(): Promise<void> {
144    if (this.strValueMap.size === 0) {
145      await queryThreadStateArgsByName('next_info', this.selectionParam?.traceId || undefined).
146      then((value): void => {
147        for (const item of value) {
148          this.strValueMap.set(item.argset, item.strValue);
149        }
150      });
151    }
152  }
153
154  private getDataByPriority(source: Array<Priority>): void {
155    const priorityMap: Map<string, Priority> = new Map<string, Priority>();
156    const stateMap: Map<string, Priority> = new Map<string, Priority>();
157    this.prepareMaps(source, priorityMap, stateMap);
158
159    const priorityArr: Array<Priority> = [];
160    for (const key of priorityMap.keys()) {
161      const ptsValues = priorityMap.get(key);
162      ptsValues!.children = [];
163      for (const itemKey of stateMap.keys()) {
164        if (itemKey.startsWith(`${key}_`)) {
165          const sp = stateMap.get(itemKey);
166          ptsValues!.children.push(sp!);
167        }
168      }
169      priorityArr.push(ptsValues!);
170    }
171    this.priorityTbl!.loading = false;
172    this.priorityTbl!.recycleDataSource = priorityArr;
173    this.theadClick(priorityArr);
174  }
175
176  private prepareMaps(
177    source: Array<Priority>,
178    priorityMap: Map<string, Priority>,
179    stateMap: Map<string, Priority>
180  ): void {
181    source.map((priorityItem): void => {
182      if (priorityMap.has(`${priorityItem.priorityType}`)) {
183        const priorityMapObj = priorityMap.get(`${priorityItem.priorityType}`);
184        priorityMapObj!.count++;
185        priorityMapObj!.wallDuration += priorityItem.dur;
186        priorityMapObj!.avgDuration = (priorityMapObj!.wallDuration / priorityMapObj!.count).toFixed(2);
187        if (priorityItem.dur > priorityMapObj!.maxDuration) {
188          priorityMapObj!.maxDuration = priorityItem.dur;
189        }
190        if (priorityItem.dur < priorityMapObj!.minDuration) {
191          priorityMapObj!.minDuration = priorityItem.dur;
192        }
193      } else {
194        const stateMapObj = new Priority();
195        stateMapObj.title = priorityItem.priorityType;
196        stateMapObj.minDuration = priorityItem.dur;
197        stateMapObj.maxDuration = priorityItem.dur;
198        stateMapObj.count = 1;
199        stateMapObj.avgDuration = `${priorityItem.dur}`;
200        stateMapObj.wallDuration = priorityItem.dur;
201        priorityMap.set(`${priorityItem.priorityType}`, stateMapObj);
202      }
203      if (stateMap.has(`${priorityItem.priorityType}_${priorityItem.state}`)) {
204        const ptsPtMapObj = stateMap.get(`${priorityItem.priorityType}_${priorityItem.state}`);
205        ptsPtMapObj!.count++;
206        ptsPtMapObj!.wallDuration += priorityItem.dur;
207        ptsPtMapObj!.avgDuration = (ptsPtMapObj!.wallDuration / ptsPtMapObj!.count).toFixed(2);
208        if (priorityItem.dur > ptsPtMapObj!.maxDuration) {
209          ptsPtMapObj!.maxDuration = priorityItem.dur;
210        }
211        if (priorityItem.dur < ptsPtMapObj!.minDuration) {
212          ptsPtMapObj!.minDuration = priorityItem.dur;
213        }
214      } else {
215        const ptsPtMapObj = new Priority();
216        ptsPtMapObj.title = priorityItem.state;
217        ptsPtMapObj.minDuration = priorityItem.dur;
218        ptsPtMapObj.maxDuration = priorityItem.dur;
219        ptsPtMapObj.count = 1;
220        ptsPtMapObj.avgDuration = `${priorityItem.dur}`;
221        ptsPtMapObj.wallDuration = priorityItem.dur;
222        stateMap.set(`${priorityItem.priorityType}_${priorityItem.state}`, ptsPtMapObj);
223      }
224    });
225  }
226
227  private theadClick(data: Array<Priority>): void {
228    let labels = this.priorityTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label');
229    if (labels) {
230      for (let i = 0; i < labels.length; i++) {
231        let label = labels[i].innerHTML;
232        labels[i].addEventListener('click', (): void => {
233          if (label.includes('Priority') && i === 0) {
234            this.priorityTbl!.setStatus(data, false);
235            this.priorityTbl!.recycleDs = this.priorityTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract);
236          } else if (label.includes('State') && i === 1) {
237            this.priorityTbl!.setStatus(data, true);
238            this.priorityTbl!.recycleDs = this.priorityTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand);
239          }
240        });
241      }
242    }
243  }
244
245  public initHtml(): string {
246    return `
247        <style>
248        :host{
249            display: flex;
250            flex-direction: column;
251            padding: 10px 10px;
252        }
253        </style>
254        <label id="priority-time-range" style="width: 100%;height: 20px;text-align: end;font-size: 10pt;margin-bottom: 5px">Selected range:0.0 ms</label>
255        <lit-table id="priority-tbl" style="height: auto" tree>
256            <lit-table-column width="27%" data-index="title" key="title" align="flex-start" title="Priority/State" retract>
257            </lit-table-column>
258            <lit-table-column width="1fr" data-index="count" key="count" align="flex-start" title="Count">
259            </lit-table-column>
260            <lit-table-column width="1fr" data-index="wallDuration" key="wallDuration" align="flex-start" title="Duration(ns)">
261            </lit-table-column>
262            <lit-table-column width="1fr" data-index="minDuration" key="minDuration" align="flex-start" title="Min Duration(ns)">
263            </lit-table-column>
264            <lit-table-column width="1fr" data-index="avgDuration" key="avgDuration" align="flex-start" title="Avg Duration(ns)">
265            </lit-table-column>
266            <lit-table-column width="1fr" data-index="maxDuration" key="maxDuration" align="flex-start" title="Max Duration(ns)">
267            </lit-table-column>
268        </lit-table>
269        `;
270  }
271}
272