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