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 */ 15import { element } from '../../../../../base-ui/BaseElement'; 16import { type LitSelect } from '../../../../../base-ui/select/LitSelect'; 17import { LitSelectOption } from '../../../../../base-ui/select/LitSelectOption'; 18import { type LitTable } from '../../../../../base-ui/table/lit-table'; 19import { type SnapshotStruct } from '../../../../database/ui-worker/ProcedureWorkerSnapshot'; 20import { VmTrackerChart } from '../../../chart/SpVmTrackerChart'; 21import { compare, CompareStruct, resizeObserverFromMemory } from '../SheetUtils'; 22import '../TabPaneJsMemoryFilter'; 23import { type TabPaneJsMemoryFilter } from '../TabPaneJsMemoryFilter'; 24import { TabPaneGpuClickSelect } from './TabPaneGpuClickSelect'; 25import { queryGpuDataByTs } from '../../../../database/sql/Gpu.sql'; 26interface GpuTreeItem { 27 name: string; 28 id: number; 29 size: number; 30 sizeStr: string; 31 children?: GpuTreeItem[] | undefined; 32} 33@element('tabpane-gpu-click-select-comparison') 34export class TabPaneGpuClickSelectComparison extends TabPaneGpuClickSelect { 35 private comparisonSelect: TabPaneJsMemoryFilter | null | undefined; 36 private selectEl: LitSelect | null | undefined; 37 private gpuComparisonTbl: LitTable | null | undefined; 38 private baseGpuData: Array<GpuDumpComparison> = []; 39 private gpuComparisonSource: Array<GpuTreeItem> = []; 40 private comparisonSortData: Array<GpuTreeItem> = []; 41 42 initElements(): void { 43 this.gpuComparisonTbl = this.shadowRoot?.querySelector<LitTable>('#tb-gpu'); 44 this.comparisonSelect = this.shadowRoot?.querySelector('#filter') as TabPaneJsMemoryFilter; 45 this.selectEl = this.comparisonSelect?.shadowRoot?.querySelector<LitSelect>('lit-select'); 46 this.gpuComparisonTbl!.addEventListener('column-click', (e) => { 47 // @ts-ignore 48 this.sortGpuByColumn(e.detail.key, e.detail.sort); 49 }); 50 } 51 connectedCallback(): void { 52 super.connectedCallback(); 53 resizeObserverFromMemory(this.parentElement!, this.gpuComparisonTbl!, this.comparisonSelect!); 54 } 55 async queryDataByDB(type: string, startTs: number): Promise<unknown> { 56 let gpuData: Array<unknown> = []; 57 let window = type === 'total' ? 0 : VmTrackerChart.gpuWindow; 58 let module = type === 'total' ? VmTrackerChart.gpuTotalModule : VmTrackerChart.gpuWindowModule; 59 await queryGpuDataByTs(startTs, window || 0, module).then((result) => { 60 gpuData = result; 61 }); 62 return gpuData; 63 } 64 async getGpuClickDataByDB(type: string, startTs: number, dataList: Array<SnapshotStruct>): Promise<void> { 65 const dataArray = []; 66 let td = this.gpuComparisonTbl!.shadowRoot!.querySelector('.thead')?.firstChild?.firstChild as HTMLDivElement; 67 let title = type === 'total' ? 'Module / Category' : 'Window / Module / Category'; 68 let titleArr = title.split('/'); 69 if (td) { 70 let labelEls = td.querySelectorAll('label'); 71 if (labelEls) { 72 for (let el of labelEls) { 73 td.removeChild(el); 74 } 75 } 76 for (let i = 0; i < titleArr.length; i++) { 77 let label = document.createElement('label'); 78 label.style.cursor = 'pointer'; 79 i == 0 ? (label.innerHTML = titleArr[i]) : (label.innerHTML = '/' + titleArr[i]); 80 td.appendChild(label); 81 } 82 } 83 //@ts-ignore 84 this.gpuComparisonTbl?.shadowRoot?.querySelector('.table')?.style?.height = 85 this.parentElement!.clientHeight - 45 + 'px'; 86 this.gpuComparisonTbl!.loading = true; 87 this.baseGpuData = []; 88 let baseGpuData = await this.queryDataByDB(type, startTs); 89 // @ts-ignore 90 for (const item of baseGpuData) { 91 this.baseGpuData.push( 92 new GpuDumpComparison(item.windowNameId, item.windowId, item.moduleId, item.categoryId, item.size) 93 ); 94 } 95 for (let item of dataList) { 96 if (item.startNs !== startTs) { 97 dataArray.push(item); 98 } 99 } 100 this.selectStamps(dataArray, type); 101 this.getComparisonData(dataArray[0].startNs, type); 102 } 103 selectStamps(gpuSelectComList: Array<SnapshotStruct>, type: string): void { 104 let input = this.selectEl!.shadowRoot?.querySelector('input') as HTMLInputElement; 105 this.selectEl!.innerHTML = ''; 106 let option = new LitSelectOption(); 107 option.innerHTML = 'File Name'; 108 option.setAttribute('disabled', 'disabled'); 109 this.selectEl?.appendChild(option); 110 if (gpuSelectComList[0].name) { 111 option.setAttribute('value', gpuSelectComList[0].name); 112 } 113 option.setAttribute('value', gpuSelectComList[0].name); 114 this.selectEl!.defaultValue = gpuSelectComList[0].name || ''; 115 this.selectEl!.placeholder = gpuSelectComList[0].name || ''; 116 this.selectEl!.dataSource = gpuSelectComList; 117 this.selectEl!.querySelectorAll('lit-select-option').forEach((option) => { 118 option.addEventListener('onSelected', async (e) => { 119 for (let f of gpuSelectComList) { 120 if (input.value === f.name) { 121 this.getComparisonData(f.startNs, type); 122 } 123 } 124 e.stopPropagation(); 125 }); 126 }); 127 } 128 async getComparisonData(targetStartNs: number, type: string): Promise<void> { 129 let comparisonData: Array<GpuDumpComparison> = []; 130 let targetGpuData: Array<GpuDumpComparison> = []; 131 let data = await this.queryDataByDB(type, targetStartNs); 132 // @ts-ignore 133 for (const item of data) { 134 targetGpuData.push( 135 new GpuDumpComparison(item.windowNameId, item.windowId, item.moduleId, item.categoryId, item.size) 136 ); 137 } 138 comparisonData = compare(this.baseGpuData!, targetGpuData); 139 for (const item of comparisonData) { 140 item.size = item.value; 141 } 142 let items = this.createTreeData(comparisonData); 143 // @ts-ignore 144 this.gpuComparisonSource = (type === 'total' ? items[0].children : items) || []; 145 this.comparisonSortData = this.gpuComparisonSource; 146 this.gpuComparisonTbl!.recycleDataSource = this.gpuComparisonSource; 147 let labels = this.gpuComparisonTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); 148 this.theadClick(this.gpuComparisonTbl!, this.gpuComparisonSource); 149 this.gpuComparisonTbl!.loading = false; 150 } 151 152 sortGpuByColumn(column: string, sort: number): void { 153 switch (sort) { 154 case 0: 155 this.gpuComparisonTbl!.recycleDataSource = this.comparisonSortData; 156 break; 157 default: 158 let array = [...this.comparisonSortData]; 159 switch (column) { 160 case 'name': 161 this.gpuComparisonTbl!.recycleDataSource = array.sort((gpuComparisonLeftData, gpuComparisonRightData) => { 162 return sort === 1 163 ? `${gpuComparisonLeftData.name}`.localeCompare(`${gpuComparisonRightData.name}`) 164 : `${gpuComparisonRightData.name}`.localeCompare(`${gpuComparisonLeftData.name}`); 165 }); 166 break; 167 case 'sizeDelta': 168 this.gpuComparisonTbl!.recycleDataSource = array.sort((gpuComparisonLeftData, gpuComparisonRightData) => { 169 return sort === 1 170 ? gpuComparisonLeftData.size - gpuComparisonRightData.size 171 : gpuComparisonRightData.size - gpuComparisonLeftData.size; 172 }); 173 break; 174 } 175 break; 176 } 177 } 178 179 initHtml(): string { 180 return ` 181 <style> 182 :host{ 183 display: flex; 184 flex-direction: column; 185 padding: 10px 10px; 186 } 187 </style> 188 <lit-table id="tb-gpu" style="height: auto" tree> 189 <lit-table-column width="50%" title="" data-index="name" key="name" align="flex-start" order retract> 190 </lit-table-column> 191 <lit-table-column width="1fr" title="SizeDelta" data-index="sizeStr" key="sizeDelta" align="flex-start" order> 192 </lit-table-column> 193 </lit-table> 194 <tab-pane-js-memory-filter id="filter" first hideFilter ></tab-pane-js-memory-filter> 195 `; 196 } 197} 198export class GpuDumpComparison extends CompareStruct { 199 windowNameId: number = -1; 200 windowId: number = -1; 201 moduleId: number = -1; 202 categoryId: number = -1; 203 size: number = -1; 204 constructor(windowNameId: number, windowId: number, moduleId: number, categoryId: number, value: number) { 205 super(`${windowNameId}` + '' + `${windowId}` + '' + `${moduleId}` + '' + `${categoryId}`, value); 206 this.windowNameId = windowNameId; 207 this.moduleId = moduleId; 208 this.windowId = windowId; 209 this.categoryId = categoryId; 210 } 211 clone(isBase?: boolean): GpuDumpComparison { 212 const value = isBase ? this.value : -this.value; 213 return new GpuDumpComparison(this.windowNameId, this.windowId, this.moduleId, this.categoryId, value); 214 } 215} 216