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 { querySysCallEventWithBoxSelect } from '../../../../database/sql/ProcessThread.sql'; 23import { Utils } from '../../base/Utils'; 24import { SysCallMap } from '../../base/SysCallUtils'; 25 26interface SysCallItem { 27 nameId: number; 28 name: string; 29 pName: string; 30 tName: string; 31 tid: number; 32 pid: number; 33 totalCount: number; 34 sumDur: number; 35 durStr?: string; 36} 37 38interface SysCallTreeItem { 39 name: string; 40 id: number; 41 parentId?: number; 42 totalCount: number; 43 sumDur: number; 44 durStr: string; 45 level: string; 46 children: SysCallTreeItem[] 47} 48 49@element('tabpane-syscall') 50export class TabPaneSysCall extends BaseElement { 51 private sysCallTbl: LitTable | null | undefined; 52 private range: HTMLLabelElement | null | undefined; 53 private sysCallSource: Array<SysCallTreeItem> = []; 54 private currentSelectionParam: SelectionParam | undefined; 55 56 set data(sysCallParam: SelectionParam | unknown) { 57 if (this.currentSelectionParam === sysCallParam) { 58 return; 59 } // @ts-ignore 60 this.currentSelectionParam = sysCallParam; 61 //@ts-ignore 62 this.sysCallTbl?.shadowRoot?.querySelector('.table')?.style?.height = `${this.parentElement!.clientHeight - 45}px`; // @ts-ignore 63 this.range!.textContent = `Selected range: ${((sysCallParam.rightNs - sysCallParam.leftNs) / 1000000.0).toFixed( 64 5 65 )} ms`; 66 this.sysCallTbl!.loading = true; 67 let ipidArr: number[] = []; 68 Array.from(Utils.getInstance().sysCallEventTidsMap.values()).forEach(it => { 69 //@ts-ignore 70 if (sysCallParam?.processSysCallIds?.includes(it.pid)) { 71 ipidArr.push(it.ipid); 72 } 73 }) 74 //@ts-ignore 75 querySysCallEventWithBoxSelect(ipidArr, sysCallParam.threadSysCallIds, sysCallParam.leftNs, sysCallParam.rightNs).then( 76 (retult) => { 77 this.flatternToTree(retult as SysCallItem[]); 78 } 79 ); 80 } 81 82 private flatternToTree(result: SysCallItem[]): void { 83 this.sysCallTbl!.loading = false; 84 if (result !== null && result.length > 0) { 85 log(`getTabsysCalls result size : ${result.length}`); 86 let map: Map<number, SysCallTreeItem> = new Map<number, SysCallTreeItem>(); 87 result.forEach((item) => { 88 item.name = SysCallMap.get(item.nameId) || ''; 89 item.durStr = getProbablyTime(item.sumDur); 90 this.processSysCallItem(item, map); 91 }); 92 let sysCalls: SysCallTreeItem[] = Array.from(map.values()); 93 this.sysCallSource = sysCalls; 94 this.sysCallTbl!.recycleDataSource = this.sysCallSource; 95 } else { 96 this.sysCallSource = []; 97 this.sysCallTbl!.recycleDataSource = []; 98 } 99 } 100 101 private processSysCallItem(item: SysCallItem, map: Map<number, SysCallTreeItem>): void { 102 const treeItem: SysCallTreeItem = { 103 id: item.nameId, 104 name: item.name, 105 level: 'SysCall', 106 parentId: item.tid, 107 totalCount: item.totalCount, 108 sumDur: item.sumDur, 109 durStr: item.durStr!, 110 children:[] 111 }; 112 let ps = map.get(item.pid!); 113 if (ps) { 114 ps.sumDur += item.sumDur || 0; 115 ps.durStr = getProbablyTime(ps.sumDur); 116 ps.totalCount += item.totalCount || 0; 117 let ts = ps.children?.find(it => it.id === item.tid); 118 if (ts) { 119 ts.sumDur += item.sumDur || 0; 120 ts.durStr = getProbablyTime(ts.sumDur); 121 ts.totalCount += item.totalCount || 0; 122 ts.children.push(treeItem); 123 } else { 124 ps.children.push({ 125 id: item.tid, 126 name: item.tName, 127 parentId: item.pid, 128 level: 'Thread', 129 totalCount: item.totalCount, 130 sumDur: item.sumDur, 131 durStr: item.durStr!, 132 children: [treeItem] 133 }) 134 } 135 } else { 136 map.set(item.pid!, { 137 id: item.pid, 138 level: 'Process', 139 name: `${item.pName} [${item.pid}]`, 140 totalCount: item.totalCount, 141 sumDur: item.sumDur, 142 durStr: item.durStr!, 143 children: [{ 144 id: item.tid, 145 level: 'Thread', 146 parentId: item.pid, 147 name: `${item.tName} [${item.tid}]`, 148 durStr: item.durStr!, 149 totalCount: item.totalCount, 150 sumDur: item.sumDur, 151 children: [treeItem] 152 }] 153 }); 154 } 155 } 156 157 initElements(): void { 158 this.sysCallTbl = this.shadowRoot?.querySelector<LitTable>('#tb-syscall'); 159 this.range = this.shadowRoot?.querySelector('#syscall-time-range'); 160 this.sysCallTbl!.addEventListener('column-click', (evt: unknown) => { 161 // @ts-ignore 162 this.sortByColumn(evt.detail); 163 }); 164 } 165 166 connectedCallback(): void { 167 super.connectedCallback(); 168 resizeObserver(this.parentElement!, this.sysCallTbl!); 169 } 170 171 initHtml(): string { 172 return ` 173 <style> 174 .syscall-table{ 175 flex-direction: row; 176 margin-bottom: 5px; 177 } 178 :host{ 179 display: flex; 180 flex-direction: column; 181 padding: 10px 10px; 182 } 183 </style> 184 <div class="syscall-table" style="display: flex;height: 20px;align-items: center; 185 flex-direction: row;margin-bottom: 5px"> 186 <div style="flex: 1"></div> 187 <label id="syscall-time-range" style="width: auto;text-align: end;font-size: 10pt;"> 188 Selected range:0.0 ms</label> 189 </div> 190 <div style="overflow: auto"> 191 <lit-table id="tb-syscall" style="height: auto" tree > 192 <lit-table-column width="600px" title="Process / Thread / SysCall" data-index="name" 193 key="name" align="flex-start" retract> 194 </lit-table-column> 195 <lit-table-column width="200px" title="Duration" data-index="durStr" 196 key="durStr" align="flex-start" order > 197 </lit-table-column> 198 <lit-table-column width="200px" title="Count" data-index="totalCount" 199 key="totalCount" align="flex-start" order tdJump> 200 </lit-table-column> 201 </lit-table> 202 </div> 203 `; 204 } 205 206 sortByColumn(sortDetail: unknown): void { 207 let compare = (itemA: SysCallTreeItem, itemB: SysCallTreeItem): number => { 208 // @ts-ignore 209 if (sortDetail.key === 'durStr') { 210 // @ts-ignore 211 if (sortDetail.sort === 0) { 212 return itemA.sumDur - itemB.sumDur; // @ts-ignore 213 } else if (sortDetail.sort === 1) { 214 return itemA.sumDur - itemB.sumDur; 215 } else { 216 return itemB.sumDur - itemA.sumDur; 217 } 218 } else { 219 // @ts-ignore 220 if (sortDetail.sort === 0) { 221 return itemA.totalCount - itemB.totalCount; // @ts-ignore 222 } else if (sortDetail.sort === 1) { 223 return itemA.totalCount - itemB.totalCount; 224 } else { 225 return itemB.totalCount - itemA.totalCount; 226 } 227 } 228 }; 229 this.sysCallSource.forEach((syscall) => { 230 syscall.children?.sort(compare); 231 }); 232 const deepSort = (arr: SysCallTreeItem[]) => { 233 arr.sort(compare); 234 arr.forEach(item => { 235 if (item.children) { 236 deepSort(item.children); 237 } 238 }) 239 }; 240 deepSort(this.sysCallSource); 241 this.sysCallTbl!.recycleDataSource = this.sysCallSource; 242 } 243} 244