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