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'; 17import { LitTable } from '../../../../../base-ui/table/lit-table'; 18import { SelectionParam } from '../../../../bean/BoxSelection'; 19import { log } from '../../../../../log/Log'; 20import { getProbablyTime } from '../../../../database/logic-worker/ProcedureLogicWorkerCommon'; 21import { resizeObserver } from '../SheetUtils'; 22import { AppStartupStruct } from '../../../../database/ui-worker/ProcedureWorkerAppStartup'; 23import { getTabStartups } from '../../../../database/sql/ProcessThread.sql'; 24 25interface StartupTreeItem { 26 name: string; 27 step: number; 28 dur: number; 29 durStr: string; 30 ratio: string; 31 children: StartupTreeItem[] | undefined; 32} 33 34@element('tabpane-startup') 35export class TabPaneStartup extends BaseElement { 36 private startupTbl: LitTable | null | undefined; 37 private range: HTMLLabelElement | null | undefined; 38 private startupSource: Array<StartupTreeItem> = []; 39 private currentSelectionParam: SelectionParam | undefined; 40 41 set data(startupParam: SelectionParam | unknown) { 42 if (this.currentSelectionParam === startupParam) { 43 return; 44 } // @ts-ignore 45 this.currentSelectionParam = startupParam; 46 //@ts-ignore 47 this.startupTbl?.shadowRoot?.querySelector('.table')?.style?.height = `${this.parentElement!.clientHeight - 45}px`; // @ts-ignore 48 this.range!.textContent = `Selected range: ${((startupParam.rightNs - startupParam.leftNs) / 1000000.0).toFixed( 49 5 50 )} ms`; 51 this.startupTbl!.loading = true; // @ts-ignore 52 getTabStartups(startupParam.processIds, startupParam.leftNs, startupParam.rightNs).then( 53 //@ts-ignore 54 (result: AppStartupStruct[]) => { 55 this.processTabStartups(result); 56 } 57 ); 58 } 59 60 private processTabStartups(result: AppStartupStruct[]): void { 61 this.startupTbl!.loading = false; 62 if (result !== null && result.length > 0) { 63 log(`getTabStartups result size : ${result.length}`); 64 let map: Map<number, StartupTreeItem> = new Map<number, StartupTreeItem>(); 65 result.forEach((item) => { 66 this.processStartupItem(item, map); 67 }); 68 let startups = Array.from(map.values()); 69 startups.forEach((it) => { 70 it.durStr = getProbablyTime(it.dur); 71 if (it.dur === 0) { 72 it.ratio = '0%'; 73 } 74 it.children!.forEach((child) => { 75 if (it.dur === 0) { 76 child.ratio = '0%'; 77 } else { 78 child.ratio = `${((child.dur * 100) / it.dur).toFixed(2)}%`; 79 } 80 }); 81 }); 82 this.startupSource = startups; 83 this.startupTbl!.recycleDataSource = this.startupSource; 84 } else { 85 this.startupSource = []; 86 this.startupTbl!.recycleDataSource = []; 87 } 88 } 89 90 private processStartupItem(item: AppStartupStruct, map: Map<number, StartupTreeItem>): void { 91 let startup = { 92 name: AppStartupStruct.getStartupName(item.startName), 93 dur: item.dur || 0, 94 durStr: getProbablyTime(item.dur || 0), 95 ratio: '0%', 96 step: item.startName || 0, 97 children: [], 98 }; 99 if (map.has(item.pid!)) { 100 let ps = map.get(item.pid!); 101 if (ps && ps.children) { 102 ps.dur += item.dur || 0; 103 ps.children!.push(startup); 104 } 105 } else { 106 map.set(item.pid!, { 107 name: item.process || `Process ${item.pid}`, 108 dur: item.dur || 0, 109 durStr: '', 110 ratio: '100%', 111 step: 0, 112 children: [startup], 113 }); 114 } 115 } 116 117 initElements(): void { 118 this.startupTbl = this.shadowRoot?.querySelector<LitTable>('#tb-startup'); 119 this.range = this.shadowRoot?.querySelector('#startup-time-range'); 120 this.startupTbl!.addEventListener('column-click', (evt: unknown) => { 121 // @ts-ignore 122 this.sortByColumn(evt.detail); 123 }); 124 } 125 126 connectedCallback(): void { 127 super.connectedCallback(); 128 resizeObserver(this.parentElement!, this.startupTbl!); 129 } 130 131 initHtml(): string { 132 return ` 133 <style> 134 .startup-table{ 135 flex-direction: row; 136 margin-bottom: 5px; 137 } 138 :host{ 139 display: flex; 140 flex-direction: column; 141 padding: 10px 10px; 142 } 143 </style> 144 <div class="startup-table" style="display: flex;height: 20px;align-items: center; 145 flex-direction: row;margin-bottom: 5px"> 146 <div style="flex: 1"></div> 147 <label id="startup-time-range" style="width: auto;text-align: end;font-size: 10pt;"> 148 Selected range:0.0 ms</label> 149 </div> 150 <div style="overflow: auto"> 151 <lit-table id="tb-startup" style="height: auto" tree > 152 <lit-table-column width="600px" title="Process / Startup" data-index="name" 153 key="name" align="flex-start" retract> 154 </lit-table-column> 155 <lit-table-column width="200px" title="Duration" data-index="durStr" 156 key="durStr" align="flex-start" order > 157 </lit-table-column> 158 <lit-table-column width="200px" title="%" data-index="ratio" 159 key="ratio" align="flex-start" order > 160 </lit-table-column> 161 </lit-table> 162 </div> 163 `; 164 } 165 166 sortByColumn(startupDetail: unknown): void { 167 let compare = (startupA: StartupTreeItem, startupB: StartupTreeItem): number => { 168 // @ts-ignore 169 if (startupDetail.sort === 0) { 170 return startupA.step - startupB.step; // @ts-ignore 171 } else if (startupDetail.sort === 1) { 172 return startupA.dur - startupB.dur; 173 } else { 174 return startupB.dur - startupA.dur; 175 } 176 }; 177 this.startupSource.forEach((startup) => { 178 startup.children?.sort(compare); 179 }); 180 this.startupSource.sort(compare); 181 this.startupTbl!.recycleDataSource = this.startupSource; 182 } 183} 184