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