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