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<any> = []; 50 private dataBig: Array<any> = []; 51 private dataMid: Array<any> = []; 52 private dataSmall: Array<any> = []; 53 private sort: any = { 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 = () => { 109 this.cpuSetting!.style.display = 'none'; 110 (this.shadowRoot!.querySelector('#total')! as any).style.display = 'grid'; 111 (this.shadowRoot!.querySelector('#small')! as any).style.display = 112 CheckCpuSetting.small_cores.length > 0 ? 'grid' : 'none'; 113 (this.shadowRoot!.querySelector('#mid')! as any).style.display = 114 CheckCpuSetting.mid_cores.length > 0 ? 'grid' : 'none'; 115 (this.shadowRoot!.querySelector('#big')! as any).style.display = 116 CheckCpuSetting.big_cores.length > 0 ? 'grid' : 'none'; 117 this.queryData(); 118 }; 119 this.setting?.addEventListener('click', (event) => { 120 for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) { 121 (node as any).style.display = 'none'; 122 } 123 this.cpuSetting!.style.display = 'inline'; 124 this.cpuSetting?.init(); 125 }); 126 this.tabListener(); 127 } 128 129 private tabListener(): void { 130 for (let key of this.map!.keys()) { 131 let tab = this.map!.get(key)!.table; 132 let chart = this.map!.get(key)!.chart; 133 tab!.addEventListener('row-click', (evt: any) => { 134 let data = evt.detail.data; 135 data.isSelected = true; 136 // @ts-ignore 137 if ((evt.detail as any).callBack) { 138 // @ts-ignore 139 (evt.detail as any).callBack(true); 140 } 141 }); 142 tab!.addEventListener('column-click', (evt: any) => { 143 this.sort[key].key = evt.detail.key; 144 this.sort[key].sort = evt.detail.sort; 145 if (key == 'total') { 146 this.sortByColumn(evt.detail, tab, this.data); 147 } else if (key == 'small') { 148 this.sortByColumn(evt.detail, tab, this.dataSmall); 149 } else if (key == 'mid') { 150 this.sortByColumn(evt.detail, tab, this.dataMid); 151 } else if (key == 'big') { 152 this.sortByColumn(evt.detail, tab, this.dataBig); 153 } 154 }); 155 tab!.addEventListener('row-hover', (evt: any) => { 156 if (evt.detail.data) { 157 let data = evt.detail.data; 158 data.isHover = true; 159 if ((evt.detail as any).callBack) { 160 (evt.detail as any).callBack(true); 161 } 162 chart.showHoverColumn(data.no); 163 } 164 }); 165 } 166 } 167 168 sortByColumn(detail: any, table: LitTable | null | undefined, data: Array<any>) { 169 // @ts-ignore 170 function compare(threadCpuUsageProperty, sort, type) { 171 return function (a: any, b: any) { 172 if (type === 'number') { 173 // @ts-ignore 174 return sort === 2 175 ? parseFloat(b[threadCpuUsageProperty]) - parseFloat(a[threadCpuUsageProperty]) 176 : parseFloat(a[threadCpuUsageProperty]) - parseFloat(b[threadCpuUsageProperty]); 177 } else { 178 if (sort === 2) { 179 return b[threadCpuUsageProperty].toString().localeCompare(a[threadCpuUsageProperty].toString()); 180 } else { 181 return a[threadCpuUsageProperty].toString().localeCompare(b[threadCpuUsageProperty].toString()); 182 } 183 } 184 }; 185 } 186 187 let type = 'number'; 188 189 if (detail.key === 'bigTimeStr') { 190 detail.key = 'big'; 191 } else if (detail.key === 'midTimeStr') { 192 detail.key = 'mid'; 193 } else if (detail.key === 'smallTimeStr') { 194 detail.key = 'small'; 195 } else if ( 196 detail.key === 'bigPercent' || 197 detail.key === 'ratio' || 198 detail.key === 'tid' || 199 detail.key === 'pid' || 200 detail.key === 'midPercent' || 201 detail.key.includes('cpu') 202 ) { 203 } else { 204 type = 'string'; 205 } 206 data.sort(compare(detail.key, detail.sort, type)); 207 table!.recycleDataSource = data; 208 } 209 210 init() { 211 if (!this.traceChange) { 212 for (let key of this.map!.keys()) { 213 this.map!.get(key)!.table.reMeauseHeight(); 214 } 215 return; 216 } 217 this.traceChange = false; 218 for (let key of this.map!.keys()) { 219 let table = this.map!.get(key)!.table; 220 table.innerHTML = ''; 221 let columns = this.getTableColumns(key); 222 for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { 223 columns = ` 224 ${columns} 225 <lit-table-column width="120px" title="cpu${i}(us)" data-index="cpu${i}" key="cpu${i}" align="flex-start" order></lit-table-column> 226 `; 227 } 228 table.innerHTML = columns; 229 } 230 231 if (!CheckCpuSetting.init_setting) { 232 for (let node of this.shadowRoot!.querySelectorAll('.content_grid')) { 233 (node as any).style.display = 'none'; 234 } 235 this.cpuSetting!.style.display = 'inline'; 236 this.cpuSetting?.init(); 237 } else { 238 this.queryData(); 239 } 240 } 241 242 clearData() { 243 this.traceChange = true; 244 for (let key of this.map!.keys()) { 245 this.map!.get(key)!.chart.dataSource = []; 246 this.map!.get(key)!.table.recycleDataSource = []; 247 } 248 } 249 250 queryData(): void { 251 this.progress!.loading = true; 252 this.queryLogicWorker(`scheduling-Thread CpuUsage`, `query Thread Cpu Usage Analysis Time:`, (res) => { 253 this.nodata!.noData = res.keys().length === 0; 254 for (let key of this.map!.keys()) { 255 let obj = this.map!.get(key)!; 256 let source: any[] = res.get(key) || []; 257 source = source.map((it: any, index: number) => { 258 let data: any = { 259 pid: it.pid, 260 pName: it.pName, 261 tid: it.tid, 262 tName: it.tName, 263 total: it.total, 264 big: it.big, 265 mid: it.mid, 266 small: it.small, 267 no: index + 1, 268 visible: 1, 269 bigPercent: it.bigPercent, 270 midPercent: it.midPercent, 271 smallPercent: it.smallPercent, 272 bigTimeStr: it.bigTimeStr, 273 midTimeStr: it.midTimeStr, 274 smallTimeStr: it.smallTimeStr, 275 hideHandler: () => { 276 let arr = source.filter((o) => o.visible === 1); 277 obj.chart.dataSource = this.getArrayDataBySize(key, arr); 278 }, 279 }; 280 for (let i = 0; i < SpSchedulingAnalysis.cpuCount; i++) { 281 data[`cpu${i}`] = (it[`cpu${i}`] || 0) / 1000; 282 } 283 return data; 284 }); 285 this.setChartConfig(obj, key, source); 286 this.assignmentData(key, source, obj); 287 } 288 this.progress!.loading = false; 289 }); 290 } 291 292 private assignmentData(key: string, source: any[], obj: { chart: LitChartColumn; table: LitTable }): void { 293 if (key == 'total') { 294 this.data = source; 295 } else if (key == 'small') { 296 this.dataSmall = source; 297 } else if (key == 'mid') { 298 this.dataMid = source; 299 } else if (key == 'big') { 300 this.dataBig = source; 301 } 302 if (this.sort[key].key != '') { 303 this.sortByColumn(this.sort[key], obj.table, source); 304 } else { 305 obj.table.recycleDataSource = source; 306 } 307 } 308 309 private setChartConfig(obj: { chart: LitChartColumn; table: LitTable }, key: string, source: any[]): void { 310 obj.chart.config = { 311 data: this.getArrayDataBySize(key, source), 312 appendPadding: 10, 313 xField: 'tid', 314 yField: 'total', 315 seriesField: key === 'total' ? 'size' : '', 316 color: (a) => { 317 if (a.size === 'big core') { 318 return '#2f72f8'; 319 } else if (a.size === 'middle core') { 320 return '#ffab67'; 321 } else if (a.size === 'small core') { 322 return '#a285d2'; 323 } else { 324 return '#0a59f7'; 325 } 326 }, 327 hoverHandler: (no) => { 328 this.setHover(source, no, obj); 329 }, 330 tip: (a) => { 331 if (a && a[0]) { 332 let tip = ''; 333 let total = 0; 334 for (let obj of a) { 335 total += obj.obj.total; 336 tip = `${tip} 337 <div style="display:flex;flex-direction: row;align-items: center;"> 338 <div style="width: 10px;height: 5px;background-color: ${ 339 obj.color 340 };margin-right: 5px"></div> 341 <div>${obj.type || key}:${obj.obj.timeStr}</div> 342 </div> 343 `; 344 } 345 tip = `<div> 346 <div>tid:${a[0].obj.tid}</div> 347 ${tip} 348 ${a.length > 1 ? `<div>total:${getProbablyTime(total)}</div>` : ''} 349 </div>`; 350 return tip; 351 } else { 352 return ''; 353 } 354 }, 355 label: null, 356 }; 357 } 358 359 private setHover(source: any[], no: number, obj: { chart: LitChartColumn; table: LitTable }): void { 360 let data = source.find((it) => it.no === no); 361 if (data) { 362 data.isHover = true; 363 obj.table!.setCurrentHover(data); 364 } else { 365 obj.table!.mouseOut(); 366 } 367 } 368 369 getArrayDataBySize(type: string, arr: Array<any>) { 370 let data: any[] = []; 371 for (let obj of arr) { 372 if (type === 'total') { 373 data.push({ 374 pid: obj.pid, 375 pName: obj.pName, 376 tid: obj.tid, 377 tName: obj.tName, 378 total: obj.big, 379 size: 'big core', 380 no: obj.no, 381 timeStr: obj.bigTimeStr, 382 }); 383 data.push({ 384 pid: obj.pid, 385 pName: obj.pName, 386 tid: obj.tid, 387 tName: obj.tName, 388 total: obj.mid, 389 size: 'middle core', 390 no: obj.no, 391 timeStr: obj.midTimeStr, 392 }); 393 data.push({ 394 pid: obj.pid, 395 pName: obj.pName, 396 tid: obj.tid, 397 tName: obj.tName, 398 total: obj.small, 399 size: 'small core', 400 no: obj.no, 401 timeStr: obj.smallTimeStr, 402 }); 403 } else { 404 data.push({ 405 pid: obj.pid, 406 pName: obj.pName, 407 tid: obj.tid, 408 tName: obj.tName, 409 total: obj[type], 410 no: obj.no, 411 timeStr: obj[`${type}TimeStr`], 412 }); 413 } 414 } 415 return data; 416 } 417 418 queryLogicWorker(option: string, log: string, handler: (res: any) => void) { 419 let time = new Date().getTime(); 420 procedurePool.submitWithName( 421 'logic0', 422 option, 423 { 424 bigCores: CheckCpuSetting.big_cores, 425 midCores: CheckCpuSetting.mid_cores, 426 smallCores: CheckCpuSetting.small_cores, 427 }, 428 undefined, 429 handler 430 ); 431 let durTime = new Date().getTime() - time; 432 info(log, durTime); 433 } 434 435 getTableColumns(type: string) { 436 if (type === 'total') { 437 return `${this.publicColumns}${this.bigColumn}${this.midColumn}${this.smallColumn}`; 438 } else if (type === 'big') { 439 return `${this.publicColumns}${this.bigColumn}`; 440 } else if (type === 'mid') { 441 return `${this.publicColumns}${this.midColumn}`; 442 } else if (type === 'small') { 443 return `${this.publicColumns}${this.smallColumn}`; 444 } else { 445 return ''; 446 } 447 } 448 449 initHtml(): string { 450 return Top20ThreadCpuUsageHtml; 451 } 452} 453