1/* 2 * Copyright (C) 2023 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 { LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; 17import { SelectionParam } from '../../../../bean/BoxSelection'; 18import '../../../StackBar'; 19import { getTabRunningPercent } from '../../../../database/sql/ProcessThread.sql'; 20import { queryCpuFreqUsageData, queryCpuFreqFilterId } from '../../../../database/sql/Cpu.sql'; 21import { querySearchFuncData } from '../../../../database/sql/Func.sql'; 22import { Utils } from '../../base/Utils'; 23import { resizeObserver } from '../SheetUtils'; 24import { LitChartScatter } from '../../../../../base-ui/chart/scatter/LitChartScatter'; 25import { SpSegmentationChart } from '../../../chart/SpSegmentationChart'; 26import { TabPaneFreqUsageConfig, type TabPaneRunningConfig, TabPaneCpuFreqConfig } from './TabPaneFreqUsageConfig'; 27@element('tabpane-freqdatacut') 28export class TabPaneFreqDataCut extends BaseElement { 29 private threadStatesTbl: LitTable | null | undefined; 30 private threadStatesTblSource: Array<TabPaneFreqUsageConfig> = []; 31 private currentSelectionParam: SelectionParam | any; 32 private threadStatesDIV: HTMLDivElement | null | undefined; 33 private scatterInput: HTMLInputElement | null | undefined; 34 private initData: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 35 private processArr: Array<TabPaneFreqUsageConfig> = []; 36 private threadArr: Array<TabPaneFreqUsageConfig> = []; 37 private statisticsScatter: LitChartScatter | null | undefined; 38 set data(threadStatesParam: SelectionParam) { 39 if (this.currentSelectionParam === threadStatesParam) { 40 return; 41 } 42 this.currentSelectionParam = threadStatesParam; 43 this.initData = new Map(); 44 this.threadArr = []; 45 this.initUI(); 46 this.init(threadStatesParam); 47 let pidArr: Array<TabPaneFreqUsageConfig> = []; 48 // 整理进程级的数组信息 49 let processArr: Array<number> = 50 threadStatesParam.processIds.length > 1 51 ? [...new Set(threadStatesParam.processIds)] 52 : threadStatesParam.processIds; 53 for (let i of processArr) { 54 pidArr.push( 55 new TabPaneFreqUsageConfig( 56 Utils.getInstance().getProcessMap().get(i) === null 57 ? 'Process ' + i 58 : Utils.getInstance().getProcessMap().get(i) + ' ' + i, 59 '', 60 i, 61 '', 62 0, 63 '', 64 '', 65 0, 66 '', 67 0, 68 'process', 69 -1, 70 [] 71 ) 72 ); 73 } 74 // 拷贝给私有属性,以便后续进行数据切割时免除整理进程层级数据 75 this.processArr = pidArr; 76 } 77 /** 78 * 初始化数据 79 */ 80 async init(threadStatesParam: SelectionParam): Promise<void> { 81 let { 82 runningMap, 83 sum, 84 }: { 85 runningMap: Map<string, Array<TabPaneRunningConfig>>; 86 sum: number; 87 } = await this.queryRunningData(threadStatesParam); 88 let cpuFreqData: Array<TabPaneCpuFreqConfig> = await this.queryCpuFreqData(threadStatesParam); 89 if (runningMap.size > 0) { 90 // 将cpu频点数据与running状态数据整合,保证其上该段时长内有对应的cpu频点数据 91 this.mergeFreqData(runningMap, cpuFreqData, sum); 92 this.threadStatesTbl!.loading = false; 93 } else { 94 this.threadStatesTblSource = []; 95 this.threadStatesTbl!.recycleDataSource = []; 96 this.threadStatesTbl!.loading = false; 97 } 98 } 99 /** 100 * 重置UI输入框等组件为默认状态 101 */ 102 initUI(): void { 103 this.threadStatesTblSource = []; 104 this.threadStatesTbl!.recycleDataSource = []; 105 this.threadStatesTbl!.loading = true; 106 // @ts-ignore 107 this.threadStatesTbl.value = []; 108 // @ts-ignore 109 this.shadowRoot?.querySelector('#dataCutThreadId').style.border = '1px solid rgb(151,151,151)'; 110 // @ts-ignore 111 this.shadowRoot?.querySelector('#dataCutThreadFunc').style.border = '1px solid rgb(151,151,151)'; 112 // @ts-ignore 113 this.shadowRoot?.querySelector('#maxFreq').style.border = '1px solid rgb(151,151,151)'; 114 // @ts-ignore 115 this.shadowRoot?.querySelector('#maxHz').style.border = '1px solid rgb(151,151,151)'; 116 // @ts-ignore 117 this.shadowRoot?.querySelector('#cycle-a-start-range').value = ''; 118 // @ts-ignore 119 this.shadowRoot?.querySelector('#cycle-a-end-range').value = ''; 120 // @ts-ignore 121 this.shadowRoot?.querySelector('#cycle-b-start-range').value = ''; 122 // @ts-ignore 123 this.shadowRoot?.querySelector('#cycle-b-end-range').value = ''; 124 // @ts-ignore 125 this.shadowRoot?.querySelector('#cycleQuery')!.style.display = 'none'; 126 // @ts-ignore 127 this.shadowRoot?.querySelector('#dataCut')?.children[2].children[0].style.backgroundColor = '#fff'; 128 // @ts-ignore 129 this.shadowRoot?.querySelector('#dataCut')?.children[2].children[0].style.color = '#000'; 130 // @ts-ignore 131 this.shadowRoot?.querySelector('#dataCut')?.children[2].children[1].style.backgroundColor = '#fff'; 132 // @ts-ignore 133 this.shadowRoot?.querySelector('#dataCut')?.children[2].children[1].style.color = '#000'; 134 // @ts-ignore 135 this.statisticsScatter!.config = undefined; 136 this.parentElement!.style.overflow = 'hidden'; 137 } 138 /** 139 * 查询cpu频点信息 140 */ 141 async queryCpuFreqData(threadStatesParam: SelectionParam): Promise<Array<TabPaneCpuFreqConfig>> { 142 // 查询cpu及id信息 143 let result: Array<{ id: number; cpu: number }> = await queryCpuFreqFilterId(); 144 // 以键值对形式将cpu及id进行对应,后续会将频点数据与其对应cpu进行整合 145 let idMap: Map<number, number> = new Map(); 146 let queryId: Array<number> = []; 147 for (let i = 0; i < result.length; i++) { 148 queryId.push(result[i].id); 149 idMap.set(result[i].id, result[i].cpu); 150 } 151 let dealArr: Array<TabPaneCpuFreqConfig> = []; 152 // 通过id去查询频点数据 153 let res: Array<{ 154 startNS: number; 155 filter_id: number; 156 value: number; 157 dur: number; 158 }> = await queryCpuFreqUsageData(queryId); 159 for (let i of res) { 160 dealArr.push( 161 new TabPaneCpuFreqConfig(i.startNS + threadStatesParam.recordStartNs, idMap.get(i.filter_id)!, i.value, i.dur) 162 ); 163 } 164 return dealArr; 165 } 166 /** 167 * 查询框选区域内的所有running状态数据 168 */ 169 async queryRunningData( 170 threadStatesParam: SelectionParam 171 ): Promise<{ runningMap: Map<string, Array<TabPaneRunningConfig>>; sum: number }> { 172 let result: Array<TabPaneRunningConfig> = await getTabRunningPercent( 173 threadStatesParam.threadIds, 174 threadStatesParam.processIds, 175 threadStatesParam.leftNs, 176 threadStatesParam.rightNs 177 ); 178 let needDeal: Map<string, Array<TabPaneRunningConfig>> = new Map(); 179 let sum: number = 0; 180 if (result !== null && result.length > 0) { 181 let processArr: Array<number> = 182 threadStatesParam.processIds.length > 1 183 ? [...new Set(threadStatesParam.processIds)] 184 : threadStatesParam.processIds; 185 for (let e of result) { 186 if (processArr.includes(e.pid)) { 187 if (needDeal.get(e.pid + '_' + e.tid) === undefined) { 188 this.threadArr.push( 189 new TabPaneFreqUsageConfig( 190 Utils.getInstance().getThreadMap().get(e.tid) + ' ' + e.tid, 191 '', 192 e.pid, 193 e.tid, 194 0, 195 '', 196 '', 197 0, 198 '', 199 0, 200 'thread', 201 -1, 202 [] 203 ) 204 ); 205 needDeal.set(e.pid + '_' + e.tid, new Array()); 206 } 207 if ( 208 e.ts < threadStatesParam.leftNs + threadStatesParam.recordStartNs && 209 e.ts + e.dur > threadStatesParam.leftNs + threadStatesParam.recordStartNs 210 ) { 211 const ts = e.ts; 212 e.ts = threadStatesParam.leftNs + threadStatesParam.recordStartNs; 213 e.dur = ts + e.dur - (threadStatesParam.leftNs + threadStatesParam.recordStartNs); 214 } 215 if (e.ts + e.dur > threadStatesParam.rightNs + threadStatesParam.recordStartNs) { 216 e.dur = threadStatesParam.rightNs + threadStatesParam.recordStartNs - e.ts; 217 } 218 e.process = 219 Utils.getInstance().getProcessMap().get(e.pid) === null 220 ? '[NULL]' 221 : Utils.getInstance().getProcessMap().get(e.pid)!; 222 e.thread = 223 Utils.getInstance().getThreadMap().get(e.tid) === null 224 ? '[NULL]' 225 : Utils.getInstance().getThreadMap().get(e.tid)!; 226 let arr: Array<TabPaneRunningConfig> | undefined = needDeal.get(e.pid + '_' + e.tid); 227 sum += e.dur; 228 arr?.push(e); 229 } 230 } 231 } 232 return { runningMap: needDeal, sum: sum }; 233 } 234 /** 235 * 将cpu频点数据与running状态数据整合,保证其上该段时长内有对应的cpu频点数据 236 */ 237 mergeFreqData( 238 needDeal: Map<string, Array<TabPaneRunningConfig>>, 239 dealArr: Array<TabPaneCpuFreqConfig>, 240 sum: number 241 ): void { 242 needDeal.forEach((value: Array<TabPaneRunningConfig>, key: string) => { 243 let resultList: Array<TabPaneFreqUsageConfig> = []; 244 for (let i = 0; i < value.length; i++) { 245 for (let j = 0; j < dealArr.length; j++) { 246 // 只需要判断running状态数据与频点数据cpu相同的情况 247 if (value[i].cpu === dealArr[j].cpu) { 248 // running状态数据的开始时间大于频点数据开始时间,小于频点结束时间。且running状态数据的持续时间小于频点结束时间减去running状态数据开始时间的情况 249 if ( 250 value[i].ts > dealArr[j].startNS && 251 value[i].ts < dealArr[j].startNS + dealArr[j].dur && 252 value[i].dur < dealArr[j].startNS + dealArr[j].dur - value[i].ts 253 ) { 254 resultList.push( 255 new TabPaneFreqUsageConfig( 256 value[i].thread, 257 value[i].ts, 258 value[i].pid, 259 value[i].tid, 260 0, 261 value[i].cpu, 262 dealArr[j].value, 263 value[i].dur, 264 '', 265 (value[i].dur / sum) * 100, 266 'freqdata', 267 -1, 268 undefined 269 ) 270 ); 271 break; 272 } 273 // running状态数据的开始时间大于频点数据开始时间,小于频点结束时间。且running状态数据的持续时间大于频点结束时间减去running状态数据开始时间的情况 274 if ( 275 value[i].ts > dealArr[j].startNS && 276 value[i].ts < dealArr[j].startNS + dealArr[j].dur && 277 value[i].dur > dealArr[j].startNS + dealArr[j].dur - value[i].ts 278 ) { 279 resultList.push( 280 new TabPaneFreqUsageConfig( 281 value[i].thread, 282 value[i].ts, 283 value[i].pid, 284 value[i].tid, 285 0, 286 value[i].cpu, 287 dealArr[j].value, 288 dealArr[j].startNS + dealArr[j].dur - value[i].ts, 289 '', 290 ((dealArr[j].startNS + dealArr[j].dur - value[i].ts) / sum) * 100, 291 'freqdata', 292 -1, 293 undefined 294 ) 295 ); 296 } 297 // running状态数据的开始时间小于频点数据开始时间,running状态数据的结束时间大于频点数据开始时间。且running状态数据在频点数据开始时间后的持续时间小于频点数据持续时间的情况 298 if ( 299 value[i].ts < dealArr[j].startNS && 300 value[i].ts + value[i].dur > dealArr[j].startNS && 301 value[i].dur + value[i].ts - dealArr[j].startNS < dealArr[j].dur 302 ) { 303 resultList.push( 304 new TabPaneFreqUsageConfig( 305 value[i].thread, 306 dealArr[j].startNS, 307 value[i].pid, 308 value[i].tid, 309 0, 310 value[i].cpu, 311 dealArr[j].value, 312 value[i].dur + value[i].ts - dealArr[j].startNS, 313 '', 314 ((value[i].dur + value[i].ts - dealArr[j].startNS) / sum) * 100, 315 'freqdata', 316 -1, 317 undefined 318 ) 319 ); 320 break; 321 } 322 // running状态数据的开始时间小于频点数据开始时间,running状态数据的结束时间大于频点数据开始时间。且running状态数据在频点数据开始时间后的持续时间大于频点数据持续时间的情况 323 if ( 324 value[i].ts < dealArr[j].startNS && 325 value[i].ts + value[i].dur > dealArr[j].startNS && 326 value[i].dur + value[i].ts - dealArr[j].startNS > dealArr[j].dur 327 ) { 328 resultList.push( 329 new TabPaneFreqUsageConfig( 330 value[i].thread, 331 dealArr[j].startNS, 332 value[i].pid, 333 value[i].tid, 334 0, 335 value[i].cpu, 336 dealArr[j].value, 337 dealArr[j].dur, 338 '', 339 (dealArr[j].dur / sum) * 100, 340 'freqdata', 341 -1, 342 undefined 343 ) 344 ); 345 } 346 // running状态数据的开始时间小于频点数据开始时间,running状态数据的持续时间小于频点数据开始时间的情况 347 if (value[i].ts < dealArr[j].startNS && value[i].ts + value[i].dur < dealArr[j].startNS) { 348 resultList.push( 349 new TabPaneFreqUsageConfig( 350 value[i].thread, 351 value[i].ts, 352 value[i].pid, 353 value[i].tid, 354 0, 355 value[i].cpu, 356 'unknown', 357 value[i].dur, 358 '', 359 (value[i].dur / sum) * 100, 360 'freqdata', 361 -1, 362 undefined 363 ) 364 ); 365 break; 366 } 367 } 368 } 369 } 370 this.initData.set(key, resultList); 371 }); 372 } 373 /** 374 * single方式切割数据功能 375 */ 376 dataSingleCut( 377 threadId: HTMLInputElement, 378 threadFunc: HTMLInputElement, 379 resultList: Map<string, Array<TabPaneFreqUsageConfig>> 380 ): void { 381 let threadIdValue: string = threadId.value.trim(); 382 let threadFuncName: string = threadFunc.value.trim(); 383 let rightNS: number = this.currentSelectionParam.rightNs; 384 let recordStartNs: number = this.currentSelectionParam.recordStartNs; 385 // @ts-ignore 386 this.threadStatesTbl.value = []; 387 if (threadIdValue !== '' && threadFuncName !== '') { 388 // 根据用户输入的线程ID,方法名去查询数据库,得到对应的方法起始时间,持续时间等数据,以便作为依据进行后续数据切割 389 querySearchFuncData(threadFuncName, Number(threadIdValue), this.currentSelectionParam.leftNs, rightNS).then( 390 (result) => { 391 if (result !== null && result.length > 0) { 392 // targetMap为全局initData的拷贝对象,dealArr数组用来存放周期切割依据数据 393 let targetMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 394 let dealArr: Array<{ ts: number; dur: number }> = []; 395 // 新创建map对象接收传过来的实参map 396 resultList.forEach((item: Array<TabPaneFreqUsageConfig>, key: string) => { 397 targetMap.set(key, JSON.parse(JSON.stringify(item))); 398 }); 399 // 整理周期切割依据的数据 400 for (let i of result) { 401 if (i.startTime! + recordStartNs + i.dur! < rightNS + recordStartNs) { 402 dealArr.push({ ts: i.startTime! + recordStartNs, dur: i.dur! }); 403 } 404 } 405 let cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 406 let totalList: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 407 this.mergeSingleData(dealArr, targetMap, cycleMap, totalList); 408 // 拷贝线程数组,防止数据污染 409 let threadArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.threadArr)); 410 // 拷贝进程数组,防止数据污染 411 let processArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.processArr)); 412 // 将周期层级防止到线程层级下 413 this.mergeThreadData(threadArr, cycleMap); 414 // 将原始数据放置到对应的线程层级下,周期数据前 415 this.mergeTotalData(threadArr, this.merge(totalList)); 416 // 合并数据到进程层级下 417 this.mergePidData(processArr, threadArr); 418 this.fixedDeal(processArr); 419 this.threadStatesTblSource = processArr; 420 this.threadStatesTbl!.recycleDataSource = processArr; 421 this.threadClick(processArr); 422 } else { 423 this.threadStatesTblSource = []; 424 this.threadStatesTbl!.recycleDataSource = []; 425 } 426 this.threadStatesTbl!.loading = false; 427 } 428 ); 429 } else { 430 this.threadStatesTbl!.loading = false; 431 if (threadIdValue === '') { 432 threadId.style.border = '2px solid rgb(255,0,0)'; 433 } 434 if (threadFuncName === '') { 435 threadFunc.style.border = '2px solid rgb(255,0,0)'; 436 } 437 } 438 } 439 /** 440 * 整合Single切割方式中的频点数据与方法周期数据 441 */ 442 mergeSingleData( 443 dealArr: Array<{ ts: number; dur: number }>, 444 targetMap: Map<string, Array<TabPaneFreqUsageConfig>>, 445 cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>, 446 totalList: Map<string, Array<TabPaneFreqUsageConfig>> 447 ): void { 448 let timeDur = this.currentSelectionParam.recordStartNs; 449 targetMap.forEach((value: any, key) => { 450 cycleMap.set(key, new Array()); 451 totalList.set(key, new Array()); 452 for (let i = 0; i < dealArr.length; i++) { 453 let cpuArr: Array<number> = []; 454 let resList: Array<TabPaneFreqUsageConfig> = []; 455 let cpuMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 456 // 时间倍数值 457 const countMutiple: number = 1000000; 458 const MIN_NUM: number = 3; 459 cpuMap.set(key, new Array()); 460 cycleMap 461 .get(key) 462 ?.push( 463 new TabPaneFreqUsageConfig( 464 'cycle' + (i + 1) + '—' + value[0].thread, 465 ((dealArr[i].ts - timeDur) / countMutiple).toFixed(MIN_NUM), 466 key.split('_')[0], 467 key.split('_')[1], 468 0, 469 '', 470 '', 471 0, 472 (dealArr[i].dur / countMutiple).toFixed(MIN_NUM), 473 0, 474 'cycle', 475 i + 1, 476 [] 477 ) 478 ); 479 this.dismantlingSingle( 480 value, 481 dealArr[i], 482 { 483 i: i, 484 key: key, 485 countMutiple: countMutiple, 486 cpuArr, 487 cpuMap, 488 }, 489 resList, 490 totalList 491 ); 492 this.mergeData(resList); 493 // 整理排序相同周期下的数据 494 this.mergeCpuData(cpuMap.get(key)!, resList); 495 // 将cpu数据放置到对应周期层级下 496 this.mergeCycleData(cycleMap.get(key)![i], cpuMap.get(key)!); 497 } 498 }); 499 } 500 /** 501 * 拆解Single大函数 502 * @param value 频点数据数组 503 * @param funData 方法对象 504 * @param constant 常量 505 * @param resList 周期数组 506 * @param totalList total数组 507 */ 508 dismantlingSingle( 509 value: Array<TabPaneFreqUsageConfig>, 510 funData: { ts: number; dur: number }, 511 constant: { 512 i: number; 513 key: string; 514 countMutiple: number; 515 cpuArr: Array<number>; 516 cpuMap: Map<string, Array<TabPaneFreqUsageConfig>>; 517 }, 518 resList: Array<TabPaneFreqUsageConfig>, 519 totalList: Map<string, Array<TabPaneFreqUsageConfig>> 520 ): void { 521 // 判断若用户导入json文件,则替换为对应cpu下的对应频点的算力值进行算力消耗计算 522 for (let j = 0; j < value.length; j++) { 523 let startTime = Number(value[j].ts); 524 let percent = Number(value[j].percent); 525 // @ts-ignore 526 let consumptionMap: Map<number, number> = 527 SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu)); 528 // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容 529 const consumption: number = Number( 530 consumptionMap && consumptionMap.get(Number(value[j].freq)) 531 ? consumptionMap.get(Number(value[j].freq)) 532 : value[j].freq === 'unknown' 533 ? 0 534 : value[j].freq 535 ); 536 if (!constant.cpuArr.includes(Number(value[j].cpu))) { 537 constant.cpuArr.push(Number(value[j].cpu)); 538 constant.cpuMap 539 .get(constant.key) 540 ?.push( 541 new TabPaneFreqUsageConfig( 542 'cycle' + (constant.i + 1) + '—' + value[j].thread, 543 '', 544 value[j].pid, 545 value[j].tid, 546 0, 547 value[j].cpu, 548 '', 549 0, 550 '', 551 0, 552 'cpu', 553 -1, 554 [] 555 ) 556 ); 557 } 558 // 以下为频点数据按Single周期切割数据如何取舍的判断条件,dealArr为周期切割依据,value为某一线程下的频点汇总数据 559 // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间小于周期结束时间的情况 560 if ( 561 funData.ts < startTime && 562 funData.ts + funData.dur > startTime && 563 funData.ts + funData.dur > startTime + value[j].dur 564 ) { 565 resList.push( 566 this.returnSingleObj( 567 'cycle' + (constant.i + 1) + '—' + value[j].thread, 568 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 569 value[j], 570 funData, 571 1 572 )! 573 ); 574 totalList 575 .get(constant.key) 576 ?.push( 577 this.returnSingleObj( 578 value[j].thread, 579 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 580 value[j], 581 funData, 582 1 583 )! 584 ); 585 } 586 // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间大于等于周期结束时间的情况 587 if ( 588 funData.ts < startTime && 589 funData.ts + funData.dur > startTime && 590 funData.ts + funData.dur <= startTime + value[j].dur 591 ) { 592 resList.push( 593 this.returnSingleObj( 594 'cycle' + (constant.i + 1) + '—' + value[j].thread, 595 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 596 value[j], 597 funData, 598 2 599 )! 600 ); 601 totalList 602 .get(constant.key) 603 ?.push( 604 this.returnSingleObj( 605 value[j].thread, 606 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 607 value[j], 608 funData, 609 2 610 )! 611 ); 612 break; 613 } 614 // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间大于周期结束时间的情况 615 if ( 616 funData.ts > startTime && 617 startTime + value[j].dur > funData.ts && 618 startTime + value[j].dur > funData.ts + funData.dur 619 ) { 620 resList.push( 621 this.returnSingleObj( 622 'cycle' + (constant.i + 1) + '—' + value[j].thread, 623 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 624 value[j], 625 funData, 626 3 627 )! 628 ); 629 totalList 630 .get(constant.key) 631 ?.push( 632 this.returnSingleObj( 633 value[j].thread, 634 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 635 value[j], 636 funData, 637 3 638 )! 639 ); 640 break; 641 } 642 // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间小于等于周期结束时间的情况 643 if ( 644 funData.ts > startTime && 645 startTime + value[j].dur > funData.ts && 646 startTime + value[j].dur <= funData.ts + funData.dur 647 ) { 648 resList.push( 649 this.returnSingleObj( 650 'cycle' + (constant.i + 1) + '—' + value[j].thread, 651 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 652 value[j], 653 funData, 654 4 655 )! 656 ); 657 totalList 658 .get(constant.key) 659 ?.push( 660 this.returnSingleObj( 661 value[j].thread, 662 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 663 value[j], 664 funData, 665 4 666 )! 667 ); 668 } 669 } 670 } 671 /** 672 * 673 * @param str 周期列头 674 * @param arg 常量参数 675 * @param value 频点数据对象 676 * @param funData 方法对象 677 * @param flag 标志位 678 * @returns 频点数据对象 679 */ 680 returnSingleObj( 681 str: string, 682 arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number }, 683 value: TabPaneFreqUsageConfig, 684 funData: { ts: number; dur: number }, 685 flag: number 686 ): TabPaneFreqUsageConfig | undefined { 687 switch (flag) { 688 case 1: 689 return new TabPaneFreqUsageConfig( 690 str, 691 '', 692 value.pid, 693 value.tid, 694 (arg.consumption * value.dur) / arg.countMutiple, 695 value.cpu, 696 value.freq, 697 value.dur, 698 '', 699 arg.percent, 700 'freqdata', 701 arg.i, 702 undefined 703 ); 704 case 2: 705 return new TabPaneFreqUsageConfig( 706 str, 707 '', 708 value.pid, 709 value.tid, 710 ((funData.ts + funData.dur - arg.startTime) * arg.consumption) / arg.countMutiple, 711 value.cpu, 712 value.freq, 713 funData.ts + funData.dur - arg.startTime, 714 '', 715 ((funData.ts + funData.dur - arg.startTime) / value.dur) * arg.percent, 716 'freqdata', 717 arg.i, 718 undefined 719 ); 720 case 3: 721 return new TabPaneFreqUsageConfig( 722 str, 723 '', 724 value.pid, 725 value.tid, 726 (funData.dur * arg.consumption) / arg.countMutiple, 727 value.cpu, 728 value.freq, 729 funData.dur, 730 '', 731 (funData.dur / value.dur) * arg.percent, 732 'freqdata', 733 arg.i, 734 undefined 735 ); 736 case 4: 737 return new TabPaneFreqUsageConfig( 738 str, 739 '', 740 value.pid, 741 value.tid, 742 ((arg.startTime + value.dur - funData.ts) * arg.consumption) / arg.countMutiple, 743 value.cpu, 744 value.freq, 745 arg.startTime + value.dur - funData.ts, 746 '', 747 ((arg.startTime + value.dur - funData.ts) / value.dur) * arg.percent, 748 'freqdata', 749 arg.i, 750 undefined 751 ); 752 default: 753 break; 754 } 755 } 756 /** 757 * Loop方式切割数据功能 758 */ 759 dataLoopCut( 760 threadId: HTMLInputElement, 761 threadFunc: HTMLInputElement, 762 resultList: Map<string, Array<TabPaneFreqUsageConfig>> 763 ): void { 764 let threadIdValue: string = threadId.value.trim(); 765 let threadFuncName: string = threadFunc.value.trim(); 766 let rightNS: number = this.currentSelectionParam.rightNs; 767 let recordStartNs: number = this.currentSelectionParam.recordStartNs; 768 // @ts-ignore 769 this.threadStatesTbl.value = []; 770 if (threadIdValue !== '' && threadFuncName !== '') { 771 querySearchFuncData(threadFuncName, Number(threadIdValue), this.currentSelectionParam.leftNs, rightNS).then( 772 (res) => { 773 if (res !== null && res.length > 0) { 774 // targetMap为全局initData的拷贝对象,cutArr数组用来存放周期切割依据数据 775 let targetMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 776 let cutArr: Array<{ ts: number; dur?: number }> = []; 777 // 新创建map对象接收传过来的实参map 778 resultList.forEach((item: Array<TabPaneFreqUsageConfig>, key: string) => { 779 targetMap.set(key, JSON.parse(JSON.stringify(item))); 780 }); 781 // 根据线程id及方法名获取的数据,处理后用作切割时间依据,时间跨度为整个方法开始时间到末个方法开始时间 782 for (let i of res) { 783 cutArr[cutArr.length - 1] && 784 (cutArr[cutArr.length - 1].dur = i.startTime 785 ? i.startTime + recordStartNs - cutArr[cutArr.length - 1].ts 786 : 0); 787 cutArr.push({ ts: i.startTime! + recordStartNs }); 788 } 789 let cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 790 let totalList: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 791 this.mergeLoopData(cutArr, targetMap, cycleMap, totalList); 792 let threadArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.threadArr)); 793 let processArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.processArr)); 794 this.mergeThreadData(threadArr, cycleMap); 795 this.mergeTotalData(threadArr, this.merge(totalList)); 796 this.mergePidData(processArr, threadArr); 797 this.fixedDeal(processArr); 798 this.threadStatesTblSource = processArr; 799 this.threadStatesTbl!.recycleDataSource = processArr; 800 this.threadClick(processArr); 801 } else { 802 this.threadStatesTblSource = []; 803 this.threadStatesTbl!.recycleDataSource = []; 804 } 805 } 806 ); 807 this.threadStatesTbl!.loading = false; 808 } else { 809 this.threadStatesTbl!.loading = false; 810 if (threadIdValue === '') { 811 threadId.style.border = '2px solid rgb(255,0,0)'; 812 } 813 if (threadFuncName === '') { 814 threadFunc.style.border = '2px solid rgb(255,0,0)'; 815 } 816 } 817 } 818 /** 819 * 整合Loop切割方式中的频点数据与方法周期数据 820 */ 821 mergeLoopData( 822 cutArr: Array<{ ts: number; dur?: number }>, 823 targetMap: Map<string, Array<TabPaneFreqUsageConfig>>, 824 cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>, 825 totalList: Map<string, Array<TabPaneFreqUsageConfig>> 826 ): void { 827 let timeDur: number = this.currentSelectionParam.recordStartNs; 828 targetMap.forEach((value: any, key) => { 829 cycleMap.set(key, new Array()); 830 totalList.set(key, new Array()); 831 for (let i = 0; i < cutArr.length - 1; i++) { 832 let cpuArr: Array<number> = []; 833 let resList: Array<TabPaneFreqUsageConfig> = []; 834 let cpuMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 835 // 时间倍数值 836 const countMutiple: number = 1000000; 837 const MIN_NUM: number = 3; 838 cpuMap.set(key, new Array()); 839 // 创建周期层级数据 840 cycleMap 841 .get(key) 842 ?.push( 843 new TabPaneFreqUsageConfig( 844 'cycle' + (i + 1) + '—' + value[0].thread, 845 ((cutArr[i].ts - timeDur) / countMutiple).toFixed(MIN_NUM), 846 key.split('_')[0], 847 key.split('_')[1], 848 0, 849 '', 850 '', 851 0, 852 (cutArr[i].dur! / countMutiple).toFixed(MIN_NUM), 853 0, 854 'cycle', 855 i + 1, 856 [] 857 ) 858 ); 859 this.dismantlingLoop( 860 value, 861 cutArr, 862 { 863 i: i, 864 key: key, 865 countMutiple: countMutiple, 866 cpuArr, 867 cpuMap, 868 }, 869 resList, 870 totalList 871 ); 872 // 合并相同周期内的数据 873 this.mergeData(resList); 874 // 整理排序相同周期下的数据 875 this.mergeCpuData(cpuMap.get(key)!, resList); 876 // 将cpu数据放置到对应周期层级下 877 this.mergeCycleData(cycleMap.get(key)![i], cpuMap.get(key)!); 878 } 879 }); 880 } 881 /** 882 * 拆解Loop大函数 883 * @param value 频点数据数组 884 * @param funData 方法对象 885 * @param constant 常量 886 * @param resList 周期数组 887 * @param totalList total数组 888 */ 889 dismantlingLoop( 890 value: Array<TabPaneFreqUsageConfig>, 891 cutArr: Array<{ ts: number; dur?: number }>, 892 constant: { 893 i: number; 894 key: string; 895 countMutiple: number; 896 cpuArr: Array<number>; 897 cpuMap: Map<string, Array<TabPaneFreqUsageConfig>>; 898 }, 899 resList: Array<TabPaneFreqUsageConfig>, 900 totalList: Map<string, Array<TabPaneFreqUsageConfig>> 901 ): void { 902 for (let j = 0; j < value.length; j++) { 903 // 判断若用户导入json文件,则替换为对应cpu下的对应频点的算力值进行算力消耗计算 904 let startTime = Number(value[j].ts); 905 let percent = Number(value[j].percent); 906 // @ts-ignore 907 let consumptionMap: Map<number, number> = 908 SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu)); 909 // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容 910 const consumption: number = Number( 911 consumptionMap && consumptionMap.get(Number(value[j].freq)) 912 ? consumptionMap.get(Number(value[j].freq)) 913 : value[j].freq === 'unknown' 914 ? 0 915 : value[j].freq 916 ); 917 if (!constant.cpuArr.includes(Number(value[j].cpu))) { 918 constant.cpuArr.push(Number(value[j].cpu)); 919 // 创建cpu层级数据,以便后续生成树结构 920 constant.cpuMap 921 .get(constant.key) 922 ?.push( 923 new TabPaneFreqUsageConfig( 924 'cycle' + (constant.i + 1) + '—' + value[j].thread, 925 '', 926 value[j].pid, 927 value[j].tid, 928 0, 929 value[j].cpu, 930 '', 931 0, 932 '', 933 0, 934 'cpu', 935 -1, 936 [] 937 ) 938 ); 939 } 940 // 以下为频点数据按Loop周期切割数据如何取舍的判断条件,cutArr为周期切割依据,value为某一线程下的频点汇总数据 941 // 如果频点数据开始时间大于某一周期起始时间,且结束时间小于等于下一同名方法开始时间的情况 942 if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur <= cutArr[constant.i + 1].ts) { 943 resList.push( 944 this.returnLoopObj( 945 'cycle' + (constant.i + 1) + '—' + value[j].thread, 946 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 947 value[j], 948 cutArr, 949 1 950 )! 951 ); 952 totalList 953 .get(constant.key) 954 ?.push( 955 this.returnLoopObj( 956 value[j].thread, 957 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 958 value[j], 959 cutArr, 960 1 961 )! 962 ); 963 } 964 // 如果频点数据开始时间大于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况 965 if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) { 966 if (cutArr[constant.i + 1].ts - startTime > 0) { 967 resList.push( 968 this.returnLoopObj( 969 'cycle' + (constant.i + 1) + '—' + value[j].thread, 970 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 971 value[j], 972 cutArr, 973 2 974 )! 975 ); 976 totalList 977 .get(constant.key) 978 ?.push( 979 this.returnLoopObj( 980 value[j].thread, 981 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 982 value[j], 983 cutArr, 984 2 985 )! 986 ); 987 break; 988 } 989 } 990 // 如果频点数据开始时间小于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况 991 if (startTime < cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) { 992 resList.push( 993 this.returnLoopObj( 994 'cycle' + (constant.i + 1) + '—' + value[j].thread, 995 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 996 value[j], 997 cutArr, 998 3 999 )! 1000 ); 1001 totalList 1002 .get(constant.key) 1003 ?.push( 1004 this.returnLoopObj( 1005 value[j].thread, 1006 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 1007 value[j], 1008 cutArr, 1009 3 1010 )! 1011 ); 1012 } 1013 // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该方法开始时间。且频点数据结束时间小于下一同名方法开始时间 1014 if ( 1015 startTime < cutArr[constant.i].ts && 1016 startTime + value[j].dur > cutArr[constant.i].ts && 1017 startTime + value[j].dur < cutArr[constant.i + 1].ts 1018 ) { 1019 resList.push( 1020 this.returnLoopObj( 1021 'cycle' + (constant.i + 1) + '—' + value[j].thread, 1022 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 1023 value[j], 1024 cutArr, 1025 4 1026 )! 1027 ); 1028 totalList 1029 .get(constant.key) 1030 ?.push( 1031 this.returnLoopObj( 1032 value[j].thread, 1033 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 1034 value[j], 1035 cutArr, 1036 4 1037 )! 1038 ); 1039 } 1040 } 1041 } 1042 /** 1043 * 1044 * @param str 周期列头 1045 * @param arg 常量参数 1046 * @param value 频点数据对象 1047 * @param funData 方法对象 1048 * @param flag 标志位 1049 * @returns 频点数据对象 1050 */ 1051 returnLoopObj( 1052 str: string, 1053 arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number }, 1054 value: TabPaneFreqUsageConfig, 1055 cutArr: Array<{ ts: number; dur?: number }>, 1056 flag: number 1057 ): TabPaneFreqUsageConfig | undefined { 1058 switch (flag) { 1059 case 1: 1060 return new TabPaneFreqUsageConfig( 1061 str, 1062 '', 1063 value.pid, 1064 value.tid, 1065 (arg.consumption * value.dur) / arg.countMutiple, 1066 value.cpu, 1067 value.freq, 1068 value.dur, 1069 '', 1070 value.percent, 1071 'freqdata', 1072 arg.i, 1073 undefined 1074 ); 1075 case 2: 1076 return new TabPaneFreqUsageConfig( 1077 str, 1078 '', 1079 value.pid, 1080 value.tid, 1081 (arg.consumption * (cutArr[arg.i + 1].ts - arg.startTime)) / arg.countMutiple, 1082 value.cpu, 1083 value.freq, 1084 cutArr[arg.i + 1].ts - arg.startTime, 1085 '', 1086 arg.percent * ((cutArr[arg.i + 1].ts - arg.startTime) / value.dur), 1087 'freqdata', 1088 arg.i, 1089 undefined 1090 ); 1091 case 3: 1092 return new TabPaneFreqUsageConfig( 1093 str, 1094 '', 1095 value.pid, 1096 value.tid, 1097 (arg.consumption * (cutArr[arg.i + 1].ts - cutArr[arg.i].ts)) / arg.countMutiple, 1098 value.cpu, 1099 value.freq, 1100 cutArr[arg.i + 1].ts - cutArr[arg.i].ts, 1101 '', 1102 arg.percent * ((cutArr[arg.i + 1].ts - cutArr[arg.i].ts) / value.dur), 1103 'freqdata', 1104 arg.i, 1105 undefined 1106 ); 1107 case 4: 1108 return new TabPaneFreqUsageConfig( 1109 str, 1110 '', 1111 value.pid, 1112 value.tid, 1113 (arg.consumption * (value.dur + arg.startTime - cutArr[arg.i].ts)) / arg.countMutiple, 1114 value.cpu, 1115 value.freq, 1116 value.dur + arg.startTime - cutArr[arg.i].ts, 1117 '', 1118 arg.percent * ((value.dur + arg.startTime - cutArr[arg.i].ts) / value.dur), 1119 'freqdata', 1120 arg.i, 1121 undefined 1122 ); 1123 default: 1124 break; 1125 } 1126 } 1127 /** 1128 * 切割后整合好的周期频点数据放置到对应的线程下 1129 */ 1130 mergeThreadData( 1131 threadArr: Array<TabPaneFreqUsageConfig>, 1132 cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> 1133 ): void { 1134 for (let i = 0; i < threadArr.length; i++) { 1135 let cycleMapData: Array<TabPaneFreqUsageConfig> = cycleMap.get(threadArr[i].pid + '_' + threadArr[i].tid)!; 1136 for (let j = 0; j < cycleMapData!.length; j++) { 1137 threadArr[i].children?.push(cycleMapData![j]); 1138 threadArr[i].count += cycleMapData![j].count; 1139 threadArr[i].dur += cycleMapData![j].dur; 1140 // @ts-ignore 1141 threadArr[i].percent += cycleMapData![j].percent; 1142 } 1143 } 1144 } 1145 /** 1146 * 切割后整合好的线程级频点数据放置到对应的进程 1147 */ 1148 mergePidData(pidArr: Array<TabPaneFreqUsageConfig>, threadArr: Array<TabPaneFreqUsageConfig>): void { 1149 for (let i = 0; i < pidArr.length; i++) { 1150 for (let j = 0; j < threadArr.length; j++) { 1151 if (pidArr[i].pid === threadArr[j].pid) { 1152 pidArr[i].children?.push(threadArr[j]); 1153 pidArr[i].count += threadArr[j].count; 1154 pidArr[i].dur += threadArr[j].dur; 1155 // @ts-ignore 1156 pidArr[i].percent += threadArr[j].percent; 1157 } 1158 } 1159 } 1160 } 1161 /** 1162 * 合并相同周期内运行所在cpu相同、频点相同的数据 1163 */ 1164 mergeData(resList: Array<TabPaneFreqUsageConfig>): void { 1165 // 合并相同周期内的数据 1166 for (let i = 0; i < resList.length; i++) { 1167 for (let j = i + 1; j < resList.length; j++) { 1168 if ( 1169 resList[i].cpu === resList[j].cpu && 1170 resList[i].freq === resList[j].freq && 1171 resList[i].id === resList[j].id 1172 ) { 1173 resList[i].dur += resList[j].dur; 1174 // @ts-ignore 1175 resList[i].percent += resList[j].percent; 1176 resList[i].count += resList[j].count; 1177 resList.splice(j, 1); 1178 j--; 1179 } 1180 } 1181 } 1182 } 1183 /** 1184 * 将cpu层级数据放到对应的周期层级下 1185 */ 1186 mergeCycleData(obj: TabPaneFreqUsageConfig, arr: Array<TabPaneFreqUsageConfig>): void { 1187 for (let i = 0; i < arr!.length; i++) { 1188 if (arr![i].count === 0 && arr![i].dur === 0) { 1189 continue; 1190 } 1191 obj.children?.push(arr![i]); 1192 obj.count += arr![i].count; 1193 obj.dur += arr![i].dur; 1194 // @ts-ignore 1195 obj.percent += arr![i].percent; 1196 } 1197 } 1198 /** 1199 * 将切割好的不区分周期的数据作为total数据放到对应的线程层级下,周期数据前 1200 */ 1201 mergeTotalData(threadArr: Array<TabPaneFreqUsageConfig>, totalData: Array<TabPaneFreqUsageConfig>): void { 1202 for (let i = 0; i < threadArr.length; i++) { 1203 for (let j = 0; j < totalData.length; j++) { 1204 if ( 1205 Number(threadArr[i].pid) === Number(totalData[j].pid) && 1206 Number(threadArr[i].tid) === Number(totalData[j].tid) 1207 ) { 1208 totalData[j].thread = 'TotalData'; 1209 totalData[j].flag = 't_cycle'; 1210 // @ts-ignore 1211 threadArr[i].children.unshift(totalData[j]); 1212 } 1213 } 1214 } 1215 } 1216 /** 1217 * 整理排序相同周期下的数据 1218 */ 1219 mergeCpuData(cpuArray: Array<TabPaneFreqUsageConfig>, resList: Array<TabPaneFreqUsageConfig>): void { 1220 // 以算力消耗降序排列 1221 resList.sort((a, b) => b.count - a.count); 1222 // 以cpu升序排列 1223 cpuArray.sort((a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu)); 1224 cpuArray.forEach((item: TabPaneFreqUsageConfig) => { 1225 for (let s = 0; s < resList.length; s++) { 1226 if (item.cpu === resList[s].cpu) { 1227 item.children?.push(resList[s]); 1228 item.count += resList[s].count; 1229 item.dur += resList[s].dur; 1230 // @ts-ignore 1231 item.percent += resList[s].percent; 1232 } 1233 } 1234 }); 1235 } 1236 /** 1237 * 切割好的不区分周期的数据,以相同cpu相同频点的进行整合 1238 */ 1239 merge(totalList: Map<string, Array<TabPaneFreqUsageConfig>>): Array<TabPaneFreqUsageConfig> { 1240 let result: Array<TabPaneFreqUsageConfig> = new Array(); 1241 totalList.forEach((value: Array<TabPaneFreqUsageConfig>, key: string) => { 1242 let countNum = result.push( 1243 new TabPaneFreqUsageConfig('', '', key.split('_')[0], key.split('_')[1], 0, '', '', 0, '', 0, 'cycle', 0, []) 1244 ); 1245 let cpuArr: Array<TabPaneFreqUsageConfig> = []; 1246 let flagArr: Array<number | string> = []; 1247 for (let i = 0; i < value.length; i++) { 1248 if (!flagArr.includes(value[i].cpu)) { 1249 flagArr.push(value[i].cpu); 1250 let flag = cpuArr.push( 1251 new TabPaneFreqUsageConfig( 1252 value[i].thread, 1253 '', 1254 value[i].pid, 1255 value[i].tid, 1256 0, 1257 value[i].cpu, 1258 '', 1259 0, 1260 '', 1261 0, 1262 'cpu', 1263 -1, 1264 [] 1265 ) 1266 ); 1267 result[countNum - 1].children?.push(cpuArr[flag - 1]); 1268 } 1269 for (let j = i + 1; j < value.length; j++) { 1270 if (value[i].cpu === value[j].cpu && value[i].freq === value[j].freq) { 1271 value[i].dur += value[j].dur; 1272 // @ts-ignore 1273 value[i].percent += value[j].percent; 1274 value[i].count += value[j].count; 1275 value.splice(j, 1); 1276 j--; 1277 } 1278 } 1279 } 1280 result[countNum - 1].children?.sort( 1281 (a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu) 1282 ); 1283 for (let i = 0; i < cpuArr.length; i++) { 1284 for (let j = 0; j < value.length; j++) { 1285 if (cpuArr[i].cpu === value[j].cpu) { 1286 cpuArr[i].children?.push(value[j]); 1287 cpuArr[i].dur += value[j].dur; 1288 cpuArr[i].count += value[j].count; 1289 // @ts-ignore 1290 cpuArr[i].percent += value[j].percent; 1291 } 1292 } 1293 result[countNum - 1].dur += cpuArr[i].dur; 1294 result[countNum - 1].count += cpuArr[i].count; 1295 // @ts-ignore 1296 result[countNum - 1].percent += cpuArr[i].percent; 1297 } 1298 }); 1299 return result; 1300 } 1301 /** 1302 * 递归整理数据,取小数位数,转换单位 1303 */ 1304 fixedDeal(arr: Array<TabPaneFreqUsageConfig>): void { 1305 if (arr === undefined) { 1306 return; 1307 } 1308 for (let i = 0; i < arr.length; i++) { 1309 // @ts-ignore 1310 arr[i].percent = arr[i].percent.toFixed(2); 1311 // @ts-ignore 1312 arr[i].dur = (arr[i].dur / 1000000).toFixed(3); 1313 if (arr[i].freq !== '') { 1314 if (arr[i].freq === 'unknown') { 1315 arr[i].freq = 'unknown'; 1316 } else { 1317 // @ts-ignore 1318 arr[i].freq = arr[i].freq / 1000; 1319 } 1320 } 1321 if (!(SpSegmentationChart.freqInfoMapData.size > 0)) { 1322 // @ts-ignore 1323 arr[i].count = (arr[i].count / 1000).toFixed(3); 1324 } else { 1325 // @ts-ignore 1326 arr[i].count = arr[i].count.toFixed(3); 1327 } 1328 // @ts-ignore 1329 this.fixedDeal(arr[i].children); 1330 } 1331 } 1332 /** 1333 * 绑定表格点击事件 1334 */ 1335 private threadClick(data: Array<TabPaneFreqUsageConfig>): void { 1336 let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); 1337 if (labels) { 1338 for (let i = 0; i < labels.length; i++) { 1339 let label = labels[i].innerHTML; 1340 labels[i].addEventListener('click', (e) => { 1341 if (!this.threadStatesTblSource.length && !this.threadStatesTbl!.recycleDataSource.length) { 1342 data = []; 1343 } 1344 if (label.includes('Process') && i === 0) { 1345 this.threadStatesTbl!.setStatus(data, false); 1346 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 1347 } else if (label.includes('Thread') && i === 1) { 1348 for (let item of data) { 1349 // @ts-ignore 1350 item.status = true; 1351 if (item.children !== undefined && item.children.length > 0) { 1352 this.threadStatesTbl!.setStatus(item.children, false); 1353 } 1354 } 1355 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 1356 } else if (label.includes('Cycle') && i === 2) { 1357 for (let item of data) { 1358 // @ts-ignore 1359 item.status = true; 1360 for (let value of item.children ? item.children : []) { 1361 // @ts-ignore 1362 value.status = true; 1363 if (value.children !== undefined && value.children.length > 0) { 1364 this.threadStatesTbl!.setStatus(value.children, false); 1365 } 1366 } 1367 } 1368 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 1369 } else if (label.includes('CPU') && i === 3) { 1370 this.threadStatesTbl!.setStatus(data, true); 1371 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand); 1372 } 1373 }); 1374 } 1375 } 1376 } 1377 /** 1378 * 散点图渲染数据整理 1379 */ 1380 render(res: Array<TabPaneFreqUsageConfig>, str: string, queryCycleScatter: Array<number>): void { 1381 let maxFreq: HTMLInputElement = this.scatterInput!.querySelector('#maxFreq')!; 1382 let maxHz: HTMLInputElement = this.scatterInput!.querySelector('#maxHz')!; 1383 if (maxFreq.value && maxHz.value) { 1384 if (/^[0-9]*$/.test(maxFreq.value) && /^[0-9]*$/.test(maxHz.value)) { 1385 this.organizeData(res, str, queryCycleScatter, maxFreq.value, maxHz.value); 1386 } else { 1387 if (!/^[0-9]*$/.test(maxFreq.value)) { 1388 maxFreq.style.border = '2px solid rgb(255,0,0)'; 1389 } 1390 if (!/^[0-9]*$/.test(maxHz.value)) { 1391 maxHz.style.border = '2px solid rgb(255,0,0)'; 1392 } 1393 } 1394 } else { 1395 if (maxFreq.value === '') { 1396 maxFreq.style.border = '2px solid rgb(255,0,0)'; 1397 } 1398 if (maxHz.value === '') { 1399 maxHz.style.border = '2px solid rgb(255,0,0)'; 1400 } 1401 SpSegmentationChart.setChartData('CPU-FREQ', []); 1402 } 1403 } 1404 /** 1405 * 数据整理 1406 */ 1407 organizeData( 1408 res: Array<TabPaneFreqUsageConfig>, 1409 str: string, 1410 queryCycleScatter: Array<number>, 1411 maxFreqValue: string, 1412 maxHzValue: string 1413 ): void { 1414 // @ts-ignore 1415 this.shadowRoot?.querySelector('#cycleQuery')!.style.display = 'block'; 1416 // @ts-ignore 1417 let freq: Map<number, number> = 1418 SpSegmentationChart.freqInfoMapData.size > 0 && 1419 SpSegmentationChart.freqInfoMapData.get(SpSegmentationChart.freqInfoMapData.size - 1); 1420 // @ts-ignore 1421 let yAxis: number = 1422 freq && freq.get(Number(maxFreqValue) * 1000) ? freq.get(Number(maxFreqValue) * 1000) : Number(maxFreqValue); 1423 let xAxis: number = (yAxis * 1000) / Number(maxHzValue); 1424 // 需要做筛选时,会利用下面的cycleA、cycleB数组 1425 let scatterArr: Array<Array<number>> = []; 1426 let traceRowdata: Array<{ 1427 dur: number; 1428 startNS: number; 1429 value: number; 1430 cycle: number; 1431 }> = []; 1432 let cycleA: Array<Array<number>> = []; 1433 let cycleB: Array<Array<number>> = []; 1434 let cycleAStart: number = queryCycleScatter[0] || 0; 1435 let cycleAEnd: number = queryCycleScatter[1] || 0; 1436 let cycleBStart: number = queryCycleScatter[2] || 0; 1437 let cycleBEnd: number = queryCycleScatter[3] || 0; 1438 for (let i = 1; i < res.length; i++) { 1439 const count: number = Number(res[i].count); 1440 const dur: number = Number(res[i].cdur); 1441 const rdur: number = Number(res[i].dur); //MHz·ms ms ms 1442 scatterArr.push([count, count / dur, i, dur, rdur]); 1443 traceRowdata.push({ 1444 dur: dur * 1000000, 1445 value: count, 1446 startNS: Number(res[i].ts) * 1000000, 1447 cycle: i - 1, 1448 }); 1449 if (dur >= cycleAStart && dur < cycleAEnd) { 1450 cycleA.push([count, count / dur, i, dur, rdur]); 1451 } 1452 if (dur >= cycleBStart && dur < cycleBEnd) { 1453 cycleB.push([count, count / dur, i, dur, rdur]); 1454 } 1455 } 1456 this.setConfig(Number(maxHzValue), str, scatterArr, yAxis, xAxis, cycleA, cycleB); 1457 SpSegmentationChart.setChartData('CPU-FREQ', traceRowdata); 1458 } 1459 /** 1460 * 配置散点图 1461 */ 1462 setConfig( 1463 maxHz: number, 1464 str: string, 1465 scatterArr: Array<Array<number>>, 1466 yAxis: number, 1467 xAxis: number, 1468 cycleA: Array<Array<number>>, 1469 cycleB: Array<Array<number>> 1470 ): void { 1471 const DELTA: number = 5; 1472 this.statisticsScatter!.config = { 1473 // 纵轴坐标值 1474 yAxisLabel: [ 1475 Math.round(yAxis / DELTA), 1476 Math.round((yAxis * 2) / DELTA), 1477 Math.round((yAxis * 3) / DELTA), 1478 Math.round((yAxis * 4) / DELTA), 1479 Math.round(yAxis), 1480 ], 1481 // 横轴坐标值 1482 xAxisLabel: [ 1483 Math.round(xAxis / DELTA), 1484 Math.round((xAxis * 2) / DELTA), 1485 Math.round((xAxis * 3) / DELTA), 1486 Math.round((xAxis * 4) / DELTA), 1487 Math.round(xAxis), 1488 Math.round((xAxis * 6) / DELTA), 1489 ], 1490 // 横轴字段、纵轴字段 1491 axisLabel: ['负载', '算力供给'], 1492 // 是否加载最大负载线及均衡线 1493 drawload: true, 1494 // 最大负载线及均衡线值 1495 load: [xAxis, maxHz], 1496 // 绘制点数据信息存储数组 1497 paintingData: [], 1498 // 当前移入点坐标信息 1499 hoverData: {}, 1500 // 颜色池 1501 colorPool: () => ['#2f72f8', '#ffab67', '#a285d2'], 1502 // 移入数据点时是否触发函数 1503 //@ts-ignore 1504 hoverEvent: SpSegmentationChart.tabHover, 1505 // 渐变色背景信息 1506 globalGradient: undefined, 1507 // 渲染数据点 1508 data: [scatterArr, cycleA, cycleB], 1509 // 散点图title 1510 title: str, 1511 colorPoolText: (): Array<string> => ['Total', 'CycleA', 'CycleB'], 1512 tip: (data: { c: Array<number> }): string => { 1513 return ` 1514 <div> 1515 <span>Cycle: ${data.c[2]};</span></br> 1516 <span>Comsumption: ${data.c[0]};</span></br> 1517 <span>Cycle_dur: ${data.c[3]} ms;</span></br> 1518 <span>Running_dur: ${data.c[4]} ms;</span></br> 1519 </div> 1520 `; 1521 }, 1522 }; 1523 } 1524 initElements(): void { 1525 this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-running-datacut'); 1526 // 绑定事件 1527 this.addListener(); 1528 this.statisticsScatter = this.shadowRoot?.querySelector('#chart-scatter'); 1529 // 增加表格thread层级点击更新散点图事件、周期层级点击高亮泳道图对应段事件 1530 let scatterData: Array<TabPaneFreqUsageConfig> = new Array(); 1531 let str: string = ''; 1532 this.threadStatesTbl!.addEventListener('row-click', (evt): void => { 1533 // @ts-ignore 1534 if (evt.detail.flag === 'thread') { 1535 // @ts-ignore 1536 scatterData = evt.detail.children; 1537 // @ts-ignore 1538 str = evt.detail.thread; 1539 this.render(scatterData, str, []); 1540 } 1541 1542 if ( 1543 // @ts-ignore 1544 evt.detail.flag === 'cycle' && 1545 // @ts-ignore 1546 evt.detail.pid === scatterData[evt.detail.id - 1].pid && 1547 // @ts-ignore 1548 evt.detail.tid === scatterData[evt.detail.id - 1].tid && 1549 // @ts-ignore 1550 evt.detail.id > 0 1551 ) { 1552 // @ts-ignore 1553 SpSegmentationChart.tabHover('CPU-FREQ', true, evt.detail.id - 1); 1554 } 1555 }); 1556 this.scatterInput = this.shadowRoot?.querySelector('.chart-box'); 1557 this.shadowRoot?.querySelector('#query-btn')!.addEventListener('click', (e) => { 1558 // @ts-ignore 1559 let cycleAStartValue = this.shadowRoot?.querySelector('#cycle-a-start-range')!.value; 1560 // @ts-ignore 1561 let cycleAEndValue = this.shadowRoot?.querySelector('#cycle-a-end-range')!.value; 1562 // @ts-ignore 1563 let cycleBStartValue = this.shadowRoot?.querySelector('#cycle-b-start-range')!.value; 1564 // @ts-ignore 1565 let cycleBEndValue = this.shadowRoot?.querySelector('#cycle-b-end-range')!.value; 1566 let queryCycleScatter = [ 1567 Number(cycleAStartValue), 1568 Number(cycleAEndValue), 1569 Number(cycleBStartValue), 1570 Number(cycleBEndValue), 1571 ]; 1572 this.render(scatterData, str, queryCycleScatter); 1573 }); 1574 } 1575 /** 1576 * 配置监听事件 1577 */ 1578 addListener(): void { 1579 // 绑定single、loop按钮点击事件 1580 this.threadStatesDIV = this.shadowRoot?.querySelector('#dataCut'); 1581 this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => { 1582 this.threadStatesTbl!.loading = true; 1583 // @ts-ignore 1584 this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#666666'; 1585 // @ts-ignore 1586 this.threadStatesDIV?.children[2].children[0].style.color = '#fff'; 1587 // @ts-ignore 1588 this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#fff'; 1589 // @ts-ignore 1590 this.threadStatesDIV?.children[2].children[1].style.color = '#000'; 1591 // @ts-ignore 1592 1593 this.dataSingleCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData); 1594 }); 1595 this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => { 1596 this.threadStatesTbl!.loading = true; 1597 // @ts-ignore 1598 this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#666666'; 1599 // @ts-ignore 1600 this.threadStatesDIV?.children[2].children[1].style.color = '#fff'; 1601 // @ts-ignore 1602 this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#fff'; 1603 // @ts-ignore 1604 this.threadStatesDIV?.children[2].children[0].style.color = '#000'; 1605 // @ts-ignore 1606 this.dataLoopCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData); 1607 }); 1608 this.threadStatesDIV?.children[0].addEventListener('focus', (e) => { 1609 // @ts-ignore 1610 this.threadStatesDIV?.children[0]!.style.border = '1px solid rgb(151,151,151)'; 1611 }); 1612 this.threadStatesDIV?.children[1].addEventListener('focus', (e) => { 1613 // @ts-ignore 1614 this.threadStatesDIV?.children[1]!.style.border = '1px solid rgb(151,151,151)'; 1615 }); 1616 this.shadowRoot?.querySelector('#maxFreq')?.addEventListener('focus', (e) => { 1617 // @ts-ignore 1618 this.shadowRoot?.querySelector('#maxFreq')!.style.border = '1px solid rgb(151,151,151)'; 1619 }); 1620 this.shadowRoot?.querySelector('#maxHz')?.addEventListener('focus', (e) => { 1621 // @ts-ignore 1622 this.shadowRoot?.querySelector('#maxHz')!.style.border = '1px solid rgb(151,151,151)'; 1623 }); 1624 } 1625 connectedCallback(): void { 1626 super.connectedCallback(); 1627 resizeObserver(this.parentElement!, this.threadStatesTbl!); 1628 } 1629 initHtml(): string { 1630 return ( 1631 ` 1632 <style> 1633 :host{ 1634 padding: 10px 10px; 1635 display: flex; 1636 flex-direction: column; 1637 height: 100%; 1638 } 1639 #dataCut{ 1640 display: flex; 1641 justify-content: space-between; 1642 width:100%; 1643 height:20px; 1644 margin-bottom:2px; 1645 align-items:center; 1646 } 1647 button{ 1648 width:40%; 1649 height:100%; 1650 border: solid 1px #666666; 1651 background-color: rgba(0,0,0,0); 1652 border-radius:10px; 1653 } 1654 button:hover{ 1655 background-color:#666666; 1656 color:white; 1657 } 1658 .d-box{ 1659 display: flex; 1660 margin-left: 0; 1661 height: 100%; 1662 } 1663 .chart-box{ 1664 width: 35%; 1665 min-width: 486px; 1666 overflow: auto; 1667 margin-bottom: 10px; 1668 } 1669 #chart-scatter{ 1670 height: 100%; 1671 max-height: 390px; 1672 } 1673 #query-btn{ 1674 width:90px; 1675 } 1676 </style> 1677 ` + 1678 this.htmlUp() + 1679 this.htmlDown() 1680 ); 1681 } 1682 htmlUp(): string { 1683 return ` 1684 <div id='dataCut'> 1685 <input id="dataCutThreadId" type="text" style="width: 15%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%" placeholder="Please input thread id" value='' /> 1686 <input id="dataCutThreadFunc" type="text" style="width: 20%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%" placeholder="Please input function name" value='' /> 1687 <div style="width:20%;height: 100%;display:flex;justify-content: space-around;"> 1688 <button>Single</button> 1689 <button>Loop</button> 1690 </div> 1691 </div> 1692 <selector class="d-box"> 1693 <lit-slicer style="width:100%"> 1694 <div class="table-box" style="width: 65%; max-width: calc(100%-495px); min-width: 60%"> 1695 <lit-table id="tb-running-datacut" style="height: auto; overflow:auto;margin-top:5px" tree> 1696 <lit-table-column class="running-percent-column" width="250px" title="Process/Thread/Cycle/CPU" data-index="thread" key="thread" align="flex-start" retract> 1697 </lit-table-column> 1698 <lit-table-column class="running-percent-column" width="100px" title="Cycle_st(ms)" data-index="ts" key="ts" align="flex-start"> 1699 </lit-table-column> 1700 <lit-table-column class="running-percent-column" width="110px" title="Cycle_dur(ms)" data-index="cdur" key="cdur" align="flex-start"> 1701 </lit-table-column> 1702 <lit-table-column class="running-percent-column" width="50px" title="CPU" data-index="cpu" key="cpu" align="flex-start"> 1703 </lit-table-column> 1704 <lit-table-column class="running-percent-column" width="140px" title="Consumption" data-index="count" key="count" align="flex-start"> 1705 </lit-table-column> 1706 <lit-table-column class="running-percent-column" width="100px" title="Freq(MHz)" data-index="freq" key="freq" align="flex-start"> 1707 </lit-table-column> 1708 <lit-table-column class="running-percent-column" width="120px" title="Running_dur(ms)" data-index="dur" key="dur" align="flex-start"> 1709 </lit-table-column> 1710 <lit-table-column class="running-percent-column" width="100px" title="Percent(%)" data-index="percent" key="percent" align="flex-start"> 1711 </lit-table-column> 1712 </lit-table> 1713 </div> 1714 `; 1715 } 1716 htmlDown(): string { 1717 return ` 1718 <lit-slicer-track ></lit-slicer-track> 1719 <div class="chart-box"> 1720 <div> 1721 <span>maxFreq: </span> 1722 <input id="maxFreq" type="text" style="width: 27%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Please input maxFreq" value='' /> 1723 <span>Fps: </span> 1724 <input id="maxHz" type="text" style="width: 27%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Please input Fps" value='' /> 1725 </div> 1726 <div style="flex: 1;display: flex; flex-direction: row;"> 1727 </div> 1728 <lit-chart-scatter id="chart-scatter"></lit-chart-scatter> 1729 <div id= "cycleQuery" style="margin-bottom:5px;margin-top:5px;display:none"> 1730 <div id="cycle-a"> 1731 <span>Cycle A: </span> 1732 <input id="cycle-a-start-range" type="text" class="cycle-range-input" style="width: 15%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' /> 1733 <span>~</span> 1734 <input id="cycle-a-end-range" type="text" class="cycle-range-input" style="width: 15%;height:90%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' /> 1735 </div> 1736 <div style="margin-top: 5px; display:flex; flex-derection:row; justify-content:space-between"> 1737 <div id="cycle-b"> 1738 <span>Cycle B: </span> 1739 <input id="cycle-b-start-range" type="text" class="cycle-range-input" style="width: 18%;height:77%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' /> 1740 <span>~</span> 1741 <input id="cycle-b-end-range" type="text" class="cycle-range-input" style="width: 18%;height:77%;border-radius:10px;border:solid 1px #979797;font-size:15px;text-indent:3%;" placeholder="Time(ms)" value='' /> 1742 </div> 1743 <div> 1744 <button id="query-btn">Query</button> 1745 </div> 1746 </div> 1747 </div> 1748 </div> 1749 </lit-slicer> 1750 </selector> 1751 `; 1752 } 1753} 1754