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 { 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: any; 30 private loadingList: number[] = []; 31 private ioTierStatisticsSource: Array<any> = []; 32 private ioTierStatisticsSortKey: string = ''; 33 private ioTierStatisticsSortType: number = 0; 34 private ioTierStatisticsResultData: Array<any> = []; 35 36 set data(ioTierStatisticsSelection: SelectionParam | any) { 37 if (ioTierStatisticsSelection == this.ioTierStatisticsSelectionParam) { 38 return; 39 } 40 this.ioTierStatisticsProgressEL!.loading = true; 41 this.loadingPage.style.visibility = 'visible'; 42 this.ioTierStatisticsSelectionParam = ioTierStatisticsSelection; 43 // @ts-ignore 44 this.ioTierStatisticsTbl!.shadowRoot!.querySelector('.table').style.height = 45 this.parentElement!.clientHeight - 20 + 'px'; 46 this.queryDataByDB(ioTierStatisticsSelection); 47 } 48 49 initElements(): void { 50 this.ioTierStatisticsProgressEL = this.shadowRoot!.querySelector<LitProgressBar>('.progress'); 51 this.loadingPage = this.shadowRoot!.querySelector('.loading'); 52 this.ioTierStatisticsTbl = this.shadowRoot!.querySelector<LitTable>('#tb-io-tier-statistics'); 53 this.ioTierStatisticsTbl!.addEventListener('column-click', (evt) => { 54 // @ts-ignore 55 this.ioTierStatisticsSortKey = evt.detail.key; 56 // @ts-ignore 57 this.ioTierStatisticsSortType = evt.detail.sort; 58 59 let newSource = JSON.parse(JSON.stringify(this.ioTierStatisticsSource)); 60 if (this.ioTierStatisticsSortType != 0 && newSource.length > 0) 61 this.sortTable(newSource[0], this.ioTierStatisticsSortKey); 62 this.ioTierStatisticsTbl!.recycleDataSource = newSource; 63 }); 64 } 65 66 connectedCallback() { 67 super.connectedCallback(); 68 new ResizeObserver((entries) => { 69 if (this.parentElement!.clientHeight != 0) { 70 // @ts-ignore 71 this.ioTierStatisticsTbl!.shadowRoot!.querySelector('.table').style.height = 72 this.parentElement!.clientHeight - 25 + 'px'; 73 this.ioTierStatisticsTbl!.reMeauseHeight(); 74 this.loadingPage.style.height = this.parentElement!.clientHeight - 24 + 'px'; 75 } 76 }).observe(this.parentElement!); 77 } 78 79 getInitData(initIoTierItem: any, nameTitle: any = 'pname', subtitle: any = null) { 80 if (nameTitle == 'path') { 81 initIoTierItem.path = 82 initIoTierItem.path != null ? SpSystemTrace.DATA_DICT.get(parseInt(initIoTierItem.path)) : '-'; 83 } 84 return { 85 ...initIoTierItem, 86 title: initIoTierItem[nameTitle] + (subtitle ? '(' + initIoTierItem[subtitle] + ')' : ''), 87 allDuration: Utils.getProbablyTime(initIoTierItem.allDuration), 88 minDuration: Utils.getProbablyTime(initIoTierItem.minDuration), 89 maxDuration: Utils.getProbablyTime(initIoTierItem.maxDuration), 90 avgDuration: Utils.getProbablyTime(initIoTierItem.avgDuration), 91 node: { ...initIoTierItem, children: [] }, 92 }; 93 } 94 95 queryDataByDB(ioTierParam: SelectionParam | any) { 96 this.loadingList.push(1); 97 this.ioTierStatisticsProgressEL!.loading = true; 98 this.loadingPage.style.visibility = 'visible'; 99 getTabPaneIOTierStatisticsData( 100 ioTierParam.leftNs + ioTierParam.recordStartNs, 101 ioTierParam.rightNs + ioTierParam.recordStartNs, 102 ioTierParam.diskIOipids 103 ).then((result) => { 104 this.loadingList.splice(0, 1); 105 if (this.loadingList.length == 0) { 106 this.ioTierStatisticsProgressEL!.loading = false; 107 this.loadingPage.style.visibility = 'hidden'; 108 } 109 this.ioTierStatisticsResultData = JSON.parse(JSON.stringify(result)); 110 this.sortioTierStatisticsStatus(result, 'tier', 'ipid'); 111 }); 112 } 113 114 sortioTierStatisticsStatus(result: Array<any>, firstLevel: string, secondLevel: string) { 115 let ioTierFatherMap = new Map<any, any>(); 116 let ioTierChildMap = new Map<any, any>(); 117 let ioTierAllNode: any = { 118 title: 'All', 119 count: 0, 120 allDuration: 0, 121 minDuration: 0, 122 maxDuration: 0, 123 avgDuration: '', 124 children: [], 125 }; 126 result.forEach((resultItem, idx) => { 127 this.updateIoTierChildMap(ioTierChildMap, resultItem, firstLevel, secondLevel); 128 this.updateIoTierFatherMap(ioTierFatherMap, resultItem, firstLevel); 129 if (idx == 0) { 130 ioTierAllNode.minDuration = resultItem.minDuration; 131 } else { 132 ioTierAllNode.minDuration = 133 ioTierAllNode.minDuration <= resultItem.minDuration ? ioTierAllNode.minDuration : resultItem.minDuration; 134 } 135 ioTierAllNode.count += resultItem.count; 136 ioTierAllNode.allDuration += resultItem.allDuration; 137 ioTierAllNode.maxDuration = 138 ioTierAllNode.maxDuration >= resultItem.maxDuration ? ioTierAllNode.maxDuration : resultItem.maxDuration; 139 }); 140 this.calculateAvgDuration(ioTierFatherMap, ioTierChildMap, ioTierAllNode); 141 ioTierAllNode = this.getInitData(ioTierAllNode); 142 ioTierAllNode.title = 'All'; 143 ioTierAllNode.path = {tier: null, pid: null, path: null, value: 'All'}; 144 this.ioTierStatisticsSource = result.length > 0 ? [ioTierAllNode] : []; 145 let newSource = JSON.parse(JSON.stringify(this.ioTierStatisticsSource)); 146 if (this.ioTierStatisticsSortType != 0 && result.length > 0) 147 this.sortTable(newSource[0], this.ioTierStatisticsSortKey); 148 this.ioTierStatisticsTbl!.recycleDataSource = newSource; 149 } 150 151 private updateIoTierFatherMap(ioTierFatherMap: Map<any, any>, resultItem: any, firstLevel: string): void { 152 if (ioTierFatherMap.has(resultItem[firstLevel])) { 153 let currentFatherObject = ioTierFatherMap.get(resultItem[firstLevel]); 154 currentFatherObject.count += resultItem.count; 155 currentFatherObject.allDuration += resultItem.allDuration; 156 currentFatherObject.minDuration = 157 currentFatherObject.minDuration <= resultItem.minDuration 158 ? currentFatherObject.minDuration 159 : resultItem.minDuration; 160 currentFatherObject.maxDuration = 161 currentFatherObject.maxDuration >= resultItem.maxDuration 162 ? currentFatherObject.maxDuration 163 : resultItem.maxDuration; 164 currentFatherObject.children.push(this.getInitData(resultItem)); 165 } else { 166 ioTierFatherMap.set(resultItem[firstLevel], { 167 ...resultItem, 168 children: [this.getInitData(resultItem)], 169 }); 170 } 171 } 172 173 private updateIoTierChildMap(ioTierChildMap: Map<any, any>, resultItem: any, firstLevel: string, 174 secondLevel: string): void { 175 if (ioTierChildMap.has(resultItem[firstLevel] + '_' + resultItem[secondLevel])) { 176 let currentChildObject = ioTierChildMap.get(resultItem[firstLevel] + '_' + resultItem[secondLevel]); 177 currentChildObject.count += resultItem.count; 178 currentChildObject.allDuration += resultItem.allDuration; 179 currentChildObject.minDuration = 180 currentChildObject.minDuration <= resultItem.minDuration 181 ? currentChildObject.minDuration 182 : resultItem.minDuration; 183 currentChildObject.maxDuration = 184 currentChildObject.maxDuration >= resultItem.maxDuration 185 ? currentChildObject.maxDuration 186 : resultItem.maxDuration; 187 currentChildObject.children.push(this.getInitData(resultItem, 'path', null)); 188 } else { 189 ioTierChildMap.set(resultItem[firstLevel] + '_' + resultItem[secondLevel], { 190 ...resultItem, 191 children: [this.getInitData(resultItem, 'path', null)], 192 }); 193 } 194 } 195 196 private calculateAvgDuration(ioTierFatherMap: Map<any, any>, ioTierChildMap: Map<any, any>, ioTierAllNode: any): void { 197 for (let ks of ioTierFatherMap.keys()) { 198 let sp = ioTierFatherMap.get(ks); 199 sp!.children = []; 200 sp.avgDuration = sp.allDuration / sp.count; 201 let ioTierNode = this.getInitData(sp, 'tier', null); 202 ioTierNode.path = { 203 tier: ioTierNode.tier, 204 pid: null, 205 path: null, 206 value: ioTierNode.title, 207 }; 208 for (let kst of ioTierChildMap.keys()) { 209 if (kst.startsWith(ks + '_')) { 210 let spt = ioTierChildMap.get(kst); 211 let data = this.getInitData(spt!, 'pname', 'pid'); 212 data.path = { 213 tier: ioTierNode.tier, 214 pid: data.pid, 215 path: null, 216 value: 'All-' + ioTierNode.title + '-' + data.title, 217 }; 218 data.children.forEach((e: any) => { 219 e.path = { 220 tier: ioTierNode.tier, 221 pid: data.pid, 222 path: e.path, 223 value: 'All-' + ioTierNode.title + '-' + data.title + '-' + e.title, 224 }; 225 }); 226 sp!.children.push(data); 227 } 228 } 229 ioTierAllNode.children.push(ioTierNode); 230 } 231 232 ioTierAllNode.avgDuration = ioTierAllNode.allDuration / ioTierAllNode.count; 233 } 234 235 sortTable(allNode: any, key: string) { 236 allNode.children.sort((ioTierStatNodeA: any, ioTierStatNodeB: any) => { 237 if (this.ioTierStatisticsSortType == 1) { 238 return ioTierStatNodeA.node[key] - ioTierStatNodeB.node[key]; 239 } else if (this.ioTierStatisticsSortType == 2) { 240 return ioTierStatNodeB.node[key] - ioTierStatNodeA.node[key]; 241 } 242 }); 243 allNode.children.forEach((item: any) => { 244 item.children.sort((ioTierStatItemA: any, ioTierStatItemB: any) => { 245 if (this.ioTierStatisticsSortType == 1) { 246 return ioTierStatItemA.node[key] - ioTierStatItemB.node[key]; 247 } else if (this.ioTierStatisticsSortType == 2) { 248 return ioTierStatItemB.node[key] - ioTierStatItemA.node[key]; 249 } 250 }); 251 item.children.forEach((ioTierStatItem: any) => { 252 ioTierStatItem.children.sort((ioTierStatItemA: any, ioTierStatItemB: any) => { 253 if (this.ioTierStatisticsSortType == 1) { 254 return ioTierStatItemA.node[key] - ioTierStatItemB.node[key]; 255 } else if (this.ioTierStatisticsSortType == 2) { 256 return ioTierStatItemB.node[key] - ioTierStatItemA.node[key]; 257 } 258 }); 259 }); 260 }); 261 } 262 263 initHtml(): string { 264 return ` 265 <style> 266 .io-tier-stat-progress{ 267 bottom: 5px; 268 position: absolute; 269 height: 1px; 270 left: 0; 271 right: 0; 272 } 273 :host{ 274 padding: 10px 10px 0 10px; 275 display: flex; 276 flex-direction: column; 277 } 278 .io-tier-stat-loading{ 279 bottom: 0; 280 position: absolute; 281 left: 0; 282 right: 0; 283 width:100%; 284 background:transparent; 285 z-index: 999999; 286 } 287 </style> 288 <lit-table id="tb-io-tier-statistics" style="height: auto" tree> 289 <lit-table-column class="io-tier-stat-column" width="20%" title="Tier/Process/Path" data-index="title" key="title" align="flex-start"retract> 290 </lit-table-column> 291 <lit-table-column class="io-tier-stat-column" width="1fr" title="Count" data-index="count" key="count" align="flex-start" order> 292 </lit-table-column> 293 <lit-table-column class="io-tier-stat-column" width="1fr" title="Total Latency" data-index="allDuration" key="allDuration" align="flex-start" order> 294 </lit-table-column> 295 <lit-table-column class="io-tier-stat-column" width="1fr" title="Min Total Latency" data-index="minDuration" key="minDuration" align="flex-start" order> 296 </lit-table-column> 297 <lit-table-column class="io-tier-stat-column" width="1fr" title="Avg Total Latency" data-index="avgDuration" key="avgDuration" align="flex-start" order> 298 </lit-table-column> 299 <lit-table-column class="io-tier-stat-column" width="1fr" title="Max Total Latency" data-index="maxDuration" key="maxDuration" align="flex-start" order> 300 </lit-table-column> 301 </lit-table> 302 <lit-progress-bar class="progress io-tier-stat-progress"></lit-progress-bar> 303 <div class="loading io-tier-stat-loading"></div> 304 `; 305 } 306} 307