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 { Counter, SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; 19import { resizeObserver } from '../SheetUtils'; 20import { getTabCounters } from '../../../../database/sql/Cpu.sql'; 21 22@element('tabpane-counter') 23export class TabPaneCounter extends BaseElement { 24 private counterTbl: LitTable | null | undefined; 25 private counterRange: HTMLLabelElement | null | undefined; 26 private counterSource: Array<SelectionData> = []; 27 private currentSelectionParam: SelectionParam | undefined; 28 29 set data(counterParam: SelectionParam | unknown) { 30 if (this.currentSelectionParam === counterParam) { 31 return; 32 } 33 // @ts-ignore 34 this.currentSelectionParam = counterParam; 35 //@ts-ignore 36 this.counterTbl?.shadowRoot?.querySelector('.table')?.style?.height = `${this.parentElement!.clientHeight - 45}px`; 37 this.counterRange!.textContent = `Selected range: ${parseFloat( 38 // @ts-ignore 39 ((counterParam.rightNs - counterParam.leftNs) / 1000000.0).toFixed(5) 40 )} ms`; 41 this.counterTbl!.loading = true; 42 // @ts-ignore 43 getTabCounters(counterParam.processTrackIds, counterParam.virtualTrackIds, counterParam.rightNs).then((result) => { 44 this.counterTbl!.loading = false; 45 //@ts-ignore 46 if (result !== null && result.length > 0) { 47 let dataSource: Array<SelectionData> = []; 48 //@ts-ignore 49 let collect = this.groupByTrackIdToMap(result); 50 let sumCount = 0; 51 for (let key of collect.keys()) { 52 let counters = collect.get(key); 53 let list: Array<Counter> = []; 54 // @ts-ignore 55 let index = counters!.findIndex((item) => item.startTime >= counterParam.leftNs); 56 if (index !== -1) { 57 list = counters!.splice(index > 0 ? index - 1 : index); 58 } else { 59 list.push(counters![counters!.length - 1]); 60 } 61 // @ts-ignore 62 let sd = this.createSelectCounterData(list, counterParam.leftNs, counterParam.rightNs); 63 sumCount += Number.parseInt(sd.count); 64 dataSource.push(sd); 65 } 66 let sumData = new SelectionData(); 67 sumData.count = sumCount.toString(); 68 sumData.process = ' '; 69 dataSource.splice(0, 0, sumData); 70 this.counterSource = dataSource; 71 this.counterTbl!.recycleDataSource = dataSource; 72 } else { 73 this.counterSource = []; 74 this.counterTbl!.recycleDataSource = this.counterSource; 75 } 76 }); 77 } 78 79 initElements(): void { 80 this.counterTbl = this.shadowRoot?.querySelector<LitTable>('#tb-counter'); 81 this.counterRange = this.shadowRoot?.querySelector('#time-range'); 82 this.counterTbl!.addEventListener('column-click', (evt) => { 83 // @ts-ignore 84 this.sortByColumn(evt.detail); 85 }); 86 } 87 88 connectedCallback(): void { 89 super.connectedCallback(); 90 resizeObserver(this.parentElement!, this.counterTbl!); 91 } 92 93 initHtml(): string { 94 return ` 95 <style> 96 .counter-label{ 97 width: 100%; 98 } 99 :host{ 100 flex-direction: column; 101 display: flex; 102 padding: 10px 10px; 103 } 104 </style> 105 <label id="time-range" class="counter-label" 106 style="height: 20px;text-align: end;font-size: 10pt;margin-bottom: 5px">Selected range:0.0 ms</label> 107 <lit-table id="tb-counter" style="height: auto"> 108 <lit-table-column width="25%" title="Name" data-index="name" key="name" align="flex-start" order> 109 </lit-table-column> 110 <lit-table-column width="1fr" title="Delta value" data-index="delta" key="delta" align="flex-start" order > 111 </lit-table-column> 112 <lit-table-column width="1fr" title="Rate /s" data-index="rate" key="rate" align="flex-start" order > 113 </lit-table-column> 114 <lit-table-column width="1fr" title="Weighted avg value" data-index="avgWeight" key="avgWeight" 115 align="flex-start" order > 116 </lit-table-column> 117 <lit-table-column width="1fr" title="Count" data-index="count" key="count" align="flex-start" order > 118 </lit-table-column> 119 <lit-table-column width="1fr" title="First value" data-index="first" key="first" align="flex-start" order > 120 </lit-table-column> 121 <lit-table-column width="1fr" title="Last value" data-index="last" key="last" align="flex-start" order > 122 </lit-table-column> 123 <lit-table-column width="1fr" title="Min value" data-index="min" key="min" align="flex-start" order > 124 </lit-table-column> 125 <lit-table-column width="1fr" title="Max value" data-index="max" key="max" align="flex-start" order > 126 </lit-table-column> 127 </lit-table> 128 `; 129 } 130 131 groupByTrackIdToMap(arr: Array<Counter>): Map<number, Array<Counter>> { 132 let map = new Map<number, Array<Counter>>(); 133 for (let counter of arr) { 134 counter.name = counter.name.replace('sys.virtual.mem.', ''); 135 if (map.has(counter.trackId)) { 136 map.get(counter.trackId)!.push(counter); 137 } else { 138 let list: Array<Counter> = []; 139 list.push(counter); 140 map.set(counter.trackId, list); 141 } 142 } 143 return map; 144 } 145 146 createSelectCounterData(list: Array<Counter>, leftNs: number, rightNs: number): SelectionData { 147 let counterData = new SelectionData(); 148 if (list.length > 0) { 149 let range = rightNs - leftNs; 150 let first = list[0]; 151 counterData.trackId = first.trackId; 152 counterData.name = first.name; 153 counterData.first = `${first.value}`; 154 counterData.count = `${list.length}`; 155 counterData.last = `${list[list.length - 1].value}`; 156 counterData.delta = `${parseInt(counterData.last) - parseInt(counterData.first)}`; 157 counterData.rate = (parseInt(counterData.delta) / ((range * 1.0) / 1000000000)).toFixed(4); 158 counterData.min = `${first.value}`; 159 counterData.max = '0'; 160 let weightAvg = 0.0; 161 for (let i = 0; i < list.length; i++) { 162 let counter = list[i]; 163 if (counter.value < parseInt(counterData.min)) { 164 counterData.min = counter.value.toString(); 165 } 166 if (counter.value > parseInt(counterData.max)) { 167 counterData.max = counter.value.toString(); 168 } 169 let start = i === 0 ? leftNs : counter.startTime; 170 let end = i === list.length - 1 ? rightNs : list[i + 1].startTime; 171 weightAvg += counter.value * (((end - start) * 1.0) / range); 172 } 173 counterData.avgWeight = weightAvg.toFixed(2); 174 } 175 return counterData; 176 } 177 178 sortByColumn(detail: unknown): void { 179 // @ts-ignore 180 function compare(property, sort, type) { 181 return function (counterLeftData: SelectionData, counterRightData: SelectionData) { 182 if (counterLeftData.process === ' ' || counterRightData.process === ' ') { 183 return 0; 184 } 185 if (type === 'number') { 186 return sort === 2 // @ts-ignore 187 ? parseFloat(counterRightData[property]) - parseFloat(counterLeftData[property]) // @ts-ignore 188 : parseFloat(counterLeftData[property]) - parseFloat(counterRightData[property]); 189 } else { 190 // @ts-ignore 191 if (counterRightData[property] > counterLeftData[property]) { 192 return sort === 2 ? 1 : -1; 193 } else { 194 // @ts-ignore 195 if (counterRightData[property] === counterLeftData[property]) { 196 return 0; 197 } else { 198 return sort === 2 ? -1 : 1; 199 } 200 } 201 } 202 }; 203 } 204 205 // @ts-ignore 206 if (detail.key === 'name') { 207 // @ts-ignore 208 this.counterSource.sort(compare(detail.key, detail.sort, 'string')); 209 } else { 210 // @ts-ignore 211 this.counterSource.sort(compare(detail.key, detail.sort, 'number')); 212 } 213 this.counterTbl!.recycleDataSource = this.counterSource; 214 } 215} 216