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 { LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; 18import { Utils } from '../../base/Utils'; 19import { SelectionParam } from '../../../../bean/BoxSelection'; 20import { BinderGroup, DataSource } from '../../../../bean/BinderProcessThread'; 21import { 22 querySingleFuncNameCycleStates, 23 queryStatesCut, 24 queryLoopFuncNameCycle, 25} from '../../../../database/sql/Func.sql'; 26import { FuncNameCycle } from '../../../../bean/BinderProcessThread'; 27import { resizeObserver } from '../SheetUtils'; 28import { LitChartColumn } from '../../../../../base-ui/chart/column/LitChartColumn'; 29import '../../../../../base-ui/chart/column/LitChartColumn'; 30import { SpSegmentationChart } from '../../../chart/SpSegmentationChart'; 31import { StateGroup } from '../../../../bean/StateModle'; 32import { TraceSheet } from '../../base/TraceSheet'; 33import { Flag } from '../../timer-shaft/Flag'; 34import { TraceRow } from '../../base/TraceRow'; 35import { Rect, ns2x } from '../../../../database/ui-worker/ProcedureWorkerCommon'; 36import { SpSystemTrace } from '../../../SpSystemTrace'; 37 38@element('tabpane-states-datacut') 39export class TabPaneFreqStatesDataCut extends BaseElement { 40 private threadBindersTbl: LitTable | null | undefined; 41 private currentSelectionParam: SelectionParam | any; 42 private threadStatesDIV: Element | null | undefined; 43 private cycleARangeArr: StateGroup[] | undefined; 44 private cycleBRangeArr: StateGroup[] | undefined; 45 private cycleAStartRangeDIV: HTMLInputElement | null | undefined; 46 private cycleAEndRangeDIV: HTMLInputElement | null | undefined; 47 private cycleBStartRangeDIV: HTMLInputElement | null | undefined; 48 private cycleBEndRangeDIV: HTMLInputElement | null | undefined; 49 private chartTotal: LitChartColumn | null | undefined; 50 private dataSource: DataSource[] | undefined; 51 private rowCycleData: StateGroup[] | undefined; 52 private funcNameCycleArr: FuncNameCycle[] | undefined; 53 private currentThreadId: string | undefined; 54 private cycleStartTime: number | undefined; 55 private cycleEndTime: number | undefined; 56 private filterState: Array<StateGroup> = []; 57 private traceSheetEl: TraceSheet | undefined | null; 58 private spSystemTrace: SpSystemTrace | undefined | null; 59 private lineCycleNum: number = -1; 60 private cycleIsClick: Boolean = false; 61 static isStateTabHover: boolean = false; 62 63 // tab页入口函数 64 set data(threadStatesParam: SelectionParam | any) { 65 // 获取输入框 66 let threadIdDIV = this.shadowRoot!.querySelector('.thread-id-input') as HTMLElement; 67 threadIdDIV.style.border = '1px solid rgb(151,151,151)'; 68 let cycleNameDIV = this.shadowRoot!.querySelector('.cycle-name-input') as HTMLElement; 69 cycleNameDIV.style.border = '1px solid rgb(151,151,151)'; 70 if (this.currentSelectionParam === threadStatesParam) { 71 return; 72 } 73 // 隐藏右半边区域 74 this.dispalyQueryArea(true); 75 // 清空切割按钮状态 76 this.clickLoop(false); 77 this.clickSingle(false); 78 this.currentSelectionParam = threadStatesParam; 79 // 清空表格数据 80 this.threadBindersTbl!.recycleDataSource = []; 81 this.theadClick(this.threadBindersTbl!.recycleDataSource as Array<BinderGroup>); 82 } 83 84 initTabSheetEl(traceSheet: TraceSheet): void { 85 this.traceSheetEl = traceSheet; 86 } 87 88 dispalyQueryArea(b: boolean) { 89 if (b) { 90 this.setAttribute('dispalyQueryArea', ''); 91 } else { 92 this.removeAttribute('dispalyQueryArea'); 93 } 94 } 95 96 clickSingle(b: boolean) { 97 if (b) { 98 this.setAttribute('clickSingle', ''); 99 } else { 100 this.removeAttribute('clickSingle'); 101 } 102 } 103 104 clickLoop(b: boolean) { 105 if (b) { 106 this.setAttribute('clickLoop', ''); 107 } else { 108 this.removeAttribute('clickLoop'); 109 } 110 } 111 112 // LOOP切割方法 113 async dataLoopCut(threadId: HTMLInputElement, threadFunc: HTMLInputElement): Promise<void> { 114 // 清除表格数据 115 SpSegmentationChart.setStateChartData([]); 116 // 获取框选范围内包含的进程和线程ID 117 let threadIds: number[] = this.currentSelectionParam.threadIds; 118 let processIds: number[] = this.currentSelectionParam.processIds; 119 // 获取输入的进程号和方法名 120 let threadIdValue: string = threadId.value.trim(); 121 let threadFuncName: string = threadFunc.value.trim(); 122 // 获取框选的左右边界 123 let leftNS: number = this.currentSelectionParam.leftNs; 124 let rightNS: number = this.currentSelectionParam.rightNs; 125 // 判断进程号和方法名是否都输入了内容 126 if (threadIdValue !== '' && threadFuncName !== '') { 127 // 修改按钮样式 128 this.clickLoop(true); 129 this.clickSingle(false); 130 threadId.style.border = '1px solid rgb(151,151,151)'; 131 threadFunc.style.border = '1px solid rgb(151,151,151)'; 132 this.threadBindersTbl!.loading = true; 133 this.funcNameCycleArr = await queryLoopFuncNameCycle(threadFuncName, threadIdValue, leftNS, rightNS); 134 this.cycleStartTime = this.funcNameCycleArr!.length > 0 ? this.funcNameCycleArr![0].cycleStartTime : undefined; 135 this.cycleEndTime = 136 this.funcNameCycleArr!.length > 1 137 ? this.funcNameCycleArr![this.funcNameCycleArr!.length - 1].cycleStartTime 138 : undefined; 139 // 遍历设置周期的起始时间 140 for (let i = 0; i < this.funcNameCycleArr!.length - 1; i++) { 141 this.funcNameCycleArr![i].endTime = this.funcNameCycleArr![i + 1].cycleStartTime; 142 } 143 // 框选范围内的状态数据 144 let stateItemArr = await queryStatesCut(threadIds, leftNS, rightNS); 145 // 周期数组里的最后一项不满足loop要求,直接删除 146 this.funcNameCycleArr!.pop(); 147 if (this.funcNameCycleArr!.length !== 0) { 148 let stateCutArr: StateGroup[] = []; 149 // pid数组去重 150 processIds = Array.from(new Set(processIds)); 151 // 去除切割范围以外的数据 152 this.filterState = new Array<StateGroup>(); 153 stateItemArr.map((stateItem) => { 154 for (let i = 0; i < this.funcNameCycleArr!.length; i++) { 155 if ( 156 ((stateItem.ts > this.funcNameCycleArr![i].cycleStartTime && stateItem.ts < this.funcNameCycleArr![i].endTime) || 157 (stateItem.ts + stateItem.dur! > this.funcNameCycleArr![i].cycleStartTime && 158 stateItem.ts + stateItem.dur! < this.funcNameCycleArr![i].endTime) || 159 (this.funcNameCycleArr![i].cycleStartTime > stateItem.ts && this.funcNameCycleArr![i].endTime < stateItem.ts + stateItem.dur!)) && 160 (stateItem.state === 'S' || 161 stateItem.state === 'R' || 162 stateItem.state === 'D' || 163 stateItem.state === 'Running') 164 ) { 165 stateItem.startTs = stateItem.ts; 166 stateItem.chartDur = stateItem.dur; 167 this.filterState!.push(stateItem); 168 } 169 } 170 }); 171 this.filterState = Array.from(new Set(this.filterState)); 172 // 周期内有数据 173 if (this.filterState.length !== 0) { 174 for (let i = 0; i < processIds.length; i++) { 175 this.setProcessData(this.filterState, processIds[i], stateCutArr); 176 } 177 } 178 this.threadBindersTbl!.recycleDataSource = stateCutArr; 179 this.threadBindersTbl!.loading = false; 180 // 表格添加点击事件 181 this.theadClick(this.threadBindersTbl!.recycleDataSource as Array<BinderGroup>); 182 } else { 183 this.threadBindersTbl!.recycleDataSource = []; 184 this.threadBindersTbl!.loading = false; 185 this.theadClick(this.threadBindersTbl!.recycleDataSource as Array<BinderGroup>); 186 } 187 } else { 188 this.verifyInputIsEmpty(threadIdValue, threadFuncName, threadId, threadFunc); 189 } 190 } 191 192 async dataSingleCut(threadId: HTMLInputElement, threadFunc: HTMLInputElement): Promise<void> { 193 SpSegmentationChart.setStateChartData([]); 194 this.currentThreadId = ''; 195 let threadIds: number[] = this.currentSelectionParam.threadIds; 196 let processIds: number[] = this.currentSelectionParam.processIds; 197 let threadIdValue: string = threadId.value.trim(); 198 let threadFuncName: string = threadFunc.value.trim(); 199 let leftNS: number = this.currentSelectionParam.leftNs; 200 let rightNS: number = this.currentSelectionParam.rightNs; 201 if (threadIdValue !== '' && threadFuncName !== '') { 202 this.clickLoop(false); 203 this.clickSingle(true); 204 threadId.style.border = '1px solid rgb(151,151,151)'; 205 threadFunc.style.border = '1px solid rgb(151,151,151)'; 206 this.threadBindersTbl!.loading = true; 207 this.funcNameCycleArr = await querySingleFuncNameCycleStates(threadFuncName, threadIdValue, leftNS, rightNS); 208 this.cycleStartTime = this.funcNameCycleArr!.length > 0 ? this.funcNameCycleArr![0].cycleStartTime : undefined; 209 this.cycleEndTime = 210 this.funcNameCycleArr!.length > 0 211 ? this.funcNameCycleArr![this.funcNameCycleArr!.length - 1].endTime 212 : undefined; 213 let stateItemArr = await queryStatesCut(threadIds, leftNS, rightNS); 214 if (this.funcNameCycleArr!.length !== 0) { 215 let stateCutArr: StateGroup[] = []; 216 // pid数组去重 217 processIds = Array.from(new Set(processIds)); 218 // 去除切割范围以外的数据 219 this.filterState = new Array<StateGroup>(); 220 stateItemArr.map((stateItem) => { 221 for (let i = 0; i < this.funcNameCycleArr!.length; i++) { 222 if ( 223 ((stateItem.ts > this.funcNameCycleArr![i].cycleStartTime && stateItem.ts < this.funcNameCycleArr![i].endTime) || 224 (stateItem.ts + stateItem.dur! > this.funcNameCycleArr![i].cycleStartTime && 225 stateItem.ts + stateItem.dur! < this.funcNameCycleArr![i].endTime) || 226 (this.funcNameCycleArr![i].cycleStartTime > stateItem.ts && this.funcNameCycleArr![i].endTime < stateItem.ts + stateItem.dur!)) && 227 (stateItem.state === 'S' || 228 stateItem.state === 'R' || 229 stateItem.state === 'D' || 230 stateItem.state === 'Running') 231 ) { 232 stateItem.startTs = stateItem.ts; 233 stateItem.chartDur = stateItem.dur; 234 // @ts-ignore 周期第一条数据开始时间设置为周期开始时间 235 if (stateItem.ts + stateItem.dur > this.funcNameCycleArr[i].cycleStartTime && stateItem.ts < this.funcNameCycleArr[i].cycleStartTime) { 236 stateItem.dur = stateItem.ts + stateItem.dur! - this.funcNameCycleArr![i].cycleStartTime; 237 stateItem.ts = this.funcNameCycleArr![i].cycleStartTime; 238 } 239 this.filterState!.push(stateItem); 240 } 241 } 242 }); 243 if (this.filterState.length > 0) { 244 for (let i = 0; i < processIds.length; i++) { 245 this.setProcessData(this.filterState, processIds[i], stateCutArr); 246 } 247 } 248 this.threadBindersTbl!.recycleDataSource = stateCutArr; 249 this.threadBindersTbl!.loading = false; 250 this.theadClick(this.threadBindersTbl!.recycleDataSource as BinderGroup[]); 251 } else { 252 this.threadBindersTbl!.recycleDataSource = []; 253 this.threadBindersTbl!.loading = false; 254 this.theadClick(this.threadBindersTbl!.recycleDataSource as BinderGroup[]); 255 } 256 } else { 257 this.verifyInputIsEmpty(threadIdValue, threadFuncName, threadId, threadFunc); 258 } 259 } 260 261 // 处理进程数据 262 setProcessData(filterState: StateGroup[], processId: number, stateCutArr: StateGroup[]): void { 263 // 当前进程级别的数据 264 let filterObj = new StateGroup(); 265 // 筛选出当前进程下的所有数据 266 let processArr = new Array<StateGroup>(); 267 filterState.map((filterItem) => { 268 if (filterItem.pid === processId) { 269 processArr.push(filterItem); 270 filterObj.totalCount! += 1; 271 filterItem.state === 'R' 272 ? (filterObj.RunnableCount += 1, filterObj.RunnableDur += filterItem.dur!) 273 : filterItem.state === 'Running' 274 ? (filterObj.RunningCount += 1, filterObj.RunningDur += filterItem.dur!) 275 : filterItem.state === 'D' 276 ? (filterObj.DCount += 1, filterObj.DDur += filterItem.dur!) 277 : (filterObj.SleepingCount += 1, filterObj.SleepingDur += filterItem.dur!); 278 filterObj.title = (Utils.getInstance().getProcessMap().get(processId) || 'Process') + processId; 279 filterObj.pid = processId; 280 filterObj.type = 'process'; 281 // @ts-ignore 282 filterObj.cycleDur! += filterItem.dur!; 283 } 284 }); 285 // @ts-ignore 286 filterObj.RunningDur = this.formatNumber(filterObj.RunningDur / 1000000); 287 // @ts-ignore 288 filterObj.RunnableDur = this.formatNumber(filterObj.RunnableDur / 1000000); 289 // @ts-ignore 290 filterObj.DDur = this.formatNumber(filterObj.DDur / 1000000); 291 // @ts-ignore 292 filterObj.SleepingDur = this.formatNumber(filterObj.SleepingDur / 1000000); 293 // @ts-ignore 294 filterObj.cycleDur = this.formatNumber(filterObj.cycleDur! / 1000000); 295 if (processArr.length > 0) { 296 filterObj.children = this.setThreadData(processArr); 297 } 298 stateCutArr.push(filterObj); 299 } 300 301 // 是0为0,非0保留三位小数 302 formatNumber(num: number): string | 0 { 303 return num === 0 ? 0 : num.toFixed(3); 304 } 305 306 // 处理线程数据 307 setThreadData(threadData: Array<StateGroup>) { 308 // 进程下面的线程,相当于process的children 309 let threadArr = new Array<StateGroup>(); 310 let threads = this.currentSelectionParam.threadIds; 311 for (let i = 0; i < threads.length; i++) { 312 // 单个线程 313 let threadObj = new StateGroup(); 314 threadObj.tid = threads[i]; 315 threadObj.pid = threadData[0].pid; 316 threadObj.children = new Array<StateGroup>(); 317 threadObj.type = 'thread'; 318 (threadObj.title = (Utils.getInstance().getProcessMap().get(threads[i]) || 'Process') + threads[i]), 319 threadArr.push(threadObj); 320 } 321 for (let i = 0; i < threadArr.length; i++) { 322 let threadList = new Array<StateGroup>(); 323 threadData.map((threadItem) => { 324 if (threadItem.tid === threadArr[i].tid) { 325 threadList.push(threadItem); 326 threadArr[i].totalCount! += 1; 327 threadItem.state === 'R' 328 ? ((threadArr[i].RunnableCount += 1), (threadArr[i].RunnableDur += threadItem.dur!)) 329 : threadItem.state === 'Running' 330 ? ((threadArr[i].RunningCount += 1), (threadArr[i].RunningDur += threadItem.dur!)) 331 : threadItem.state === 'S' 332 ? ((threadArr[i].SleepingCount += 1), (threadArr[i].SleepingDur += threadItem.dur!)) 333 : ((threadArr[i].DCount += 1), (threadArr[i].DDur += threadItem.dur!)); 334 // @ts-ignore 335 threadArr[i].cycleDur! += threadItem.dur!; 336 } 337 }); 338 // @ts-ignore 339 threadArr[i].SleepingDur = this.formatNumber(threadArr[i].SleepingDur / 1000000); 340 // @ts-ignore 341 threadArr[i].RunnableDur = this.formatNumber(threadArr[i].RunnableDur / 1000000); 342 // @ts-ignore 343 threadArr[i].RunningDur = this.formatNumber(threadArr[i].RunningDur / 1000000); 344 // @ts-ignore 345 threadArr[i].DDur = this.formatNumber(threadArr[i].DDur / 1000000); 346 // @ts-ignore 347 threadArr[i].cycleDur = this.formatNumber(threadArr[i].cycleDur / 1000000); 348 if (threadList.length > 0) { 349 threadArr[i].children = this.setCycleData(threadList); 350 } 351 } 352 threadArr = threadArr.filter((V) => { 353 return V.totalCount! > 0; 354 }); 355 return threadArr; 356 } 357 358 // 处理周期数据 359 setCycleData(threadData: Array<StateGroup>): Array<StateGroup> { 360 let cycleArr = new Array<StateGroup>(); 361 if (this.funcNameCycleArr !== undefined && this.funcNameCycleArr.length > 0) { 362 for (let i = 0; i < this.funcNameCycleArr!.length; i++) { 363 let cycleItem = new StateGroup(); 364 cycleItem.title = `cycle-${i + 1}`; 365 cycleItem.cycle = i; 366 threadData.map((v) => { 367 if ( 368 (v.ts > this.funcNameCycleArr![i].cycleStartTime && v.ts < this.funcNameCycleArr![i].endTime) || 369 (v.ts + v.dur! > this.funcNameCycleArr![i].cycleStartTime && v.ts + v.dur! < this.funcNameCycleArr![i].endTime) || 370 (this.funcNameCycleArr![i].cycleStartTime > v.ts && this.funcNameCycleArr![i].endTime < v.ts + v.dur!) 371 ) { 372 cycleItem.totalCount! += 1; 373 v.state === 'R' 374 ? ((cycleItem.RunnableCount += 1), (cycleItem.RunnableDur += v.dur!)) 375 : v.state === 'Running' 376 ? ((cycleItem.RunningCount += 1), (cycleItem.RunningDur += v.dur!)) 377 : v.state === 'S' 378 ? ((cycleItem.SleepingCount += 1), (cycleItem.SleepingDur += v.dur!)) 379 : ((cycleItem.DCount += 1), (cycleItem.DDur += v.dur!)); 380 } 381 }); 382 // @ts-ignore 383 cycleItem.SleepingDur = this.formatNumber(cycleItem.SleepingDur / 1000000); 384 // @ts-ignore 385 cycleItem.RunningDur = this.formatNumber(cycleItem.RunningDur / 1000000); 386 // @ts-ignore 387 cycleItem.RunnableDur = this.formatNumber(cycleItem.RunnableDur / 1000000); 388 // @ts-ignore 389 cycleItem.DDur = this.formatNumber(cycleItem.DDur / 1000000); 390 cycleItem.cycleDur! = this.formatNumber((this.funcNameCycleArr[i].endTime - this.funcNameCycleArr[i].cycleStartTime) / 1000000); 391 cycleItem.type = 'cycle'; 392 cycleArr.push(cycleItem); 393 } 394 } 395 return cycleArr; 396 } 397 398 // 输入框为空点击按钮之后的样式 399 verifyInputIsEmpty( 400 threadIdValue: string, 401 threadFuncName: string, 402 threadId: HTMLInputElement, 403 threadFunc: HTMLInputElement 404 ): void { 405 if (threadIdValue === '') { 406 threadId.style.border = '1px solid rgb(255,0,0)'; 407 threadId.setAttribute('placeholder', 'Please input thread id'); 408 } else { 409 threadId.style.border = '1px solid rgb(151,151,151)'; 410 } 411 412 if (threadFuncName === '') { 413 threadFunc.style.border = '1px solid rgb(255,0,0)'; 414 threadFunc.setAttribute('placeholder', 'Please input function name'); 415 } else { 416 threadFunc.style.border = '1px solid rgb(151,151,151)'; 417 } 418 } 419 420 // 线程点击 421 private theadClick(data: Array<BinderGroup>): void { 422 let labels = this.threadBindersTbl?.shadowRoot?.querySelector('.th > .td')?.querySelectorAll('label'); 423 if (labels) { 424 for (let i = 0; i < labels.length; i++) { 425 let label = labels[i].innerHTML; 426 labels[i].addEventListener('click', (e) => { 427 if (label.includes('Process') && i === 0) { 428 // 数据递归设置status 429 this.threadBindersTbl!.setStatus(data, false); 430 this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement( 431 data, 432 RedrawTreeForm.Retract 433 ); 434 } else if (label.includes('Thread') && i === 1) { 435 for (let item of data) { 436 item.status = true; 437 if (item.children != undefined && item.children.length > 0) { 438 this.threadBindersTbl!.setStatus(item.children, false); 439 } 440 } 441 this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement( 442 data, 443 RedrawTreeForm.Retract 444 ); 445 } else if (label.includes('Cycle') && i === 2) { 446 this.threadBindersTbl!.setStatus(data, true); 447 this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand); 448 } 449 }); 450 } 451 } 452 } 453 454 initElements(): void { 455 this.threadBindersTbl = this.shadowRoot?.querySelector<LitTable>('#tb-binder-count'); 456 this.chartTotal = this.shadowRoot!.querySelector<LitChartColumn>('#chart_cycle'); 457 this.cycleAStartRangeDIV = this.shadowRoot?.querySelector('#cycle-a-start-range'); 458 this.cycleAEndRangeDIV = this.shadowRoot?.querySelector('#cycle-a-end-range'); 459 this.cycleBStartRangeDIV = this.shadowRoot?.querySelector('#cycle-b-start-range'); 460 this.cycleBEndRangeDIV = this.shadowRoot?.querySelector('#cycle-b-end-range'); 461 462 this.threadStatesDIV = this.shadowRoot!.querySelector('#dataCut'); 463 this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => { 464 this.dispalyQueryArea(true); 465 this.dataSource = []; 466 // @ts-ignore 467 this.dataSingleCut(this.threadStatesDIV!.children[0], this.threadStatesDIV?.children[1]); 468 }); 469 this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => { 470 this.dispalyQueryArea(true); 471 this.dataSource = []; 472 // @ts-ignore 473 this.dataLoopCut(this.threadStatesDIV?.children[0], this.threadStatesDIV?.children[1]); 474 }); 475 476 this.threadBindersTbl!.addEventListener('mouseout', (): void => { 477 this.cycleIsClick = false; 478 this.lineCycleNum = -1; 479 this.traceSheetEl!.systemLogFlag = undefined; 480 SpSegmentationChart.tabHoverObj = { key: '', cycle: -1 }; 481 TabPaneFreqStatesDataCut.isStateTabHover = false; 482 this.spSystemTrace?.refreshCanvas(false); 483 }); 484 485 this.threadBindersTbl!.addEventListener('row-click', (evt: any) => { 486 let currentData: StateGroup = evt.detail.data; 487 if (currentData.type === 'thread') { 488 this.currentThreadId = currentData.tid + '' + currentData.pid; 489 this.clearCycleRange(); 490 currentData.isSelected = true; 491 this.threadBindersTbl!.clearAllSelection(currentData); 492 this.threadBindersTbl!.setCurrentSelection(currentData); 493 this.rowCycleData = currentData.children; 494 this.dispalyQueryArea(false); 495 let totalCount = 496 currentData.SleepingCount + currentData.RunnableCount + currentData.DCount + currentData.RunningCount; 497 this.dataSource = []; 498 this.dataSource.push({ 499 xName: 'Total', 500 yAverage: totalCount !== 0 ? Math.ceil(totalCount! / this.rowCycleData!.length) : 0, 501 }); 502 if (this.dataSource!.length !== 0) { 503 this.drawColumn(); 504 } 505 let statesChartData = this.filCycleData(currentData.pid, currentData.tid); 506 SpSegmentationChart.setStateChartData(statesChartData); 507 } 508 if (currentData.type === 'cycle') { 509 currentData.isSelected = true; 510 this.threadBindersTbl!.clearAllSelection(currentData); 511 this.threadBindersTbl!.setCurrentSelection(currentData); 512 if (currentData.cycle === this.lineCycleNum && this.cycleIsClick === true) { 513 this.traceSheetEl!.systemLogFlag = undefined; 514 SpSegmentationChart.tabHoverObj = { key: '', cycle: -1 }; 515 TabPaneFreqStatesDataCut.isStateTabHover = false; 516 this.cycleIsClick = false; 517 } else { 518 SpSegmentationChart.tabHoverObj = { key: '', cycle: -1 }; 519 let pointX: number = ns2x( 520 this.funcNameCycleArr![currentData.cycle].cycleStartTime || 0, 521 TraceRow.range!.startNS, 522 TraceRow.range!.endNS, 523 TraceRow.range!.totalNS, 524 new Rect(0, 0, TraceRow.FRAME_WIDTH, 0) 525 ); 526 SpSegmentationChart.tabHoverObj.key = 'STATES'; 527 SpSegmentationChart.trace.traceSheetEL!.systemLogFlag = new Flag( 528 Math.floor(pointX), 529 0, 530 0, 531 0, 532 this.funcNameCycleArr![currentData.cycle].cycleStartTime!, 533 '#000000', 534 '', 535 true, 536 '' 537 ); 538 TabPaneFreqStatesDataCut.isStateTabHover = true; 539 this.lineCycleNum = currentData.cycle; 540 this.cycleIsClick = true; 541 } 542 SpSegmentationChart.trace.refreshCanvas(false); 543 } 544 }); 545 546 // 筛选柱状图数据 547 this.shadowRoot?.querySelector('#query-btn')?.addEventListener('click', () => { 548 this.cycleARangeArr = this.rowCycleData?.filter((it: StateGroup) => { 549 return ( 550 // @ts-ignore 551 it.cycleDur! >= Number(this.cycleAStartRangeDIV!.value) && 552 // @ts-ignore 553 it.cycleDur! < Number(this.cycleAEndRangeDIV!.value) 554 ); 555 }); 556 this.cycleBRangeArr = this.rowCycleData?.filter((it: StateGroup) => { 557 return ( 558 // @ts-ignore 559 it.cycleDur! >= Number(this.cycleBStartRangeDIV!.value) && 560 // @ts-ignore 561 it.cycleDur! < Number(this.cycleBEndRangeDIV!.value) 562 ); 563 }); 564 let cycleACount: number = 0; 565 this.cycleARangeArr?.forEach((it: StateGroup) => { 566 cycleACount += it.totalCount!; 567 }); 568 let cycleBCount: number = 0; 569 this.cycleBRangeArr?.forEach((it: StateGroup) => { 570 cycleBCount += it.totalCount!; 571 }); 572 this.dataSource!.length > 1 && this.dataSource?.splice(1); 573 this.dataSource!.push({ 574 xName: 'cycleA', 575 yAverage: cycleACount !== 0 ? Math.ceil(cycleACount / this.cycleARangeArr!.length) : 0, 576 }); 577 this.dataSource!.push({ 578 xName: 'cycleB', 579 yAverage: cycleBCount !== 0 ? Math.ceil(cycleBCount / this.cycleBRangeArr!.length) : 0, 580 }); 581 if (this.dataSource!.length !== 0) { 582 this.drawColumn(); 583 } 584 }); 585 } 586 587 // 筛选出点击的线程数据 588 filCycleData(pid: number, tid: number): Array<StateGroup> { 589 return this.filterState?.filter((v: StateGroup) => { 590 return v.pid === pid && v.tid === tid && ( 591 (v.ts > this.cycleStartTime! && v.ts < this.cycleEndTime!) || 592 (v.ts + v.dur! > this.cycleStartTime! && v.ts + v.dur! < this.cycleEndTime!) || 593 (this.cycleStartTime! > v.ts && this.cycleEndTime! < v.ts + v.dur!)); 594 }) 595 }; 596 597 // 清空dur筛选输入框内容 598 clearCycleRange(): void { 599 this.cycleAStartRangeDIV!.value = ''; 600 this.cycleAEndRangeDIV!.value = ''; 601 this.cycleBStartRangeDIV!.value = ''; 602 this.cycleBEndRangeDIV!.value = ''; 603 } 604 605 // 画柱状图 606 drawColumn(): void { 607 this.chartTotal!.dataSource = this.dataSource!; 608 this.chartTotal!.config = { 609 data: this.dataSource!, 610 appendPadding: 10, 611 xField: 'xName', 612 yField: 'yAverage', 613 seriesField: '', 614 removeUnit: true, 615 notSort: true, 616 color: (a) => { 617 //@ts-ignore 618 const xName = a.xName; 619 if (xName === 'Total') { 620 return '#2f72f8'; 621 } else if (xName === 'cycleA') { 622 return '#ffab67'; 623 } else if (xName === 'cycleB') { 624 return '#a285d2'; 625 } else { 626 return '#0a59f7'; 627 } 628 }, 629 tip: (a) => { 630 //@ts-ignore 631 if (a && a[0]) { 632 //@ts-ignore 633 const obj = a[0]; 634 let tip: string = ''; 635 tip = `<div> 636 <div>Average count: ${obj.obj.yAverage}</div> 637 </div>`; 638 return tip; 639 } else { 640 return ''; 641 } 642 }, 643 label: null, 644 }; 645 } 646 647 connectedCallback(): void { 648 super.connectedCallback(); 649 resizeObserver(this.parentElement!, this.threadBindersTbl!); 650 } 651 652 // 页面结构 653 654 initHtml(): string { 655 return ` 656 <style> 657 :host{ 658 padding: 10px 10px; 659 display: flex; 660 flex-direction: column; 661 } 662 #dataCut{ 663 display: flex; 664 justify-content: space-between; 665 width:100%; 666 height:20px; 667 padding:auto; 668 align-items:center; 669 } 670 button{ 671 width:40%; 672 height:100%; 673 border: solid 1px #666666; 674 background-color: rgba(0,0,0,0); 675 border-radius:10px; 676 cursor: pointer; 677 } 678 button:hover{ 679 background-color:#666666; 680 color:white; 681 } 682 :host([clickSingle]) .click_single{ 683 background-color:#666666; 684 color:white; 685 } 686 :host([clickLoop]) .click_loop{ 687 background-color:#666666; 688 color:white; 689 } 690 .thread-id-input{ 691 width: 15%; 692 height:90%; 693 border-radius:10px; 694 border:solid 1px #979797; 695 font-size:15px; 696 text-indent:3% 697 } 698 .cycle-name-input{ 699 width: 20%; 700 height:90%; 701 border-radius:10px; 702 border:solid 1px #979797; 703 font-size:15px; 704 text-indent:3% 705 } 706 .data-cut-area{ 707 width:20%; 708 height: 100%; 709 display:flex; 710 justify-content: space-around; 711 } 712 .main-area{ 713 width:100%; 714 display:flex; 715 margin-top:5px; 716 } 717 lit-table{ 718 height: auto; 719 overflow-x:auto; 720 width:100% 721 } 722 #query-btn{ 723 width:90px; 724 } 725 .cycle-range-input { 726 width: 120px; 727 height: 18px; 728 padding: 1px 5px; 729 border-radius: 12px; 730 border: solid 1px #979797; 731 font-size: 15px; 732 text-indent: 3% 733 } 734 :host([dispalyQueryArea]) .query-cycle-area{ 735 display: none; 736 } 737 #chart_cycle{ 738 width:100%; 739 height:300px; 740 } 741 .chart_labels{ 742 height: 30px; 743 width: 100%; 744 display: flex; 745 flex-direction: row; 746 align-items: center; 747 justify-content: center; 748 margin-top:12px; 749 } 750 .labels{ 751 display: flex; 752 flex-direction: row; 753 align-items: center; 754 justify-content: center; 755 font-size: 9pt; 756 padding-right: 15px; 757 } 758 .labels_item{ 759 width: 20px; 760 height: 10px; 761 background-color: #2f72f8; 762 margin-right: 5px; 763 } 764 .chart_area{ 765 margin-top:40px; 766 height:0; 767 } 768 .chart_title{ 769 line-height: 40px; 770 height: 40px; 771 width: 100%; 772 text-align: center; 773 } 774 </style> 775 <div id='dataCut'> 776 <input id="dataCutThreadId" type="text" class="thread-id-input" placeholder="Please input thread id" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" /> 777 <input id="dataCutThreadFunc" type="text" class="cycle-name-input" placeholder="Please input function name" value='' /> 778 <div class="data-cut-area"> 779 <button id="single-btn" class="click_single">Single</button> 780 <button id="loop-btn" class="click_loop">Loop</button> 781 </div> 782 </div> 783 <div class="main-area"> 784 <lit-slicer style="width:100%"> 785 <div style="width:70%;"> 786 <lit-table id="tb-binder-count" style="height: auto; overflow-x:auto;width:100%;" tree> 787 <lit-table-column width="250px" title="Process/Thread/Cycle" data-index="title" key="title" align="flex-start" retract> 788 </lit-table-column> 789 <lit-table-column width="80px" title="Running count" data-index="RunningCount" key="RunningCoung" align="center"> 790 </lit-table-column> 791 <lit-table-column width="80px" title="Running dur(ms)" data-index="RunningDur" key="RunningDur" align="center"> 792 </lit-table-column> 793 <lit-table-column width="80px" title="Runnable count" data-index="RunnableCount" key="RunnableCount" align="center"> 794 </lit-table-column> 795 <lit-table-column width="80px" title="Runnable dur(ms)" data-index="RunnableDur" key="RunnableDur" align="center"> 796 </lit-table-column> 797 <lit-table-column width="80px" title="Sleeping count" data-index="SleepingCount" key="SleepingCount" align="center"> 798 </lit-table-column> 799 <lit-table-column width="80px" title="Sleeping dur(ms)" data-index="SleepingDur" key="SleepingDur" align="center"> 800 </lit-table-column> 801 <lit-table-column width="80px" title="D count" data-index="DCount" key="DCount" align="center"> 802 </lit-table-column> 803 <lit-table-column width="80px" title="D dur(ms)" data-index="DDur" key="DDUR" align="center"> 804 </lit-table-column> 805 <lit-table-column width="80px" title="Duration(ms)" data-index="cycleDur" key="cycleDur" align="center"> 806 </lit-table-column> 807 <lit-table-column width="80px" title="Total" data-index="totalCount" key="totalCount" align="center"> 808 </lit-table-column> 809 </lit-table> 810 </div> 811 <lit-slicer-track ></lit-slicer-track> 812 <div style="width:30%;padding: 16px;height:auto;overflow:auto;" class="query-cycle-area"> 813 <div > 814 <div id="cycle-a"> 815 <span>Cycle A: </span> 816 <input id="cycle-a-start-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" /> 817 <span>~</span> 818 <input id="cycle-a-end-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" /> 819 </div> 820 <div style="margin-top: 10px; display:flex; flex-derection:row; justify-content:space-between"> 821 <div id="cycle-b"> 822 <span>Cycle B: </span> 823 <input id="cycle-b-start-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" /> 824 <span>~</span> 825 <input id="cycle-b-end-range" type="text" class="cycle-range-input" placeholder="Duration(ms)" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" /> 826 </div> 827 <div> 828 <button id="query-btn">Query</button> 829 </div> 830 </div> 831 </div> 832 <div class="chart_area"> 833 <div class="chart_title">Average State Count</div> 834 <lit-chart-column id="chart_cycle"></lit-chart-column> 835 <div class="chart_labels"> 836 <div class="labels"><div class="labels_item"></div>Total</div> 837 <div class="labels"><div class="labels_item" style="background-color: #ffab67;"></div>CycleA</div> 838 <div class="labels"><div class="labels_item" style="background-color: #a285d2;"></div>CycleB</div> 839 </div> 840 </div> 841 </div> 842 </lit-slicer> 843 </div> 844 `; 845 } 846} 847