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