1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { BaseElement, element } from '../../../base-ui/BaseElement.js'; 17import { LitTable } from '../../../base-ui/table/lit-table.js'; 18import { LitChartColumn } from '../../../base-ui/chart/column/LitChartColumn.js'; 19import '../../../base-ui/chart/column/LitChartColumn.js'; 20import './CheckCpuSetting.js'; 21import '../../../base-ui/icon/LitIcon.js'; 22import { CheckCpuSetting } from './CheckCpuSetting.js'; 23import { procedurePool } from '../../database/Procedure.js'; 24import { info } from '../../../log/Log.js'; 25import '../../../base-ui/progress-bar/LitProgressBar.js'; 26import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar.js'; 27import './TableNoData.js'; 28import { TableNoData } from './TableNoData.js'; 29import { getProbablyTime } from '../../database/logic-worker/ProcedureLogicWorkerCommon.js'; 30import { SpSchedulingAnalysis } from './SpSchedulingAnalysis.js'; 31 32@element('top20-thread-cpu-usage') 33export class Top20ThreadCpuUsage extends BaseElement { 34 traceChange: boolean = false; 35 private table: LitTable | null | undefined; 36 private tableBig: LitTable | null | undefined; 37 private tableMid: LitTable | null | undefined; 38 private tableSmall: LitTable | null | undefined; 39 private chartTotal: LitChartColumn | null | undefined; 40 private chart2: LitChartColumn | null | undefined; 41 private chart3: LitChartColumn | null | undefined; 42 private chart4: LitChartColumn | null | undefined; 43 private cpuSetting: CheckCpuSetting | undefined | null; 44 private setting: HTMLDivElement | null | undefined; 45 private progress: LitProgressBar | null | undefined; 46 private nodata: TableNoData | null | undefined; 47 private map: Map<string, { chart: LitChartColumn; table: LitTable }> | undefined; 48 private data: Array<any> = []; 49 private dataBig: Array<any> = []; 50 private dataMid: Array<any> = []; 51 private dataSmall: Array<any> = []; 52 private sort: any = { 53 total: { key: '', sort: 0 }, 54 small: { key: '', sort: 0 }, 55 mid: { key: '', sort: 0 }, 56 big: { key: '', sort: 0 }, 57 }; 58 59 private publicColumns = ` 60 <lit-table-column width="50px" title=" " data-index="no" key="no" align="flex-start"></lit-table-column> 61 <lit-table-column width="50px" title="" data-index="visible" key="visible" align="flex-start"> 62 <template> 63 <lit-icon name="{{ visible === 1 ? 'eye':'eye-close' }}" onclick="{ 64 let data = this.parentElement.parentElement.data; 65 data.visible = data.visible === 1 ? 0 : 1 66 this.name = data.visible === 1 ? 'eye':'eye-close' 67 data.hideHandler() 68 }" size="20"></lit-icon> 69 </template> 70 </lit-table-column> 71 <lit-table-column width="100px" title="tid" data-index="tid" key="tid" align="flex-start" order></lit-table-column> 72 <lit-table-column width="200px" title="t_name" data-index="tName" key="tName" align="flex-start" order></lit-table-column> 73 <lit-table-column width="100px" title="pid" data-index="pid" key="pid" align="flex-start" order></lit-table-column> 74 <lit-table-column width="200px" title="p_name" data-index="pName" key="pName" align="flex-start" order></lit-table-column> 75 `; 76 private bigColumn = ` 77 <lit-table-column width="100px" title="big core" data-index="bigTimeStr" key="bigTimeStr" align="flex-start" order></lit-table-column> 78 <lit-table-column width="100px" title="%" data-index="bigPercent" key="bigPercent" align="flex-start" order></lit-table-column> 79 `; 80 private midColumn = ` 81 <lit-table-column width="100px" title="middle core" data-index="midTimeStr" key="midTimeStr" align="flex-start" order></lit-table-column> 82 <lit-table-column width="100px" title="%" data-index="midPercent" key="midPercent" align="flex-start" order></lit-table-column> 83 `; 84 private smallColumn = ` 85 <lit-table-column width="100px" title="small core" data-index="smallTimeStr" key="smallTimeStr" align="flex-start" order></lit-table-column> 86 <lit-table-column width="100px" title="%" data-index="smallPercent" key="smallPercent" align="flex-start" order></lit-table-column> 87 `; 88 89 initElements(): void { 90 this.nodata = this.shadowRoot!.querySelector<TableNoData>('#nodata'); 91 this.progress = this.shadowRoot!.querySelector<LitProgressBar>('#loading'); 92 this.table = this.shadowRoot!.querySelector<LitTable>('#tb-thread-usage'); 93 this.tableBig = this.shadowRoot!.querySelector<LitTable>('#tb-thread-big'); 94 this.tableMid = this.shadowRoot!.querySelector<LitTable>('#tb-thread-mid'); 95 this.tableSmall = this.shadowRoot!.querySelector<LitTable>('#tb-thread-small'); 96 this.chartTotal = this.shadowRoot!.querySelector<LitChartColumn>('#chart_total'); 97 this.chart2 = this.shadowRoot!.querySelector<LitChartColumn>('#chart_2'); 98 this.chart3 = this.shadowRoot!.querySelector<LitChartColumn>('#chart_3'); 99 this.chart4 = this.shadowRoot!.querySelector<LitChartColumn>('#chart_4'); 100 this.map = new Map<string, { chart: LitChartColumn; table: LitTable }>(); 101 this.map.set('total', { chart: this.chartTotal!, table: this.table! }); 102 this.map.set('small', { chart: this.chart2!, table: this.tableSmall! }); 103 this.map.set('mid', { chart: this.chart3!, table: this.tableMid! }); 104 this.map.set('big', { chart: this.chart4!, table: this.tableBig! }); 105 this.setting = this.shadowRoot!.querySelector<HTMLDivElement>('#setting'); 106 this.cpuSetting = this.shadowRoot!.querySelector<CheckCpuSetting>('#cpu_setting'); 107 this.cpuSetting!.cpuSetListener = () => { 108 this.cpuSetting!.style.display = 'none'; 109 (this.shadowRoot!.querySelector('#total')! as any).style.display = 'grid'; 110 (this.shadowRoot!.querySelector('#small')! as any).style.display = 111 CheckCpuSetting.small_cores.length > 0 ? 'grid' : 'none'; 112 (this.shadowRoot!.querySelector('#mid')! as any).style.display = 113 CheckCpuSetting.mid_cores.length > 0 ? 'grid' : 'none'; 114 (this.shadowRoot!.querySelector('#big')! as any).style.display = 115 CheckCpuSetting.big_cores.length > 0 ? 'grid' : 'none'; 116 this.queryData(); 117 }; 118 this.setting?.addEventListener('click', (event) => { 119 for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) { 120 (node as any).style.display = 'none'; 121 } 122 this.cpuSetting!.style.display = 'inline'; 123 this.cpuSetting?.init(); 124 }); 125 126 for (let key of this.map!.keys()) { 127 let tab = this.map!.get(key)!.table; 128 let chart = this.map!.get(key)!.chart; 129 tab!.addEventListener('row-click', (evt: any) => { 130 let data = evt.detail.data; 131 data.isSelected = true; 132 // @ts-ignore 133 if ((evt.detail as any).callBack) { 134 // @ts-ignore 135 (evt.detail as any).callBack(true); 136 } 137 }); 138 tab!.addEventListener('column-click', (evt: any) => { 139 this.sort[key].key = evt.detail.key; 140 this.sort[key].sort = evt.detail.sort; 141 if (key == 'total') { 142 this.sortByColumn(evt.detail, tab, this.data); 143 } else if (key == 'small') { 144 this.sortByColumn(evt.detail, tab, this.dataSmall); 145 } else if (key == 'mid') { 146 this.sortByColumn(evt.detail, tab, this.dataMid); 147 } else if (key == 'big') { 148 this.sortByColumn(evt.detail, tab, this.dataBig); 149 } 150 }); 151 tab!.addEventListener('row-hover', (evt: any) => { 152 if (evt.detail.data) { 153 let data = evt.detail.data; 154 data.isHover = true; 155 if ((evt.detail as any).callBack) { 156 (evt.detail as any).callBack(true); 157 } 158 chart.showHoverColumn(data.no); 159 } 160 }); 161 } 162 } 163 164 sortByColumn(detail: any, table: LitTable | null | undefined, data: Array<any>) { 165 // @ts-ignore 166 function compare(threadCpuUsageProperty, sort, type) { 167 return function (a: any, b: any) { 168 if (type === 'number') { 169 // @ts-ignore 170 return sort === 2 171 ? parseFloat(b[threadCpuUsageProperty]) - parseFloat(a[threadCpuUsageProperty]) 172 : parseFloat(a[threadCpuUsageProperty]) - parseFloat(b[threadCpuUsageProperty]); 173 } else { 174 if (sort === 2) { 175 return b[threadCpuUsageProperty].toString().localeCompare(a[threadCpuUsageProperty].toString()); 176 } else { 177 return a[threadCpuUsageProperty].toString().localeCompare(b[threadCpuUsageProperty].toString()); 178 } 179 } 180 }; 181 } 182 let type = 'number'; 183 184 if (detail.key === 'bigTimeStr') { 185 detail.key = 'big'; 186 } else if (detail.key === 'midTimeStr') { 187 detail.key = 'mid'; 188 } else if (detail.key === 'smallTimeStr') { 189 detail.key = 'small'; 190 } else if ( 191 detail.key === 'bigPercent' || 192 detail.key === 'ratio' || 193 detail.key === 'tid' || 194 detail.key === 'pid' || 195 detail.key === 'midPercent' || 196 detail.key.includes('cpu') 197 ) { 198 } else { 199 type = 'string'; 200 } 201 data.sort(compare(detail.key, detail.sort, type)); 202 table!.recycleDataSource = data; 203 } 204 205 init() { 206 if (!this.traceChange) { 207 for (let key of this.map!.keys()) { 208 this.map!.get(key)!.table.reMeauseHeight(); 209 } 210 return; 211 } 212 this.traceChange = false; 213 for (let key of this.map!.keys()) { 214 let table = this.map!.get(key)!.table; 215 table.innerHTML = ''; 216 let columns = this.getTableColumns(key); 217 for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { 218 columns = ` 219 ${columns} 220 <lit-table-column width="120px" title="cpu${i}(us)" data-index="cpu${i}" key="cpu${i}" align="flex-start" order></lit-table-column> 221 `; 222 } 223 table.innerHTML = columns; 224 } 225 226 if (!CheckCpuSetting.init_setting) { 227 for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) { 228 (node as any).style.display = 'none'; 229 } 230 this.cpuSetting!.style.display = 'inline'; 231 this.cpuSetting?.init(); 232 } else { 233 this.queryData(); 234 } 235 } 236 237 clearData() { 238 this.traceChange = true; 239 for (let key of this.map!.keys()) { 240 this.map!.get(key)!.chart.dataSource = []; 241 this.map!.get(key)!.table.recycleDataSource = []; 242 } 243 } 244 245 queryData() { 246 this.progress!.loading = true; 247 this.queryLogicWorker(`scheduling-Thread CpuUsage`, `query Thread Cpu Usage Analysis Time:`, (res) => { 248 this.nodata!.noData = res.keys().length === 0; 249 for (let key of this.map!.keys()) { 250 let obj = this.map!.get(key)!; 251 let source: any[] = res.get(key) || []; 252 source = source.map((it: any, index: number) => { 253 let data: any = { 254 pid: it.pid, 255 pName: it.pName, 256 tid: it.tid, 257 tName: it.tName, 258 total: it.total, 259 big: it.big, 260 mid: it.mid, 261 small: it.small, 262 no: index + 1, 263 visible: 1, 264 bigPercent: it.bigPercent, 265 midPercent: it.midPercent, 266 smallPercent: it.smallPercent, 267 bigTimeStr: it.bigTimeStr, 268 midTimeStr: it.midTimeStr, 269 smallTimeStr: it.smallTimeStr, 270 hideHandler: () => { 271 let arr = source.filter((o) => o.visible === 1); 272 obj.chart.dataSource = this.getArrayDataBySize(key, arr); 273 }, 274 }; 275 for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { 276 data[`cpu${i}`] = (it[`cpu${i}`] || 0) / 1000; 277 } 278 return data; 279 }); 280 obj.chart.config = { 281 data: this.getArrayDataBySize(key, source), 282 appendPadding: 10, 283 xField: 'tid', 284 yField: 'total', 285 seriesField: key === 'total' ? 'size' : '', 286 color: (a) => { 287 if (a.size === 'big core') { 288 return '#2f72f8'; 289 } else if (a.size === 'middle core') { 290 return '#ffab67'; 291 } else if (a.size === 'small core') { 292 return '#a285d2'; 293 } else { 294 return '#0a59f7'; 295 } 296 }, 297 hoverHandler: (no) => { 298 let data = source.find((it) => it.no === no); 299 if (data) { 300 data.isHover = true; 301 obj.table!.setCurrentHover(data); 302 } else { 303 obj.table!.mouseOut(); 304 } 305 }, 306 tip: (a) => { 307 if (a && a[0]) { 308 let tip = ''; 309 let total = 0; 310 for (let obj of a) { 311 total += obj.obj.total; 312 tip = `${tip} 313 <div style="display:flex;flex-direction: row;align-items: center;"> 314 <div style="width: 10px;height: 5px;background-color: ${ 315 obj.color 316 };margin-right: 5px"></div> 317 <div>${obj.type || key}:${obj.obj.timeStr}</div> 318 </div> 319 `; 320 } 321 tip = `<div> 322 <div>tid:${a[0].obj.tid}</div> 323 ${tip} 324 ${a.length > 1 ? `<div>total:${getProbablyTime(total)}</div>` : ''} 325 </div>`; 326 return tip; 327 } else { 328 return ''; 329 } 330 }, 331 label: null, 332 }; 333 if (key == 'total') { 334 this.data = source; 335 } else if (key == 'small') { 336 this.dataSmall = source; 337 } else if (key == 'mid') { 338 this.dataMid = source; 339 } else if (key == 'big') { 340 this.dataBig = source; 341 } 342 if (this.sort[key].key != '') { 343 this.sortByColumn(this.sort[key], obj.table, source); 344 } else { 345 obj.table.recycleDataSource = source; 346 } 347 } 348 this.progress!.loading = false; 349 }); 350 } 351 352 getArrayDataBySize(type: string, arr: Array<any>) { 353 let data: any[] = []; 354 for (let obj of arr) { 355 if (type === 'total') { 356 data.push({ 357 pid: obj.pid, 358 pName: obj.pName, 359 tid: obj.tid, 360 tName: obj.tName, 361 total: obj.big, 362 size: 'big core', 363 no: obj.no, 364 timeStr: obj.bigTimeStr, 365 }); 366 data.push({ 367 pid: obj.pid, 368 pName: obj.pName, 369 tid: obj.tid, 370 tName: obj.tName, 371 total: obj.mid, 372 size: 'middle core', 373 no: obj.no, 374 timeStr: obj.midTimeStr, 375 }); 376 data.push({ 377 pid: obj.pid, 378 pName: obj.pName, 379 tid: obj.tid, 380 tName: obj.tName, 381 total: obj.small, 382 size: 'small core', 383 no: obj.no, 384 timeStr: obj.smallTimeStr, 385 }); 386 } else { 387 data.push({ 388 pid: obj.pid, 389 pName: obj.pName, 390 tid: obj.tid, 391 tName: obj.tName, 392 total: obj[type], 393 no: obj.no, 394 timeStr: obj[`${type}TimeStr`], 395 }); 396 } 397 } 398 return data; 399 } 400 401 queryLogicWorker(option: string, log: string, handler: (res: any) => void) { 402 let time = new Date().getTime(); 403 procedurePool.submitWithName( 404 'logic1', 405 option, 406 { 407 bigCores: CheckCpuSetting.big_cores, 408 midCores: CheckCpuSetting.mid_cores, 409 smallCores: CheckCpuSetting.small_cores, 410 }, 411 undefined, 412 handler 413 ); 414 let durTime = new Date().getTime() - time; 415 info(log, durTime); 416 } 417 418 getTableColumns(type: string) { 419 if (type === 'total') { 420 return `${this.publicColumns}${this.bigColumn}${this.midColumn}${this.smallColumn}`; 421 } else if (type === 'big') { 422 return `${this.publicColumns}${this.bigColumn}`; 423 } else if (type === 'mid') { 424 return `${this.publicColumns}${this.midColumn}`; 425 } else if (type === 'small') { 426 return `${this.publicColumns}${this.smallColumn}`; 427 } else { 428 return ''; 429 } 430 } 431 432 initHtml(): string { 433 return ` 434 <style> 435 .content_grid{ 436 display: grid; 437 padding: 15px; 438 grid-column-gap: 15px; 439 grid-row-gap: 15px; 440 grid-template-columns: 1fr 1fr; 441 background-color: var(--dark-background5,#F6F6F6); 442 } 443 .chart_div{ 444 display: flex; 445 flex-direction: column; 446 background-color: var(--dark-background,#FFFFFF); 447 align-items: center; 448 height: 370px; 449 padding-left: 5px; 450 padding-right: 5px; 451 border-radius: 5px 452 } 453 :host { 454 width: 100%; 455 height: 100%; 456 background: var(--dark-background5,#F6F6F6); 457 } 458 .tb_cpu_usage{ 459 overflow: auto; 460 background-color: var(--dark-background,#FFFFFF); 461 border-radius: 5px; 462 border: solid 1px var(--dark-border1,#e0e0e0); 463 display: flex; 464 } 465 .root{ 466 overflow-y: auto;height: 80vh;background-color: var(--dark-background5,#F6F6F6) 467 } 468 .bg{ 469 background-color: var(--dark-background5,#F6F6F6); 470 padding-left: 10px; 471 } 472 .labels{ 473 display: flex; 474 flex-direction: row; 475 align-items: center; 476 justify-content: center; 477 font-size: 9pt; 478 padding-right: 15px; 479 } 480 481 </style> 482 483 <lit-progress-bar id="loading" style="height: 1px;width: 100%"></lit-progress-bar> 484 <table-no-data id="nodata" contentHeight="500px"> 485 <div class="root"> 486 <div class="bg" style="display: flex;flex-direction: row;"> 487 <div id="setting" style="height: 45px;display: flex;flex-direction: row;align-items: center;cursor: pointer"> 488 CPU Setting 489 <span style="width: 10px"></span> 490 <lit-icon name="setting" size="20"></lit-icon> 491 </div> 492 </div> 493 <check-cpu-setting id="cpu_setting" style="display: none"></check-cpu-setting> 494 <div class="content_grid" id="total"> 495 <div class="chart_div"> 496 <div style="line-height: 40px;height: 40px;width: 100%;text-align: center;">Top20线程大中小核占用率</div> 497 <lit-chart-column id="chart_total" style="width:100%;height:300px"></lit-chart-column> 498 <div style="height: 30px;width: 100%;display: flex;flex-direction: row;align-items: center;justify-content: center"> 499 <div class="labels"><div style="width: 20px;height: 10px;background-color: #2f72f8;margin-right: 5px"></div>big</div> 500 <div class="labels"><div style="width: 20px;height: 10px;background-color: #ffab67;margin-right: 5px"></div>mid</div> 501 <div class="labels"><div style="width: 20px;height: 10px;background-color: #a285d2;margin-right: 5px"></div>small</div> 502 </div> 503 </div> 504 <div class="tb_cpu_usage" > 505 <lit-table id="tb-thread-usage" hideDownload style="height: 360px;margin: 5px 15px"></lit-table> 506 </div> 507 </div> 508 <div class="content_grid" id="small"> 509 <div class="chart_div"> 510 <div style="line-height: 40px;height: 40px;width: 100%;text-align: center;">Top20线程小核占用率</div> 511 <lit-chart-column id="chart_2" style="width:100%;height:300px"></lit-chart-column> 512 <div style="height: 30px;width: 100%;display: flex;flex-direction: row;align-items: center;justify-content: center"> 513 <div class="labels"><div style="width: 20px;height: 10px;background-color: #0a59f7;margin-right: 5px"></div>small</div> 514 </div> 515 </div> 516 <div class="tb_cpu_usage"> 517 <lit-table id="tb-thread-small" hideDownload style="height: 360px;margin: 5px 15px "></lit-table> 518 </div> 519 </div> 520 <div class="content_grid" id="mid"> 521 <div class="chart_div"> 522 <div style="line-height: 40px;height: 40px;width: 100%;text-align: center;">Top20线程中核占用率</div> 523 <lit-chart-column id="chart_3" style="width:100%;height:300px"></lit-chart-column> 524 <div style="height: 30px;width: 100%;display: flex;flex-direction: row;align-items: center;justify-content: center"> 525 <div class="labels"><div style="width: 20px;height: 10px;background-color: #0a59f7;margin-right: 5px"></div>mid</div> 526 </div> 527 </div> 528 <div class="tb_cpu_usage"> 529 <lit-table id="tb-thread-mid" hideDownload style="height: 360px;margin: 5px 15px"></lit-table> 530 </div> 531 </div> 532 <div class="content_grid" id="big"> 533 <div class="chart_div"> 534 <div style="line-height: 40px;height: 40px;width: 100%;text-align: center;">Top20线程大核占用率</div> 535 <lit-chart-column id="chart_4" style="width:100%;height:300px"></lit-chart-column> 536 <div style="height: 30px;width: 100%;display: flex;flex-direction: row;align-items: center;justify-content: center"> 537 <div class="labels"><div style="width: 20px;height: 10px;background-color: #0a59f7;margin-right: 5px"></div>big</div> 538 </div> 539 </div> 540 <div class="tb_cpu_usage"> 541 <lit-table id="tb-thread-big" hideDownload style="height: 360px;margin: 5px 15px"></lit-table> 542 </div> 543 </div> 544 </div> 545 </table-no-data> 546 547 `; 548 } 549} 550