• 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 { SelectionParam } from '../../../../bean/BoxSelection';
18import { LitTable } from '../../../../../base-ui/table/lit-table';
19import { resizeObserver } from '../SheetUtils';
20import { FuncStruct } from '../../../../database/ui-worker/ProcedureWorkerFunc';
21import { BaseStruct } from '../../../../database/ui-worker/ProcedureWorkerCommon';
22import { SpSystemTrace } from '../../../SpSystemTrace';
23import { type LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar';
24import {queryTaskListByExecuteTaskIds, queryTaskPoolTotalNum} from "../../../../database/sql/SqlLite.sql";
25import {queryConcurrencyTask} from "../../../../database/sql/Perf.sql";
26
27const ALLOCATION_TASK = 'H:Task Allocation:';
28const PERFORM_TASK = 'H:Task Perform:';
29const END_TASK = 'H:Task PerformTask End:';
30const TABLE_CURRENCY = 'Task Concurrency';
31
32@element('tabpane-task-frames')
33export class TabPaneTaskFrames extends BaseElement {
34  private taskFramesTbl: LitTable | null | undefined;
35  private range: HTMLLabelElement | null | undefined;
36  private taskFramesSource: Array<TaskTabStruct> = [];
37  private taskFramesGroupSource: Array<Array<TaskTabStruct>> = [];
38  private progressEL: LitProgressBar | null | undefined;
39  static TaskArray: Array<FuncStruct> = [];
40  static IsShowConcurrency: boolean = false;
41
42  set data(framesParam: SelectionParam) {
43    if (TabPaneTaskFrames.TaskArray && TabPaneTaskFrames.TaskArray.length > 0) {
44      this.progressEL!.loading = true;
45      //点选
46      this.setTaskData(TabPaneTaskFrames.TaskArray, framesParam, true);
47    } else {
48      if (!framesParam) {
49        this.taskFramesTbl!!.recycleDataSource = [];
50        this.taskFramesSource = [];
51        this.taskFramesGroupSource = [];
52        return;
53      }
54      //框选
55      this.range!.textContent = `Selected range:
56      ${parseFloat(((framesParam.rightNs - framesParam.leftNs) / 1000000.0).toFixed(5))} ms`;
57      this.progressEL!.loading = true;
58      this.queryDataByDB(framesParam, false);
59    }
60  }
61
62  setTaskData(taskArray: Array<FuncStruct>, framesParam: SelectionParam, isClick: boolean): void {
63    if (taskArray.length < 2) {
64      this.taskFramesTbl!!.recycleDataSource = [];
65      this.taskFramesSource = [];
66      this.taskFramesGroupSource = [];
67      return;
68    } else {
69      let allocationTime = 0;
70      let executeTime = 0;
71      let returnTime = 0;
72      let allocationStartTime = 0;
73      let executeStartTime = 0;
74      let returnEndTime = 0;
75      let priorityId = 1;
76      let executeId = '';
77      let executeStruct: FuncStruct | undefined = undefined;
78      taskArray.forEach((item) => {
79        if (item.funName!.indexOf(ALLOCATION_TASK) >= 0) {
80          allocationStartTime = item.startTs!;
81          priorityId = TabPaneTaskFrames.getPriorityId(item.funName!);
82          executeId = TabPaneTaskFrames.getExecuteId(item.funName!);
83        } else if (item.funName!.indexOf(PERFORM_TASK) >= 0) {
84          executeStruct = item;
85          executeStartTime = item.startTs!;
86          executeTime = item.dur!;
87        } else if (item.funName!.indexOf(END_TASK) >= 0) {
88          returnEndTime = item.startTs! + item.dur!;
89        }
90      });
91      allocationTime = executeStartTime - allocationStartTime;
92      returnTime = returnEndTime === 0 ? 0 : returnEndTime - (executeStartTime + executeTime);
93      if (TabPaneTaskFrames.IsShowConcurrency) {
94        let tableList: TaskTabStruct[] = [];
95        this.buildConcurrencyTable(executeStruct!, tableList, framesParam, isClick);
96      } else {
97        this.buildNoConcurrencyTable(executeId, priorityId, allocationTime, executeTime, returnTime);
98      }
99    }
100  }
101
102  private buildConcurrencyTable(
103    executeStruct: FuncStruct,
104    tableList: TaskTabStruct[],
105    framesParam: SelectionParam,
106    isClick: boolean
107  ): void {
108    this.countConcurrency(executeStruct, tableList, framesParam, isClick).then((result) => {
109      let concurrencyColumn: TaskTabStruct = new TaskTabStruct();
110      concurrencyColumn.executeId = TABLE_CURRENCY;
111      concurrencyColumn.taskPriority = `${result}`;
112      tableList.push(concurrencyColumn);
113      let filterList = [];
114      let map = new Map();
115      for (const item of tableList) {
116        if (!map.has(item.executeId)) {
117          map.set(item.executeId, true);
118          filterList.push(item);
119        }
120      }
121      this.taskFramesGroupSource = [filterList];
122      this.taskFramesSource = filterList;
123      this.taskFramesTbl!!.recycleDataSource = this.taskFramesSource;
124      this.progressEL!.loading = false;
125    });
126  }
127  private buildNoConcurrencyTable(
128    executeId: string,
129    priorityId: number,
130    sTime: number,
131    eTime: number,
132    rTime: number
133  ): void {
134    let task: TaskTabStruct = new TaskTabStruct();
135    task.executeId = executeId;
136    task.taskPriority = Priority[priorityId];
137    task.taskST = this.getMsTime(sTime);
138    task.taskET = this.getMsTime(eTime);
139    task.taskRT = this.getMsTime(rTime);
140    this.taskFramesSource = [task];
141    this.taskFramesGroupSource = [[task]];
142    this.taskFramesTbl!!.recycleDataSource = this.taskFramesSource;
143    this.progressEL!.loading = false;
144  }
145  async queryDataByDB(framesParam: SelectionParam, isClick: boolean): Promise<void> {
146    this.taskFramesGroupSource = [];
147    let tableList: TaskTabStruct[] = [];
148    this.taskFramesTbl!.recycleDataSource = [];
149    let groups = new Map();
150    framesParam.taskFramesData.forEach((obj) => {
151      const key = obj.ipid;
152      if (!groups.has(key)) {
153        groups.set(key, []);
154      }
155      groups.get(key).push(obj);
156    });
157    for (let [key, groupsValue] of groups) {
158      let tempTableList: TaskTabStruct[] = [];
159      let tempExecuteTaskList: FuncStruct[] = [];
160      let tempExecuteTaskIds: number[] = [];
161      for (let index = 0; index < groupsValue.length; index++) {
162        let data = groupsValue[index];
163        let executeId = TabPaneTaskFrames.getExecuteId(data.funName!);
164        if (data.funName!.indexOf(PERFORM_TASK) >= 0) {
165          tempExecuteTaskList.push(data);
166        }
167        tempExecuteTaskIds.push(parseInt(executeId));
168      }
169      let uniqueArr = [...new Set(tempExecuteTaskIds)];
170      let taskList = await queryTaskListByExecuteTaskIds(uniqueArr, key);
171      for (let index = 0; index < taskList.length; index++) {
172        this.pushTaskToList(taskList[index], tempTableList);
173      }
174      let filterArray = await this.handleConcurrency(tempExecuteTaskList, tempTableList, framesParam, isClick);
175      this.taskFramesGroupSource.push(filterArray);
176    }
177    this.taskFramesGroupSource.forEach((framesSource) => {
178      tableList.push(...framesSource);
179    });
180    this.taskFramesSource = tableList;
181    this.taskFramesTbl!.recycleDataSource = tableList;
182    this.progressEL!.loading = false;
183  }
184
185  initElements(): void {
186    this.taskFramesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-frames');
187    this.range = this.shadowRoot?.querySelector('#task-frames-time-range');
188    this.progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar;
189    this.taskFramesTbl!.addEventListener('column-click', (evt: CustomEventInit) => {
190      this.sortByColumn(evt.detail);
191    });
192  }
193
194  getMsTime(ts: number): number {
195    return parseFloat((ts / 1000000.0).toFixed(6));
196  }
197
198  connectedCallback(): void {
199    super.connectedCallback();
200    resizeObserver(this.parentElement!, this.taskFramesTbl!);
201  }
202
203  initHtml(): string {
204    return `
205        <style>
206        .task-frames-label{
207          height: 20px;
208          text-align: end;
209        }
210        :host{
211            padding: 10px 10px;
212            display: flex;
213            flex-direction: column;
214        }
215        </style>
216        <label id="task-frames-time-range" class="task-frames-label" style="width: 100%;font-size: 10pt;margin-bottom: 5px">
217        Selected range:0.0 ms</label>
218        <lit-progress-bar class="progress"></lit-progress-bar>
219        <lit-table id="tb-frames" style="height: auto">
220            <lit-table-column class="task-frames-column" title="Execute Id" width="1fr" data-index="executeId"
221            key="executeId"  align="flex-start" order>
222            </lit-table-column>
223            <lit-table-column class="task-frames-column" title="Task Priority" width="1fr" data-index="taskPriority"
224            key="taskPriority"  align="flex-start" order >
225            </lit-table-column>
226            <lit-table-column class="task-frames-column" title="Scheduling Time(ms)" width="1fr"
227            data-index="taskST" key="taskST"  align="flex-start" order >
228            </lit-table-column>
229            <lit-table-column class="task-frames-column" title="Execution Time(ms)" width="1fr" data-index="taskET"
230            key="taskET"  align="flex-start" order >
231            </lit-table-column>
232            <lit-table-column class="task-frames-column" title="Return Time(ms)" width="1fr" data-index="taskRT"
233            key="taskRT"  align="flex-start" order >
234            </lit-table-column>
235        </lit-table>
236        `;
237  }
238
239  sortByColumn(framesDetail: { sort: number; key: string }): void {
240    // @ts-ignore
241    let compare = function (property, sort, type) {
242      return function (taskFramesLeftData: TaskTabStruct, taskFramesRightData: TaskTabStruct): number {
243        if (taskFramesLeftData.executeId === TABLE_CURRENCY) {
244          return 1;
245        }
246        if (type === 'number') {
247          // @ts-ignore
248          let forwardNum = parseFloat(taskFramesRightData[property]) - parseFloat(taskFramesLeftData[property]);
249          // @ts-ignore
250          let reserveNum = parseFloat(taskFramesLeftData[property]) - parseFloat(taskFramesRightData[property]);
251          return sort === 2 ? forwardNum : reserveNum;
252        } else {
253          // @ts-ignore
254          if (taskFramesRightData[property] > taskFramesLeftData[property]) {
255            return sort === 2 ? 1 : -1;
256          } else {
257            // @ts-ignore
258            if (taskFramesRightData[property] === taskFramesLeftData[property]) {
259              return 0;
260            } else {
261              return sort === 2 ? -1 : 1;
262            }
263          }
264        }
265      };
266    };
267    let tableList: TaskTabStruct[] = [];
268    this.taskFramesGroupSource.forEach((framesGroup) => {
269      if (framesDetail.key === 'taskPriority') {
270        framesGroup.sort(compare(framesDetail.key, framesDetail.sort, 'string'));
271      } else {
272        framesGroup.sort(compare(framesDetail.key, framesDetail.sort, 'number'));
273      }
274      tableList.push(...framesGroup);
275    });
276    this.taskFramesSource = tableList;
277    this.taskFramesTbl!.recycleDataSource = tableList;
278  }
279
280  static getExecuteId(funName: string): string {
281    const executeIdMatch = funName.match(/executeId\s*:\s*(\d+)/i);
282    if (executeIdMatch && executeIdMatch.length > 1) {
283      return executeIdMatch[1];
284    }
285    return '';
286  }
287
288  static getPriorityId(funName: string): number {
289    let strArray = funName.split(',');
290    let priorityId = '';
291    if (strArray.length >= 2) {
292      let executeStr = strArray[2];
293      if (funName.indexOf(ALLOCATION_TASK) >= 0) {
294        priorityId = executeStr.split(':')[1].trim();
295      }
296    }
297    return parseInt(priorityId);
298  }
299
300  private async countConcurrency(
301    selectFuncStruct: FuncStruct | undefined,
302    tableList: TaskTabStruct[],
303    framesParam: SelectionParam,
304    isClick: boolean
305  ): Promise<number> {
306    let selectStartTime = selectFuncStruct!.startTs! + (window as any).recordStartNS;
307    let selectEndTime = selectFuncStruct!.startTs! + selectFuncStruct!.dur! + (window as any).recordStartNS;
308    if (!isClick) {
309      selectStartTime = framesParam.recordStartNs + framesParam.leftNs;
310      selectEndTime = framesParam.recordStartNs + framesParam.rightNs;
311    }
312    let res = await Promise.all([
313      queryTaskPoolTotalNum(selectFuncStruct!.itid!),
314      queryConcurrencyTask(selectFuncStruct!.itid!, selectStartTime, selectEndTime),
315    ]);
316    let tasks: Array<TaskTabStruct> = res[1];
317    let maxConcurrency = 0;
318    let timePointArray: { time: number; isStart: boolean }[] = [];
319    for (let i = 0; i < tasks.length; i++) {
320      timePointArray.push({ time: tasks[i].startTs!, isStart: true });
321      timePointArray.push({ time: tasks[i].startTs! + tasks[i].dur!, isStart: false });
322    }
323    timePointArray.sort((timePointA, timePointB) => {
324      if (timePointA.time === timePointB.time) {
325        return timePointA.isStart ? -1 : 1;
326      }
327      return timePointA.time - timePointB.time;
328    });
329    let currentConcurrency = 0;
330    for (let i = 0; i < timePointArray.length; i++) {
331      if (timePointArray[i].isStart) {
332        currentConcurrency++;
333      } else {
334        currentConcurrency--;
335      }
336      if (currentConcurrency > maxConcurrency) {
337        maxConcurrency = currentConcurrency;
338        if (maxConcurrency === res[0].length) {
339          break;
340        }
341      }
342    }
343    for (const item of res[1]) {
344      this.pushTaskToList(item, tableList);
345    }
346    return maxConcurrency;
347  }
348
349  private async handleConcurrency(
350    executeTaskList: FuncStruct[],
351    tableList: TaskTabStruct[],
352    framesParam: SelectionParam,
353    isClick: boolean
354  ): Promise<Array<TaskTabStruct>> {
355    let maxNumConcurrency = 0;
356    if (executeTaskList.length > 0) {
357      let countConcurrencyPromise = await this.countConcurrency(executeTaskList[0], tableList, framesParam, isClick);
358      maxNumConcurrency = countConcurrencyPromise;
359      let concurrencyColumn: TaskTabStruct = new TaskTabStruct();
360      concurrencyColumn.executeId = TABLE_CURRENCY;
361      concurrencyColumn.taskPriority = `${maxNumConcurrency}`;
362      tableList.push(concurrencyColumn);
363      //去重
364      let filterList = [];
365      let map = new Map();
366      for (const ConcurrencyTblItem of tableList) {
367        if (!map.has(ConcurrencyTblItem.executeId)) {
368          map.set(ConcurrencyTblItem.executeId, true);
369          filterList.push(ConcurrencyTblItem);
370        }
371      }
372      return filterList;
373    }
374    return tableList;
375  }
376
377  private pushTaskToList(value: TaskTabStruct, tableList: TaskTabStruct[]): void {
378    let allocationTask = SpSystemTrace.DATA_TASK_POOL_CALLSTACK.get(value.allocationTaskRow!);
379    let executeTask = SpSystemTrace.DATA_TASK_POOL_CALLSTACK.get(value.executeTaskRow!);
380    let returnTask = SpSystemTrace.DATA_TASK_POOL_CALLSTACK.get(value.returnTaskRow!);
381    let tempTask: TaskTabStruct = new TaskTabStruct();
382    let executeStartTime = executeTask!.ts!;
383    let executeTime = executeTask!.dur! === -1 ? (window as any).recordEndNS - executeTask!.ts : executeTask!.dur;
384    let allocationStartTime = allocationTask!.ts!;
385    let returnEndTime = 0;
386    if (returnTask) {
387      returnEndTime = returnTask!.ts! + returnTask!.dur! - (executeStartTime + executeTime);
388    }
389    tempTask.executeId = value.executeId;
390    tempTask.taskPriority = Priority[value.priority!];
391    tempTask.taskST = this.getMsTime(executeStartTime - allocationStartTime);
392    tempTask.taskET = this.getMsTime(executeTime);
393    tempTask.taskRT = this.getMsTime(returnEndTime);
394    tableList.push(tempTask);
395  }
396}
397
398enum Priority {
399  HIGH,
400  MEDIUM,
401  LOW,
402}
403
404export class TaskTabStruct extends BaseStruct {
405  static maxValue: number = 0;
406  static maxName: string = '';
407  static index = 0;
408  id: number | undefined;
409  tid: number | undefined;
410  ipid: number | undefined;
411  executeId: string | undefined;
412  startTs: number | undefined;
413  funName: string | undefined;
414  dur: number | undefined;
415  taskST: number | undefined;
416  taskET: number | undefined;
417  taskRT: number | undefined;
418  allocationTaskRow: number | undefined;
419  executeTaskRow: number | undefined;
420  returnTaskRow: number | undefined;
421  priority: number | undefined;
422  taskPriority: string | undefined;
423  isUse: boolean = false;
424}
425