• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, '&lt;').replace(/>/gi, '&gt;');
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, '&lt;').replace(/>/gi, '&gt;');
347        }
348    }
349  }
350}
351