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