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 */ 15import { BaseElement, element } from '../../../../../base-ui/BaseElement'; 16import { type LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; 17import { Utils } from '../../base/Utils'; 18import { type SelectionParam } from '../../../../bean/BoxSelection'; 19import { 20 type BinderItem, 21 type ProcessBinderItem, 22 type ThreadBinderItem, 23 type DataSource, 24 type FunctionItem, 25 type BinderDataStruct, 26 CycleBinderItem, 27} from '../../../../bean/BinderProcessThread'; 28import { queryFuncNameCycle, queryLoopFuncNameCycle } from '../../../../../trace/database/sql/Func.sql'; 29import { queryBinderByThreadId } from '../../../../../trace/database/sql/ProcessThread.sql'; 30import { resizeObserver } from '../SheetUtils'; 31import { type LitChartColumn } from '../../../../../base-ui/chart/column/LitChartColumn'; 32import '../../../../../base-ui/chart/column/LitChartColumn'; 33import { SpSegmentationChart } from '../../../chart/SpSegmentationChart'; 34import { SliceGroup } from '../../../../bean/StateProcessThread'; 35 36const MILLIONS: number = 1000000; 37const THREE: number = 3; 38@element('tabpane-binder-datacut') 39export class TabPaneBinderDataCut extends BaseElement { 40 private threadBindersTbl: LitTable | null | undefined; 41 private currentSelectionParam: SelectionParam | any; 42 private threadStatesDIV: Element | null | undefined; 43 private cycleColumnDiv: HTMLDivElement | null | undefined; 44 private cycleARangeArr: CycleBinderItem[] = []; 45 private cycleBRangeArr: CycleBinderItem[] = []; 46 private cycleAStartRangeDIV: HTMLInputElement | null | undefined; 47 private cycleAEndRangeDIV: HTMLInputElement | null | undefined; 48 private cycleBStartRangeDIV: HTMLInputElement | null | undefined; 49 private cycleBEndRangeDIV: HTMLInputElement | null | undefined; 50 private chartTotal: LitChartColumn | null | undefined; 51 private dataSource: DataSource[] = []; 52 private rowCycleData: CycleBinderItem[] = []; 53 private currentThreadId: string = ''; 54 private threadArr: Array<ThreadBinderItem> = []; 55 private threadBinderMap: Map<string, Array<BinderItem>> = new Map(); 56 private processIds: Array<number> = []; 57 private funcCycleArr: Array<FunctionItem> = []; 58 59 set data(threadStatesParam: SelectionParam) { 60 if (this.currentSelectionParam === threadStatesParam) { 61 return; 62 } 63 this.currentSelectionParam = threadStatesParam; 64 SpSegmentationChart.setBinderChartData([]); 65 SpSegmentationChart.tabHover('BINDER', false, -1); 66 // @ts-ignore 67 this.processIds = [...new Set(this.currentSelectionParam.processIds)]; 68 this.threadArr = []; 69 this.threadBinderMap.clear(); 70 this.hideQueryArea(true); 71 this.clickLoop(false); 72 this.clickSingle(false); 73 this.threadBindersTbl!.recycleDataSource = []; 74 // @ts-ignore 75 this.tHeadClick(this.threadBindersTbl!.recycleDataSource); 76 this.parentElement!.style.overflow = 'hidden'; 77 new ResizeObserver(() => { 78 // @ts-ignore 79 let lastHeight: number = this.threadBindersTbl.tableElement!.offsetHeight; 80 this.cycleColumnDiv!.style.height = lastHeight + 'px'; 81 }).observe(this.threadBindersTbl!); 82 } 83 84 hideQueryArea(b: boolean): void { 85 if (b) { 86 this.setAttribute('hideQueryArea', ''); 87 } else { 88 this.removeAttribute('hideQueryArea'); 89 } 90 } 91 92 clickSingle(b: boolean): void { 93 if (b) { 94 this.setAttribute('clickSingle', ''); 95 } else { 96 this.removeAttribute('clickSingle'); 97 } 98 } 99 100 clickLoop(b: boolean): void { 101 if (b) { 102 this.setAttribute('clickLoop', ''); 103 } else { 104 this.removeAttribute('clickLoop'); 105 } 106 } 107 108 // 查询数据库,binder和Function查询 109 async queryDataFromDb( 110 threadIdValue: string, 111 threadFuncName: string, 112 threadIds: Array<number>, 113 leftNS: number, 114 rightNS: number, 115 type: string 116 ): Promise<void> { 117 let binderArr: Array<BinderItem> = await queryBinderByThreadId(this.processIds, threadIds, leftNS, rightNS); 118 if (binderArr.length > 0) { 119 this.structureThreadBinderMap(binderArr); 120 } 121 if (type === 'loop') { 122 //@ts-ignore 123 this.funcCycleArr = await queryLoopFuncNameCycle(threadFuncName, threadIdValue, leftNS, rightNS); 124 } else { 125 this.funcCycleArr = await queryFuncNameCycle(threadFuncName, threadIdValue, leftNS, rightNS); 126 } 127 } 128 129 //点击single loop 切割按钮方法 130 async dataCutFunc(threadId: HTMLInputElement, threadFunc: HTMLInputElement, type: string): Promise<void> { 131 this.currentThreadId = ''; 132 let threadIdValue = threadId.value.trim(); 133 let threadFuncName = threadFunc.value.trim(); 134 135 this.clickLoop(type === 'loop' ? true : false); 136 this.clickSingle(type === 'loop' ? false : true); 137 //清空泳道图 138 SpSegmentationChart.setBinderChartData([]); 139 SpSegmentationChart.tabHover('BINDER', false, -1); 140 if (threadIdValue !== '' && threadFuncName !== '') { 141 this.threadBindersTbl!.loading = true; 142 threadId.style.border = '1px solid rgb(151,151,151)'; 143 threadFunc.style.border = '1px solid rgb(151,151,151)'; 144 let threadIds = this.currentSelectionParam.threadIds; 145 let leftNS = this.currentSelectionParam.leftNs; 146 let rightNS = this.currentSelectionParam.rightNs; 147 this.threadArr = []; 148 this.threadBinderMap.clear(); 149 await this.queryDataFromDb(threadIdValue, threadFuncName, threadIds, leftNS, rightNS, type); 150 if (this.funcCycleArr.length !== 0) { 151 let cycleMap: Map<string, Array<CycleBinderItem>> = type === 'loop' 152 ? this.loopDataCutCycleMap(this.funcCycleArr) 153 : this.singleDataCutCycleMap(this.funcCycleArr); 154 this.threadBindersTbl!.recycleDataSource = this.mergeData(cycleMap); 155 this.threadBindersTbl!.loading = false; // @ts-ignore 156 this.tHeadClick(this.threadBindersTbl!.recycleDataSource); 157 } else { 158 this.threadBindersTbl!.recycleDataSource = []; 159 this.threadBindersTbl!.loading = false; // @ts-ignore 160 this.tHeadClick(this.threadBindersTbl!.recycleDataSource); 161 } 162 } else { 163 this.verifyInputIsEmpty(threadIdValue, threadFuncName, threadId, threadFunc); 164 } 165 } 166 167 verifyInputIsEmpty( 168 threadIdValue: string, 169 threadFuncName: string, 170 threadId: HTMLInputElement, 171 threadFunc: HTMLInputElement 172 ): void { 173 if (threadIdValue === '') { 174 threadId.style.border = '1px solid rgb(255,0,0)'; 175 threadId.setAttribute('placeholder', 'Please input thread id'); 176 this.threadBindersTbl!.recycleDataSource = []; 177 this.threadBindersTbl!.loading = false; // @ts-ignore 178 this.tHeadClick(this.threadBindersTbl!.recycleDataSource); 179 } else { 180 threadId.style.border = '1px solid rgb(151,151,151)'; 181 } 182 if (threadFuncName === '') { 183 threadFunc.style.border = '1px solid rgb(255,0,0)'; 184 threadFunc.setAttribute('placeholder', 'Please input function name'); 185 this.threadBindersTbl!.recycleDataSource = []; 186 this.threadBindersTbl!.loading = false; // @ts-ignore 187 this.tHeadClick(this.threadBindersTbl!.recycleDataSource); 188 } else { 189 threadFunc.style.border = '1px solid rgb(151,151,151)'; 190 } 191 } 192 193 // 构建线程 binder Map数据 194 structureThreadBinderMap(binderArr: Array<BinderItem>): void { 195 for (let b of binderArr) { 196 if (!this.threadBinderMap.has(b.pid + '_' + b.tid)) { 197 this.threadArr.push({ 198 title: 199 Utils.getInstance().getThreadMap().get(b.tid) === null 200 ? 'Thread' + ' ' + '[' + b.tid + ']' 201 : Utils.getInstance().getThreadMap().get(b.tid) + ' ' + '[' + b.tid + ']', 202 totalCount: 0, 203 tid: b.tid, 204 pid: b.pid, 205 children: [], 206 type: 'Thread', 207 }); 208 this.threadBinderMap.set(b.pid + '_' + b.tid, new Array()); 209 } 210 let arr: Array<BinderItem> | undefined = this.threadBinderMap.get(b.pid + '_' + b.tid); 211 arr?.push(b); 212 } 213 } 214 215 deepCloneThreadBinderMap(threadBinderMap: Map<string, Array<BinderItem>>): Map<string, Array<BinderItem>> { 216 let cloneThreadBinderMap: Map<string, Array<BinderItem>> = new Map(); 217 if (cloneThreadBinderMap instanceof Map) { 218 threadBinderMap.forEach((val, key) => { 219 const k = key; 220 const v = JSON.parse(JSON.stringify(val)); 221 cloneThreadBinderMap.set(k, v); 222 }); 223 } 224 return cloneThreadBinderMap; 225 } 226 227 // 构建single切割cycle Map数据 228 singleDataCutCycleMap(funcNameArr: Array<FunctionItem>): Map<string, Array<CycleBinderItem>> { 229 let cloneThreadBinderMap: Map<string, Array<BinderItem>> = this.deepCloneThreadBinderMap(this.threadBinderMap); 230 let cycleMap: Map<string, Array<CycleBinderItem>> = new Map(); 231 cloneThreadBinderMap.forEach((tBinder: Array<BinderItem>) => { 232 funcNameArr.forEach((func, idx) => { 233 let cycleArr: Array<CycleBinderItem> | undefined = []; 234 let countBinder: CycleBinderItem = new CycleBinderItem(); 235 let cid = func.id; 236 for (let j: number = 0; j < tBinder.length; j++) { 237 if (!cycleMap.has(tBinder[j].tid + '_' + cid)) { 238 cycleMap.set(tBinder[j].tid + '_' + cid, new Array()); 239 } 240 cycleArr = cycleMap.get(tBinder[j].tid + '_' + cid); 241 let thread: string = Utils.getInstance().getThreadMap().get(tBinder[j].tid) || 'Thread'; 242 countBinder.title = 'cycle ' + (idx + 1) + '_' + thread; 243 countBinder.tid = tBinder[j].tid; 244 countBinder.pid = tBinder[j].pid; 245 countBinder.durNs = func.dur; 246 countBinder.tsNs = func.cycleStartTime; 247 countBinder.cycleDur = Number((func.dur / MILLIONS).toFixed(THREE)); 248 countBinder.cycleStartTime = Number((func.cycleStartTime / MILLIONS).toFixed(THREE)); 249 if ( 250 tBinder[j].ts + tBinder[j].dur > func.cycleStartTime && 251 tBinder[j].ts + tBinder[j].dur < func.cycleStartTime + func!.dur 252 ) { 253 countBinder.totalCount += 1; 254 countBinder.binderTransactionCount += tBinder[j].name === 'binder transaction' ? 1 : 0; 255 countBinder.binderAsyncRcvCount += tBinder[j].name === 'binder async rcv' ? 1 : 0; 256 countBinder.binderReplyCount += tBinder[j].name === 'binder reply' ? 1 : 0; 257 countBinder.binderTransactionAsyncCount += tBinder[j].name === 'binder transaction async' ? 1 : 0; 258 countBinder.idx = idx + 1; 259 tBinder.splice(j, 1); 260 j--; 261 } 262 } 263 cycleArr?.push(countBinder); 264 }); 265 }); 266 return cycleMap; 267 } 268 269 // 构建loop切割cycle Map数据 270 loopDataCutCycleMap(funcNameArr: Array<FunctionItem>): Map<string, Array<CycleBinderItem>> { 271 let cloneThreadBinderMap: Map<string, Array<BinderItem>> = this.deepCloneThreadBinderMap(this.threadBinderMap); 272 let cycleMap: Map<string, Array<CycleBinderItem>> = new Map(); 273 cloneThreadBinderMap.forEach((tBinder: Array<BinderItem>) => { 274 for (let i: number = 0; i < funcNameArr.length - 1; i++) { 275 let cycleArr: Array<CycleBinderItem> | undefined = []; 276 let countBinder: CycleBinderItem = new CycleBinderItem(); 277 let cid: number = funcNameArr[i].id; 278 for (let j: number = 0; j < tBinder.length; j++) { 279 if (!cycleMap.has(tBinder[j].tid + '_' + cid)) { 280 cycleMap.set(tBinder[j].tid + '_' + cid, new Array()); 281 } 282 cycleArr = cycleMap.get(tBinder[j].tid + '_' + cid); 283 let thread: string = Utils.getInstance().getThreadMap().get(tBinder[j].tid) || 'Thread'; 284 countBinder.title = 'cycle ' + (i + 1) + '_' + thread; 285 countBinder.tid = tBinder[j].tid; 286 countBinder.pid = tBinder[j].pid; 287 countBinder.durNs = funcNameArr[i + 1].cycleStartTime - funcNameArr[i].cycleStartTime; 288 countBinder.tsNs = funcNameArr[i].cycleStartTime; 289 countBinder.cycleDur = Number( 290 ((funcNameArr[i + 1].cycleStartTime - funcNameArr[i].cycleStartTime) / MILLIONS).toFixed(THREE) 291 ); 292 countBinder.cycleStartTime = Number((funcNameArr[i].cycleStartTime / MILLIONS).toFixed(THREE)); 293 if ( 294 tBinder[j].ts + tBinder[j].dur > funcNameArr[i].cycleStartTime && 295 tBinder[j].ts + tBinder[j].dur < funcNameArr[i + 1].cycleStartTime 296 ) { 297 countBinder.totalCount += 1; 298 countBinder!.binderTransactionCount += tBinder[j].name === 'binder transaction' ? 1 : 0; 299 countBinder!.binderAsyncRcvCount += tBinder[j].name === 'binder async rcv' ? 1 : 0; 300 countBinder.binderReplyCount += tBinder[j].name === 'binder reply' ? 1 : 0; 301 countBinder.binderTransactionAsyncCount += tBinder[j].name === 'binder transaction async' ? 1 : 0; 302 countBinder.idx = i + 1; 303 tBinder.splice(j, 1); 304 j--; 305 } 306 } 307 cycleArr?.push(countBinder); 308 } 309 }); 310 return cycleMap; 311 } 312 313 //组成树结构数据 314 mergeData(cycleMap: Map<string, Array<CycleBinderItem>>): Array<ProcessBinderItem> { 315 let processArr: Array<ProcessBinderItem> = []; 316 let processIds: Array<number> = []; 317 // 将thread级下的周期数据放入对应的thread下。树结构的第二层thread数据 318 for (let thread of this.threadArr) { 319 if (!processIds.includes(thread.pid)) { 320 processIds.push(thread.pid); 321 } 322 thread.totalCount = 0; 323 thread.children = []; 324 for (let key of cycleMap!.keys()) { 325 let cycle: Array<CycleBinderItem> | undefined = cycleMap.get(key); 326 if (key.split('_')[0] === thread.tid + '') { 327 thread.totalCount += cycle![0].totalCount; 328 thread.children.push(cycle![0]); 329 } 330 } 331 } 332 // process级的数组数据,也就是树结构的根数据层 333 processIds.forEach((pid) => { 334 processArr.push({ 335 pid: pid, 336 title: 337 Utils.getInstance().getProcessMap().get(pid) === null 338 ? 'Process' + ' ' + '[' + pid + ']' 339 : Utils.getInstance().getProcessMap().get(pid) + ' ' + '[' + pid + ']', 340 totalCount: 0, 341 type: 'Process', 342 children: [], 343 }); 344 }); 345 // 将process级下的thread数据放入对应的process下 346 for (let process of processArr) { 347 for (let thread of this.threadArr) { 348 if (thread.pid === process.pid) { 349 process.totalCount += thread.totalCount; 350 process.children.push(thread); 351 } 352 } 353 } 354 return processArr; 355 } 356 357 // 构建画泳道图的数据 358 structuredLaneChartData(rowCycleData: CycleBinderItem[]): Array<BinderDataStruct[]> { 359 let laneChartData: Array<BinderDataStruct[]> = []; 360 rowCycleData.forEach((it) => { 361 if (it.totalCount !== 0) { 362 let cycleDataArr: BinderDataStruct[] = []; 363 if (it.binderTransactionCount !== 0) { 364 cycleDataArr.push({ 365 name: 'binder transaction', 366 value: it.binderTransactionCount!, 367 dur: it.durNs, 368 startNS: it.tsNs, 369 cycle: it.idx, 370 }); 371 } 372 if (it.binderTransactionAsyncCount !== 0) { 373 cycleDataArr.push({ 374 name: 'binder transaction async', 375 value: it.binderTransactionAsyncCount!, 376 dur: it.durNs, 377 startNS: it.tsNs, 378 cycle: it.idx, 379 }); 380 } 381 if (it.binderReplyCount !== 0) { 382 cycleDataArr.push({ 383 name: 'binder reply', 384 value: it.binderReplyCount!, 385 dur: it.durNs, 386 startNS: it.tsNs, 387 cycle: it.idx, 388 }); 389 } 390 if (it.binderAsyncRcvCount !== 0) { 391 cycleDataArr.push({ 392 name: 'binder async rcv', 393 value: it.binderAsyncRcvCount!, 394 dur: it.durNs, 395 startNS: it.tsNs, 396 cycle: it.idx, 397 }); 398 } 399 laneChartData.push(cycleDataArr); 400 } 401 }); 402 return laneChartData; 403 } 404 405 clearCycleRange(): void { 406 this.cycleAStartRangeDIV!.value = ''; 407 this.cycleAEndRangeDIV!.value = ''; 408 this.cycleBStartRangeDIV!.value = ''; 409 this.cycleBEndRangeDIV!.value = ''; 410 } 411 412 drawColumn(): void { 413 this.chartTotal!.dataSource = this.dataSource!; 414 this.chartTotal!.config = { 415 data: this.dataSource!, 416 appendPadding: 10, 417 xField: 'xName', 418 yField: 'yAverage', 419 seriesField: '', 420 removeUnit: true, 421 notSort: true, 422 color: (a) => { 423 //@ts-ignore 424 if (a.xName === 'Total') { 425 return '#2f72f8'; //@ts-ignore 426 } else if (a.xName === 'cycleA') { 427 return '#ffab67'; //@ts-ignore 428 } else if (a.xName === 'cycleB') { 429 return '#a285d2'; 430 } else { 431 return '#0a59f7'; 432 } 433 }, 434 tip: (a) => { 435 //@ts-ignore 436 if (a && a[0]) { 437 let tip: string = ''; 438 tip = `<div> 439 <div>Average count: ${ 440 //@ts-ignore 441 a[0].obj.yAverage 442 }</div> 443 </div>`; 444 return tip; 445 } else { 446 return ''; 447 } 448 }, 449 label: null, 450 }; 451 } 452 453 tHeadClick(data: Array<SliceGroup>): void { 454 let labels = this.threadBindersTbl?.shadowRoot?.querySelector('.th > .td')?.querySelectorAll('label'); 455 if (labels) { 456 for (let i = 0; i < labels.length; i++) { 457 let label = labels[i].innerHTML; 458 labels[i].addEventListener('click', (e) => { 459 if (label.includes('Process')) { 460 this.threadBindersTbl!.setStatus(data, false); 461 this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement( 462 data, 463 RedrawTreeForm.Retract 464 ); 465 } else if (label.includes('Thread')) { 466 for (let item of data) { 467 item.status = true; 468 if (item.children !== undefined && item.children.length > 0) { 469 this.threadBindersTbl!.setStatus(item.children, false); 470 } 471 } 472 this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement( 473 data, 474 RedrawTreeForm.Retract 475 ); 476 } else if (label.includes('Cycle')) { 477 this.threadBindersTbl!.setStatus(data, true); 478 this.threadBindersTbl!.recycleDs = this.threadBindersTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand); 479 } 480 }); 481 } 482 } 483 } 484 485 //点击Thread行表格数据时 486 tableRowClickFunc(): void { 487 this.threadBindersTbl!.addEventListener('row-click', (evt: any) => { 488 let currentData = evt.detail.data; 489 if (currentData.type === 'Process') { 490 currentData.isSelected = true; 491 this.threadBindersTbl!.clearAllSelection(currentData); 492 this.threadBindersTbl!.setCurrentSelection(currentData); 493 this.hideQueryArea(true); 494 SpSegmentationChart.setBinderChartData([]); 495 SpSegmentationChart.tabHover('BINDER', false, -1); 496 } 497 if (currentData.type === 'Thread') { 498 SpSegmentationChart.tabHover('BINDER', false, -1); 499 this.currentThreadId = currentData.tid + '' + currentData.pid; 500 this.clearCycleRange(); 501 currentData.isSelected = true; 502 this.threadBindersTbl!.clearAllSelection(currentData); 503 this.threadBindersTbl!.setCurrentSelection(currentData); 504 this.rowCycleData = currentData.children; 505 this.hideQueryArea(false); 506 let totalCount = currentData.totalCount; 507 this.dataSource = []; 508 this.dataSource.push({ 509 xName: 'Total', 510 yAverage: totalCount > 0 ? Math.ceil(totalCount / this.rowCycleData!.length) : 0, 511 }); 512 //绘制柱状图 513 this.drawColumn(); 514 let laneChartData: Array<BinderDataStruct[]> = this.structuredLaneChartData(currentData.children!); 515 //绘制泳道图 516 SpSegmentationChart.setBinderChartData(laneChartData); 517 } 518 519 if (currentData.type === 'Cycle' && currentData.tid + '' + currentData.pid === this.currentThreadId) { 520 currentData.isSelected = true; 521 this.threadBindersTbl!.clearAllSelection(currentData); 522 this.threadBindersTbl!.setCurrentSelection(currentData); 523 //泳道图的鼠标悬浮 524 SpSegmentationChart.tabHover('BINDER', true, currentData.idx); 525 } 526 }); 527 } 528 529 //点击query按钮绘制柱状图 530 queryBtnClick(): void { 531 this.shadowRoot?.querySelector('#query-btn')?.addEventListener('click', () => { 532 this.cycleARangeArr = this.rowCycleData?.filter((it: CycleBinderItem) => { 533 return ( 534 it.cycleDur >= Number(this.cycleAStartRangeDIV!.value) && it.cycleDur < Number(this.cycleAEndRangeDIV!.value) 535 ); 536 }); 537 this.cycleBRangeArr = this.rowCycleData?.filter((it: CycleBinderItem) => { 538 return ( 539 it.cycleDur >= Number(this.cycleBStartRangeDIV!.value) && it.cycleDur < Number(this.cycleBEndRangeDIV!.value) 540 ); 541 }); 542 let cycleACount: number = 0; 543 this.cycleARangeArr?.forEach((it: CycleBinderItem) => { 544 cycleACount += it.totalCount; 545 }); 546 let cycleBCount: number = 0; 547 this.cycleBRangeArr?.forEach((it: CycleBinderItem) => { 548 cycleBCount += it.totalCount; 549 }); 550 this.dataSource!.length > 1 && this.dataSource?.splice(1); 551 this.dataSource!.push({ 552 xName: 'cycleA', 553 yAverage: cycleACount !== 0 ? Math.ceil(cycleACount / this.cycleARangeArr!.length) : 0, 554 }); 555 this.dataSource!.push({ 556 xName: 'cycleB', 557 yAverage: cycleBCount !== 0 ? Math.ceil(cycleBCount / this.cycleBRangeArr!.length) : 0, 558 }); 559 this.drawColumn(); 560 }); 561 } 562 563 initElements(): void { 564 this.threadBindersTbl = this.shadowRoot?.querySelector<LitTable>('#tb-binder-count'); 565 this.chartTotal = this.shadowRoot!.querySelector<LitChartColumn>('#chart_cycle'); 566 this.cycleAStartRangeDIV = this.shadowRoot?.querySelector('#cycle-a-start-range'); 567 this.cycleAEndRangeDIV = this.shadowRoot?.querySelector('#cycle-a-end-range'); 568 this.cycleBStartRangeDIV = this.shadowRoot?.querySelector('#cycle-b-start-range'); 569 this.cycleBEndRangeDIV = this.shadowRoot?.querySelector('#cycle-b-end-range'); 570 this.cycleColumnDiv = this.shadowRoot?.querySelector('#cycleColumn'); 571 this.threadStatesDIV = this.shadowRoot!.querySelector('#dataCut'); 572 this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => { 573 this.hideQueryArea(true); 574 this.dataSource = []; 575 // @ts-ignore 576 this.dataCutFunc(this.threadStatesDIV!.children[0], this.threadStatesDIV?.children[1], 'single'); 577 }); 578 this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => { 579 this.hideQueryArea(true); 580 this.dataSource = []; 581 // @ts-ignore 582 this.dataCutFunc(this.threadStatesDIV?.children[0], this.threadStatesDIV?.children[1], 'loop'); 583 }); 584 this.tableRowClickFunc(); 585 this.queryBtnClick(); 586 } 587 588 connectedCallback(): void { 589 super.connectedCallback(); 590 resizeObserver(this.parentElement!, this.threadBindersTbl!); 591 } 592 593 initHtml(): string { 594 return ` 595 <style> 596 :host{ 597 padding: 10px 10px; 598 display: flex; 599 flex-direction: column; 600 } 601 #dataCut{ 602 display: flex; 603 justify-content: space-between; 604 width:100%; 605 height:20px; 606 padding:auto; 607 align-items:center; 608 } 609 button{ 610 width:40%; 611 min-width:90px; 612 height:100%; 613 border: solid 1px #666666; 614 background-color: rgba(0,0,0,0); 615 border-radius:10px; 616 cursor: pointer; 617 } 618 button:hover{ 619 background-color:#666666; 620 color:white; 621 } 622 :host([clickSingle]) .click_single{ 623 background-color:#666666; 624 color:white; 625 } 626 :host([clickLoop]) .click_loop{ 627 background-color:#666666; 628 color:white; 629 } 630 .thread-id-input{ 631 width: 15%; 632 height:90%; 633 border-radius:10px; 634 border:solid 1px #979797; 635 font-size:15px; 636 text-indent:3% 637 } 638 .cycle-name-input{ 639 width: 20%; 640 height:90%; 641 border-radius:10px; 642 border:solid 1px #979797; 643 font-size:15px; 644 text-indent:3% 645 } 646 .data-cut-area{ 647 width:20%; 648 height: 100%; 649 display:flex; 650 justify-content: space-around; 651 } 652 .main-area{ 653 width:100%; 654 display:flex; 655 margin-top:5px; 656 } 657 lit-table{ 658 height: auto; 659 overflow-x:auto; 660 width:100% 661 } 662 #query-btn{ 663 width:90px; 664 } 665 .cycle-range-input { 666 width: 24%; 667 height: 18px; 668 padding: 1px 5px; 669 border-radius: 12px; 670 border: solid 1px #979797; 671 font-size: 15px; 672 text-indent: 3% 673 } 674 :host([hideQueryArea]) .query-cycle-area{ 675 display: none; 676 } 677 #chart_cycle{ 678 width:100%; 679 height:300px; 680 } 681 .chart_labels{ 682 height: 30px; 683 width: 100%; 684 display: flex; 685 flex-direction: row; 686 align-items: center; 687 justify-content: center; 688 margin-top:12px; 689 margin-bottom:20px; 690 } 691 .labels{ 692 display: flex; 693 flex-direction: row; 694 align-items: center; 695 justify-content: center; 696 font-size: 9pt; 697 padding-right: 15px; 698 } 699 .labels_item{ 700 width: 20px; 701 height: 10px; 702 background-color: #2f72f8; 703 margin-right: 5px; 704 } 705 .chart_area{ 706 margin-top:20px; 707 } 708 .chart_title{ 709 line-height: 40px; 710 height: 40px; 711 width: 100%; 712 text-align: center; 713 } 714 </style> 715 <div id='dataCut'> 716 <input id="dataCutThreadId" type="text" class="thread-id-input" placeholder="Please input thread id" value='' onblur="this.value=this.value.replace(/[^0-9.]/g,'')" /> 717 <input id="dataCutThreadFunc" type="text" class="cycle-name-input" placeholder="Please input function name" value='' /> 718 <div class="data-cut-area"> 719 <button id="single-btn" class="click_single">Single</button> 720 <button id="loop-btn" class="click_loop">Loop</button> 721 </div> 722 </div> 723 <div class="main-area"> 724 <lit-slicer style="width:100%"> 725 <div style="width:65%;"> 726 <lit-table id="tb-binder-count" style="height: auto; overflow-x:auto;width:100%" tree> 727 <lit-table-column width="250px" title="Process/Thread/Cycle" data-index="title" key="title" align="flex-start" retract> 728 </lit-table-column> 729 <lit-table-column width="100px" title="Total count" data-index="totalCount" key="totalCount" align="center"> 730 </lit-table-column> 731 <lit-table-column width="100px" title="Binder transaction count" data-index="binderTransactionCount" key="binderTransactionCount" align="center"> 732 </lit-table-column> 733 <lit-table-column width="100px" title="Binder transaction async count" data-index="binderTransactionAsyncCount" key="binderTransactionAsyncCount" align="center"> 734 </lit-table-column> 735 <lit-table-column width="100px" title="Binder reply count" data-index="binderReplyCount" key="binderReplyCount" align="center"> 736 </lit-table-column> 737 <lit-table-column width="100px" title="Binder async rcv count" data-index="binderAsyncRcvCount" key="binderAsyncRcvCount" align="center"> 738 </lit-table-column> 739 <lit-table-column width="100px" title="Cycle start time(ms)" data-index="cycleStartTime" key="cycleStartTime" align="flex-start"> 740 </lit-table-column> 741 <lit-table-column width="110px" title="Duration(ms)" data-index="cycleDur" key="cycleDur" align="flex-start"> 742 </lit-table-column> 743 </lit-table> 744 </div> 745 <lit-slicer-track ></lit-slicer-track> 746 <div style="width:35%;min-width:350px;padding:16px;overflow:auto;" id="cycleColumn" class="query-cycle-area"> 747 <div id="cycle-a" style="width:84%"> 748 <span>Cycle A: </span> 749 <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,'')" /> 750 <span>~</span> 751 <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,'')" /> 752 </div> 753 <div style="margin-top: 10px; display:flex; flex-derection:row; justify-content:space-between;width:100%"> 754 <div id="cycle-b" style="width:84%"> 755 <span>Cycle B: </span> 756 <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,'')" /> 757 <span>~</span> 758 <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,'')" /> 759 </div> 760 <div> 761 <button id="query-btn">Query</button> 762 </div> 763 </div> 764 <div class="chart_area"> 765 <div class="chart_title">Average Binder Count</div> 766 <lit-chart-column id="chart_cycle"></lit-chart-column> 767 <div class="chart_labels"> 768 <div class="labels"><div class="labels_item"></div>Total</div> 769 <div class="labels"><div class="labels_item" style="background-color: #ffab67;"></div>Cycle A</div> 770 <div class="labels"><div class="labels_item" style="background-color: #a285d2;"></div>Cycle B</div> 771 </div> 772 </div> 773 </div> 774 </lit-slicer> 775 </div> 776 `; 777 } 778} 779