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, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; 18import { SelectionParam } from '../../../../bean/BoxSelection'; 19import { Utils } from '../../base/Utils'; 20import { LitProgressBar } from '../../../../../base-ui/progress-bar/LitProgressBar'; 21import { SpSystemTrace } from '../../../SpSystemTrace'; 22import { getTabPaneIOTierStatisticsData } from '../../../../database/sql/SqlLite.sql'; 23 24@element('tabpane-io-tier-statistics') 25export class TabPaneIOTierStatistics extends BaseElement { 26 private ioTierStatisticsTbl: LitTable | null | undefined; 27 private ioTierStatisticsSelectionParam: SelectionParam | null | undefined; 28 private ioTierStatisticsProgressEL: LitProgressBar | null | undefined; 29 private loadingPage: unknown; 30 private loadingList: number[] = []; 31 private ioTierStatisticsSource: Array<unknown> = []; 32 private ioTierStatisticsSortKey: string = ''; 33 private ioTierStatisticsSortType: number = 0; 34 35 set data(ioTierStatisticsSelection: SelectionParam | unknown) { 36 if (ioTierStatisticsSelection === this.ioTierStatisticsSelectionParam) { 37 return; 38 } 39 this.ioTierStatisticsProgressEL!.loading = true; 40 // @ts-ignore 41 this.loadingPage.style.visibility = 'visible'; 42 // @ts-ignore 43 this.ioTierStatisticsSelectionParam = ioTierStatisticsSelection; 44 // @ts-ignore 45 this.ioTierStatisticsTbl!.shadowRoot!.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 20 46 }px`; 47 this.queryDataByDB(ioTierStatisticsSelection); 48 } 49 50 initElements(): void { 51 this.ioTierStatisticsProgressEL = this.shadowRoot!.querySelector<LitProgressBar>('.progress'); 52 this.loadingPage = this.shadowRoot!.querySelector('.loading'); 53 this.ioTierStatisticsTbl = this.shadowRoot!.querySelector<LitTable>('#tb-io-tier-statistics'); 54 this.ioTierStatisticsTbl!.addEventListener('column-click', (evt) => { 55 // @ts-ignore 56 this.ioTierStatisticsSortKey = evt.detail.key; 57 // @ts-ignore 58 this.ioTierStatisticsSortType = evt.detail.sort; 59 if (this.ioTierStatisticsSortType !== 0 && this.ioTierStatisticsSource.length > 0) { 60 this.sortTable(this.ioTierStatisticsSource[0], this.ioTierStatisticsSortKey); 61 } 62 this.ioTierStatisticsTbl!.recycleDataSource = this.ioTierStatisticsSource; 63 }); 64 } 65 66 connectedCallback(): void { 67 super.connectedCallback(); 68 new ResizeObserver((): void => { 69 if (this.parentElement!.clientHeight !== 0) { 70 // @ts-ignore 71 this.ioTierStatisticsTbl!.shadowRoot!.querySelector('.table').style.height = `${this.parentElement!.clientHeight - 25 72 }px`; 73 this.ioTierStatisticsTbl!.reMeauseHeight(); 74 // @ts-ignore 75 this.loadingPage.style.height = `${this.parentElement!.clientHeight - 24}px`; 76 } 77 }).observe(this.parentElement!); 78 } 79 80 getInitData(initIoTierItem: unknown, nameTitle: unknown = 'pname', subtitle: unknown = null): unknown { 81 if (nameTitle === 'path') { 82 // @ts-ignore 83 initIoTierItem.path = 84 // @ts-ignore 85 initIoTierItem.path !== null ? SpSystemTrace.DATA_DICT.get(parseInt(initIoTierItem.path)) : '-'; 86 } 87 return { 88 // @ts-ignore 89 ...initIoTierItem, 90 // @ts-ignore 91 title: initIoTierItem[nameTitle] + (subtitle ? `(${initIoTierItem[subtitle]})` : ''), 92 // @ts-ignore 93 allDuration: Utils.getProbablyTime(initIoTierItem.allDuration), 94 // @ts-ignore 95 minDuration: Utils.getProbablyTime(initIoTierItem.minDuration), 96 // @ts-ignore 97 maxDuration: Utils.getProbablyTime(initIoTierItem.maxDuration), 98 // @ts-ignore 99 avgDuration: Utils.getProbablyTime(initIoTierItem.avgDuration), 100 // @ts-ignore 101 node: { ...initIoTierItem, children: [] }, 102 }; 103 } 104 105 queryDataByDB(ioTierParam: SelectionParam | unknown): void { 106 this.loadingList.push(1); 107 this.ioTierStatisticsProgressEL!.loading = true; 108 // @ts-ignore 109 this.loadingPage.style.visibility = 'visible'; 110 getTabPaneIOTierStatisticsData( 111 // @ts-ignore 112 ioTierParam.leftNs + ioTierParam.recordStartNs, 113 // @ts-ignore 114 ioTierParam.rightNs + ioTierParam.recordStartNs, 115 // @ts-ignore 116 ioTierParam.diskIOipids 117 ).then((result): void => { 118 this.loadingList.splice(0, 1); 119 if (this.loadingList.length === 0) { 120 this.ioTierStatisticsProgressEL!.loading = false; 121 // @ts-ignore 122 this.loadingPage.style.visibility = 'hidden'; 123 } 124 this.sortioTierStatisticsStatus(result, 'tier', 'ipid'); 125 }); 126 } 127 private theadClick(res: Array<unknown>): void { 128 let labels = this.ioTierStatisticsTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); 129 if (labels) { 130 for (let i = 0; i < labels.length; i++) { 131 let label = labels[i].innerHTML; 132 labels[i].addEventListener('click', (): void => { 133 if (label.includes('Tier') && i === 0) { 134 this.ioTierStatisticsTbl!.setStatus(res, false, 0, 1); 135 this.ioTierStatisticsTbl!.recycleDs = this.ioTierStatisticsTbl!.meauseTreeRowElement( 136 res, 137 RedrawTreeForm.Retract 138 ); 139 } else if (label.includes('Process') && i === 1) { 140 this.ioTierStatisticsTbl!.setStatus(res, false, 0, 2); 141 this.ioTierStatisticsTbl!.recycleDs = this.ioTierStatisticsTbl!.meauseTreeRowElement( 142 res, 143 RedrawTreeForm.Retract 144 ); 145 } else if (label.includes('Path') && i === 2) { 146 this.ioTierStatisticsTbl!.setStatus(res, true); 147 this.ioTierStatisticsTbl!.recycleDs = this.ioTierStatisticsTbl!.meauseTreeRowElement( 148 res, 149 RedrawTreeForm.Expand 150 ); 151 } 152 }); 153 } 154 } 155 } 156 157 sortioTierStatisticsStatus(result: Array<unknown>, firstLevel: string, secondLevel: string): void { 158 let ioTierFatherMap = new Map<unknown, unknown>(); 159 let ioTierChildMap = new Map<unknown, unknown>(); 160 let ioTierAllNode: unknown = { 161 title: 'All', 162 count: 0, 163 allDuration: 0, 164 minDuration: 0, 165 maxDuration: 0, 166 avgDuration: '', 167 children: [], 168 }; 169 result.forEach((resultItem, idx): void => { 170 this.updateIoTierChildMap(ioTierChildMap, resultItem, firstLevel, secondLevel); 171 this.updateIoTierFatherMap(ioTierFatherMap, resultItem, firstLevel); 172 if (idx === 0) { 173 // @ts-ignore 174 ioTierAllNode.minDuration = resultItem.minDuration; 175 } else { 176 // @ts-ignore 177 ioTierAllNode.minDuration = 178 // @ts-ignore 179 ioTierAllNode.minDuration <= resultItem.minDuration ? ioTierAllNode.minDuration : resultItem.minDuration; 180 } // @ts-ignore 181 ioTierAllNode.count += resultItem.count; 182 // @ts-ignore 183 ioTierAllNode.allDuration += resultItem.allDuration; 184 // @ts-ignore 185 ioTierAllNode.maxDuration = 186 // @ts-ignore 187 ioTierAllNode.maxDuration >= resultItem.maxDuration ? ioTierAllNode.maxDuration : resultItem.maxDuration; 188 }); 189 this.calculateAvgDuration(ioTierFatherMap, ioTierChildMap, ioTierAllNode); 190 ioTierAllNode = this.getInitData(ioTierAllNode); 191 // @ts-ignore 192 ioTierAllNode.title = 'All'; 193 // @ts-ignore 194 ioTierAllNode.path = { tier: null, pid: null, path: null, value: 'All' }; 195 this.ioTierStatisticsSource = result.length > 0 ? [ioTierAllNode] : []; 196 if (this.ioTierStatisticsSortType !== 0 && result.length > 0) { 197 this.sortTable(this.ioTierStatisticsSource[0], this.ioTierStatisticsSortKey); 198 } 199 this.theadClick(this.ioTierStatisticsSource); 200 this.ioTierStatisticsTbl!.recycleDataSource = this.ioTierStatisticsSource; 201 } 202 203 private updateIoTierFatherMap(ioTierFatherMap: Map<unknown, unknown>, resultItem: unknown, firstLevel: string): void { 204 // @ts-ignore 205 if (ioTierFatherMap.has(resultItem[firstLevel])) { 206 // @ts-ignore 207 let currentFatherObject = ioTierFatherMap.get(resultItem[firstLevel]); 208 // @ts-ignore 209 currentFatherObject.count += resultItem.count; 210 // @ts-ignore 211 currentFatherObject.allDuration += resultItem.allDuration; 212 // @ts-ignore 213 currentFatherObject.minDuration = 214 // @ts-ignore 215 currentFatherObject.minDuration <= resultItem.minDuration 216 ? // @ts-ignore 217 currentFatherObject.minDuration 218 : // @ts-ignore 219 resultItem.minDuration; 220 // @ts-ignore 221 currentFatherObject.maxDuration = 222 // @ts-ignore 223 currentFatherObject.maxDuration >= resultItem.maxDuration 224 ? // @ts-ignore 225 currentFatherObject.maxDuration 226 : // @ts-ignore 227 resultItem.maxDuration; 228 // @ts-ignore 229 currentFatherObject.children.push(this.getInitData(resultItem)); 230 } else { 231 // @ts-ignore 232 ioTierFatherMap.set(resultItem[firstLevel], { 233 // @ts-ignore 234 ...resultItem, 235 children: [this.getInitData(resultItem)], 236 }); 237 } 238 } 239 240 private updateIoTierChildMap( 241 ioTierChildMap: Map<unknown, unknown>, 242 resultItem: unknown, 243 firstLevel: string, 244 secondLevel: string 245 ): void { 246 // @ts-ignore 247 if (ioTierChildMap.has(`${resultItem[firstLevel]}_${resultItem[secondLevel]}`)) { 248 // @ts-ignore 249 let currentChildObject = ioTierChildMap.get(`${resultItem[firstLevel]}_${resultItem[secondLevel]}`); 250 // @ts-ignore 251 currentChildObject.count += resultItem.count; 252 // @ts-ignore 253 currentChildObject.allDuration += resultItem.allDuration; // @ts-ignore 254 currentChildObject.minDuration = // @ts-ignore 255 currentChildObject.minDuration <= resultItem.minDuration // @ts-ignore 256 ? currentChildObject.minDuration // @ts-ignore 257 : resultItem.minDuration; // @ts-ignore 258 currentChildObject.maxDuration = // @ts-ignore 259 currentChildObject.maxDuration >= resultItem.maxDuration // @ts-ignore 260 ? currentChildObject.maxDuration // @ts-ignore 261 : resultItem.maxDuration; // @ts-ignore 262 currentChildObject.children.push(this.getInitData(resultItem, 'path', null)); 263 } else { 264 // @ts-ignore 265 ioTierChildMap.set(`${resultItem[firstLevel]}_${resultItem[secondLevel]}`, { 266 // @ts-ignore 267 ...resultItem, 268 children: [this.getInitData(resultItem, 'path', null)], 269 }); 270 } 271 } 272 273 private calculateAvgDuration( 274 ioTierFatherMap: Map<unknown, unknown>, 275 ioTierChildMap: Map<unknown, unknown>, 276 ioTierAllNode: unknown 277 ): void { 278 for (let ks of ioTierFatherMap.keys()) { 279 let sp = ioTierFatherMap.get(ks); // @ts-ignore 280 sp!.children = []; // @ts-ignore 281 sp.avgDuration = sp.allDuration / sp.count; 282 let ioTierNode = this.getInitData(sp, 'tier', null); // @ts-ignore 283 ioTierNode.path = { 284 // @ts-ignore 285 tier: ioTierNode.tier, 286 pid: null, 287 path: null, // @ts-ignore 288 value: ioTierNode.title, 289 }; 290 for (let kst of ioTierChildMap.keys()) { 291 // @ts-ignore 292 if (kst.startsWith(`${ks}_`)) { 293 let spt = ioTierChildMap.get(kst); // @ts-ignore 294 spt.avgDuration = spt.allDuration / spt.count; 295 let data = this.getInitData(spt!, 'pname', 'pid'); // @ts-ignore 296 data.path = { 297 // @ts-ignore 298 tier: ioTierNode.tier, // @ts-ignore 299 pid: data.pid, 300 path: null, // @ts-ignore 301 value: `All-${ioTierNode.title}-${data.title}`, 302 }; // @ts-ignore 303 data.children.forEach((e: unknown): void => { 304 // @ts-ignore 305 e.path = { 306 // @ts-ignore 307 tier: ioTierNode.tier, // @ts-ignore 308 pid: data.pid, // @ts-ignore 309 path: e.path, // @ts-ignore 310 value: `All-${ioTierNode.title}-${data.title}-${e.title}`, 311 }; 312 }); // @ts-ignore 313 sp!.children.push(data); 314 } 315 } // @ts-ignore 316 ioTierAllNode.children.push(ioTierNode); 317 } 318 // @ts-ignore 319 ioTierAllNode.avgDuration = ioTierAllNode.allDuration / ioTierAllNode.count; 320 } 321 322 sortTable(allNode: unknown, key: string): void { 323 // @ts-ignore 324 allNode.children.sort((ioTierStatNodeA: unknown, ioTierStatNodeB: unknown) => { 325 return this.ioTierStatisticsSortType === 1 ? 326 // @ts-ignore 327 ioTierStatNodeA.node[key] - ioTierStatNodeB.node[key] : 328 this.ioTierStatisticsSortType === 2 ? 329 // @ts-ignore 330 ioTierStatNodeB.node[key] - ioTierStatNodeA.node[key] : 0; 331 332 }); // @ts-ignore 333 allNode.children.forEach((item: unknown): void => { 334 // @ts-ignore 335 item.children.sort((ioTierStatItemA: unknown, ioTierStatItemB: unknown) => { 336 return this.ioTierStatisticsSortType === 1 ? 337 // @ts-ignore 338 ioTierStatItemA.node[key] - ioTierStatItemB.node[key] : 339 this.ioTierStatisticsSortType === 2 ? 340 // @ts-ignore 341 ioTierStatItemB.node[key] - ioTierStatItemA.node[key] : 0; 342 }); // @ts-ignore 343 item.children.forEach((ioTierStatItem: unknown): void => { 344 // @ts-ignore 345 ioTierStatItem.children.sort((ioTierStatItemA: unknown, ioTierStatItemB: unknown) => { 346 return this.ioTierStatisticsSortType === 1 ? 347 // @ts-ignore 348 ioTierStatItemA.node[key] - ioTierStatItemB.node[key] : 349 this.ioTierStatisticsSortType === 2 ? 350 // @ts-ignore 351 ioTierStatItemB.node[key] - ioTierStatItemA.node[key] : 0; 352 }); 353 }); 354 }); 355 } 356 357 initHtml(): string { 358 return ` 359 <style> 360 .io-tier-stat-progress{ 361 bottom: 5px; 362 position: absolute; 363 height: 1px; 364 left: 0; 365 right: 0; 366 } 367 :host{ 368 padding: 10px 10px 0 10px; 369 display: flex; 370 flex-direction: column; 371 } 372 .io-tier-stat-loading{ 373 bottom: 0; 374 position: absolute; 375 left: 0; 376 right: 0; 377 width:100%; 378 background:transparent; 379 z-index: 999999; 380 } 381 </style> 382 <lit-table id="tb-io-tier-statistics" style="height: auto" tree> 383 <lit-table-column class="io-tier-stat-column" width="20%" title="Tier/Process/Path" data-index="title" key="title" align="flex-start"retract> 384 </lit-table-column> 385 <lit-table-column class="io-tier-stat-column" width="1fr" title="Count" data-index="count" key="count" align="flex-start" order> 386 </lit-table-column> 387 <lit-table-column class="io-tier-stat-column" width="1fr" title="Total Latency" data-index="allDuration" key="allDuration" align="flex-start" order> 388 </lit-table-column> 389 <lit-table-column class="io-tier-stat-column" width="1fr" title="Min Total Latency" data-index="minDuration" key="minDuration" align="flex-start" order> 390 </lit-table-column> 391 <lit-table-column class="io-tier-stat-column" width="1fr" title="Avg Total Latency" data-index="avgDuration" key="avgDuration" align="flex-start" order> 392 </lit-table-column> 393 <lit-table-column class="io-tier-stat-column" width="1fr" title="Max Total Latency" data-index="maxDuration" key="maxDuration" align="flex-start" order> 394 </lit-table-column> 395 </lit-table> 396 <lit-progress-bar class="progress io-tier-stat-progress"></lit-progress-bar> 397 <div class="loading io-tier-stat-loading"></div> 398 `; 399 } 400} 401