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