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 { SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; 19import { XpowerThreadInfoStruct } from '../../../../database/ui-worker/ProcedureWorkerXpowerThreadInfo'; 20import { SortDetail, resizeObserver } from '../SheetUtils'; 21 22@element('tabpane-xpower-thread-load') 23export class TabPaneXpowerThreadLoad extends BaseElement { 24 private XpowerThreadLoadTbl: LitTable | null | undefined; 25 private XpowerThreadLoadRange: HTMLLabelElement | null | undefined; 26 private XpowerThreadLoadSource: Array<SelectionData> = []; 27 private sumCount: number = 0; 28 private tabTitle: HTMLDivElement | undefined | null; 29 30 set data(XpowerThreadLoadValue: SelectionParam) { 31 this.init(); 32 this.XpowerThreadLoadTbl!.shadowRoot!.querySelector<HTMLDivElement>('.table')!.style!.height = `${ 33 this.parentElement!.clientHeight - 45 34 }px`; 35 this.XpowerThreadLoadRange!.textContent = `Selected range: ${parseFloat( 36 ((XpowerThreadLoadValue.rightNs - XpowerThreadLoadValue.leftNs) / 1000000.0).toFixed(5) 37 )} ms`; 38 this.getThreadLoadData(XpowerThreadLoadValue).then(); 39 } 40 41 async getThreadLoadData(XpowerThreadLoadValue: SelectionParam): Promise<void> { 42 this.sumCount = 0; 43 let dataSource: SelectionData[] = []; 44 let collect = XpowerThreadLoadValue.xpowerThreadLoadMapData; 45 this.XpowerThreadLoadTbl!.loading = true; 46 for (let key of collect.keys()) { 47 let threadInfos = collect.get(key); 48 let res = (await threadInfos?.({ 49 startNS: XpowerThreadLoadValue.leftNs, 50 endNS: XpowerThreadLoadValue.rightNs, 51 queryAll: true, 52 })) as XpowerThreadInfoStruct[]; 53 let sd = this.createSelectThreadLoadData(res || []); 54 dataSource = dataSource.concat(sd); 55 } 56 this.XpowerThreadLoadTbl!.loading = false; 57 this.XpowerThreadLoadSource = dataSource; 58 this.XpowerThreadLoadTbl!.recycleDataSource = dataSource; 59 } 60 61 private init(): void { 62 const thTable = this.tabTitle!.querySelector('.th'); 63 const list = thTable!.querySelectorAll('div'); 64 if (this.tabTitle!.hasAttribute('sort')) { 65 this.tabTitle!.removeAttribute('sort'); 66 list.forEach((item) => { 67 item.querySelectorAll('svg').forEach((svg) => { 68 svg.style.display = 'none'; 69 }); 70 }); 71 } 72 } 73 74 initElements(): void { 75 this.XpowerThreadLoadTbl = this.shadowRoot?.querySelector<LitTable>('#tb-thread-info'); 76 this.tabTitle = this.XpowerThreadLoadTbl!.shadowRoot?.querySelector('.thead') as HTMLDivElement; 77 this.XpowerThreadLoadRange = this.shadowRoot?.querySelector('#time-range'); 78 this.XpowerThreadLoadTbl!.addEventListener('column-click', (evt): void => { 79 // @ts-ignore 80 this.sortByColumn(evt.detail); 81 }); 82 } 83 84 connectedCallback(): void { 85 super.connectedCallback(); 86 resizeObserver(this.parentElement!, this.XpowerThreadLoadTbl!); 87 } 88 89 initHtml(): string { 90 return ` 91 <style> 92 .xpower-thread-info-label{ 93 margin-bottom: 5px; 94 } 95 :host{ 96 padding: 10px 10px; 97 display: flex; 98 flex-direction: column; 99 } 100 </style> 101 <label id="time-range" class="xpower-thread-info-label" style="width: 100%;height: 20px;text-align: end;font-size: 10pt;">Selected range:0.0 ms</label> 102 <lit-table id="tb-thread-info" style="height: auto"> 103 <lit-table-column order title="ThreadName" data-index="name" key="name" align="flex-start" width="25%"> 104 </lit-table-column> 105 <lit-table-column data-index="count" title="Count" order key="count" align="flex-start" width="1fr"> 106 </lit-table-column> 107 <lit-table-column title="Avg Load(%)" data-index="avgNumber" order key="avgNumber" align="flex-start" width="1fr"> 108 </lit-table-column> 109 <lit-table-column title="Max Load(%)" align="flex-start" order data-index="maxNumber" key="maxNumber" width="1fr"> 110 </lit-table-column> 111 <lit-table-column title="Min Load(%)" key="minNumber" data-index="minNumber" order align="flex-start" width="1fr"> 112 </lit-table-column> 113 </lit-table> 114 `; 115 } 116 117 private createSelectThreadLoadData(list: Array<XpowerThreadInfoStruct>): SelectionData[] { 118 let SelectThreadLoadArray: SelectionData[] = []; 119 if (list.length > 0) { 120 let threadInfoMap = new Map(); 121 list.forEach((item) => { 122 // 如果value为0,泳道不显示,tab也不显示该线程 123 if (item.value > 0) { 124 if (threadInfoMap.has(item.threadName)) { 125 const data = threadInfoMap.get(item.threadName)!; 126 data.push(item); 127 } else { 128 const data: XpowerThreadInfoStruct[] = []; 129 data.push(item); 130 threadInfoMap.set(item.threadName, data); 131 } 132 } 133 }); 134 for (let itemArray of threadInfoMap.values()) { 135 let SelectThreadLoadData = new SelectionData(); 136 let max = 0; 137 let min = 0; 138 let sum = 0; 139 SelectThreadLoadData.name = itemArray[0].threadName; 140 SelectThreadLoadData.count = itemArray.length; 141 if (itemArray.length > 1) { 142 max = itemArray.map((item: { value: number }) => item.value).reduce((a: number, b: number) => Math.max(a, b)); 143 min = itemArray.map((item: { value: number }) => item.value).reduce((a: number, b: number) => Math.min(a, b)); 144 sum = itemArray.reduce((acc: number, obj: { value: number }) => acc + obj.value, 0); 145 SelectThreadLoadData.avgNumber = parseFloat((sum / itemArray.length).toFixed(2)); 146 SelectThreadLoadData.maxNumber = max; 147 SelectThreadLoadData.minNumber = min; 148 } else if (itemArray.length === 1) { 149 let value = itemArray[0].value; 150 SelectThreadLoadData.avgNumber = value; 151 SelectThreadLoadData.maxNumber = value; 152 SelectThreadLoadData.minNumber = value; 153 } 154 this.sumCount += itemArray.length; 155 SelectThreadLoadArray.push(SelectThreadLoadData); 156 } 157 } 158 return SelectThreadLoadArray; 159 } 160 161 private sortByColumn(detail: SortDetail): void { 162 function compare(property: string | number, sort: number, type: string) { 163 return function (xpowerThreadLoadLeftData: SelectionData, xpowerThreadLoadRightData: SelectionData): number { 164 if (xpowerThreadLoadLeftData.process === ' ' || xpowerThreadLoadRightData.process === ' ') { 165 return 0; 166 } 167 if (type === 'number') { 168 return sort === 2 // @ts-ignore 169 ? parseFloat(xpowerThreadLoadRightData[property]) - parseFloat(xpowerThreadLoadLeftData[property]) // @ts-ignore 170 : parseFloat(xpowerThreadLoadLeftData[property]) - parseFloat(xpowerThreadLoadRightData[property]); 171 } else { 172 // @ts-ignore 173 if (xpowerThreadLoadRightData[property] > xpowerThreadLoadLeftData[property]) { 174 return sort === 2 ? 1 : -1; 175 } else { 176 // @ts-ignore 177 if (xpowerThreadLoadRightData[property] === xpowerThreadLoadLeftData[property]) { 178 return 0; 179 } else { 180 return sort === 2 ? -1 : 1; 181 } 182 } 183 } 184 }; 185 } 186 if (detail.key === 'name') { 187 this.XpowerThreadLoadSource.sort(compare(detail.key, detail.sort, 'string')); 188 } else { 189 this.XpowerThreadLoadSource.sort(compare(detail.key, detail.sort, 'number')); 190 } 191 this.XpowerThreadLoadTbl!.recycleDataSource = this.XpowerThreadLoadSource; 192 } 193} 194