1/* 2 * Copyright (C) 2024 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 { type LitTable, RedrawTreeForm } from '../../../../../base-ui/table/lit-table'; 18import { type SelectionParam } from '../../../../bean/BoxSelection'; 19import { resizeObserver } from '../SheetUtils'; 20import { queryDmaFenceData } from '../../../../database/sql/dmaFence.sql'; 21import { DmaFenceDataBean, DmaFenceTreeBean, DmaFenceStringBean } from './DmaFenceBean'; 22 23@element('tabpane-dmafrence') 24export class TabPaneDmaFence extends BaseElement { 25 private dmaFenceTbl: LitTable | null | undefined; 26 private currentSelectionParam: SelectionParam | undefined; 27 private timeSelection: HTMLLabelElement | null | undefined; 28 private finaldmaFenceData: Array<DmaFenceStringBean> = []; 29 private sortKey: string = 'name'; 30 private sortType: number = 0; 31 32 set data(dmaFenceValue: SelectionParam) { 33 if (this.currentSelectionParam === dmaFenceValue) { 34 return; 35 }; 36 this.currentSelectionParam = dmaFenceValue; 37 this.dmaFenceTbl!.recycleDataSource = []; 38 this.dmaFenceTbl!.loading = true; 39 //@ts-ignore 40 this.dmaFenceTbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; 41 queryDmaFenceData(dmaFenceValue.leftNs, dmaFenceValue.rightNs, dmaFenceValue.dmaFenceNameData).then((result: Array<DmaFenceDataBean>) => { 42 if (result !== null && result.length > 0) { 43 this.dmaFenceTbl!.loading = false; 44 let resultList: Array<DmaFenceDataBean> = JSON.parse(JSON.stringify(result)); 45 this.finaldmaFenceData = this.createTree(resultList); 46 this.timeSelection!.innerHTML = 47 'Selection start: ' + (resultList[0].startTime / 1000000).toFixed(3) + ' ms' + ' ' + 'Selection extent: ' + ((resultList[resultList.length - 1].endTime / 1000000) - (resultList[0].startTime / 1000000)).toFixed(3) + ' ms'; 48 this.sortByColumn(this.sortKey, this.sortType, false); 49 } else { 50 this.dmaFenceTbl!.recycleDataSource = []; 51 this.dmaFenceTbl!.loading = false; 52 this.timeSelection!.innerHTML = 53 'Selection start: ' + 0 + ' ms' + ' ' + 'Selection extent: ' + 0 + ' ms'; 54 } 55 }); 56 } 57 58 private createTree(data: Array<DmaFenceDataBean>): Array<DmaFenceStringBean> { 59 const treeMap = new Map<string, { dur: number; occurrences: number; children: Array<DmaFenceTreeBean> }>(); 60 data.forEach(item => { 61 const timeline = item.timeline; 62 const nameBase = item.cat.startsWith('dma_fence_signaled') ? 'fence_signal' : item.cat.split('dma_')[1]; 63 const name = `${nameBase}(${item.seqno})`; 64 const durValue = item.dur / 1000000; 65 66 let timelineRecord = treeMap.get(timeline); 67 if (!timelineRecord) { 68 timelineRecord = { 69 dur: 0, 70 occurrences: 0, 71 children: [] 72 }; 73 treeMap.set(timeline, timelineRecord); 74 } 75 76 let node = timelineRecord.children.find(child => child.name === name); 77 if (!node) { 78 node = { 79 name, 80 dur: durValue, 81 occurrences: 1, 82 average: durValue, 83 status: item.status, 84 }; 85 timelineRecord.children.push(node); 86 } else { 87 node.dur += durValue; 88 node.occurrences += 1; 89 node.average = node.dur / node.occurrences; 90 } 91 timelineRecord.dur += durValue; 92 timelineRecord.occurrences += 1; 93 }); 94 const root: DmaFenceTreeBean = { 95 name: 'totals', 96 dur: 0, 97 occurrences: 0, 98 children: [], 99 average: 0, 100 status: false 101 }; 102 103 // 遍历treeMap来创建子节点,并按timeline分组 104 treeMap.forEach((timelineRecord, timeline) => { 105 const timelineAverage = timelineRecord.dur / timelineRecord.occurrences; 106 const timelineNode: DmaFenceTreeBean = { 107 name: timeline, 108 dur: timelineRecord.dur, 109 occurrences: timelineRecord.occurrences, 110 average: timelineAverage, 111 children: timelineRecord.children, 112 status: false 113 }; 114 root.dur += timelineNode.dur; 115 root.occurrences += timelineNode.occurrences; 116 117 root.children!.push(timelineNode); 118 }); 119 root.average = root.occurrences > 0 ? root.dur / root.occurrences : 0; 120 let rootList: Array<DmaFenceStringBean> = this.convertString([root]); 121 return rootList; 122 } 123 124 private convertString(data: Array<DmaFenceTreeBean>): Array<DmaFenceStringBean> { 125 const result: Array<DmaFenceStringBean> = []; 126 data.forEach(item => { 127 const stringBean: DmaFenceStringBean = { 128 name: item.name, 129 dur: item.dur.toFixed(3), 130 average: item.average.toFixed(3), 131 occurrences: String(item.occurrences), 132 children: item.children ? this.convertString(item.children) : undefined, 133 status: item.status 134 }; 135 result.push(stringBean); 136 }); 137 return result; 138 } 139 140 private sortByColumn(key: string, type: number, isExpand: boolean): void { 141 let sortObject = JSON.parse(JSON.stringify(this.finaldmaFenceData)); 142 let sortList: Array<DmaFenceStringBean> = []; 143 sortList.push(sortObject[0]); 144 if (type === 0) { 145 this.dmaFenceTbl!.recycleDataSource = this.finaldmaFenceData; 146 this.expandFunction(isExpand, this.finaldmaFenceData); 147 return; 148 } else { 149 sortList.forEach((item) => { 150 if (item.children) { 151 item.children.forEach((child) => { 152 if (child.children) { 153 child.children.sort((a, b) => { 154 let aValue: number | string; 155 let bValue: number | string; 156 if (key === 'name') { 157 aValue = a[key]; 158 bValue = b[key]; 159 } else { 160 // @ts-ignore 161 aValue = parseFloat(a[key]); 162 // @ts-ignore 163 bValue = parseFloat(b[key]); 164 } 165 if (typeof aValue === 'string' && typeof bValue === 'string') { 166 return type === 1 ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue); 167 } else if (typeof aValue === 'number' && typeof bValue === 'number') { 168 return type === 1 ? aValue - bValue : bValue - aValue; 169 } else { 170 return 0; 171 } 172 }); 173 } 174 }); 175 } 176 }); 177 this.dmaFenceTbl!.recycleDataSource = sortList; 178 this.expandFunction(isExpand, sortList); 179 } 180 } 181 182 private expandFunction(isExpand: boolean, list: Array<DmaFenceStringBean>): void { 183 if (isExpand) { 184 this.dmaFenceTbl!.setStatus(list, true); 185 this.dmaFenceTbl!.recycleDs = this.dmaFenceTbl!.meauseTreeRowElement(list, RedrawTreeForm.Expand); 186 } 187 } 188 189 initElements(): void { 190 this.dmaFenceTbl = this.shadowRoot?.querySelector<LitTable>('#tb-dmafence-slices'); 191 this.timeSelection = this.shadowRoot?.querySelector('#time-selection'); 192 this.dmaFenceTbl!.addEventListener('column-click', (evt) => { 193 // @ts-ignore 194 this.sortKey = evt.detail.key; 195 // @ts-ignore 196 this.sortType = evt.detail.sort; 197 // @ts-ignore 198 this.sortByColumn(evt.detail.key, evt.detail.sort, true); 199 }); 200 } 201 202 connectedCallback(): void { 203 super.connectedCallback(); 204 resizeObserver(this.parentElement!, this.dmaFenceTbl!); 205 } 206 207 initHtml(): string { 208 return ` 209 <style> 210 .dmafence-select-label{ 211 margin-bottom: 5px; 212 } 213 :host{ 214 padding: 10px 10px; 215 display: flex; 216 flex-direction: column; 217 } 218 </style> 219 <label id="time-selection" class="dmafence-select-label" style="width: 100%;height: 20px;text-align: end;font-size: 10pt;">Selection start:0.0 ms Selection extent:0.0 ms</label> 220 <lit-table id="tb-dmafence-slices" style="height: auto; overflow-x:auto;width:calc(100vw - 270px)" tree> 221 <lit-table-column order class="dmafence-slices-column" width='25%' title="Name" data-index="name" key="name" align="flex-start" retract> 222 </lit-table-column> 223 <lit-table-column order class="dmafence-slices-column" width='1fr' title="Wall Duration(ms)" data-index="dur" key="dur" align="flex-start"> 224 </lit-table-column> 225 <lit-table-column order class="dmafence-slices-column" width='1fr' title="Average Wall Duration(ms)" data-index="average" key="average" align="flex-start"> 226 </lit-table-column> 227 <lit-table-column order class="dmafence-slices-column" width='1fr' title="Occurrences" data-index="occurrences" key="occurrences" align="flex-start"> 228 </lit-table-column> 229 </lit-table> 230 `; 231 } 232 233}