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.js"; 17import {LitTable} from "../../../../../base-ui/table/lit-table.js"; 18import {SelectionParam} from "../../../../bean/BoxSelection.js"; 19import { 20 getTabPaneIOTierStatisticsData, 21} from "../../../../database/SqlLite.js"; 22import {Utils} from "../../base/Utils.js"; 23import {LitProgressBar} from "../../../../../base-ui/progress-bar/LitProgressBar.js"; 24import {TabPaneFilter} from "../TabPaneFilter.js"; 25 26@element('tabpane-io-tier-statistics') 27export class TabPaneIOTierStatistics extends BaseElement { 28 private tbl: LitTable | null | undefined; 29 private range: HTMLLabelElement | null | undefined; 30 private loadDataInCache: boolean = true; 31 private selectionParam:SelectionParam | null | undefined; 32 private progressEL:LitProgressBar | null | undefined; 33 private filter: TabPaneFilter | null | undefined; 34 private loadingPage:any; 35 private loadingList:number[] = []; 36 private source: Array<any> = []; 37 private typeList: Array<string> = ["OPEN", "CLOSE", "READ" , "WRITE"]; 38 private sortKey: string = ""; 39 private sortType: number = 0; 40 private resultData: Array<any> = []; 41 42 set data(val: SelectionParam | any) { 43 if(val == this.selectionParam){ 44 return; 45 } 46 this.progressEL!.loading = true 47 this.loadingPage.style.visibility = "visible" 48 this.selectionParam = val; 49 // @ts-ignore 50 this.tbl!.shadowRoot!.querySelector(".table").style.height = (this.parentElement!.clientHeight - 20) + "px" 51 this.queryDataByDB(val) 52 } 53 54 initElements(): void { 55 this.progressEL = this.shadowRoot!.querySelector<LitProgressBar>('.progress') 56 this.loadingPage = this.shadowRoot!.querySelector('.loading'); 57 this.tbl = this.shadowRoot!.querySelector<LitTable>('#tb-states'); 58 this.tbl!.addEventListener('column-click', (evt) => { 59 // @ts-ignore 60 this.sortKey = evt.detail.key 61 // @ts-ignore 62 this.sortType = evt.detail.sort; 63 64 let newSource = JSON.parse(JSON.stringify(this.source)); 65 if (this.sortType != 0 && newSource.length > 0) this.sortTable(newSource[0],this.sortKey); 66 this.tbl!.recycleDataSource = newSource; 67 }) 68 } 69 70 connectedCallback() { 71 super.connectedCallback(); 72 new ResizeObserver((entries) => { 73 if (this.parentElement!.clientHeight != 0) { 74 // @ts-ignore 75 this.tbl!.shadowRoot!.querySelector(".table").style.height = (this.parentElement!.clientHeight - 25) + "px" 76 this.tbl!.reMeauseHeight() 77 this.loadingPage.style.height = (this.parentElement!.clientHeight - 24) + "px" 78 } 79 }).observe(this.parentElement!); 80 } 81 82 getInitData(item:any,nameTitle:any = "pname",subtitle:any = null){ 83 return { 84 ...item, 85 title : item[nameTitle]+(subtitle?("("+item[subtitle]+")"):""), 86 allDuration : Utils.getProbablyTime(item.allDuration), 87 minDuration : Utils.getProbablyTime(item.minDuration), 88 maxDuration : Utils.getProbablyTime(item.maxDuration), 89 avgDuration : Utils.getProbablyTime(item.avgDuration), 90 node:{...item,children:[]}, 91 } 92 } 93 94 queryDataByDB(val: SelectionParam | any) { 95 this.loadingList.push(1) 96 this.progressEL!.loading = true 97 this.loadingPage.style.visibility = "visible"; 98 getTabPaneIOTierStatisticsData(val.leftNs + val.recordStartNs,val.rightNs + val.recordStartNs,val.diskIOipids).then(result => { 99 this.loadingList.splice(0,1) 100 if(this.loadingList.length == 0) { 101 this.progressEL!.loading = false 102 this.loadingPage.style.visibility = "hidden" 103 } 104 this.resultData = JSON.parse(JSON.stringify(result)); 105 this.sortStatus(result,"tier","ipid") 106 }) 107 } 108 109 sortStatus(result:Array<any>,firstLevel:string,secondLevel:string){ 110 let fatherMap = new Map<any,any>(); 111 let childMap = new Map<any,any>(); 112 let allNode:any = { 113 title:"All", 114 count:0, 115 allDuration:0, 116 minDuration:0, 117 maxDuration:0, 118 avgDuration:"", 119 children:[], 120 }; 121 result.forEach((item,idx)=>{ 122 if (childMap.has(item[firstLevel]+"_"+item[secondLevel])) { 123 let obj1 = childMap.get(item[firstLevel]+"_"+item[secondLevel]); 124 obj1.count += item.count; 125 obj1.allDuration += item.allDuration; 126 obj1.minDuration = obj1.minDuration<=item.minDuration?obj1.minDuration:item.minDuration; 127 obj1.maxDuration = obj1.maxDuration>=item.maxDuration?obj1.maxDuration:item.maxDuration; 128 obj1.children.push(this.getInitData(item,"path",null)); 129 }else { 130 childMap.set(item[firstLevel]+"_"+item[secondLevel],{ 131 ...item, 132 children:[this.getInitData(item,"path",null)] 133 }) 134 } 135 136 if (fatherMap.has(item[firstLevel])) { 137 let obj1 = fatherMap.get(item[firstLevel]); 138 obj1.count += item.count; 139 obj1.allDuration += item.allDuration; 140 obj1.minDuration = obj1.minDuration<=item.minDuration?obj1.minDuration:item.minDuration; 141 obj1.maxDuration = obj1.maxDuration>=item.maxDuration?obj1.maxDuration:item.maxDuration; 142 obj1.children.push(this.getInitData(item)); 143 }else { 144 fatherMap.set(item[firstLevel],{ 145 ...item, 146 children:[this.getInitData(item)] 147 }) 148 } 149 if (idx == 0) { 150 allNode.minDuration = item.minDuration; 151 }else { 152 allNode.minDuration = allNode.minDuration<=item.minDuration?allNode.minDuration:item.minDuration; 153 } 154 allNode.count += item.count; 155 allNode.allDuration += item.allDuration; 156 allNode.maxDuration = allNode.maxDuration>=item.maxDuration?allNode.maxDuration:item.maxDuration; 157 }) 158 159 for (let ks of fatherMap.keys()) { 160 let sp = fatherMap.get(ks) 161 sp!.children = []; 162 sp.avgDuration = sp.allDuration/sp.count; 163 let node = this.getInitData(sp,"tier",null); 164 node.path = {tier:node.tier,pid:null,path:null,value:node.title} 165 for (let kst of childMap.keys()) { 166 if (kst.startsWith(ks + "_")) { 167 let spt = childMap.get(kst) 168 let data = this.getInitData(spt!,"pname","pid") 169 data.path = {tier:node.tier,pid:data.pid,path:null,value:"All-"+node.title+"-"+data.title} 170 data.children.forEach((e:any)=>{ 171 e.path = {tier:node.tier,pid:data.pid,path:e.pid,value:"All-"+node.title+"-"+data.title+"-"+e.title} 172 }) 173 sp!.children.push(data); 174 } 175 } 176 allNode.children.push(node) 177 } 178 179 allNode.avgDuration = allNode.allDuration/allNode.count; 180 allNode = this.getInitData(allNode); 181 allNode.title = "All"; 182 allNode.path = {tier:null,pid:null,path:null,value:"All"} 183 this.source = result.length > 0 ? [allNode] : []; 184 let newSource = JSON.parse(JSON.stringify(this.source)); 185 if (this.sortType != 0 && result.length > 0) this.sortTable(newSource[0],this.sortKey); 186 this.tbl!.recycleDataSource = newSource; 187 } 188 189 sortTable(allNode:any,key:string){ 190 allNode.children.sort((a:any, b:any) => { 191 if (this.sortType == 1) { 192 return a.node[key] - b.node[key] 193 }else if (this.sortType == 2) { 194 return b.node[key] - a.node[key] 195 } 196 }); 197 allNode.children.forEach((item:any)=>{ 198 item.children.sort((a:any, b:any) => { 199 if (this.sortType == 1) { 200 return a.node[key] - b.node[key] 201 }else if (this.sortType == 2) { 202 return b.node[key] - a.node[key] 203 } 204 }) 205 item.children.forEach((i:any)=>{ 206 i.children.sort((a:any, b:any) => { 207 if (this.sortType == 1) { 208 return a.node[key] - b.node[key] 209 }else if (this.sortType == 2) { 210 return b.node[key] - a.node[key] 211 } 212 }) 213 }); 214 }); 215 } 216 217 initHtml(): string { 218 return ` 219 <style> 220 :host{ 221 display: flex; 222 flex-direction: column; 223 padding: 10px 10px 0 10px; 224 } 225 .progress{ 226 bottom: 5px; 227 position: absolute; 228 height: 1px; 229 left: 0; 230 right: 0; 231 } 232 .loading{ 233 bottom: 0; 234 position: absolute; 235 left: 0; 236 right: 0; 237 width:100%; 238 background:transparent; 239 z-index: 999999; 240 } 241 </style> 242 <lit-table id="tb-states" style="height: auto" tree> 243 <lit-table-column width="20%" title="Tier/Process/Path" data-index="title" key="title" align="flex-start"> 244 </lit-table-column> 245 <lit-table-column width="1fr" title="Count" data-index="count" key="count" align="flex-start" order> 246 </lit-table-column> 247 <lit-table-column width="1fr" title="Total Latency" data-index="allDuration" key="allDuration" align="flex-start" order> 248 </lit-table-column> 249 <lit-table-column width="1fr" title="Min Total Latency" data-index="minDuration" key="minDuration" align="flex-start" order> 250 </lit-table-column> 251 <lit-table-column width="1fr" title="Avg Total Latency" data-index="avgDuration" key="avgDuration" align="flex-start" order> 252 </lit-table-column> 253 <lit-table-column width="1fr" title="Max Total Latency" data-index="maxDuration" key="maxDuration" align="flex-start" order> 254 </lit-table-column> 255 </lit-table> 256 <lit-progress-bar class="progress"></lit-progress-bar> 257 <div class="loading"></div> 258 `; 259 } 260} 261