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 { SelectionData, SelectionParam } from '../../../../bean/BoxSelection'; 19import { LitTableColumn } from '../../../../../base-ui/table/lit-table-column'; 20import { Utils } from '../../base/Utils'; 21import { SpSystemTrace } from '../../../SpSystemTrace'; 22import { TabUtil } from './TabUtil'; 23import { resizeObserver } from '../SheetUtils'; 24import { getTabSdkSliceData } from '../../../../database/sql/Sdk.sql'; 25import { queryTotalTime } from '../../../../database/sql/SqlLite.sql'; 26import { SdkSliceSummary } from '../../../../bean/SdkSummary.js'; 27 28@element('tabpane-sdk-slice') 29export class TabPaneSdkSlice extends BaseElement { 30 private tblSdkSlice: LitTable | null | undefined; 31 private sdkSliceRange: HTMLLabelElement | null | undefined; 32 private keyList: Array<string> | undefined; 33 private statDataArray: any = []; 34 private columnMap: any = {}; 35 private sqlMap: Map<number, string> = new Map<number, string>(); 36 37 set data(valSdkSlice: SelectionParam | any) { 38 let millisecond = 1000_000; 39 this.sdkSliceRange!.textContent = 40 'Selected range: ' + ((valSdkSlice.rightNs - valSdkSlice.leftNs) / millisecond).toFixed(5) + ' ms'; 41 this.queryDataByDB(valSdkSlice); 42 } 43 44 initElements(): void { 45 this.tblSdkSlice = this.shadowRoot?.querySelector<LitTable>('#tb-sdk-slice'); 46 this.sdkSliceRange = this.shadowRoot?.querySelector('#sdk-slice-time-range'); 47 this.tblSdkSlice!.addEventListener('column-click', (evt) => { 48 // @ts-ignore 49 this.sortByColumn(evt.detail); 50 }); 51 } 52 53 connectedCallback() { 54 super.connectedCallback(); 55 resizeObserver(this.parentElement!, this.tblSdkSlice!); 56 } 57 58 queryDataByDB(sdkSliceVal: SelectionParam | any) { 59 queryTotalTime().then((res) => { 60 let startTime = res[0].recordStartNS; 61 let totalTime = res[0].total; 62 let componentId: number = -1; 63 let slices: Array<string> = []; 64 for (let index = 0; index < sdkSliceVal.sdkSliceIds.length; index++) { 65 let values = sdkSliceVal.sdkSliceIds[index].split('-'); 66 let value = values[0]; 67 componentId = Number(values[1]); 68 slices.push(value); 69 } 70 this.parseJson(SpSystemTrace.SDK_CONFIG_MAP); 71 let sql = this.sqlMap.get(componentId); 72 if (sql == undefined) { 73 return; 74 } 75 getTabSdkSliceData(sql, startTime, sdkSliceVal.leftNs, sdkSliceVal.rightNs, slices, componentId).then( 76 (sliceItem) => { 77 this.keyList = []; 78 this.tblSdkSlice!.innerHTML = ''; 79 this.statDataArray = []; 80 if (sliceItem.length != null && sliceItem.length > 0) { 81 this.initSdkSliceData(sliceItem, totalTime, sdkSliceVal); 82 } else { 83 this.tblSdkSlice!.recycleDataSource = []; 84 } 85 this.initDataElement(); 86 87 setTimeout(() => { 88 this.tblSdkSlice!.recycleDataSource = this.statDataArray; 89 new ResizeObserver(() => { 90 if (this.parentElement?.clientHeight != 0) { 91 this.tblSdkSlice!.style.height = '100%'; 92 this.tblSdkSlice!.reMeauseHeight(); 93 } 94 }).observe(this.parentElement!); 95 }, 200); 96 } 97 ); 98 }); 99 } 100 101 initSdkSliceData(sliceItem: SdkSliceSummary[], totalTime: number, sdkSliceVal: SelectionParam | any): void { 102 for (let sliceItemIndex = 0; sliceItemIndex < sliceItem.length; sliceItemIndex++) { 103 const dataResult = sliceItem[sliceItemIndex]; 104 let keys = Object.keys(dataResult); 105 // @ts-ignore 106 let values = Object.values(dataResult); 107 let sliceJsonText = '{'; 108 for (let sliceKeyIndex = 0; sliceKeyIndex < keys.length; sliceKeyIndex++) { 109 let sliceKey = keys[sliceKeyIndex]; 110 if (this.keyList!.indexOf(sliceKey) <= -1) { 111 this.keyList!.push(sliceKey); 112 } 113 let sliceValue = values[sliceKeyIndex]; 114 if (this.columnMap[sliceKey] == 'TimeStamp') { 115 sliceValue = Utils.getTimeString(Number(sliceValue)); 116 } else if (this.columnMap[sliceKey] == 'ClockTime') { 117 sliceValue = Utils.getTimeStampHMS(Number(sliceValue)); 118 } else if (this.columnMap[sliceKey] == 'RangTime') { 119 sliceValue = Utils.getDurString(Number(sliceValue)); 120 } else if (this.columnMap[sliceKey] == 'PercentType') { 121 sliceValue = sliceValue + '%'; 122 } else if (this.columnMap[sliceKey] == 'CurrencyType') { 123 // @ts-ignore 124 sliceValue = sliceValue.toString().replace(/\B(?=(\d{3})+$)/g, ','); 125 } else if (this.columnMap[sliceKey] == 'FIXED') { 126 sliceValue = sliceValue.toFixed(2); 127 } 128 if (typeof sliceValue == 'string') { 129 sliceValue = sliceValue.replace(/</gi, '<').replace(/>/gi, '>'); 130 } 131 sliceJsonText += '"' + sliceKey + '"' + ': ' + '"' + sliceValue + '"'; 132 if (sliceKeyIndex != keys.length - 1) { 133 sliceJsonText += ','; 134 } else { 135 sliceJsonText += '}'; 136 } 137 } 138 let sliceParseData = JSON.parse(sliceJsonText); 139 if (sliceParseData.start_ts != null && sliceParseData.end_ts != null && 140 sliceParseData.start_ts > sliceParseData.end_ts && sliceParseData.end_ts == 0) { 141 sliceParseData.end_ts = totalTime; 142 } 143 if (this.isDateIntersection(sdkSliceVal.leftNs, sdkSliceVal.rightNs, 144 sliceParseData.start_ts, sliceParseData.end_ts)) { 145 this.statDataArray.push(sliceParseData); 146 } 147 } 148 this.tblSdkSlice!.recycleDataSource = this.statDataArray; 149 } 150 151 private isDateIntersection(selectStartTime: number, selectEndTime: number, startTime: number, endTime: number) { 152 if (selectStartTime > startTime && selectStartTime < endTime) { 153 return true; 154 } 155 if (selectEndTime > startTime && selectEndTime < endTime) { 156 return true; 157 } 158 if (selectStartTime < startTime && selectEndTime > endTime) { 159 return true; 160 } 161 return false; 162 } 163 164 parseJson(map: Map<number, string>): string { 165 for (let [key, value] of map) { 166 let sliceConfigObj: any = value; 167 if (sliceConfigObj !== undefined) { 168 let {jsonConfig} = sliceConfigObj; 169 let {tableConfig} = JSON.parse(jsonConfig); 170 if (tableConfig) { 171 for (let showType of tableConfig.showType) { 172 let innerTableName = this.getInnerTableName(showType); 173 let type = TabUtil.getTableType(showType); 174 if (type === 'slice') { 175 let sliceSelectSql = 'select '; 176 for (let {column, displayName, showType: columnShowType} of showType.columns) { 177 this.columnMap[column] = displayName; 178 if (columnShowType.includes(3)) { 179 switch (column) { 180 case 'slice_id': 181 sliceSelectSql += 'a.slice_id,b.slice_name,'; 182 break; 183 case 'start_ts': 184 case 'end_ts': 185 sliceSelectSql += `(a.${column} - $startTime) as ${column},`; 186 break; 187 default: 188 sliceSelectSql += `a.${column},`; 189 break; 190 } 191 } 192 } 193 let sliceSql = `${sliceSelectSql.slice(0, -1)} from ${showType.tableName} as a,${innerTableName} as b 194 where a.slice_id in ($slices) 195 and a.slice_id = b.slice_id 196 and ((a.start_ts - $startTime) >= $leftNs and (a.end_ts - $startTime) <= $rightNs 197 or (a.start_ts - $startTime) <= $leftNs and $leftNs <= (a.end_ts - $startTime) 198 or (a.start_ts - $startTime) <= $rightNs and $rightNs <= (a.end_ts - $startTime))`; 199 this.sqlMap.set(key, sliceSql); 200 } 201 } 202 } 203 } 204 } 205 return ''; 206 } 207 208 initDataElement() { 209 if (this.keyList) { 210 this.keyList.forEach((sdkSliceItemKey) => { 211 let sdkSliceEl = document.createElement('lit-table-column') as LitTableColumn; 212 sdkSliceEl.setAttribute('title', sdkSliceItemKey); 213 sdkSliceEl.setAttribute('data-index', sdkSliceItemKey); 214 sdkSliceEl.setAttribute('key', sdkSliceItemKey); 215 sdkSliceEl.setAttribute('align', 'flex-start'); 216 if (sdkSliceItemKey === 'slice_id') { 217 sdkSliceEl.setAttribute('width', '0.5fr'); 218 } else { 219 sdkSliceEl.setAttribute('width', '1fr'); 220 } 221 sdkSliceEl.setAttribute('order', ''); 222 this.tblSdkSlice!.appendChild(sdkSliceEl); 223 }); 224 } 225 } 226 227 initHtml(): string { 228 return ` 229<style> 230.sdk-slice-table{ 231 height: 20px; 232 margin-bottom: 5px; 233} 234:host{ 235 padding: 10px 10px; 236 flex-direction: column; 237 display: flex; 238} 239</style> 240<div class="sdk-slice-content" class="sdk-slice-table" style="display: flex;align-items: center;flex-direction: row;"> 241 <stack-bar id="sdk-slice-stack-bar" style="flex: 1"></stack-bar> 242 <label id="sdk-slice-time-range" style="width: auto;text-align: end;font-size: 10pt;">Selected range:0.0 ms</label> 243 </div> 244<lit-table id="tb-sdk-slice" class="sdk-slice-tbl" style="height: auto"> 245</lit-table> 246 `; 247 } 248 249 sortByColumn(sliceDetail: any) { 250 // @ts-ignore 251 function compare(property, sliceSort, type) { 252 return function (aSdkSlice: SelectionData, bSdkSlice: SelectionData) { 253 if (aSdkSlice.process === ' ' || bSdkSlice.process === ' ') { 254 return 0; 255 } 256 if (type === 'number') { 257 return sliceSort === 2 258 ? // @ts-ignore 259 parseFloat(bSdkSlice[property]) - parseFloat(aSdkSlice[property]) 260 : // @ts-ignore 261 parseFloat(aSdkSlice[property]) - parseFloat(bSdkSlice[property]); 262 } 263 // @ts-ignore 264 if (bSdkSlice[property] > aSdkSlice[property]) { 265 return sliceSort === 2 ? 1 : -1; 266 } else { 267 // @ts-ignore 268 if (bSdkSlice[property] === aSdkSlice[property]) { 269 return 0; 270 } else { 271 return sliceSort === 2 ? -1 : 1; 272 } 273 } 274 }; 275 } 276 277 if (sliceDetail.key.indexOf('name') !== -1) { 278 this.statDataArray.sort(compare(sliceDetail.key, sliceDetail.sort, 'string')); 279 } else { 280 this.statDataArray.sort(compare(sliceDetail.key, sliceDetail.sort, 'number')); 281 } 282 this.tblSdkSlice!.recycleDataSource = this.statDataArray; 283 } 284 285 private getInnerTableName(showType: any) { 286 let inner = showType.inner; 287 if (inner !== null) { 288 return inner.tableName; 289 } 290 return ''; 291 } 292 293 filterSliceItem(sliceItem: Array<SdkSliceSummary>, totalTime: number, sdkSliceVal: any) { 294 this.tblSdkSlice!.innerHTML = ''; 295 this.statDataArray = []; 296 if (sliceItem.length > 0) { 297 sliceItem.forEach((dataResult) => { 298 let keys = Object.keys(dataResult); 299 let values = Object.values(dataResult); 300 let sliceJsonText = '{'; 301 keys.forEach((sliceKey, sliceKeyIndex) => { 302 this.keyList = []; 303 if (this.keyList.indexOf(sliceKey) <= -1) { 304 this.keyList.push(sliceKey); 305 } 306 let sliceValue = values[sliceKeyIndex]; 307 sliceValue = this.getFormattedSliceValue(sliceKey, sliceValue); 308 sliceJsonText += `"${sliceKey}": "${sliceValue}"`; 309 if (sliceKeyIndex !== keys.length - 1) { 310 sliceJsonText += ','; 311 } else { 312 sliceJsonText += '}'; 313 } 314 }); 315 let sliceParseData = JSON.parse(sliceJsonText); 316 if (sliceParseData.start_ts !== null && sliceParseData.end_ts !== null && 317 sliceParseData.start_ts > sliceParseData.end_ts && sliceParseData.end_ts === 0) { 318 sliceParseData.end_ts = totalTime; 319 } 320 if (this.isDateIntersection(sdkSliceVal.leftNs, sdkSliceVal.rightNs, sliceParseData.start_ts, sliceParseData.end_ts)) { 321 this.statDataArray.push(sliceParseData); 322 } 323 }); 324 this.tblSdkSlice!.recycleDataSource = this.statDataArray; 325 } else { 326 this.tblSdkSlice!.recycleDataSource = []; 327 } 328 } 329 330 getFormattedSliceValue(sliceKey: string, sliceValue: any) { 331 switch (this.columnMap[sliceKey]) { 332 case 'TimeStamp': 333 return Utils.getTimeString(Number(sliceValue)); 334 case 'ClockTime': 335 return Utils.getTimeStampHMS(Number(sliceValue)); 336 case 'RangTime': 337 return Utils.getDurString(Number(sliceValue)); 338 case 'PercentType': 339 return `${sliceValue}%`; 340 case 'CurrencyType': 341 return sliceValue.toString().replace(/\B(?=(\d{3})+$)/g, ','); 342 case 'FIXED': 343 return sliceValue.toFixed(2); 344 default: 345 if (typeof sliceValue === 'string') { 346 return sliceValue.replace(/</gi, '<').replace(/>/gi, '>'); 347 } 348 } 349 } 350} 351