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 { procedurePool } from '../../../database/Procedure'; 19import { info } from '../../../../log/Log'; 20import { TableNoData } from '../TableNoData'; 21import '../TableNoData'; 22import { LitProgressBar } from '../../../../base-ui/progress-bar/LitProgressBar'; 23import '../../../../base-ui/progress-bar/LitProgressBar'; 24import { LitChartPie } from '../../../../base-ui/chart/pie/LitChartPie'; 25import '../../../../base-ui/chart/pie/LitChartPie'; 26import { Utils } from '../../trace/base/Utils'; 27 28@element('top10-process-switch-count') 29export class Top10ProcessSwitchCount extends BaseElement { 30 traceChange: boolean = false; 31 private processSwitchCountTbl: LitTable | null | undefined; 32 private threadSwitchCountTbl: LitTable | null | undefined; 33 private nodataPro: TableNoData | null | undefined; 34 private nodataThr: TableNoData | null | undefined; 35 private processSwitchCountData: Array<Top10ProcSwiCount> = []; 36 private threadSwitchCountData: Array<Top10ProcSwiCount> = []; 37 private threadSwitchCountPie: LitChartPie | null | undefined; 38 private processSwitchCountPie: LitChartPie | null | undefined; 39 private display_pro: HTMLDivElement | null | undefined; 40 private display_thr: HTMLDivElement | null | undefined; 41 private processSwitchCountProgress: LitProgressBar | null | undefined; 42 private processId: number | undefined; 43 private display_flag: boolean = true; 44 private back: HTMLDivElement | null | undefined; 45 private processMap: Map<number, string> = new Map(); 46 private threadMap: Map<number, string> = new Map(); 47 48 /** 49 * 初始化操作,若trace发生改变,将所有变量设置为默认值并重新请求数据。若trace未改变,跳出初始化 50 */ 51 init(): void { 52 if (!this.traceChange) { 53 if (this.processSwitchCountTbl!.recycleDataSource.length > 0) { 54 this.processSwitchCountTbl?.reMeauseHeight(); 55 } 56 return; 57 } 58 this.traceChange = false; 59 this.processSwitchCountProgress!.loading = true; 60 this.display_flag = true; 61 this.display_pro!.style.display = 'block'; 62 this.display_thr!.style.display = 'none'; 63 this.processMap = Utils.getInstance().getProcessMap(); 64 this.threadMap = Utils.getInstance().getThreadMap(); 65 this.queryLogicWorker( 66 'scheduling-Process Top10Swicount', 67 'query Process Top10 Switch Count Analysis Time:', 68 this.callBack.bind(this) 69 ); 70 } 71 72 /** 73 * 清除已存储数据 74 */ 75 clearData(): void { 76 this.traceChange = true; 77 this.processSwitchCountPie!.dataSource = []; 78 this.processSwitchCountTbl!.recycleDataSource = []; 79 this.threadSwitchCountPie!.dataSource = []; 80 this.threadSwitchCountTbl!.recycleDataSource = []; 81 this.processSwitchCountData = []; 82 this.threadSwitchCountData = []; 83 this.processMap = new Map(); 84 this.threadMap = new Map(); 85 } 86 87 /** 88 * 提交worker线程,进行数据库查询 89 * @param option 操作的key值,用于找到并执行对应方法 90 * @param log 日志打印内容 91 * @param handler 结果回调函数 92 * @param pid 需要查询某一进程下线程数据的进程id 93 */ 94 queryLogicWorker(option: string, log: string, handler: (res: Array<Top10ProcSwiCount>) => void, pid?: number): void { 95 let processThreadCountTime = new Date().getTime(); 96 procedurePool.submitWithName('logic0', option, { pid: pid }, undefined, handler); 97 let durTime = new Date().getTime() - processThreadCountTime; 98 info(log, durTime); 99 } 100 101 /** 102 * 抽取公共方法,提取数据,用于展示到表格中 103 * @param arr 数据库查询结果 104 * @returns 整理好的数据,包含进程名,线程名等相关信息 105 */ 106 organizationData(arr: Array<Top10ProcSwiCount>): Array<Top10ProcSwiCount> { 107 let result: Array<Top10ProcSwiCount> = []; 108 for (let i = 0; i < arr.length; i++) { 109 const pStr: string | null = this.processMap.get(arr[i].pid!)!; 110 const tStr: string | null = this.threadMap.get(arr[i].tid!)!; 111 result.push({ 112 NO: i + 1, 113 pid: arr[i].pid || this.processId, 114 pName: pStr === null ? 'Process ' : pStr, 115 switchCount: arr[i].occurrences, 116 tid: arr[i].tid, 117 tName: tStr === null ? 'Thread ' : tStr 118 }); 119 } 120 return result; 121 } 122 123 /** 124 * 提交线程后,结果返回后的回调函数 125 * @param res 数据库查询结果 126 */ 127 callBack(res: Array<Top10ProcSwiCount>): void { 128 let result: Array<Top10ProcSwiCount> = this.organizationData(res); 129 // 判断当前显示的是进程组还是线程组 130 if (this.display_flag === true) { 131 this.processCallback(result); 132 } else { 133 this.threadCallback(result); 134 } 135 this.processSwitchCountProgress!.loading = false; 136 } 137 138 /** 139 * 大函数块拆解分为两部分,此部分为Top10进程数据 140 * @param result 需要显示在表格中的数据 141 */ 142 processCallback(result: Array<Top10ProcSwiCount>): void { 143 this.nodataPro!.noData = result === undefined || result.length === 0; 144 this.processSwitchCountData = result; 145 this.processSwitchCountPie!.config = { 146 appendPadding: 10, 147 data: result, 148 angleField: 'switchCount', 149 colorField: 'pid', 150 radius: 0.8, 151 label: { 152 type: 'outer', 153 }, 154 hoverHandler: (data): void => { 155 if (data) { 156 this.processSwitchCountTbl!.setCurrentHover(data); 157 } else { 158 this.processSwitchCountTbl!.mouseOut(); 159 } 160 }, 161 tip: (obj): string => { 162 return ` 163 <div> 164 <div>Process_Id:${ 165 // @ts-ignore 166 obj.obj.pid}</div> 167 <div>Process_Name:${ 168 // @ts-ignore 169 obj.obj.pName}</div> 170 <div>Switch Count:${ 171 // @ts-ignore 172 obj.obj.switchCount}</div> 173 </div> 174 `; 175 }, 176 interactions: [ 177 { 178 type: 'element-active', 179 }, 180 ], 181 }; 182 this.processSwitchCountTbl!.recycleDataSource = result; 183 this.processSwitchCountTbl!.reMeauseHeight(); 184 } 185 186 /** 187 * 大函数块拆解分为两部分,此部分为Top10线程数据 188 * @param result 需要显示在表格中的数据 189 */ 190 threadCallback(result: Array<Top10ProcSwiCount>): void { 191 this.nodataThr!.noData = result === undefined || result.length === 0; 192 this.threadSwitchCountTbl!.recycleDataSource = result; 193 this.threadSwitchCountTbl!.reMeauseHeight(); 194 this.threadSwitchCountData = result; 195 this.threadSwitchCountPie!.config = { 196 appendPadding: 10, 197 data: result, 198 angleField: 'switchCount', 199 colorField: 'tid', 200 radius: 0.8, 201 label: { 202 type: 'outer', 203 }, 204 hoverHandler: (data): void => { 205 if (data) { 206 this.threadSwitchCountTbl!.setCurrentHover(data); 207 } else { 208 this.threadSwitchCountTbl!.mouseOut(); 209 } 210 }, 211 tip: (obj): string => { 212 return ` 213 <div> 214 <div>Thread_Id:${ 215 // @ts-ignore 216 obj.obj.tid}</div> 217 <div>Thread_Name:${ 218 // @ts-ignore 219 obj.obj.tName}</div> 220 <div>Switch Count:${ 221 // @ts-ignore 222 obj.obj.switchCount}</div> 223 <div>Process_Id:${ 224 // @ts-ignore 225 obj.obj.pid}</div> 226 </div> 227 `; 228 }, 229 interactions: [ 230 { 231 type: 'element-active', 232 }, 233 ], 234 }; 235 } 236 237 /** 238 * 元素初始化,将html节点与内部变量进行绑定 239 */ 240 initElements(): void { 241 this.processSwitchCountProgress = this.shadowRoot!.querySelector<LitProgressBar>('#loading'); 242 this.processSwitchCountTbl = this.shadowRoot!.querySelector<LitTable>('#tb-process-switch-count'); 243 this.threadSwitchCountTbl = this.shadowRoot!.querySelector<LitTable>('#tb-thread-switch-count'); 244 this.processSwitchCountPie = this.shadowRoot!.querySelector<LitChartPie>('#pie_pro'); 245 this.threadSwitchCountPie = this.shadowRoot!.querySelector<LitChartPie>('#pie_thr'); 246 this.nodataPro = this.shadowRoot!.querySelector<TableNoData>('#nodata_pro'); 247 this.nodataThr = this.shadowRoot!.querySelector<TableNoData>('#nodata_thr'); 248 this.display_pro = this.shadowRoot!.querySelector<HTMLDivElement>('#display_pro'); 249 this.display_thr = this.shadowRoot!.querySelector<HTMLDivElement>('#display_thr'); 250 this.back = this.shadowRoot!.querySelector<HTMLDivElement>('#back'); 251 this.clickEventListener(); 252 this.hoverEventListener(); 253 this.addEventListener('contextmenu', (event) => { 254 event.preventDefault(); // 阻止默认的上下文菜单弹框 255 }); 256 } 257 258 /** 259 * 点击监听事件函数块 260 */ 261 clickEventListener(): void { 262 // @ts-ignore 263 this.processSwitchCountTbl!.addEventListener('row-click', (evt: CustomEvent) => { 264 this.display_flag = false; 265 let data = evt.detail.data; 266 this.processId = data.pid; 267 this.display_thr!.style.display = 'block'; 268 this.display_pro!.style.display = 'none'; 269 this.queryLogicWorker( 270 'scheduling-Process Top10Swicount', 271 'query Process Top10 Switch Count Analysis Time:', 272 this.callBack.bind(this), 273 data.pid 274 ); 275 }); 276 this.processSwitchCountTbl!.addEventListener('column-click', (evt) => { 277 // @ts-ignore 278 this.sortByColumn(evt.detail, this.processSwitchCountData); 279 this.processSwitchCountTbl!.recycleDataSource = this.processSwitchCountData; 280 }); 281 this.threadSwitchCountTbl!.addEventListener('column-click', (evt) => { 282 // @ts-ignore 283 this.sortByColumn(evt.detail, this.threadSwitchCountData); 284 this.threadSwitchCountTbl!.recycleDataSource = this.threadSwitchCountData; 285 }); 286 287 this.back!.addEventListener('click', (event) => { 288 this.display_flag = true; 289 this.display_pro!.style.display = 'block'; 290 this.display_thr!.style.display = 'none'; 291 }); 292 293 } 294 295 /** 296 * 移入事件监听函数块 297 */ 298 hoverEventListener(): void { 299 // @ts-ignore 300 this.processSwitchCountTbl!.addEventListener('row-hover', (evt: CustomEvent) => { 301 if (evt.detail.data) { 302 let data = evt.detail.data; 303 data.isHover = true; 304 if (evt.detail.callBack) { 305 evt.detail.callBack(true); 306 } 307 } 308 this.processSwitchCountPie?.showHover(); 309 }); 310 // @ts-ignore 311 this.threadSwitchCountTbl!.addEventListener('row-hover', (evt: CustomEvent) => { 312 if (evt.detail.data) { 313 let data = evt.detail.data; 314 data.isHover = true; 315 if (evt.detail.callBack) { 316 evt.detail.callBack(true); 317 } 318 } 319 this.threadSwitchCountPie?.showHover(); 320 }); 321 this.addEventListener('mouseenter', () => { 322 if (this.processSwitchCountTbl!.recycleDataSource.length > 0) { 323 this.processSwitchCountTbl?.reMeauseHeight(); 324 } 325 }); 326 } 327 328 /** 329 * 表格数据排序 330 * @param detail 点击的列名,以及排序状态0 1 2分别代表不排序、升序排序、降序排序 331 * @param data 表格中需要排序的数据 332 */ 333 sortByColumn(detail: { key: string, sort: number }, data: Array<Top10ProcSwiCount>): void { 334 // @ts-ignore 335 function compare(processThreadCountProperty, sort, type) { 336 return function (a: unknown, b: unknown) { 337 if (type === 'number') { 338 // @ts-ignore 339 return sort === 2 340 // @ts-ignore 341 ? parseFloat(b[processThreadCountProperty]) - 342 // @ts-ignore 343 parseFloat(a[processThreadCountProperty]) 344 // @ts-ignore 345 : parseFloat(a[processThreadCountProperty]) - 346 // @ts-ignore 347 parseFloat(b[processThreadCountProperty]); 348 } else { 349 if (sort === 2) { 350 // @ts-ignore 351 return b[processThreadCountProperty] 352 .toString() 353 // @ts-ignore 354 .localeCompare(a[processThreadCountProperty].toString()); 355 } else { 356 // @ts-ignore 357 return a[processThreadCountProperty] 358 .toString() 359 // @ts-ignore 360 .localeCompare(b[processThreadCountProperty].toString()); 361 } 362 } 363 }; 364 } 365 if (detail.key === 'pName' || detail.key === 'tName') { 366 data.sort( 367 compare(detail.key, detail.sort, 'string') 368 ); 369 } else { 370 data.sort( 371 compare(detail.key, detail.sort, 'number') 372 ); 373 } 374 } 375 376 /** 377 * 用于将元素节点挂载,大函数块拆分为样式、节点 378 * @returns 返回字符串形式的元素节点 379 */ 380 initHtml(): string { 381 return this.initStyleHtml() + this.initTagHtml(); 382 } 383 384 /** 385 * 样式html代码块 386 * @returns 返回样式代码块字符串 387 */ 388 initStyleHtml(): string { 389 return ` 390 <style> 391 :host { 392 width: 100%; 393 height: 100%; 394 background-color: var(--dark-background5,#F6F6F6); 395 } 396 .pie-chart{ 397 display: flex; 398 box-sizing: border-box; 399 width: 500px; 400 height: 500px; 401 } 402 .tb_switch_count{ 403 flex: 1; 404 overflow: auto ; 405 border-radius: 5px; 406 border: solid 1px var(--dark-border1,#e0e0e0); 407 margin: 15px; 408 padding: 5px 15px 409 } 410 .switchcount-root{ 411 width: 100%; 412 height: 100%; 413 box-sizing: border-box; 414 display: flex; 415 flex-direction: row; 416 } 417 .bg{ 418 background-color: var(--dark-background,#FFFFFF); 419 padding-left: 10px; 420 } 421 </style> 422 `; 423 } 424 425 /** 426 * 节点html代码块 427 * @returns 返回节点代码块字符串 428 */ 429 initTagHtml(): string { 430 return ` 431 <lit-progress-bar id='loading' style='height: 1px;width: 100%' loading></lit-progress-bar> 432 <div id='display_pro'> 433 <table-no-data id='nodata_pro' contentHeight='500px'> 434 <div class="root"> 435 <div style="width:100%;height: 45px;"></div> 436 <div class='switchcount-root'> 437 <div style='display: flex;flex-direction: column;align-items: center'> 438 <div>Statistics By Process's Switch Count</div> 439 <lit-chart-pie id='pie_pro' class='pie-chart'></lit-chart-pie> 440 </div> 441 <div class='tb_switch_count'> 442 <lit-table id='tb-process-switch-count' hideDownload style='height: auto'> 443 <lit-table-column width='1fr' title='NO' data-index='NO' key='NO' align='flex-start' order></lit-table-column> 444 <lit-table-column width='1fr' title='Process_Id' data-index='pid' key='pid' align='flex-start' order></lit-table-column> 445 <lit-table-column width='1fr' title='Process_Name' data-index='pName' key='pName' align='flex-start' order></lit-table-column> 446 <lit-table-column width='1fr' title='Switch Count' data-index='switchCount' key='switchCount' align='flex-start' order></lit-table-column> 447 </lit-table> 448 </div> 449 </div> 450 </div> 451 </table-no-data> 452 </div> 453 <div id='display_thr' style='display: none'> 454 <table-no-data id='nodata_thr' contentHeight='500px'> 455 <div class="root"> 456 <div class="bg" style="display: flex;flex-direction: row;"> 457 <div id="back" style="height: 45px;display: flex;flex-direction: row;align-items: center;cursor: pointer" title="Back Previous Level"> 458 <span style="width: 10px"></span>Previous Level<span style="width: 10px"></span><lit-icon name="vertical-align-top" size="20"></lit-icon> 459 </div> 460 </div> 461 <div class='switchcount-root'> 462 <div style='display: flex;flex-direction: column;align-items: center'> 463 <div>Statistics By Thread's Switch Count</div> 464 <lit-chart-pie id='pie_thr' class='pie-chart'></lit-chart-pie> 465 </div> 466 <div class='tb_switch_count'> 467 <lit-table id='tb-thread-switch-count' hideDownload style='height: auto'> 468 <lit-table-column width='1fr' title='NO' data-index='NO' key='NO' align='flex-start' order></lit-table-column> 469 <lit-table-column width='1fr' title='Process_Id' data-index='pid' key='pid' align='flex-start' order></lit-table-column> 470 <lit-table-column width='1fr' title='Thread_Id' data-index='tid' key='tid' align='flex-start' order></lit-table-column> 471 <lit-table-column width='1fr' title='Thread_Name' data-index='tName' key='tName' align='flex-start' order></lit-table-column> 472 <lit-table-column width='1fr' title='Switch Count' data-index='switchCount' key='switchCount' align='flex-start' order></lit-table-column> 473 </lit-table> 474 </div> 475 </div> 476 </div> 477 </table-no-data> 478 </div> 479 `; 480 } 481} 482 483interface Top10ProcSwiCount { 484 NO?: number, 485 pid?: number, 486 tid?: number, 487 pName?: string, 488 tName?: string, 489 switchCount?: number, 490 occurrences?: number 491}