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 '../../../base-ui/chart/pie/LitChartPie'; 21import { LitChartPie } from '../../../base-ui/chart/pie/LitChartPie'; 22import { LitSelect } from '../../../base-ui/select/LitSelect'; 23import { LitSelectOption } from '../../../base-ui/select/LitSelectOption'; 24import '../../../base-ui/progress-bar/LitProgressBar'; 25import { LitProgressBar } from '../../../base-ui/progress-bar/LitProgressBar'; 26import './TableNoData'; 27import { TableNoData } from './TableNoData'; 28import { getProbablyTime } from '../../database/logic-worker/ProcedureLogicWorkerCommon'; 29import {queryThreads} from "../../database/sql/ProcessThread.sql"; 30import { Top20FrequencyThreadHtml } from './Top20FrequencyThread.html'; 31 32@element('top20-frequency-thread') 33export class Top20FrequencyThread extends BaseElement { 34 static threads: { id: number; tid: number; name: string }[] | undefined; 35 traceChange: boolean = false; 36 private frequencyThreadTbl: LitTable | null | undefined; 37 private threadSelect: LitSelect | null | undefined; 38 private frequencyThreadPie: LitChartPie | null | undefined; 39 private currentThread: HTMLDivElement | null | undefined; 40 private frequencyThreadProgress: LitProgressBar | null | undefined; 41 private nodata: TableNoData | null | undefined; 42 private currentTid: number = 0; 43 private frequencyThreadData: Array<any> = []; 44 private sortColumn: string = ''; 45 private sortType: number = 0; 46 47 initElements(): void { 48 this.nodata = this.shadowRoot!.querySelector<TableNoData>('#nodata'); 49 this.frequencyThreadProgress = this.shadowRoot!.querySelector<LitProgressBar>('#loading'); 50 this.frequencyThreadTbl = this.shadowRoot!.querySelector<LitTable>('#tb-process-thread-count'); 51 this.currentThread = this.shadowRoot!.querySelector<HTMLDivElement>('#current_thread'); 52 this.threadSelect = this.shadowRoot!.querySelector<LitSelect>('#thread_select'); 53 this.frequencyThreadPie = this.shadowRoot!.querySelector<LitChartPie>('#pie'); 54 55 this.threadSelect!.onchange = (e) => { 56 this.currentThread!.textContent = (e as any).detail.text; 57 this.currentTid = parseInt((e as any).detail.value); 58 this.frequencyThreadProgress!.loading = true; 59 this.queryData(); 60 }; 61 62 this.frequencyThreadTbl!.addEventListener('row-click', (evt: any) => { 63 let data = evt.detail.data; 64 data.isSelected = true; 65 if ((evt.detail as any).callBack) { 66 (evt.detail as any).callBack(true); 67 } 68 }); 69 70 this.frequencyThreadTbl!.addEventListener('column-click', (evt: any) => { 71 this.sortColumn = evt.detail.key; 72 this.sortType = evt.detail.sort; 73 // @ts-ignore 74 this.sortByColumn(evt.detail); 75 }); 76 this.frequencyThreadTbl!.addEventListener('row-hover', (evt: any) => { 77 if (evt.detail.data) { 78 let data = evt.detail.data; 79 data.isHover = true; 80 if ((evt.detail as any).callBack) { 81 (evt.detail as any).callBack(true); 82 } 83 } 84 this.frequencyThreadPie?.showHover(); 85 }); 86 this.frequencyThreadTbl!.itemTextHandleMap.set('freq', (value) => (value === -1 ? 'unknown' : value)); 87 } 88 89 sortByColumn(detail: any) { 90 // @ts-ignore 91 function compare(frequencyThreadProperty, sort, type) { 92 return function (a: any, b: any) { 93 if (type === 'number') { 94 // @ts-ignore 95 return sort === 2 96 ? parseFloat(b[frequencyThreadProperty]) - parseFloat(a[frequencyThreadProperty]) 97 : parseFloat(a[frequencyThreadProperty]) - parseFloat(b[frequencyThreadProperty]); 98 } else { 99 if (sort === 2) { 100 return b[frequencyThreadProperty].toString().localeCompare(a[frequencyThreadProperty].toString()); 101 } else { 102 return a[frequencyThreadProperty].toString().localeCompare(b[frequencyThreadProperty].toString()); 103 } 104 } 105 }; 106 } 107 108 if (detail.key === 'timeStr') { 109 detail.key = 'time'; 110 this.frequencyThreadData.sort(compare(detail.key, detail.sort, 'number')); 111 } else if (detail.key === 'no' || detail.key === 'cpu' || detail.key === 'freq' || detail.key === 'ratio') { 112 this.frequencyThreadData.sort(compare(detail.key, detail.sort, 'number')); 113 } else { 114 this.frequencyThreadData.sort(compare(detail.key, detail.sort, 'string')); 115 } 116 this.frequencyThreadTbl!.recycleDataSource = this.frequencyThreadData; 117 } 118 119 async init() { 120 if (!this.traceChange) { 121 if (this.frequencyThreadTbl!.recycleDataSource.length > 0) { 122 this.frequencyThreadTbl?.reMeauseHeight(); 123 } 124 return; 125 } 126 this.traceChange = false; 127 this.frequencyThreadProgress!.loading = true; 128 if (Top20FrequencyThread.threads === undefined) { 129 Top20FrequencyThread.threads = (await queryThreads()) || []; 130 this.nodata!.noData = Top20FrequencyThread.threads === undefined || Top20FrequencyThread.threads.length === 0; 131 this.threadSelect!.innerHTML = ''; 132 let threads = Top20FrequencyThread.threads.map((it) => { 133 let option = new LitSelectOption(); 134 option.setAttribute('value', it.tid + ''); 135 option.textContent = it.name; 136 return option; 137 }); 138 this.threadSelect!.append(...threads); 139 this.threadSelect?.initOptions(); 140 this.threadSelect!.value = Top20FrequencyThread.threads[0].tid + ''; 141 this.currentThread!.textContent = Top20FrequencyThread.threads[0].name; 142 this.currentTid = Top20FrequencyThread.threads[0].tid; 143 this.queryData(); 144 } 145 } 146 147 queryData() { 148 this.queryLogicWorker('scheduling-Thread Freq', 'query Thread Top 20 Frequency Time:', (res) => { 149 this.nodata!.noData = 150 Top20FrequencyThread.threads === undefined || 151 Top20FrequencyThread.threads.length === 0 || 152 res === undefined || 153 res.length === 0; 154 (res as any[]).map((it: any, index: number) => { 155 it.no = index + 1; 156 }); 157 this.frequencyThreadData = res; 158 if (this.sortColumn != '') { 159 this.sortByColumn({ 160 key: this.sortColumn, 161 sort: this.sortType, 162 }); 163 } else { 164 this.frequencyThreadTbl!.recycleDataSource = res; 165 } 166 this.frequencyThreadTbl!.reMeauseHeight(); 167 this.setThreadPieConfig(res); 168 this.frequencyThreadProgress!.loading = false; 169 this.shadowRoot!.querySelector('#tb_vessel')!.scrollTop = 0; 170 }); 171 } 172 173 private setThreadPieConfig(res: any): void { 174 this.frequencyThreadPie!.config = { 175 appendPadding: 10, 176 data: this.getPieChartData(res), 177 angleField: 'time', 178 colorField: 'freq', 179 colorFieldTransferHandler: (value) => (value === -1 ? 'unknown' : value), 180 radius: 0.8, 181 label: { 182 type: 'outer', 183 }, 184 tip: (obj) => { 185 return `<div> 186 <div>freq:${obj.obj.freq === -1 ? 'unknown' : obj.obj.freq}</div> 187 <div>cpu:${obj.obj.cpu}</div> 188 <div>time:${obj.obj.timeStr}</div> 189 <div>ratio:${obj.obj.ratio}%</div> 190 </div> 191 `; 192 }, 193 hoverHandler: (data) => { 194 if (data) { 195 this.frequencyThreadTbl!.setCurrentHover(data); 196 } else { 197 this.frequencyThreadTbl!.mouseOut(); 198 } 199 }, 200 interactions: [ 201 { 202 type: 'element-active', 203 }, 204 ], 205 }; 206 } 207 208 getPieChartData(res: any[]) { 209 if (res.length > 20) { 210 let pieChartArr: any[] = []; 211 let other: any = { 212 cpu: '-', 213 freq: 'other', 214 time: 0, 215 ratio: '0', 216 totalDur: 0, 217 }; 218 for (let i = 0; i < res.length; i++) { 219 if (i < 19) { 220 pieChartArr.push(res[i]); 221 } else { 222 other.time += res[i].time; 223 other.timeStr = getProbablyTime(other.time); 224 other.totalDur = res[i].totalDur; 225 other.ratio = ((other.time / other.totalDur) * 100).toFixed(2); 226 } 227 } 228 pieChartArr.push(other); 229 return pieChartArr; 230 } 231 return res; 232 } 233 234 clearData() { 235 this.traceChange = true; 236 this.threadSelect!.innerHTML = ''; 237 this.frequencyThreadPie!.dataSource = []; 238 this.frequencyThreadTbl!.recycleDataSource = []; 239 } 240 241 queryLogicWorker(option: string, log: string, handler: (res: any) => void) { 242 let frequencyThreadTime = new Date().getTime(); 243 procedurePool.submitWithName('logic0', option, { tid: this.currentTid }, undefined, handler); 244 let durTime = new Date().getTime() - frequencyThreadTime; 245 info(log, durTime); 246 } 247 248 initHtml(): string { 249 return Top20FrequencyThreadHtml; 250 } 251} 252