• 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 { SpSystemTrace } from '../SpSystemTrace';
17import { TraceRow } from '../trace/base/TraceRow';
18
19import { BaseStruct } from '../../bean/BaseStruct';
20import { CounterStruct, SdkCounterRender } from '../../database/ui-worker/ProduceWorkerSdkCounter';
21import { renders } from '../../database/ui-worker/ProcedureWorker';
22import { SdkSliceRender, SdkSliceStruct } from '../../database/ui-worker/ProduceWorkerSdkSlice';
23import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
24import { TabUtil } from '../trace/sheet/sdk/TabUtil';
25import { queryCounterMax, querySdkCount, querySdkCounterData, querySdkSliceData } from '../../database/sql/Sdk.sql';
26import { queryStartTime } from '../../database/sql/SqlLite.sql';
27import { NUM_7 } from '../../bean/NumBean';
28import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil';
29
30export class SpSdkChart {
31  trace: SpSystemTrace;
32  private pluginName = 'dubai-plugin';
33
34  constructor(trace: SpSystemTrace) {
35    this.trace = trace;
36  }
37
38  private parseJsonByCounterType(startTime: number, showType: unknown, configObj: unknown, table: unknown): void {
39    let chartSql = this.createSql(
40      startTime, //@ts-ignore
41      showType.tableName, //@ts-ignore
42      showType.columns,
43      'where counter_id' + ' = $counter_id'
44    ); //@ts-ignore
45    let maxValue = this.createMaxValueSql(showType.tableName, 'where counter_id = $counter_id'); //@ts-ignore
46    let innerTable = showType.inner;
47    let countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns); //@ts-ignore
48    table.push({
49      countSql: countSql,
50      chartSql: chartSql,
51      maxSql: maxValue,
52      type: 'counter', //@ts-ignore
53      name: configObj.disPlayName, //@ts-ignore
54      pluginName: configObj.pluginName,
55    });
56  }
57
58  private parseJsonBySliceType(startTime: number, showType: unknown, configObj: unknown, table: unknown[]): void {
59    let chartSql = this.createSliceSql(
60      startTime, //@ts-ignore
61      showType.tableName, //@ts-ignore
62      showType.columns,
63      'where' + ` slice_id = $column_id and (start_ts - ${startTime}) between $startNS and $endNS;`
64    ); //@ts-ignore
65    let innerTable = showType.inner;
66    let countSql;
67    let countOtherSql = ''; //@ts-ignore
68    if (configObj.pluginName === this.pluginName) {
69      countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns, 'where slice_name like $suffix');
70      countOtherSql = this.createSql(
71        startTime,
72        innerTable.tableName,
73        innerTable.columns,
74        '' +
75          "where slice_name not like '%_cpu' and slice_name not like '%_display' and " +
76          "slice_name not like '%_gpu' and slice_name not like '%_System_idle' and " +
77          "slice_name not like '%_wifi_data' and slice_name not like '%_sensor' and " +
78          "slice_name not like '%_audio' "
79      );
80    } else {
81      countSql = this.createSql(startTime, innerTable.tableName, innerTable.columns);
82    }
83    table.push({
84      countSql: countSql,
85      chartSql: chartSql,
86      type: 'slice', //@ts-ignore
87      name: configObj.disPlayName, //@ts-ignore
88      pluginName: configObj.pluginName,
89      countOtherSql: countOtherSql,
90    });
91  }
92
93  parseJson(startTime: number, map: Map<number, string>): Map<number, unknown> {
94    let tablesMap = new Map();
95    let keys = map.keys();
96    for (let key of keys) {
97      let table: unknown[] = [];
98      let configObj: unknown = map.get(key);
99      if (configObj !== undefined) {
100        //@ts-ignore
101        let configStr = configObj.jsonConfig;
102        let json = JSON.parse(configStr);
103        let tableConfig = json.tableConfig;
104        if (tableConfig !== null) {
105          let showTypes = tableConfig.showType;
106          for (let i = 0; i < showTypes.length; i++) {
107            let showType = showTypes[i];
108            let type = TabUtil.getTableType(showType);
109            if (type === 'counter') {
110              this.parseJsonByCounterType(startTime, showType, configObj, table);
111            } else if (type === 'slice') {
112              this.parseJsonBySliceType(startTime, showType, configObj, table);
113            }
114          }
115          tablesMap.set(key, table);
116        }
117      }
118    }
119    return tablesMap;
120  }
121
122  private createSliceSql(startTime: number, tableName: string, columns: Array<unknown>, where?: string): string {
123    let sliceSelectSql = 'select ';
124    for (let i = 0; i < columns.length; i++) {
125      let column = columns[i]; //@ts-ignore
126      if (column.column === 'start_ts') {
127        //@ts-ignore
128        column.column = `(start_ts - ${startTime}) AS start_ts`;
129      } //@ts-ignore
130      if (column.column === 'end_ts') {
131        //@ts-ignore
132        column.column = `(end_ts - ${startTime}) AS end_ts`;
133      }
134      if (i === columns.length - 1) {
135        //@ts-ignore
136        sliceSelectSql = `${sliceSelectSql + column.column} `;
137      } else {
138        //@ts-ignore
139        sliceSelectSql = `${sliceSelectSql + column.column}, `;
140      }
141    }
142    sliceSelectSql = `${sliceSelectSql}from ${tableName}`;
143    if (where !== undefined) {
144      sliceSelectSql = `${sliceSelectSql} ${where}`;
145    }
146    return sliceSelectSql;
147  }
148
149  private createMaxValueSql(tableName: string, where?: string): string {
150    let selectSql = `select max(value) as max_value from ${tableName}`;
151    if (where !== undefined) {
152      selectSql = `${selectSql} ${where}`;
153    }
154    return selectSql;
155  }
156
157  private createSql(startTime: number, tableName: string, columns: Array<unknown>, where?: string): string {
158    let selectSql = 'select ';
159    for (let i = 0; i < columns.length; i++) {
160      let column = columns[i]; //@ts-ignore
161      if (column.column === 'ts') {
162        //@ts-ignore
163        column.column = `ts - ${startTime} AS ts`;
164      }
165      if (i === columns.length - 1) {
166        //@ts-ignore
167        selectSql = `${selectSql + column.column} `;
168      } else {
169        //@ts-ignore
170        selectSql = `${selectSql + column.column}, `;
171      }
172    }
173    selectSql = `${selectSql}from ${tableName}`;
174    if (where !== undefined) {
175      selectSql = `${selectSql} ${where}`;
176    }
177    return selectSql;
178  }
179
180  async init(): Promise<void> {
181    let configMap = SpSystemTrace.SDK_CONFIG_MAP;
182    if (configMap === undefined) {
183      return;
184    }
185    let res = await queryStartTime();
186    //@ts-ignore
187    let startTime = res[0].start_ts;
188    // @ts-ignore
189    let tablesMap = this.parseJson(startTime, configMap);
190    let tableKeys = tablesMap.keys();
191    for (let componentId of tableKeys) {
192      let table = tablesMap.get(componentId);
193      if (table !== null) {
194        //@ts-ignore
195        let nodeRow = this.initNodeRow(componentId, table[0].name); //@ts-ignore
196        for (let index = 0; index < table.length; index++) {
197          //@ts-ignore
198          let sqlMap = table[index];
199          if (sqlMap.type === 'counter') {
200            let result = await querySdkCount(sqlMap.countSql, componentId);
201            for (let i = 0; i < result.length; i++) {
202              await this.initCounter(nodeRow, i, result[i], sqlMap, componentId);
203            }
204          } else if (sqlMap.type === 'slice' && sqlMap.pluginName === this.pluginName) {
205            let suffixList = ['cpu', 'display', 'gpu', 'System_idle', 'wifi_data', 'sensor', 'audio'];
206            for (let i = 0; i < suffixList.length; i++) {
207              let result = await querySdkCount(sqlMap.countSql, componentId, { $suffix: `%${suffixList[i]}` });
208              if (result.length > 0) {
209                let groupNodeRow = await this.initSecondaryRow(nodeRow, i, suffixList[i]);
210                for (let i = 0; i < result.length; i++) {
211                  await this.initSlice(groupNodeRow, i, result[i], sqlMap, componentId);
212                }
213              }
214            }
215            let result = await querySdkCount(sqlMap.countOtherSql, componentId);
216            if (result.length > 0) {
217              let groupNodeRow = await this.initSecondaryRow(nodeRow, NUM_7, 'other');
218              for (let i = 0; i < result.length; i++) {
219                await this.initSlice(groupNodeRow, i, result[i], sqlMap, componentId);
220              }
221            }
222          } else if (sqlMap.type === 'slice') {
223            let result = await querySdkCount(sqlMap.countSql, componentId, {});
224            for (let i = 0; i < result.length; i++) {
225              await this.initSlice(nodeRow, i, result[i], sqlMap, componentId);
226            }
227          }
228        }
229      }
230    }
231  }
232
233  private initCounterChartRow(
234    componentId: number,
235    expansion: boolean,
236    counterId: string,
237    counterName: string
238  ): TraceRow<CounterStruct> {
239    let traceRow = TraceRow.skeleton<CounterStruct>();
240    traceRow.rowParentId = `Sdk-${componentId}`;
241    traceRow.rowHidden = !expansion;
242    traceRow.rowId = `${counterId}-${componentId}`;
243    traceRow.rowType = TraceRow.ROW_TYPE_SDK_COUNTER;
244    traceRow.folderPaddingLeft = 30;
245    traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
246    traceRow.selectChangeHandler = this.trace.selectChangeHandler;
247    traceRow.style.height = '40px';
248    traceRow.style.width = '100%';
249    traceRow.setAttribute('children', '');
250    traceRow.name = `${counterName}`;
251    return traceRow;
252  }
253
254  private initCounter = async (
255    nodeRow: TraceRow<BaseStruct>,
256    index: number,
257    result: unknown,
258    sqlMap: unknown,
259    componentId: number
260  ): Promise<void> => {
261    //@ts-ignore
262    let traceRow = this.initCounterChartRow(componentId, nodeRow.expansion, result.counter_id, result.counter_name);
263    traceRow.supplier = async (): Promise<CounterStruct[]> => //@ts-ignore
264      querySdkCounterData(sqlMap.chartSql, result.counter_id, componentId);
265    traceRow.focusHandler = (): void => {
266      this.trace?.displayTip(
267        traceRow,
268        CounterStruct.hoverCounterStruct,
269        `<span>${CounterStruct.hoverCounterStruct?.value?.toFixed(2)}</span>`
270      );
271    };
272    traceRow.findHoverStruct = (): void => {
273      CounterStruct.hoverCounterStruct = traceRow.getHoverStruct();
274    }; //@ts-ignore
275    let maxList = await queryCounterMax(sqlMap.maxSql, result.counter_id, componentId);
276    //@ts-ignore
277    let maxCounter = maxList[0].max_value;
278    traceRow.onThreadHandler = (useCache: boolean): void => {
279      let context: CanvasRenderingContext2D;
280      if (traceRow.currentContext) {
281        context = traceRow.currentContext;
282      } else {
283        context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
284      }
285      traceRow.canvasSave(context);
286      //@ts-ignore
287      (renders[TraceRow.ROW_TYPE_SDK_COUNTER] as SdkCounterRender).renderMainThread(
288        {
289          context: context,
290          useCache: useCache,
291          type: `sdk-counter-${index}`,
292          maxName: `${maxCounter}`,
293          maxValue: maxCounter,
294        },
295        traceRow
296      );
297      traceRow.canvasRestore(context, this.trace);
298    };
299    nodeRow.addChildTraceRow(traceRow);
300  };
301
302  private initNodeRow = (index: number, name: string): TraceRow<BaseStruct> => {
303    let sdkFolder = TraceRow.skeleton();
304    sdkFolder.rowId = `Sdk-${index}`;
305    sdkFolder.index = index;
306    sdkFolder.rowType = TraceRow.ROW_TYPE_SDK;
307    sdkFolder.rowParentId = '';
308    sdkFolder.style.height = '40px';
309    sdkFolder.folder = true;
310    sdkFolder.name = `${name}`;
311    sdkFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler;
312    sdkFolder.selectChangeHandler = this.trace.selectChangeHandler;
313    sdkFolder.supplier = async (): Promise<BaseStruct[]> => new Promise<[]>((resolve) => resolve([]));
314    sdkFolder.onThreadHandler = (useCache: boolean): void => {
315      sdkFolder.canvasSave(this.trace.canvasPanelCtx!);
316      if (sdkFolder.expansion) {
317        // @ts-ignore
318        this.trace.canvasPanelCtx?.clearRect(0, 0, sdkFolder.frame.width, sdkFolder.frame.height);
319      } else {
320        (renders.empty as EmptyRender).renderMainThread(
321          {
322            context: this.trace.canvasPanelCtx,
323            useCache: useCache,
324            type: '',
325          },
326          // @ts-ignore
327          sdkFolder
328        );
329      }
330      sdkFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
331    };
332    this.trace.rowsEL?.appendChild(sdkFolder);
333    return sdkFolder;
334  };
335
336  private initSecondaryRow = async (
337    nodeRow: TraceRow<BaseStruct>,
338    index: number,
339    name: string
340  ): Promise<TraceRow<BaseStruct>> => {
341    let sdkSecondFolder = TraceRow.skeleton();
342    sdkSecondFolder.rowId = `Sdk-${name}-${index}`;
343    sdkSecondFolder.index = index;
344    sdkSecondFolder.rowType = TraceRow.ROW_TYPE_SDK;
345    sdkSecondFolder.rowParentId = nodeRow.rowId;
346    sdkSecondFolder.rowHidden = !nodeRow.expansion;
347    sdkSecondFolder.style.height = '40px';
348    sdkSecondFolder.folder = true;
349    sdkSecondFolder.folderPaddingLeft = 30;
350    sdkSecondFolder.name = `${name}`;
351    sdkSecondFolder.favoriteChangeHandler = this.trace.favoriteChangeHandler;
352    sdkSecondFolder.selectChangeHandler = this.trace.selectChangeHandler;
353    sdkSecondFolder.supplier = async (): Promise<BaseStruct[]> => new Promise<[]>((resolve) => resolve([]));
354    sdkSecondFolder.onThreadHandler = (useCache: boolean): void => {
355      sdkSecondFolder.canvasSave(this.trace.canvasPanelCtx!);
356      if (sdkSecondFolder.expansion) {
357        // @ts-ignore
358        this.trace.canvasPanelCtx?.clearRect(0, 0, sdkSecondFolder.frame.width, sdkSecondFolder.frame.height);
359      } else {
360        (renders.empty as EmptyRender).renderMainThread(
361          {
362            context: this.trace.canvasPanelCtx,
363            useCache: useCache,
364            type: '',
365          },
366          // @ts-ignore
367          sdkSecondFolder
368        );
369      }
370      sdkSecondFolder.canvasRestore(this.trace.canvasPanelCtx!, this.trace);
371    };
372    this.trace.rowsEL?.appendChild(sdkSecondFolder);
373    return sdkSecondFolder;
374  };
375
376  private initSliceChartRow(
377    expansion: boolean,
378    rowId: string,
379    sliceId: string,
380    sliceName: string,
381    componentId: number
382  ): TraceRow<SdkSliceStruct> {
383    let traceRow = TraceRow.skeleton<SdkSliceStruct>();
384    traceRow.rowType = TraceRow.ROW_TYPE_SDK_SLICE;
385    traceRow.rowHidden = !expansion;
386    traceRow.rowParentId = rowId;
387    traceRow.folderPaddingLeft = 30;
388    traceRow.style.height = '40px';
389    traceRow.style.width = '100%';
390    traceRow.name = `${sliceName}`;
391    traceRow.setAttribute('children', '');
392    traceRow.favoriteChangeHandler = this.trace.favoriteChangeHandler;
393    traceRow.selectChangeHandler = this.trace.selectChangeHandler;
394    traceRow.rowId = `${sliceId}-${componentId}`;
395    return traceRow;
396  }
397
398  private initSlice = async (
399    nodeRow: TraceRow<BaseStruct>,
400    index: number,
401    result: unknown,
402    sqlMap: unknown,
403    componentId: number
404  ): Promise<void> => {
405    let traceRow = this.initSliceChartRow(
406      nodeRow.expansion,
407      nodeRow.rowId!, //@ts-ignore
408      result.slice_id, //@ts-ignore
409      result.slice_name,
410      componentId
411    );
412    traceRow.supplier = async (): Promise<SdkSliceStruct[]> =>
413      querySdkSliceData(
414        //@ts-ignore
415        sqlMap.chartSql, //@ts-ignore
416        result.slice_id,
417        TraceRow.range?.startNS || 0,
418        TraceRow.range?.endNS || 0,
419        componentId
420      );
421    traceRow.focusHandler = (): void => {
422      this.trace?.displayTip(
423        traceRow,
424        SdkSliceStruct.hoverSdkSliceStruct,
425        `<span>${SdkSliceStruct.hoverSdkSliceStruct?.value}</span>`
426      );
427    };
428    traceRow.findHoverStruct = (): void => {
429      SdkSliceStruct.hoverSdkSliceStruct = traceRow.getHoverStruct();
430    };
431    traceRow.onThreadHandler = (useCache: boolean): void => {
432      let context: CanvasRenderingContext2D;
433      if (traceRow.currentContext) {
434        context = traceRow.currentContext;
435      } else {
436        context = traceRow.collect ? this.trace.canvasFavoritePanelCtx! : this.trace.canvasPanelCtx!;
437      }
438      traceRow.canvasSave(context);
439      //@ts-ignore
440      (renders[TraceRow.ROW_TYPE_SDK_SLICE] as SdkSliceRender).renderMainThread(
441        {
442          context: context,
443          useCache: useCache,
444          type: `sdk-slice-${index}`,
445          maxName: '',
446          maxValue: 0,
447        },
448        traceRow
449      );
450      traceRow.canvasRestore(context, this.trace);
451    };
452    nodeRow.addChildTraceRow(traceRow);
453  };
454}
455