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