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