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