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 { LitSelect } from '../../../../../base-ui/select/LitSelect.js'; 18import { LitSelectOption } from '../../../../../base-ui/select/LitSelectOption.js'; 19import { LitTable } from '../../../../../base-ui/table/lit-table.js'; 20import { GpuMemoryComparison } from '../../../../bean/AbilityMonitor.js'; 21import { MemoryConfig } from '../../../../bean/MemoryConfig.js'; 22import { getTabGpuMemoryVmTrackerComparisonData } from '../../../../database/SqlLite.js'; 23import { SnapshotStruct } from '../../../../database/ui-worker/ProcedureWorkerSnapshot.js'; 24import { SpSystemTrace } from '../../../SpSystemTrace.js'; 25import { Utils } from '../../base/Utils.js'; 26import { compare, resizeObserverFromMemory } from '../SheetUtils.js'; 27import '../TabPaneJsMemoryFilter.js'; 28import { TabPaneJsMemoryFilter } from '../TabPaneJsMemoryFilter.js'; 29 30@element('tabpane-gpu-memory-vmtracker-comparison') 31export class TabPaneGpuMemoryVmTrackerComparison extends BaseElement { 32 private gpuMemoryClickTable: LitTable | null | undefined; 33 private comparisonSelect: TabPaneJsMemoryFilter | null | undefined; 34 private selectEl: LitSelect | null | undefined; 35 private selfData = new Array<GpuMemoryComparison>(); 36 private comparisonSource: Array<GpuMemoryComparison> = []; 37 38 initElements(): void { 39 this.gpuMemoryClickTable = this.shadowRoot?.querySelector<LitTable>('#gpuMemoryClickTable'); 40 this.selectEl = this.comparisonSelect?.shadowRoot?.querySelector<LitSelect>('lit-select'); 41 this.comparisonSelect = this.shadowRoot?.querySelector('#filter') as TabPaneJsMemoryFilter; 42 this.gpuMemoryClickTable!.addEventListener('column-click', (e) => { 43 // @ts-ignore 44 this.sortGpuMemoryByColumn(e.detail.key, e.detail.sort); 45 }); 46 } 47 48 connectedCallback(): void { 49 super.connectedCallback(); 50 resizeObserverFromMemory(this.parentElement!, this.gpuMemoryClickTable!, this.comparisonSelect!); 51 } 52 53 async queryDataByDB(startNs: number): Promise<GpuMemoryComparison[]> { 54 let timeStampData: Array<GpuMemoryComparison> = []; 55 await getTabGpuMemoryVmTrackerComparisonData(startNs, MemoryConfig.getInstance().iPid).then((data) => { 56 data.forEach((item) => { 57 if (item.threadName !== null) { 58 item.thread = `${item.threadName}(${item.threadId})`; 59 } else { 60 item.thread = `Thread(${item.threadId})`; 61 } 62 item.gpuName = SpSystemTrace.DATA_DICT.get(item.gpuNameId as number) || '-'; 63 }); 64 timeStampData = data; 65 }); 66 return timeStampData; 67 } 68 69 async comparisonDataByDB(startNs: number, dataList: Array<SnapshotStruct>): Promise<void> { 70 this.selfData = []; 71 const selfData = await this.queryDataByDB(startNs); 72 const dataArray = []; 73 for (const item of selfData) { 74 this.selfData.push(new GpuMemoryComparison('', item.thread, item.gpuName, item.value)); 75 } 76 for (let item of dataList) { 77 if (item.startNs !== startNs) { 78 dataArray.push(item); 79 } 80 } 81 this.selectStamps(dataArray); 82 this.getComparisonData(dataArray[0].startNs); 83 } 84 85 selectStamps(dataList: Array<SnapshotStruct>): void { 86 let input = this.selectEl!.shadowRoot?.querySelector('input') as HTMLInputElement; 87 this.selectEl!.innerHTML = ''; 88 let option = new LitSelectOption(); 89 option.innerHTML = 'File Name'; 90 option.setAttribute('disabled', 'disabled'); 91 this.selectEl?.appendChild(option); 92 if (dataList[0].name) { 93 option.setAttribute('value', dataList[0].name); 94 } 95 option.setAttribute('value', dataList[0].name); 96 this.selectEl!.defaultValue = dataList[0].name || ''; 97 this.selectEl!.placeholder = dataList[0].name || ''; 98 this.selectEl!.dataSource = dataList; 99 this.selectEl!.querySelectorAll('lit-select-option').forEach((option) => { 100 option.addEventListener('onSelected', async (e) => { 101 for (let f of dataList) { 102 if (input.value === f.name) { 103 this.getComparisonData(f.startNs); 104 } 105 } 106 e.stopPropagation(); 107 }); 108 }); 109 } 110 111 async getComparisonData(targetStartNs: number) { 112 let comparisonData: GpuMemoryComparison[] = []; 113 let comparison: GpuMemoryComparison[] = []; 114 let data = await this.queryDataByDB(targetStartNs); 115 for (const item of data) { 116 comparison.push(new GpuMemoryComparison('', item.thread, item.gpuName, item.value)); 117 } 118 comparisonData = compare(this.selfData!, comparison); 119 for (const item of comparisonData) { 120 item.sizes = Utils.getBinaryByteWithUnit(item.value); 121 } 122 this.comparisonSource = comparisonData; 123 this.gpuMemoryClickTable!.recycleDataSource = comparisonData; 124 } 125 126 sortGpuMemoryByColumn(column: string, sort: number): void { 127 switch (sort) { 128 case 0: 129 this.gpuMemoryClickTable!.recycleDataSource = this.comparisonSource; 130 break; 131 default: 132 let array = [...this.comparisonSource]; 133 switch (column) { 134 case 'thread': 135 this.gpuMemoryClickTable!.recycleDataSource = array.sort( 136 (gpuMComparisonLeftData, gpuMComparisonRightData) => { 137 return sort === 1 138 ? `${gpuMComparisonLeftData.thread}`.localeCompare(`${gpuMComparisonRightData.thread}`) 139 : `${gpuMComparisonRightData.thread}`.localeCompare(`${gpuMComparisonLeftData.thread}`); 140 } 141 ); 142 break; 143 case 'gpuName': 144 this.gpuMemoryClickTable!.recycleDataSource = array.sort( 145 (gpuMCompVmLeftData, gpuMCompVmRightData) => { 146 return sort === 1 147 ? `${gpuMCompVmLeftData.gpuName}`.localeCompare(`${gpuMCompVmRightData.gpuName}`) 148 : `${gpuMCompVmRightData.gpuName}`.localeCompare(`${gpuMCompVmLeftData.gpuName}`); 149 } 150 ); 151 break; 152 case 'sizeDelta': 153 this.gpuMemoryClickTable!.recycleDataSource = array.sort( 154 (gpuMCompVmLeftData, gpuMCompVmRightData) => { 155 return sort === 1 156 ? gpuMCompVmLeftData.value - gpuMCompVmRightData.value 157 : gpuMCompVmRightData.value - gpuMCompVmLeftData.value; 158 } 159 ); 160 break; 161 } 162 break; 163 } 164 } 165 166 initHtml(): string { 167 return ` 168<style> 169.gpuMemoryClickTable{ 170 height: auto; 171} 172:host{ 173 display: flex; 174 flex-direction: column; 175 padding: 10px 10px; 176} 177</style> 178<lit-table id="gpuMemoryClickTable" class="gpuMemoryClickTable"> 179 <lit-table-column order title="GpuName" data-index="gpuName" key="gpuName" align="flex-start" width="1fr" > 180 </lit-table-column> 181 <lit-table-column order title="Thread(pid)" data-index="thread" key="thread" align="flex-start" width="1fr" > 182 </lit-table-column> 183 <lit-table-column order title="SizeDelta" data-index="sizes" key="size" align="flex-start" width="1fr" > 184 </lit-table-column> 185</lit-table> 186<tab-pane-js-memory-filter id="filter" first hideFilter ></tab-pane-js-memory-filter> 187 `; 188 } 189} 190