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 //@ts-ignore 528 SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu))?.mapData; 529 // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容 530 const consumption: number = Number( 531 consumptionMap && consumptionMap.get(Number(value[j].freq)) 532 ? consumptionMap.get(Number(value[j].freq)) 533 : value[j].freq === 'unknown' 534 ? 0 535 : value[j].freq 536 ); 537 if (!constant.cpuArr.includes(Number(value[j].cpu))) { 538 constant.cpuArr.push(Number(value[j].cpu)); 539 constant.cpuMap 540 .get(constant.key) 541 ?.push( 542 new TabPaneFreqUsageConfig( 543 'cycle' + (constant.i + 1) + '—' + value[j].thread, 544 '', 545 value[j].pid, 546 value[j].tid, 547 0, 548 value[j].cpu, 549 '', 550 0, 551 '', 552 0, 553 'cpu', 554 -1, 555 [] 556 ) 557 ); 558 } 559 // 以下为频点数据按Single周期切割数据如何取舍的判断条件,dealArr为周期切割依据,value为某一线程下的频点汇总数据 560 // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间小于周期结束时间的情况 561 if ( 562 funData.ts < startTime && 563 funData.ts + funData.dur > startTime && 564 funData.ts + funData.dur > startTime + value[j].dur 565 ) { 566 resList.push( 567 this.returnSingleObj( 568 'cycle' + (constant.i + 1) + '—' + value[j].thread, 569 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 570 value[j], 571 funData, 572 1 573 )! 574 ); 575 totalList 576 .get(constant.key) 577 ?.push( 578 this.returnSingleObj( 579 value[j].thread, 580 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 581 value[j], 582 funData, 583 1 584 )! 585 ); 586 } 587 // 如果频点数据开始时间大于某一周期起始时间,小于该周期的结束时间。且频点数据结束时间大于等于周期结束时间的情况 588 if ( 589 funData.ts < startTime && 590 funData.ts + funData.dur > startTime && 591 funData.ts + funData.dur <= startTime + value[j].dur 592 ) { 593 resList.push( 594 this.returnSingleObj( 595 'cycle' + (constant.i + 1) + '—' + value[j].thread, 596 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 597 value[j], 598 funData, 599 2 600 )! 601 ); 602 totalList 603 .get(constant.key) 604 ?.push( 605 this.returnSingleObj( 606 value[j].thread, 607 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 608 value[j], 609 funData, 610 2 611 )! 612 ); 613 break; 614 } 615 // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间大于周期结束时间的情况 616 if ( 617 funData.ts > startTime && 618 startTime + value[j].dur > funData.ts && 619 startTime + value[j].dur > funData.ts + funData.dur 620 ) { 621 resList.push( 622 this.returnSingleObj( 623 'cycle' + (constant.i + 1) + '—' + value[j].thread, 624 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 625 value[j], 626 funData, 627 3 628 )! 629 ); 630 totalList 631 .get(constant.key) 632 ?.push( 633 this.returnSingleObj( 634 value[j].thread, 635 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 636 value[j], 637 funData, 638 3 639 )! 640 ); 641 break; 642 } 643 // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该周期的开始时间。且频点数据结束时间小于等于周期结束时间的情况 644 if ( 645 funData.ts > startTime && 646 startTime + value[j].dur > funData.ts && 647 startTime + value[j].dur <= funData.ts + funData.dur 648 ) { 649 resList.push( 650 this.returnSingleObj( 651 'cycle' + (constant.i + 1) + '—' + value[j].thread, 652 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 653 value[j], 654 funData, 655 4 656 )! 657 ); 658 totalList 659 .get(constant.key) 660 ?.push( 661 this.returnSingleObj( 662 value[j].thread, 663 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 664 value[j], 665 funData, 666 4 667 )! 668 ); 669 } 670 } 671 } 672 /** 673 * 674 * @param str 周期列头 675 * @param arg 常量参数 676 * @param value 频点数据对象 677 * @param funData 方法对象 678 * @param flag 标志位 679 * @returns 频点数据对象 680 */ 681 returnSingleObj( 682 str: string, 683 arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number }, 684 value: TabPaneFreqUsageConfig, 685 funData: { ts: number; dur: number }, 686 flag: number 687 ): TabPaneFreqUsageConfig | undefined { 688 switch (flag) { 689 case 1: 690 return new TabPaneFreqUsageConfig( 691 str, 692 '', 693 value.pid, 694 value.tid, 695 (arg.consumption * value.dur) / arg.countMutiple, 696 value.cpu, 697 value.freq, 698 value.dur, 699 '', 700 arg.percent, 701 'freqdata', 702 arg.i, 703 undefined 704 ); 705 case 2: 706 return new TabPaneFreqUsageConfig( 707 str, 708 '', 709 value.pid, 710 value.tid, 711 ((funData.ts + funData.dur - arg.startTime) * arg.consumption) / arg.countMutiple, 712 value.cpu, 713 value.freq, 714 funData.ts + funData.dur - arg.startTime, 715 '', 716 ((funData.ts + funData.dur - arg.startTime) / value.dur) * arg.percent, 717 'freqdata', 718 arg.i, 719 undefined 720 ); 721 case 3: 722 return new TabPaneFreqUsageConfig( 723 str, 724 '', 725 value.pid, 726 value.tid, 727 (funData.dur * arg.consumption) / arg.countMutiple, 728 value.cpu, 729 value.freq, 730 funData.dur, 731 '', 732 (funData.dur / value.dur) * arg.percent, 733 'freqdata', 734 arg.i, 735 undefined 736 ); 737 case 4: 738 return new TabPaneFreqUsageConfig( 739 str, 740 '', 741 value.pid, 742 value.tid, 743 ((arg.startTime + value.dur - funData.ts) * arg.consumption) / arg.countMutiple, 744 value.cpu, 745 value.freq, 746 arg.startTime + value.dur - funData.ts, 747 '', 748 ((arg.startTime + value.dur - funData.ts) / value.dur) * arg.percent, 749 'freqdata', 750 arg.i, 751 undefined 752 ); 753 default: 754 break; 755 } 756 } 757 /** 758 * Loop方式切割数据功能 759 */ 760 dataLoopCut( 761 threadId: HTMLInputElement, 762 threadFunc: HTMLInputElement, 763 resultList: Map<string, Array<TabPaneFreqUsageConfig>> 764 ): void { 765 let threadIdValue: string = threadId.value.trim(); 766 let threadFuncName: string = threadFunc.value.trim(); 767 let rightNS: number = this.currentSelectionParam.rightNs; 768 let recordStartNs: number = this.currentSelectionParam.recordStartNs; 769 // @ts-ignore 770 this.threadStatesTbl.value = []; 771 if (threadIdValue !== '' && threadFuncName !== '') { 772 querySearchFuncData(threadFuncName, Number(threadIdValue), this.currentSelectionParam.leftNs, rightNS).then( 773 (res) => { 774 if (res !== null && res.length > 0) { 775 // targetMap为全局initData的拷贝对象,cutArr数组用来存放周期切割依据数据 776 let targetMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 777 let cutArr: Array<{ ts: number; dur?: number }> = []; 778 // 新创建map对象接收传过来的实参map 779 resultList.forEach((item: Array<TabPaneFreqUsageConfig>, key: string) => { 780 targetMap.set(key, JSON.parse(JSON.stringify(item))); 781 }); 782 // 根据线程id及方法名获取的数据,处理后用作切割时间依据,时间跨度为整个方法开始时间到末个方法开始时间 783 for (let i of res) { 784 cutArr[cutArr.length - 1] && 785 (cutArr[cutArr.length - 1].dur = i.startTime 786 ? i.startTime + recordStartNs - cutArr[cutArr.length - 1].ts 787 : 0); 788 cutArr.push({ ts: i.startTime! + recordStartNs }); 789 } 790 let cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 791 let totalList: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 792 this.mergeLoopData(cutArr, targetMap, cycleMap, totalList); 793 let threadArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.threadArr)); 794 let processArr: Array<TabPaneFreqUsageConfig> = JSON.parse(JSON.stringify(this.processArr)); 795 this.mergeThreadData(threadArr, cycleMap); 796 this.mergeTotalData(threadArr, this.merge(totalList)); 797 this.mergePidData(processArr, threadArr); 798 this.fixedDeal(processArr); 799 this.threadStatesTblSource = processArr; 800 this.threadStatesTbl!.recycleDataSource = processArr; 801 this.threadClick(processArr); 802 } else { 803 this.threadStatesTblSource = []; 804 this.threadStatesTbl!.recycleDataSource = []; 805 } 806 } 807 ); 808 this.threadStatesTbl!.loading = false; 809 } else { 810 this.threadStatesTbl!.loading = false; 811 if (threadIdValue === '') { 812 threadId.style.border = '2px solid rgb(255,0,0)'; 813 } 814 if (threadFuncName === '') { 815 threadFunc.style.border = '2px solid rgb(255,0,0)'; 816 } 817 } 818 } 819 /** 820 * 整合Loop切割方式中的频点数据与方法周期数据 821 */ 822 mergeLoopData( 823 cutArr: Array<{ ts: number; dur?: number }>, 824 targetMap: Map<string, Array<TabPaneFreqUsageConfig>>, 825 cycleMap: Map<string, Array<TabPaneFreqUsageConfig>>, 826 totalList: Map<string, Array<TabPaneFreqUsageConfig>> 827 ): void { 828 let timeDur: number = this.currentSelectionParam.recordStartNs; 829 targetMap.forEach((value: any, key) => { 830 cycleMap.set(key, new Array()); 831 totalList.set(key, new Array()); 832 for (let i = 0; i < cutArr.length - 1; i++) { 833 let cpuArr: Array<number> = []; 834 let resList: Array<TabPaneFreqUsageConfig> = []; 835 let cpuMap: Map<string, Array<TabPaneFreqUsageConfig>> = new Map(); 836 // 时间倍数值 837 const countMutiple: number = 1000000; 838 const MIN_NUM: number = 3; 839 cpuMap.set(key, new Array()); 840 // 创建周期层级数据 841 cycleMap 842 .get(key) 843 ?.push( 844 new TabPaneFreqUsageConfig( 845 'cycle' + (i + 1) + '—' + value[0].thread, 846 ((cutArr[i].ts - timeDur) / countMutiple).toFixed(MIN_NUM), 847 key.split('_')[0], 848 key.split('_')[1], 849 0, 850 '', 851 '', 852 0, 853 (cutArr[i].dur! / countMutiple).toFixed(MIN_NUM), 854 0, 855 'cycle', 856 i + 1, 857 [] 858 ) 859 ); 860 this.dismantlingLoop( 861 value, 862 cutArr, 863 { 864 i: i, 865 key: key, 866 countMutiple: countMutiple, 867 cpuArr, 868 cpuMap, 869 }, 870 resList, 871 totalList 872 ); 873 // 合并相同周期内的数据 874 this.mergeData(resList); 875 // 整理排序相同周期下的数据 876 this.mergeCpuData(cpuMap.get(key)!, resList); 877 // 将cpu数据放置到对应周期层级下 878 this.mergeCycleData(cycleMap.get(key)![i], cpuMap.get(key)!); 879 } 880 }); 881 } 882 /** 883 * 拆解Loop大函数 884 * @param value 频点数据数组 885 * @param funData 方法对象 886 * @param constant 常量 887 * @param resList 周期数组 888 * @param totalList total数组 889 */ 890 dismantlingLoop( 891 value: Array<TabPaneFreqUsageConfig>, 892 cutArr: Array<{ ts: number; dur?: number }>, 893 constant: { 894 i: number; 895 key: string; 896 countMutiple: number; 897 cpuArr: Array<number>; 898 cpuMap: Map<string, Array<TabPaneFreqUsageConfig>>; 899 }, 900 resList: Array<TabPaneFreqUsageConfig>, 901 totalList: Map<string, Array<TabPaneFreqUsageConfig>> 902 ): void { 903 for (let j = 0; j < value.length; j++) { 904 // 判断若用户导入json文件,则替换为对应cpu下的对应频点的算力值进行算力消耗计算 905 let startTime = Number(value[j].ts); 906 let percent = Number(value[j].percent); 907 // @ts-ignore 908 let consumptionMap: Map<number, number> = 909 //@ts-ignore 910 SpSegmentationChart.freqInfoMapData.size > 0 && SpSegmentationChart.freqInfoMapData.get(Number(value[j].cpu))?.mapData; 911 // 若存在算力值,则直接取值做计算。若不存在算力值,且频点值不为unknown的情况,则取频点值做计算,若为unknown,则取0做兼容 912 const consumption: number = Number( 913 consumptionMap && consumptionMap.get(Number(value[j].freq)) 914 ? consumptionMap.get(Number(value[j].freq)) 915 : value[j].freq === 'unknown' 916 ? 0 917 : value[j].freq 918 ); 919 if (!constant.cpuArr.includes(Number(value[j].cpu))) { 920 constant.cpuArr.push(Number(value[j].cpu)); 921 // 创建cpu层级数据,以便后续生成树结构 922 constant.cpuMap 923 .get(constant.key) 924 ?.push( 925 new TabPaneFreqUsageConfig( 926 'cycle' + (constant.i + 1) + '—' + value[j].thread, 927 '', 928 value[j].pid, 929 value[j].tid, 930 0, 931 value[j].cpu, 932 '', 933 0, 934 '', 935 0, 936 'cpu', 937 -1, 938 [] 939 ) 940 ); 941 } 942 // 以下为频点数据按Loop周期切割数据如何取舍的判断条件,cutArr为周期切割依据,value为某一线程下的频点汇总数据 943 // 如果频点数据开始时间大于某一周期起始时间,且结束时间小于等于下一同名方法开始时间的情况 944 if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur <= cutArr[constant.i + 1].ts) { 945 resList.push( 946 this.returnLoopObj( 947 'cycle' + (constant.i + 1) + '—' + value[j].thread, 948 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 949 value[j], 950 cutArr, 951 1 952 )! 953 ); 954 totalList 955 .get(constant.key) 956 ?.push( 957 this.returnLoopObj( 958 value[j].thread, 959 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 960 value[j], 961 cutArr, 962 1 963 )! 964 ); 965 } 966 // 如果频点数据开始时间大于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况 967 if (startTime >= cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) { 968 if (cutArr[constant.i + 1].ts - startTime > 0) { 969 resList.push( 970 this.returnLoopObj( 971 'cycle' + (constant.i + 1) + '—' + value[j].thread, 972 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 973 value[j], 974 cutArr, 975 2 976 )! 977 ); 978 totalList 979 .get(constant.key) 980 ?.push( 981 this.returnLoopObj( 982 value[j].thread, 983 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 984 value[j], 985 cutArr, 986 2 987 )! 988 ); 989 break; 990 } 991 } 992 // 如果频点数据开始时间小于某一周期起始时间,且结束时间大于下一同名方法开始时间的情况 993 if (startTime < cutArr[constant.i].ts && startTime + value[j].dur > cutArr[constant.i + 1].ts) { 994 resList.push( 995 this.returnLoopObj( 996 'cycle' + (constant.i + 1) + '—' + value[j].thread, 997 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 998 value[j], 999 cutArr, 1000 3 1001 )! 1002 ); 1003 totalList 1004 .get(constant.key) 1005 ?.push( 1006 this.returnLoopObj( 1007 value[j].thread, 1008 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 1009 value[j], 1010 cutArr, 1011 3 1012 )! 1013 ); 1014 } 1015 // 如果频点数据开始时间小于某一周期起始时间,结束时间大于该方法开始时间。且频点数据结束时间小于下一同名方法开始时间 1016 if ( 1017 startTime < cutArr[constant.i].ts && 1018 startTime + value[j].dur > cutArr[constant.i].ts && 1019 startTime + value[j].dur < cutArr[constant.i + 1].ts 1020 ) { 1021 resList.push( 1022 this.returnLoopObj( 1023 'cycle' + (constant.i + 1) + '—' + value[j].thread, 1024 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 1025 value[j], 1026 cutArr, 1027 4 1028 )! 1029 ); 1030 totalList 1031 .get(constant.key) 1032 ?.push( 1033 this.returnLoopObj( 1034 value[j].thread, 1035 { i: constant.i, percent, startTime, consumption, countMutiple: constant.countMutiple }, 1036 value[j], 1037 cutArr, 1038 4 1039 )! 1040 ); 1041 } 1042 } 1043 } 1044 /** 1045 * 1046 * @param str 周期列头 1047 * @param arg 常量参数 1048 * @param value 频点数据对象 1049 * @param funData 方法对象 1050 * @param flag 标志位 1051 * @returns 频点数据对象 1052 */ 1053 returnLoopObj( 1054 str: string, 1055 arg: { i: number; percent: number; startTime: number; consumption: number; countMutiple: number }, 1056 value: TabPaneFreqUsageConfig, 1057 cutArr: Array<{ ts: number; dur?: number }>, 1058 flag: number 1059 ): TabPaneFreqUsageConfig | undefined { 1060 switch (flag) { 1061 case 1: 1062 return new TabPaneFreqUsageConfig( 1063 str, 1064 '', 1065 value.pid, 1066 value.tid, 1067 (arg.consumption * value.dur) / arg.countMutiple, 1068 value.cpu, 1069 value.freq, 1070 value.dur, 1071 '', 1072 value.percent, 1073 'freqdata', 1074 arg.i, 1075 undefined 1076 ); 1077 case 2: 1078 return new TabPaneFreqUsageConfig( 1079 str, 1080 '', 1081 value.pid, 1082 value.tid, 1083 (arg.consumption * (cutArr[arg.i + 1].ts - arg.startTime)) / arg.countMutiple, 1084 value.cpu, 1085 value.freq, 1086 cutArr[arg.i + 1].ts - arg.startTime, 1087 '', 1088 arg.percent * ((cutArr[arg.i + 1].ts - arg.startTime) / value.dur), 1089 'freqdata', 1090 arg.i, 1091 undefined 1092 ); 1093 case 3: 1094 return new TabPaneFreqUsageConfig( 1095 str, 1096 '', 1097 value.pid, 1098 value.tid, 1099 (arg.consumption * (cutArr[arg.i + 1].ts - cutArr[arg.i].ts)) / arg.countMutiple, 1100 value.cpu, 1101 value.freq, 1102 cutArr[arg.i + 1].ts - cutArr[arg.i].ts, 1103 '', 1104 arg.percent * ((cutArr[arg.i + 1].ts - cutArr[arg.i].ts) / value.dur), 1105 'freqdata', 1106 arg.i, 1107 undefined 1108 ); 1109 case 4: 1110 return new TabPaneFreqUsageConfig( 1111 str, 1112 '', 1113 value.pid, 1114 value.tid, 1115 (arg.consumption * (value.dur + arg.startTime - cutArr[arg.i].ts)) / arg.countMutiple, 1116 value.cpu, 1117 value.freq, 1118 value.dur + arg.startTime - cutArr[arg.i].ts, 1119 '', 1120 arg.percent * ((value.dur + arg.startTime - cutArr[arg.i].ts) / value.dur), 1121 'freqdata', 1122 arg.i, 1123 undefined 1124 ); 1125 default: 1126 break; 1127 } 1128 } 1129 /** 1130 * 切割后整合好的周期频点数据放置到对应的线程下 1131 */ 1132 mergeThreadData( 1133 threadArr: Array<TabPaneFreqUsageConfig>, 1134 cycleMap: Map<string, Array<TabPaneFreqUsageConfig>> 1135 ): void { 1136 for (let i = 0; i < threadArr.length; i++) { 1137 let cycleMapData: Array<TabPaneFreqUsageConfig> = cycleMap.get(threadArr[i].pid + '_' + threadArr[i].tid)!; 1138 for (let j = 0; j < cycleMapData!.length; j++) { 1139 threadArr[i].children?.push(cycleMapData![j]); 1140 threadArr[i].count += cycleMapData![j].count; 1141 threadArr[i].dur += cycleMapData![j].dur; 1142 // @ts-ignore 1143 threadArr[i].percent += cycleMapData![j].percent; 1144 } 1145 } 1146 } 1147 /** 1148 * 切割后整合好的线程级频点数据放置到对应的进程 1149 */ 1150 mergePidData(pidArr: Array<TabPaneFreqUsageConfig>, threadArr: Array<TabPaneFreqUsageConfig>): void { 1151 for (let i = 0; i < pidArr.length; i++) { 1152 for (let j = 0; j < threadArr.length; j++) { 1153 if (pidArr[i].pid === threadArr[j].pid) { 1154 pidArr[i].children?.push(threadArr[j]); 1155 pidArr[i].count += threadArr[j].count; 1156 pidArr[i].dur += threadArr[j].dur; 1157 // @ts-ignore 1158 pidArr[i].percent += threadArr[j].percent; 1159 } 1160 } 1161 } 1162 } 1163 /** 1164 * 合并相同周期内运行所在cpu相同、频点相同的数据 1165 */ 1166 mergeData(resList: Array<TabPaneFreqUsageConfig>): void { 1167 // 合并相同周期内的数据 1168 for (let i = 0; i < resList.length; i++) { 1169 for (let j = i + 1; j < resList.length; j++) { 1170 if ( 1171 resList[i].cpu === resList[j].cpu && 1172 resList[i].freq === resList[j].freq && 1173 resList[i].id === resList[j].id 1174 ) { 1175 resList[i].dur += resList[j].dur; 1176 // @ts-ignore 1177 resList[i].percent += resList[j].percent; 1178 resList[i].count += resList[j].count; 1179 resList.splice(j, 1); 1180 j--; 1181 } 1182 } 1183 } 1184 } 1185 /** 1186 * 将cpu层级数据放到对应的周期层级下 1187 */ 1188 mergeCycleData(obj: TabPaneFreqUsageConfig, arr: Array<TabPaneFreqUsageConfig>): void { 1189 for (let i = 0; i < arr!.length; i++) { 1190 if (arr![i].count === 0 && arr![i].dur === 0) { 1191 continue; 1192 } 1193 obj.children?.push(arr![i]); 1194 obj.count += arr![i].count; 1195 obj.dur += arr![i].dur; 1196 // @ts-ignore 1197 obj.percent += arr![i].percent; 1198 } 1199 } 1200 /** 1201 * 将切割好的不区分周期的数据作为total数据放到对应的线程层级下,周期数据前 1202 */ 1203 mergeTotalData(threadArr: Array<TabPaneFreqUsageConfig>, totalData: Array<TabPaneFreqUsageConfig>): void { 1204 for (let i = 0; i < threadArr.length; i++) { 1205 for (let j = 0; j < totalData.length; j++) { 1206 if ( 1207 Number(threadArr[i].pid) === Number(totalData[j].pid) && 1208 Number(threadArr[i].tid) === Number(totalData[j].tid) 1209 ) { 1210 totalData[j].thread = 'TotalData'; 1211 totalData[j].flag = 't_cycle'; 1212 // @ts-ignore 1213 threadArr[i].children.unshift(totalData[j]); 1214 } 1215 } 1216 } 1217 } 1218 /** 1219 * 整理排序相同周期下的数据 1220 */ 1221 mergeCpuData(cpuArray: Array<TabPaneFreqUsageConfig>, resList: Array<TabPaneFreqUsageConfig>): void { 1222 // 以算力消耗降序排列 1223 resList.sort((a, b) => b.count - a.count); 1224 // 以cpu升序排列 1225 cpuArray.sort((a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu)); 1226 cpuArray.forEach((item: TabPaneFreqUsageConfig) => { 1227 for (let s = 0; s < resList.length; s++) { 1228 if (item.cpu === resList[s].cpu) { 1229 item.children?.push(resList[s]); 1230 item.count += resList[s].count; 1231 item.dur += resList[s].dur; 1232 // @ts-ignore 1233 item.percent += resList[s].percent; 1234 } 1235 } 1236 }); 1237 } 1238 /** 1239 * 切割好的不区分周期的数据,以相同cpu相同频点的进行整合 1240 */ 1241 merge(totalList: Map<string, Array<TabPaneFreqUsageConfig>>): Array<TabPaneFreqUsageConfig> { 1242 let result: Array<TabPaneFreqUsageConfig> = new Array(); 1243 totalList.forEach((value: Array<TabPaneFreqUsageConfig>, key: string) => { 1244 let countNum = result.push( 1245 new TabPaneFreqUsageConfig('', '', key.split('_')[0], key.split('_')[1], 0, '', '', 0, '', 0, 'cycle', 0, []) 1246 ); 1247 let cpuArr: Array<TabPaneFreqUsageConfig> = []; 1248 let flagArr: Array<number | string> = []; 1249 for (let i = 0; i < value.length; i++) { 1250 if (!flagArr.includes(value[i].cpu)) { 1251 flagArr.push(value[i].cpu); 1252 let flag = cpuArr.push( 1253 new TabPaneFreqUsageConfig( 1254 value[i].thread, 1255 '', 1256 value[i].pid, 1257 value[i].tid, 1258 0, 1259 value[i].cpu, 1260 '', 1261 0, 1262 '', 1263 0, 1264 'cpu', 1265 -1, 1266 [] 1267 ) 1268 ); 1269 result[countNum - 1].children?.push(cpuArr[flag - 1]); 1270 } 1271 for (let j = i + 1; j < value.length; j++) { 1272 if (value[i].cpu === value[j].cpu && value[i].freq === value[j].freq) { 1273 value[i].dur += value[j].dur; 1274 // @ts-ignore 1275 value[i].percent += value[j].percent; 1276 value[i].count += value[j].count; 1277 value.splice(j, 1); 1278 j--; 1279 } 1280 } 1281 } 1282 result[countNum - 1].children?.sort( 1283 (a: TabPaneFreqUsageConfig, b: TabPaneFreqUsageConfig) => Number(a.cpu) - Number(b.cpu) 1284 ); 1285 for (let i = 0; i < cpuArr.length; i++) { 1286 for (let j = 0; j < value.length; j++) { 1287 if (cpuArr[i].cpu === value[j].cpu) { 1288 cpuArr[i].children?.push(value[j]); 1289 cpuArr[i].dur += value[j].dur; 1290 cpuArr[i].count += value[j].count; 1291 // @ts-ignore 1292 cpuArr[i].percent += value[j].percent; 1293 } 1294 } 1295 result[countNum - 1].dur += cpuArr[i].dur; 1296 result[countNum - 1].count += cpuArr[i].count; 1297 // @ts-ignore 1298 result[countNum - 1].percent += cpuArr[i].percent; 1299 } 1300 }); 1301 return result; 1302 } 1303 /** 1304 * 递归整理数据,取小数位数,转换单位 1305 */ 1306 fixedDeal(arr: Array<TabPaneFreqUsageConfig>): void { 1307 if (arr === undefined) { 1308 return; 1309 } 1310 for (let i = 0; i < arr.length; i++) { 1311 // @ts-ignore 1312 arr[i].percent = arr[i].percent.toFixed(2); 1313 // @ts-ignore 1314 arr[i].dur = (arr[i].dur / 1000000).toFixed(3); 1315 if (arr[i].freq !== '') { 1316 if (arr[i].freq === 'unknown') { 1317 arr[i].freq = 'unknown'; 1318 } else { 1319 // @ts-ignore 1320 arr[i].freq = arr[i].freq / 1000; 1321 } 1322 } 1323 if (!(SpSegmentationChart.freqInfoMapData.size > 0)) { 1324 // @ts-ignore 1325 arr[i].count = (arr[i].count / 1000).toFixed(3); 1326 } else { 1327 // @ts-ignore 1328 arr[i].count = arr[i].count.toFixed(3); 1329 } 1330 // @ts-ignore 1331 this.fixedDeal(arr[i].children); 1332 } 1333 } 1334 /** 1335 * 绑定表格点击事件 1336 */ 1337 private threadClick(data: Array<TabPaneFreqUsageConfig>): void { 1338 let labels = this.threadStatesTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); 1339 if (labels) { 1340 for (let i = 0; i < labels.length; i++) { 1341 let label = labels[i].innerHTML; 1342 labels[i].addEventListener('click', (e) => { 1343 if (!this.threadStatesTblSource.length && !this.threadStatesTbl!.recycleDataSource.length) { 1344 data = []; 1345 } 1346 if (label.includes('Process') && i === 0) { 1347 this.threadStatesTbl!.setStatus(data, false); 1348 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 1349 } else if (label.includes('Thread') && i === 1) { 1350 for (let item of data) { 1351 // @ts-ignore 1352 item.status = true; 1353 if (item.children !== undefined && item.children.length > 0) { 1354 this.threadStatesTbl!.setStatus(item.children, false); 1355 } 1356 } 1357 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 1358 } else if (label.includes('Cycle') && i === 2) { 1359 for (let item of data) { 1360 // @ts-ignore 1361 item.status = true; 1362 for (let value of item.children ? item.children : []) { 1363 // @ts-ignore 1364 value.status = true; 1365 if (value.children !== undefined && value.children.length > 0) { 1366 this.threadStatesTbl!.setStatus(value.children, false); 1367 } 1368 } 1369 } 1370 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 1371 } else if (label.includes('CPU') && i === 3) { 1372 this.threadStatesTbl!.setStatus(data, true); 1373 this.threadStatesTbl!.recycleDs = this.threadStatesTbl!.meauseTreeRowElement(data, RedrawTreeForm.Expand); 1374 } 1375 }); 1376 } 1377 } 1378 } 1379 /** 1380 * 散点图渲染数据整理 1381 */ 1382 render(res: Array<TabPaneFreqUsageConfig>, str: string, queryCycleScatter: Array<number>): void { 1383 let maxFreq: HTMLInputElement = this.scatterInput!.querySelector('#maxFreq')!; 1384 let maxHz: HTMLInputElement = this.scatterInput!.querySelector('#maxHz')!; 1385 if (maxFreq.value && maxHz.value) { 1386 if (/^[0-9]*$/.test(maxFreq.value) && /^[0-9]*$/.test(maxHz.value)) { 1387 this.organizeData(res, str, queryCycleScatter, maxFreq.value, maxHz.value); 1388 } else { 1389 if (!/^[0-9]*$/.test(maxFreq.value)) { 1390 maxFreq.style.border = '2px solid rgb(255,0,0)'; 1391 } 1392 if (!/^[0-9]*$/.test(maxHz.value)) { 1393 maxHz.style.border = '2px solid rgb(255,0,0)'; 1394 } 1395 } 1396 } else { 1397 if (maxFreq.value === '') { 1398 maxFreq.style.border = '2px solid rgb(255,0,0)'; 1399 } 1400 if (maxHz.value === '') { 1401 maxHz.style.border = '2px solid rgb(255,0,0)'; 1402 } 1403 SpSegmentationChart.setChartData('CPU-FREQ', []); 1404 } 1405 } 1406 /** 1407 * 数据整理 1408 */ 1409 organizeData( 1410 res: Array<TabPaneFreqUsageConfig>, 1411 str: string, 1412 queryCycleScatter: Array<number>, 1413 maxFreqValue: string, 1414 maxHzValue: string 1415 ): void { 1416 // @ts-ignore 1417 this.shadowRoot?.querySelector('#cycleQuery')!.style.display = 'block'; 1418 // @ts-ignore 1419 let freq: Map<number, number> = 1420 SpSegmentationChart.freqInfoMapData.size > 0 && 1421 //@ts-ignore 1422 SpSegmentationChart.freqInfoMapData.get(SpSegmentationChart.freqInfoMapData.size - 1)?.mapData; 1423 // @ts-ignore 1424 let yAxis: number = 1425 freq && freq.get(Number(maxFreqValue) * 1000) ? freq.get(Number(maxFreqValue) * 1000) : Number(maxFreqValue); 1426 let xAxis: number = (yAxis * 1000) / Number(maxHzValue); 1427 // 需要做筛选时,会利用下面的cycleA、cycleB数组 1428 let scatterArr: Array<Array<number>> = []; 1429 let traceRowdata: Array<{ 1430 dur: number; 1431 startNS: number; 1432 value: number; 1433 cycle: number; 1434 }> = []; 1435 let cycleA: Array<Array<number>> = []; 1436 let cycleB: Array<Array<number>> = []; 1437 let cycleAStart: number = queryCycleScatter[0] || 0; 1438 let cycleAEnd: number = queryCycleScatter[1] || 0; 1439 let cycleBStart: number = queryCycleScatter[2] || 0; 1440 let cycleBEnd: number = queryCycleScatter[3] || 0; 1441 for (let i = 1; i < res.length; i++) { 1442 const count: number = Number(res[i].count); 1443 const dur: number = Number(res[i].cdur); 1444 const rdur: number = Number(res[i].dur); //MHz·ms ms ms 1445 scatterArr.push([count, count / dur, i, dur, rdur]); 1446 traceRowdata.push({ 1447 dur: dur * 1000000, 1448 value: count, 1449 startNS: Number(res[i].ts) * 1000000, 1450 cycle: i - 1, 1451 }); 1452 if (dur >= cycleAStart && dur < cycleAEnd) { 1453 cycleA.push([count, count / dur, i, dur, rdur]); 1454 } 1455 if (dur >= cycleBStart && dur < cycleBEnd) { 1456 cycleB.push([count, count / dur, i, dur, rdur]); 1457 } 1458 } 1459 this.setConfig(Number(maxHzValue), str, scatterArr, yAxis, xAxis, cycleA, cycleB); 1460 SpSegmentationChart.setChartData('CPU-FREQ', traceRowdata); 1461 } 1462 /** 1463 * 配置散点图 1464 */ 1465 setConfig( 1466 maxHz: number, 1467 str: string, 1468 scatterArr: Array<Array<number>>, 1469 yAxis: number, 1470 xAxis: number, 1471 cycleA: Array<Array<number>>, 1472 cycleB: Array<Array<number>> 1473 ): void { 1474 const DELTA: number = 5; 1475 this.statisticsScatter!.config = { 1476 // 纵轴坐标值 1477 yAxisLabel: [ 1478 Math.round(yAxis / DELTA), 1479 Math.round((yAxis * 2) / DELTA), 1480 Math.round((yAxis * 3) / DELTA), 1481 Math.round((yAxis * 4) / DELTA), 1482 Math.round(yAxis), 1483 ], 1484 // 横轴坐标值 1485 xAxisLabel: [ 1486 Math.round(xAxis / DELTA), 1487 Math.round((xAxis * 2) / DELTA), 1488 Math.round((xAxis * 3) / DELTA), 1489 Math.round((xAxis * 4) / DELTA), 1490 Math.round(xAxis), 1491 Math.round((xAxis * 6) / DELTA), 1492 ], 1493 // 横轴字段、纵轴字段 1494 axisLabel: ['负载', '算力供给'], 1495 // 是否加载最大负载线及均衡线 1496 drawload: true, 1497 // 最大负载线及均衡线值 1498 load: [xAxis, maxHz], 1499 // 绘制点数据信息存储数组 1500 paintingData: [], 1501 // 当前移入点坐标信息 1502 hoverData: {}, 1503 // 颜色池 1504 colorPool: () => ['#2f72f8', '#ffab67', '#a285d2'], 1505 // 移入数据点时是否触发函数 1506 //@ts-ignore 1507 hoverEvent: SpSegmentationChart.tabHover, 1508 // 渐变色背景信息 1509 globalGradient: undefined, 1510 // 渲染数据点 1511 data: [scatterArr, cycleA, cycleB], 1512 // 散点图title 1513 title: str, 1514 colorPoolText: (): Array<string> => ['Total', 'CycleA', 'CycleB'], 1515 tip: (data: { c: Array<number> }): string => { 1516 return ` 1517 <div> 1518 <span>Cycle: ${data.c[2]};</span></br> 1519 <span>Comsumption: ${data.c[0]};</span></br> 1520 <span>Cycle_dur: ${data.c[3]} ms;</span></br> 1521 <span>Running_dur: ${data.c[4]} ms;</span></br> 1522 </div> 1523 `; 1524 }, 1525 }; 1526 } 1527 initElements(): void { 1528 this.threadStatesTbl = this.shadowRoot?.querySelector<LitTable>('#tb-running-datacut'); 1529 // 绑定事件 1530 this.addListener(); 1531 this.statisticsScatter = this.shadowRoot?.querySelector('#chart-scatter'); 1532 // 增加表格thread层级点击更新散点图事件、周期层级点击高亮泳道图对应段事件 1533 let scatterData: Array<TabPaneFreqUsageConfig> = new Array(); 1534 let str: string = ''; 1535 this.threadStatesTbl!.addEventListener('row-click', (evt): void => { 1536 // @ts-ignore 1537 if (evt.detail.flag === 'thread') { 1538 // @ts-ignore 1539 scatterData = evt.detail.children; 1540 // @ts-ignore 1541 str = evt.detail.thread; 1542 this.render(scatterData, str, []); 1543 } 1544 1545 if ( 1546 // @ts-ignore 1547 evt.detail.flag === 'cycle' && 1548 // @ts-ignore 1549 evt.detail.pid === scatterData[evt.detail.id - 1].pid && 1550 // @ts-ignore 1551 evt.detail.tid === scatterData[evt.detail.id - 1].tid && 1552 // @ts-ignore 1553 evt.detail.id > 0 1554 ) { 1555 // @ts-ignore 1556 SpSegmentationChart.tabHover('CPU-FREQ', true, evt.detail.id - 1); 1557 } 1558 }); 1559 this.scatterInput = this.shadowRoot?.querySelector('.chart-box'); 1560 this.shadowRoot?.querySelector('#query-btn')!.addEventListener('click', (e) => { 1561 // @ts-ignore 1562 let cycleAStartValue = this.shadowRoot?.querySelector('#cycle-a-start-range')!.value; 1563 // @ts-ignore 1564 let cycleAEndValue = this.shadowRoot?.querySelector('#cycle-a-end-range')!.value; 1565 // @ts-ignore 1566 let cycleBStartValue = this.shadowRoot?.querySelector('#cycle-b-start-range')!.value; 1567 // @ts-ignore 1568 let cycleBEndValue = this.shadowRoot?.querySelector('#cycle-b-end-range')!.value; 1569 let queryCycleScatter = [ 1570 Number(cycleAStartValue), 1571 Number(cycleAEndValue), 1572 Number(cycleBStartValue), 1573 Number(cycleBEndValue), 1574 ]; 1575 this.render(scatterData, str, queryCycleScatter); 1576 }); 1577 } 1578 /** 1579 * 配置监听事件 1580 */ 1581 addListener(): void { 1582 // 绑定single、loop按钮点击事件 1583 this.threadStatesDIV = this.shadowRoot?.querySelector('#dataCut'); 1584 this.threadStatesDIV?.children[2].children[0].addEventListener('click', (e) => { 1585 this.threadStatesTbl!.loading = true; 1586 // @ts-ignore 1587 this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#666666'; 1588 // @ts-ignore 1589 this.threadStatesDIV?.children[2].children[0].style.color = '#fff'; 1590 // @ts-ignore 1591 this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#fff'; 1592 // @ts-ignore 1593 this.threadStatesDIV?.children[2].children[1].style.color = '#000'; 1594 // @ts-ignore 1595 1596 this.dataSingleCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData); 1597 }); 1598 this.threadStatesDIV?.children[2].children[1].addEventListener('click', (e) => { 1599 this.threadStatesTbl!.loading = true; 1600 // @ts-ignore 1601 this.threadStatesDIV?.children[2].children[1].style.backgroundColor = '#666666'; 1602 // @ts-ignore 1603 this.threadStatesDIV?.children[2].children[1].style.color = '#fff'; 1604 // @ts-ignore 1605 this.threadStatesDIV?.children[2].children[0].style.backgroundColor = '#fff'; 1606 // @ts-ignore 1607 this.threadStatesDIV?.children[2].children[0].style.color = '#000'; 1608 // @ts-ignore 1609 this.dataLoopCut(this.threadStatesDIV?.children[0]!, this.threadStatesDIV?.children[1]!, this.initData); 1610 }); 1611 this.threadStatesDIV?.children[0].addEventListener('focus', (e) => { 1612 // @ts-ignore 1613 this.threadStatesDIV?.children[0]!.style.border = '1px solid rgb(151,151,151)'; 1614 }); 1615 this.threadStatesDIV?.children[1].addEventListener('focus', (e) => { 1616 // @ts-ignore 1617 this.threadStatesDIV?.children[1]!.style.border = '1px solid rgb(151,151,151)'; 1618 }); 1619 this.shadowRoot?.querySelector('#maxFreq')?.addEventListener('focus', (e) => { 1620 // @ts-ignore 1621 this.shadowRoot?.querySelector('#maxFreq')!.style.border = '1px solid rgb(151,151,151)'; 1622 }); 1623 this.shadowRoot?.querySelector('#maxHz')?.addEventListener('focus', (e) => { 1624 // @ts-ignore 1625 this.shadowRoot?.querySelector('#maxHz')!.style.border = '1px solid rgb(151,151,151)'; 1626 }); 1627 } 1628 connectedCallback(): void { 1629 super.connectedCallback(); 1630 resizeObserver(this.parentElement!, this.threadStatesTbl!); 1631 } 1632 initHtml(): string { 1633 return ( 1634 ` 1635 <style> 1636 :host{ 1637 padding: 10px 10px; 1638 display: flex; 1639 flex-direction: column; 1640 height: 100%; 1641 } 1642 #dataCut{ 1643 display: flex; 1644 justify-content: space-between; 1645 width:100%; 1646 height:20px; 1647 margin-bottom:2px; 1648 align-items:center; 1649 } 1650 button{ 1651 width:40%; 1652 height:100%; 1653 border: solid 1px #666666; 1654 background-color: rgba(0,0,0,0); 1655 border-radius:10px; 1656 } 1657 button:hover{ 1658 background-color:#666666; 1659 color:white; 1660 } 1661 .d-box{ 1662 display: flex; 1663 margin-left: 0; 1664 height: 100%; 1665 } 1666 .chart-box{ 1667 width: 35%; 1668 min-width: 486px; 1669 overflow: auto; 1670 margin-bottom: 10px; 1671 } 1672 #chart-scatter{ 1673 height: 100%; 1674 max-height: 390px; 1675 } 1676 #query-btn{ 1677 width:90px; 1678 } 1679 </style> 1680 ` + 1681 this.htmlUp() + 1682 this.htmlDown() 1683 ); 1684 } 1685 htmlUp(): string { 1686 return ` 1687 <div id='dataCut'> 1688 <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='' /> 1689 <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='' /> 1690 <div style="width:20%;height: 100%;display:flex;justify-content: space-around;"> 1691 <button>Single</button> 1692 <button>Loop</button> 1693 </div> 1694 </div> 1695 <selector class="d-box"> 1696 <lit-slicer style="width:100%"> 1697 <div class="table-box" style="width: 65%; max-width: calc(100%-495px); min-width: 60%"> 1698 <lit-table id="tb-running-datacut" style="height: auto; overflow:auto;margin-top:5px" tree> 1699 <lit-table-column class="running-percent-column" width="250px" title="Process/Thread/Cycle/CPU" data-index="thread" key="thread" align="flex-start" retract> 1700 </lit-table-column> 1701 <lit-table-column class="running-percent-column" width="100px" title="Cycle_st(ms)" data-index="ts" key="ts" align="flex-start"> 1702 </lit-table-column> 1703 <lit-table-column class="running-percent-column" width="110px" title="Cycle_dur(ms)" data-index="cdur" key="cdur" align="flex-start"> 1704 </lit-table-column> 1705 <lit-table-column class="running-percent-column" width="50px" title="CPU" data-index="cpu" key="cpu" align="flex-start"> 1706 </lit-table-column> 1707 <lit-table-column class="running-percent-column" width="140px" title="Consumption" data-index="count" key="count" align="flex-start"> 1708 </lit-table-column> 1709 <lit-table-column class="running-percent-column" width="100px" title="Freq(MHz)" data-index="freq" key="freq" align="flex-start"> 1710 </lit-table-column> 1711 <lit-table-column class="running-percent-column" width="120px" title="Running_dur(ms)" data-index="dur" key="dur" align="flex-start"> 1712 </lit-table-column> 1713 <lit-table-column class="running-percent-column" width="100px" title="Percent(%)" data-index="percent" key="percent" align="flex-start"> 1714 </lit-table-column> 1715 </lit-table> 1716 </div> 1717 `; 1718 } 1719 htmlDown(): string { 1720 return ` 1721 <lit-slicer-track ></lit-slicer-track> 1722 <div class="chart-box"> 1723 <div> 1724 <span>maxFreq: </span> 1725 <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='' /> 1726 <span>Fps: </span> 1727 <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='' /> 1728 </div> 1729 <div style="flex: 1;display: flex; flex-direction: row;"> 1730 </div> 1731 <lit-chart-scatter id="chart-scatter"></lit-chart-scatter> 1732 <div id= "cycleQuery" style="margin-bottom:5px;margin-top:5px;display:none"> 1733 <div id="cycle-a"> 1734 <span>Cycle A: </span> 1735 <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='' /> 1736 <span>~</span> 1737 <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='' /> 1738 </div> 1739 <div style="margin-top: 5px; display:flex; flex-derection:row; justify-content:space-between"> 1740 <div id="cycle-b"> 1741 <span>Cycle B: </span> 1742 <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='' /> 1743 <span>~</span> 1744 <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='' /> 1745 </div> 1746 <div> 1747 <button id="query-btn">Query</button> 1748 </div> 1749 </div> 1750 </div> 1751 </div> 1752 </lit-slicer> 1753 </selector> 1754 `; 1755 } 1756} 1757