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<any> { 56 let gpuData: Array<any> = []; 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 for (const item of baseGpuData) { 90 this.baseGpuData.push( 91 new GpuDumpComparison(item.windowNameId, item.windowId, item.moduleId, item.categoryId, item.size) 92 ); 93 } 94 for (let item of dataList) { 95 if (item.startNs !== startTs) { 96 dataArray.push(item); 97 } 98 } 99 this.selectStamps(dataArray, type); 100 this.getComparisonData(dataArray[0].startNs, type); 101 } 102 selectStamps(gpuSelectComList: Array<SnapshotStruct>, type: string): void { 103 let input = this.selectEl!.shadowRoot?.querySelector('input') as HTMLInputElement; 104 this.selectEl!.innerHTML = ''; 105 let option = new LitSelectOption(); 106 option.innerHTML = 'File Name'; 107 option.setAttribute('disabled', 'disabled'); 108 this.selectEl?.appendChild(option); 109 if (gpuSelectComList[0].name) { 110 option.setAttribute('value', gpuSelectComList[0].name); 111 } 112 option.setAttribute('value', gpuSelectComList[0].name); 113 this.selectEl!.defaultValue = gpuSelectComList[0].name || ''; 114 this.selectEl!.placeholder = gpuSelectComList[0].name || ''; 115 this.selectEl!.dataSource = gpuSelectComList; 116 this.selectEl!.querySelectorAll('lit-select-option').forEach((option) => { 117 option.addEventListener('onSelected', async (e) => { 118 for (let f of gpuSelectComList) { 119 if (input.value === f.name) { 120 this.getComparisonData(f.startNs, type); 121 } 122 } 123 e.stopPropagation(); 124 }); 125 }); 126 } 127 async getComparisonData(targetStartNs: number, type: string): Promise<void> { 128 let comparisonData: Array<GpuDumpComparison> = []; 129 let targetGpuData: Array<GpuDumpComparison> = []; 130 let data = await this.queryDataByDB(type, targetStartNs); 131 for (const item of data) { 132 targetGpuData.push( 133 new GpuDumpComparison(item.windowNameId, item.windowId, item.moduleId, item.categoryId, item.size) 134 ); 135 } 136 comparisonData = compare(this.baseGpuData!, targetGpuData); 137 for (const item of comparisonData) { 138 item.size = item.value; 139 } 140 let items = this.createTreeData(comparisonData); 141 this.gpuComparisonSource = (type === 'total' ? items[0].children : items) || []; 142 this.comparisonSortData = this.gpuComparisonSource; 143 this.gpuComparisonTbl!.recycleDataSource = this.gpuComparisonSource; 144 let labels = this.gpuComparisonTbl?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); 145 this.theadClick(this.gpuComparisonTbl!, this.gpuComparisonSource); 146 this.gpuComparisonTbl!.loading = false; 147 } 148 149 sortGpuByColumn(column: string, sort: number): void { 150 switch (sort) { 151 case 0: 152 this.gpuComparisonTbl!.recycleDataSource = this.comparisonSortData; 153 break; 154 default: 155 let array = [...this.comparisonSortData]; 156 switch (column) { 157 case 'name': 158 this.gpuComparisonTbl!.recycleDataSource = array.sort((gpuComparisonLeftData, gpuComparisonRightData) => { 159 return sort === 1 160 ? `${gpuComparisonLeftData.name}`.localeCompare(`${gpuComparisonRightData.name}`) 161 : `${gpuComparisonRightData.name}`.localeCompare(`${gpuComparisonLeftData.name}`); 162 }); 163 break; 164 case 'sizeDelta': 165 this.gpuComparisonTbl!.recycleDataSource = array.sort((gpuComparisonLeftData, gpuComparisonRightData) => { 166 return sort === 1 167 ? gpuComparisonLeftData.size - gpuComparisonRightData.size 168 : gpuComparisonRightData.size - gpuComparisonLeftData.size; 169 }); 170 break; 171 } 172 break; 173 } 174 } 175 176 initHtml(): string { 177 return ` 178 <style> 179 :host{ 180 display: flex; 181 flex-direction: column; 182 padding: 10px 10px; 183 } 184 </style> 185 <lit-table id="tb-gpu" style="height: auto" tree> 186 <lit-table-column width="50%" title="" data-index="name" key="name" align="flex-start" order retract> 187 </lit-table-column> 188 <lit-table-column width="1fr" title="SizeDelta" data-index="sizeStr" key="sizeDelta" align="flex-start" order> 189 </lit-table-column> 190 </lit-table> 191 <tab-pane-js-memory-filter id="filter" first hideFilter ></tab-pane-js-memory-filter> 192 `; 193 } 194} 195export class GpuDumpComparison extends CompareStruct { 196 windowNameId: number = -1; 197 windowId: number = -1; 198 moduleId: number = -1; 199 categoryId: number = -1; 200 size: number = -1; 201 constructor(windowNameId: number, windowId: number, moduleId: number, categoryId: number, value: number) { 202 super(`${windowNameId}` + '' + `${windowId}` + '' + `${moduleId}` + '' + `${categoryId}`, value); 203 this.windowNameId = windowNameId; 204 this.moduleId = moduleId; 205 this.windowId = windowId; 206 this.categoryId = categoryId; 207 } 208 clone(isBase?: boolean): GpuDumpComparison { 209 const value = isBase ? this.value : -this.value; 210 return new GpuDumpComparison(this.windowNameId, this.windowId, this.moduleId, this.categoryId, value); 211 } 212} 213