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 { LitChartColumn } from '../../../../base-ui/chart/column/LitChartColumn'; 25import '../../../../base-ui/chart/column/LitChartColumn'; 26import { Utils } from '../../trace/base/Utils'; 27 28@element('top10-longest-runtime-process') 29export class Top10LongestRunTimeProcess extends BaseElement { 30 traceChange: boolean = false; 31 private processRunTimeTbl: LitTable | null | undefined; 32 private threadRunTimeTbl: LitTable | null | undefined; 33 private processRunTimeProgress: LitProgressBar | null | undefined; 34 private nodataPro: TableNoData | null | undefined; 35 private processRunTimeData: Array<Top10RunTimeData> = []; 36 private threadRunTimeData: Array<Top10RunTimeData> = []; 37 private processSwitchCountChart: LitChartColumn | null | undefined; 38 private threadSwitchCountChart: LitChartColumn | null | undefined; 39 private nodataThr: TableNoData | null | undefined; 40 private display_pro: HTMLDivElement | null | undefined; 41 private display_thr: HTMLDivElement | 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.processRunTimeTbl!.recycleDataSource.length > 0) { 54 this.processRunTimeTbl?.reMeauseHeight(); 55 } 56 return; 57 } 58 this.traceChange = false; 59 this.processRunTimeProgress!.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 Top10RunTime', 67 'query Process Top10 Run Time Analysis Time:', 68 this.callBack.bind(this) 69 ); 70 } 71 72 /** 73 * 清除已存储数据 74 */ 75 clearData(): void { 76 this.traceChange = true; 77 this.processSwitchCountChart!.dataSource = []; 78 this.processRunTimeTbl!.recycleDataSource = []; 79 this.threadSwitchCountChart!.dataSource = []; 80 this.threadRunTimeTbl!.recycleDataSource = []; 81 this.processRunTimeData = []; 82 this.threadRunTimeData = []; 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<Top10RunTimeData>) => 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 * 提交worker线程,进行数据库查询 103 * @param option 操作的key值,用于找到并执行对应方法 104 * @param log 日志打印内容 105 * @param handler 结果回调函数 106 * @param pid 需要查询某一进程下线程数据的进程id 107 */ 108 organizationData(arr: Array<Top10RunTimeData>): Array<Top10RunTimeData> { 109 let result: Array<Top10RunTimeData> = []; 110 for (let i = 0; i < arr.length; i++) { 111 const pStr: string | null = this.processMap.get(arr[i].pid!)!; 112 const tStr: string | null = this.threadMap.get(arr[i].tid!)!; 113 result.push({ 114 no: i + 1, 115 pid: arr[i].pid || this.processId, 116 pName: pStr === null ? 'Process ' : pStr, 117 dur: arr[i].dur, 118 tid: arr[i].tid, 119 tName: tStr === null ? 'Thread ' : tStr 120 }); 121 } 122 return result; 123 } 124 125 /** 126 * 提交线程后,结果返回后的回调函数 127 * @param res 数据库查询结果 128 */ 129 callBack(res: Array<Top10RunTimeData>): void { 130 let result: Array<Top10RunTimeData> = this.organizationData(res); 131 if (this.display_flag === true) { 132 this.processCallback(result); 133 } else { 134 this.threadCallback(result); 135 } 136 this.processRunTimeProgress!.loading = false; 137 } 138 139 /** 140 * 大函数块拆解分为两部分,此部分为Top10进程数据 141 * @param result 需要显示在表格中的数据 142 */ 143 processCallback(result: Array<Top10RunTimeData>): void { 144 this.nodataPro!.noData = result === undefined || result.length === 0; 145 this.processRunTimeTbl!.recycleDataSource = result; 146 this.processRunTimeTbl!.reMeauseHeight(); 147 this.processRunTimeData = result; 148 this.processSwitchCountChart!.config = { 149 data: result, 150 appendPadding: 10, 151 xField: 'pid', 152 yField: 'dur', 153 seriesField: 'size', 154 color: (a): string => { 155 return '#0a59f7'; 156 }, 157 hoverHandler: (no): void => { 158 let data: unknown = result.find((it) => it.no === no); 159 if (data) { 160 // @ts-ignore 161 data.isHover = true; 162 this.processRunTimeTbl!.setCurrentHover(data); 163 } else { 164 this.processRunTimeTbl!.mouseOut(); 165 } 166 }, 167 tip: (obj): string => { 168 return ` 169 <div> 170 <div>Process_Id:${ 171 // @ts-ignore 172 obj[0].obj.pid}</div> 173 <div>Process_Name:${ 174 // @ts-ignore 175 obj[0].obj.pName}</div> 176 <div>Run_Time:${ 177 // @ts-ignore 178 obj[0].obj.dur}</div> 179 </div> 180 `; 181 }, 182 label: null, 183 }; 184 } 185 186 /** 187 * 大函数块拆解分为两部分,此部分为Top10线程数据 188 * @param result 需要显示在表格中的数据 189 */ 190 threadCallback(result: Array<Top10RunTimeData>): void { 191 this.nodataThr!.noData = result === undefined || result.length === 0; 192 this.threadRunTimeTbl!.recycleDataSource = result; 193 this.threadRunTimeTbl!.reMeauseHeight(); 194 this.threadRunTimeData = result; 195 this.threadSwitchCountChart!.config = { 196 data: result, 197 appendPadding: 10, 198 xField: 'tid', 199 yField: 'dur', 200 seriesField: 'size', 201 color: (a): string => { 202 return '#0a59f7'; 203 }, 204 hoverHandler: (no): void => { 205 let data: unknown = result.find((it) => it.no === no); 206 if (data) { 207 // @ts-ignore 208 data.isHover = true; 209 this.threadRunTimeTbl!.setCurrentHover(data); 210 } else { 211 this.threadRunTimeTbl!.mouseOut(); 212 } 213 }, 214 tip: (obj): string => { 215 return ` 216 <div> 217 <div>Process_Id:${ 218 // @ts-ignore 219 obj[0].obj.pid}</div> 220 <div>Thread_Id:${ 221 // @ts-ignore 222 obj[0].obj.tid}</div> 223 <div>Thread_Name:${ 224 // @ts-ignore 225 obj[0].obj.tName}</div> 226 <div>Run_Time:${ 227 // @ts-ignore 228 obj[0].obj.dur}</div> 229 </div> 230 `; 231 }, 232 label: null, 233 }; 234 } 235 236 /** 237 * 元素初始化,将html节点与内部变量进行绑定 238 */ 239 initElements(): void { 240 this.processRunTimeProgress = this.shadowRoot!.querySelector<LitProgressBar>('#loading'); 241 this.nodataPro = this.shadowRoot!.querySelector<TableNoData>('#nodata_Pro'); 242 this.processRunTimeTbl = this.shadowRoot!.querySelector<LitTable>('#tb-process-run-time'); 243 this.processSwitchCountChart = this.shadowRoot!.querySelector<LitChartColumn>('#chart_pro'); 244 this.nodataThr = this.shadowRoot!.querySelector<TableNoData>('#nodata_Thr'); 245 this.threadRunTimeTbl = this.shadowRoot!.querySelector<LitTable>('#tb-thread-run-time'); 246 this.threadSwitchCountChart = this.shadowRoot!.querySelector<LitChartColumn>('#chart_thr'); 247 this.display_pro = this.shadowRoot!.querySelector<HTMLDivElement>('#display_pro'); 248 this.display_thr = this.shadowRoot!.querySelector<HTMLDivElement>('#display_thr'); 249 this.back = this.shadowRoot!.querySelector<HTMLDivElement>('#back'); 250 this.clickEventListener(); 251 this.hoverEventListener(); 252 } 253 254 /** 255 * 点击监听事件函数块 256 */ 257 clickEventListener(): void { 258 // @ts-ignore 259 this.processRunTimeTbl!.addEventListener('row-click', (evt: CustomEvent) => { 260 this.display_flag = false; 261 let data = evt.detail.data; 262 this.processId = data.pid; 263 this.display_thr!.style.display = 'block'; 264 this.display_pro!.style.display = 'none'; 265 this.queryLogicWorker( 266 'scheduling-Process Top10RunTime', 267 'query Thread Top10 Run Time Analysis Time:', 268 this.callBack.bind(this), 269 data.pid 270 ); 271 }); 272 this.processRunTimeTbl!.addEventListener('column-click', (evt) => { 273 // @ts-ignore 274 this.sortByColumn(evt.detail, this.processRunTimeData); 275 this.processRunTimeTbl!.recycleDataSource = this.processRunTimeData; 276 }); 277 this.threadRunTimeTbl!.addEventListener('column-click', (evt) => { 278 // @ts-ignore 279 this.sortByColumn(evt.detail, this.threadRunTimeData); 280 this.threadRunTimeTbl!.recycleDataSource = this.threadRunTimeData; 281 }); 282 this.processRunTimeTbl!.addEventListener('contextmenu', (ev) => { 283 ev.preventDefault(); 284 }); 285 this.threadRunTimeTbl!.addEventListener('contextmenu', (ev) => { 286 ev.preventDefault(); 287 }); 288 this.back?.addEventListener('click', (event) => { 289 this.display_flag = true; 290 this.display_pro!.style.display = 'block'; 291 this.display_thr!.style.display = 'none'; 292 }); 293 } 294 295 /** 296 * 移入事件监听函数块 297 */ 298 hoverEventListener(): void { 299 // @ts-ignore 300 this.processRunTimeTbl!.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 this.processSwitchCountChart?.showHoverColumn(data.no); 308 } 309 }); 310 // @ts-ignore 311 this.threadRunTimeTbl!.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 this.threadSwitchCountChart?.showHoverColumn(data.no); 319 } 320 }); 321 } 322 323 /** 324 * 表格数据排序 325 * @param detail 点击的列名,以及排序状态0 1 2分别代表不排序、升序排序、降序排序 326 * @param data 表格中需要排序的数据 327 */ 328 sortByColumn(detail: unknown, data: Array<Top10RunTimeData>): void { 329 // @ts-ignore 330 function compare(processThreadCountProperty, sort, type) { 331 return function (a: unknown, b: unknown) { 332 if (type === 'number') { 333 // @ts-ignore 334 return sort === 2 335 // @ts-ignore 336 ? parseFloat(b[processThreadCountProperty]) - 337 // @ts-ignore 338 parseFloat(a[processThreadCountProperty]) 339 // @ts-ignore 340 : parseFloat(a[processThreadCountProperty]) - 341 // @ts-ignore 342 parseFloat(b[processThreadCountProperty]); 343 } else { 344 if (sort === 2) { 345 // @ts-ignore 346 return b[processThreadCountProperty] 347 .toString() 348 // @ts-ignore 349 .localeCompare(a[processThreadCountProperty].toString()); 350 } else { 351 // @ts-ignore 352 return a[processThreadCountProperty] 353 .toString() 354 // @ts-ignore 355 .localeCompare(b[processThreadCountProperty].toString()); 356 } 357 } 358 }; 359 } 360 // @ts-ignore 361 if (detail.key === 'pName' || detail.key === 'tName') { 362 data.sort( 363 // @ts-ignore 364 compare(detail.key, detail.sort, 'string') 365 ); 366 } else { 367 data.sort( 368 // @ts-ignore 369 compare(detail.key, detail.sort, 'number') 370 ); 371 } 372 } 373 374 /** 375 * 用于将元素节点挂载,大函数块拆分为样式、节点 376 * @returns 返回字符串形式的元素节点 377 */ 378 initHtml(): string { 379 return this.initStyleHtml() + this.initTagHtml(); 380 } 381 382 /** 383 * 样式html代码块 384 * @returns 返回样式代码块字符串 385 */ 386 initStyleHtml(): string { 387 return ` 388 <style> 389 .content_grid{ 390 display: grid; 391 padding: 15px; 392 grid-column-gap: 15px; 393 grid-row-gap: 15px; 394 grid-template-columns: 1fr 1fr; 395 background-color: var(--dark-background,#FFFFFF); 396 } 397 .chart_div{ 398 display: flex; 399 flex-direction: column; 400 background-color: var(--dark-background,#FFFFFF); 401 align-items: center; 402 height: 370px; 403 padding-left: 5px; 404 padding-right: 5px; 405 border-radius: 5px 406 } 407 :host { 408 width: 100%; 409 height: 100%; 410 background: var(--dark-background5,#F6F6F6); 411 } 412 .tb_run_time{ 413 overflow: auto; 414 background-color: var(--dark-background,#FFFFFF); 415 border-radius: 5px; 416 border: solid 1px var(--dark-border1,#e0e0e0); 417 display: flex; 418 } 419 .bg{ 420 background-color: var(--dark-background,#FFFFFF); 421 padding-left: 10px; 422 } 423 .labels{ 424 display: flex; 425 flex-direction: row; 426 align-items: center; 427 justify-content: center; 428 font-size: 9pt; 429 padding-right: 15px; 430 } 431 </style> 432 `; 433 } 434 435 /** 436 * 节点html代码块 437 * @returns 返回节点代码块字符串 438 */ 439 initTagHtml(): string { 440 return ` 441 <lit-progress-bar id="loading" style="height: 1px;width: 100%"></lit-progress-bar> 442 <div id='display_pro'> 443 <table-no-data id="nodata_Pro" contentHeight="500px"> 444 <div class="root"> 445 <div style="width:100%;height: 45px;"></div> 446 <div class="content_grid" id="total"> 447 <div class="chart_div"> 448 <div style="line-height: 40px;height: 40px;width: 100%;text-align: center;">Top10运行超长进程</div> 449 <lit-chart-column id="chart_pro" style="width:100%;height:300px"></lit-chart-column> 450 </div> 451 <div class="tb_run_time" > 452 <lit-table id='tb-process-run-time' hideDownload style='height: auto'> 453 <lit-table-column width='1fr' title='NO' data-index='no' key='no' align='flex-start' order></lit-table-column> 454 <lit-table-column width='1fr' title='Process_Id' data-index='pid' key='pid' align='flex-start' order></lit-table-column> 455 <lit-table-column width='1fr' title='Process_Name' data-index='pName' key='pName' align='flex-start' order></lit-table-column> 456 <lit-table-column width='1fr' title='Run_Time(ns)' data-index='dur' key='dur' align='flex-start' order></lit-table-column> 457 </lit-table> 458 </div> 459 </div> 460 </div> 461 </table-no-data> 462 </div> 463 <div id='display_thr' style='display: none'> 464 <table-no-data id="nodata_Thr" contentHeight="500px"> 465 <div class="root"> 466 <div class="bg" style="display: flex;flex-direction: row;"> 467 <div id="back" style="height: 45px;display: flex;flex-direction: row;align-items: center;cursor: pointer" title="Back Previous Level"> 468 <span style="width: 10px"></span>Previous Level<span style="width: 10px"></span><lit-icon name="vertical-align-top" size="20"></lit-icon> 469 </div> 470 </div> 471 <div class="content_grid" id="total"> 472 <div class="chart_div"> 473 <div style="line-height: 40px;height: 40px;width: 100%;text-align: center;">Top10运行超长线程</div> 474 <lit-chart-column id="chart_thr" style="width:100%;height:300px"></lit-chart-column> 475 </div> 476 <div class="tb_run_time" > 477 <lit-table id='tb-thread-run-time' hideDownload style='height: auto'> 478 <lit-table-column width='1fr' title='NO' data-index='no' key='no' align='flex-start' order></lit-table-column> 479 <lit-table-column width='1fr' title='Process_Id' data-index='pid' key='pid' align='flex-start' order></lit-table-column> 480 <lit-table-column width='1fr' title='Thread_Id' data-index='tid' key='tid' align='flex-start' order></lit-table-column> 481 <lit-table-column width='1fr' title='Thread_Name' data-index='tName' key='tName' align='flex-start' order></lit-table-column> 482 <lit-table-column width='1fr' title='Run_Time(ns)' data-index='dur' key='dur' align='flex-start' order></lit-table-column> 483 </lit-table> 484 </div> 485 </div> 486 </div> 487 </table-no-data> 488 </div> 489 `; 490 } 491} 492 493interface Top10RunTimeData { 494 no?: number, 495 pid?: number, 496 tid?: number, 497 pName?: string, 498 tName?: string, 499 switchCount?: number, 500 dur?: number 501}