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