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