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 { BaseElement, element } from '../../../../../base-ui/BaseElement'; 16import { RedrawTreeForm, type LitTable } from '../../../../../base-ui/table/lit-table'; 17import { resizeObserver } from '../SheetUtils'; 18import { VmTrackerChart } from '../../../chart/SpVmTrackerChart'; 19import { log } from '../../../../../log/Log'; 20import { SpSystemTrace } from '../../../SpSystemTrace'; 21import { Utils } from '../../base/Utils'; 22import { queryGpuDataByTs } from '../../../../database/sql/Gpu.sql'; 23interface GpuTreeItem { 24 name: string; 25 id: number; 26 size: number; 27 sizeStr: string; 28 children?: GpuTreeItem[] | undefined; 29} 30 31@element('tabpane-gpu-click-select') 32export class TabPaneGpuClickSelect extends BaseElement { 33 private gpuTbl: LitTable | null | undefined; 34 private gpuSource: Array<GpuTreeItem> = []; 35 gpuClickData(gpu: { type: string; startTs: number }): void { 36 let td = this.gpuTbl!.shadowRoot!.querySelector('.thead')?.firstChild?.firstChild as HTMLDivElement; 37 let title = gpu.type === 'total' ? 'Module / Category' : 'Window / Module / Category'; 38 let titleArr = title.split('/'); 39 if (td) { 40 let labelEls = td.querySelectorAll('label'); 41 if (labelEls) { 42 for (let el of labelEls) { 43 td.removeChild(el); 44 } 45 } 46 for (let i = 0; i < titleArr.length; i++) { 47 let label = document.createElement('label'); 48 label.style.cursor = 'pointer'; 49 i === 0 ? (label.innerHTML = titleArr[i]) : (label.innerHTML = '/' + titleArr[i]); 50 td.appendChild(label); 51 } 52 } 53 //@ts-ignore 54 this.gpuTbl?.shadowRoot?.querySelector('.table')?.style?.height = this.parentElement!.clientHeight - 45 + 'px'; 55 this.gpuTbl!.loading = true; 56 let window = gpu.type === 'total' ? 0 : VmTrackerChart.gpuWindow; 57 let module = gpu.type === 'total' ? VmTrackerChart.gpuTotalModule : VmTrackerChart.gpuWindowModule; 58 queryGpuDataByTs(gpu.startTs, window || 0, module).then((result) => { 59 this.gpuTbl!.loading = false; 60 if (result !== null && result.length > 0) { 61 log('queryGpuDataByTs result size : ' + result.length); 62 let items = this.createTreeData(result); 63 // @ts-ignore 64 this.gpuSource = (gpu.type === 'total' ? items[0].children : items) || []; 65 this.gpuTbl!.recycleDataSource = this.gpuSource; 66 this.theadClick(this.gpuTbl!, this.gpuSource); 67 } else { 68 this.gpuSource = []; 69 this.gpuTbl!.recycleDataSource = []; 70 } 71 }); 72 } 73 protected createTreeData(result: unknown): Array<unknown> { 74 // @ts-ignore 75 let gpuDataObj = result.reduce( 76 ( 77 group: unknown, 78 item: { categoryId: number; size: number; windowNameId: number; moduleId: number; windowId: unknown } 79 ) => { 80 let categoryItem: GpuTreeItem = this.setGpuTreeItem(item); 81 // @ts-ignore 82 if (group[`${item.windowNameId}(${item.windowId})`]) { 83 // @ts-ignore 84 let windowGroup = group[`${item.windowNameId}(${item.windowId})`] as GpuTreeItem; 85 windowGroup.size += item.size; 86 windowGroup.sizeStr = Utils.getBinaryByteWithUnit(windowGroup.size); 87 let moduleGroup = windowGroup.children!.find((it) => it.id === item.moduleId); 88 if (moduleGroup) { 89 moduleGroup.size += item.size; 90 moduleGroup.sizeStr = Utils.getBinaryByteWithUnit(moduleGroup.size); 91 moduleGroup.children?.push(categoryItem); 92 } else { 93 windowGroup.children?.push({ 94 name: SpSystemTrace.DATA_DICT.get(item.moduleId) || 'null', 95 id: item.moduleId, 96 size: item.size, 97 sizeStr: Utils.getBinaryByteWithUnit(item.size), 98 children: [categoryItem], 99 }); 100 } 101 } else { 102 // @ts-ignore 103 group[`${item.windowNameId}(${item.windowId})`] = { 104 name: SpSystemTrace.DATA_DICT.get(item.windowNameId) + `(${item.windowId})`, 105 id: item.windowNameId, 106 size: item.size, 107 sizeStr: Utils.getBinaryByteWithUnit(item.size), 108 children: [ 109 { 110 name: SpSystemTrace.DATA_DICT.get(item.moduleId), 111 id: item.moduleId, 112 size: item.size, 113 sizeStr: Utils.getBinaryByteWithUnit(item.size), 114 children: [categoryItem], 115 }, 116 ], 117 }; 118 } 119 return group; 120 }, 121 {} 122 ); 123 return Object.values(gpuDataObj) as GpuTreeItem[]; 124 } 125 126 private setGpuTreeItem(item: unknown): GpuTreeItem { 127 return { 128 // @ts-ignore 129 name: SpSystemTrace.DATA_DICT.get(item.categoryId) || 'null', 130 // @ts-ignore 131 id: item.categoryId, 132 // @ts-ignore 133 size: item.size, 134 // @ts-ignore 135 sizeStr: Utils.getBinaryByteWithUnit(item.size), 136 }; 137 } 138 initElements(): void { 139 this.gpuTbl = this.shadowRoot?.querySelector<LitTable>('#tb-gpu'); 140 this.gpuTbl!.addEventListener('column-click', (evt: unknown) => { 141 // @ts-ignore 142 this.sortByColumn(evt.detail); 143 }); 144 } 145 connectedCallback(): void { 146 super.connectedCallback(); 147 this.parentElement!.style.overflow = 'hidden'; 148 resizeObserver(this.parentElement!, this.gpuTbl!, 18); 149 } 150 public theadClick(table: LitTable, data: Array<unknown>): void { 151 let labels = table?.shadowRoot?.querySelector('.th > .td')!.querySelectorAll('label'); 152 if (labels) { 153 for (let i = 0; i < labels.length; i++) { 154 let label = labels[i].innerHTML; 155 labels[i].addEventListener('click', (e) => { 156 if ((label.includes('Window') && i === 0) || (label.includes('Module') && i === 0)) { 157 table!.setStatus(data, false); 158 table!.recycleDs = table!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 159 } else if (label.includes('Module') && i === 1) { 160 table!.setStatus(data, false, 0, 1); 161 table!.recycleDs = table!.meauseTreeRowElement(data, RedrawTreeForm.Retract); 162 } else if ((label.includes('Category') && i === 2) || (label.includes('Category') && i === 1)) { 163 table!.setStatus(data, true); 164 table!.recycleDs = table!.meauseTreeRowElement(data, RedrawTreeForm.Expand); 165 } 166 e.stopPropagation(); 167 }); 168 } 169 } 170 } 171 initHtml(): string { 172 return ` 173 <style> 174 :host{ 175 display: flex; 176 flex-direction: column; 177 padding: 10px 10px; 178 } 179 </style> 180 <lit-table id="tb-gpu" style="height: auto" tree> 181 <lit-table-column width="50%" title="" data-index="name" key="name" align="flex-start" order retract> 182 </lit-table-column> 183 <lit-table-column width="1fr" title="Size" data-index="sizeStr" key="sizeStr" align="flex-start" order> 184 </lit-table-column> 185 </lit-table> 186 `; 187 } 188 sortByColumn(gpuDetail: unknown): void { 189 let compare = (gpuA: GpuTreeItem, gpuB: GpuTreeItem): number => { 190 // @ts-ignore 191 if (gpuDetail.sort === 0) { 192 return gpuA.size - gpuB.size; 193 // @ts-ignore 194 } else if (gpuDetail.sort === 1) { 195 return gpuA.size - gpuB.size; 196 } else { 197 return gpuB.size - gpuA.size; 198 } 199 }; 200 let deepCompare = (arr: GpuTreeItem[]): void => { 201 arr.forEach((it) => { 202 if (it.children) { 203 deepCompare(it.children); 204 } 205 }); 206 arr.sort(compare); 207 }; 208 deepCompare(this.gpuSource); 209 this.gpuTbl!.recycleDataSource = this.gpuSource; 210 } 211} 212