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