• 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 { ColorUtils } from '../../component/trace/base/ColorUtils.js';
17import {
18  BaseStruct,
19  drawFlagLine,
20  drawLines,
21  drawLoading,
22  drawSelection,
23  isFrameContainPoint,
24  PerfRender,
25  RequestMessage,
26} from './ProcedureWorkerCommon.js';
27import { TraceRow } from '../../component/trace/base/TraceRow.js';
28
29export class EnergyAnomalyRender extends PerfRender {
30  renderMainThread(
31    req: {
32      useCache: boolean;
33      context: CanvasRenderingContext2D;
34      type: string;
35      appName: string;
36      canvasWidth: number;
37    },
38    row: TraceRow<EnergyAnomalyStruct>
39  ) {
40    let list = row.dataList;
41    let filter = row.dataListCache;
42    anomaly(
43      list,
44      filter,
45      TraceRow.range!.startNS,
46      TraceRow.range!.endNS,
47      TraceRow.range!.totalNS,
48      row.frame,
49      req.appName,
50      req.useCache || !TraceRow.range!.refresh
51    );
52    req.context.beginPath();
53    let find = false;
54    let spApplication = document.getElementsByTagName('sp-application')[0];
55    let isDark = spApplication.hasAttribute('dark');
56    drawLegend(req, isDark);
57    for (let re of filter) {
58      EnergyAnomalyStruct.draw(req.context, re);
59      if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
60        EnergyAnomalyStruct.hoverEnergyAnomalyStruct = re;
61        find = true;
62      }
63    }
64    if (!find && row.isHover) EnergyAnomalyStruct.hoverEnergyAnomalyStruct = undefined;
65    req.context.fillStyle = ColorUtils.FUNC_COLOR[0];
66    req.context.strokeStyle = ColorUtils.FUNC_COLOR[0];
67    req.context.closePath();
68  }
69
70  render(energyAnomalyRequest: RequestMessage, list: Array<any>, filter: Array<any>, dataList2: Array<any>) {
71    if (energyAnomalyRequest.lazyRefresh) {
72      anomaly(
73        list,
74        filter,
75        energyAnomalyRequest.startNS,
76        energyAnomalyRequest.endNS,
77        energyAnomalyRequest.totalNS,
78        energyAnomalyRequest.frame,
79        energyAnomalyRequest.params.appName,
80        energyAnomalyRequest.useCache || !energyAnomalyRequest.range.refresh
81      );
82    } else {
83      if (!energyAnomalyRequest.useCache) {
84        anomaly(
85          list,
86          filter,
87          energyAnomalyRequest.startNS,
88          energyAnomalyRequest.endNS,
89          energyAnomalyRequest.totalNS,
90          energyAnomalyRequest.frame,
91          energyAnomalyRequest.params.appName,
92          false
93        );
94      }
95    }
96    if (energyAnomalyRequest.canvas) {
97      energyAnomalyRequest.context.clearRect(
98        0,
99        0,
100        energyAnomalyRequest.canvas.width,
101        energyAnomalyRequest.canvas.height
102      );
103      let energyAnomlyArr = filter;
104      if (
105        energyAnomlyArr.length > 0 &&
106        !energyAnomalyRequest.range.refresh &&
107        !energyAnomalyRequest.useCache &&
108        energyAnomalyRequest.lazyRefresh
109      ) {
110        drawLoading(
111          energyAnomalyRequest.context,
112          energyAnomalyRequest.startNS,
113          energyAnomalyRequest.endNS,
114          energyAnomalyRequest.totalNS,
115          energyAnomalyRequest.frame,
116          energyAnomlyArr[0].startNS,
117          energyAnomlyArr[energyAnomlyArr.length - 1].startNS
118        );
119      }
120      drawLines(
121        energyAnomalyRequest.context,
122        energyAnomalyRequest.xs,
123        energyAnomalyRequest.frame.height,
124        energyAnomalyRequest.lineColor
125      );
126      energyAnomalyRequest.context.stroke();
127      energyAnomalyRequest.context.beginPath();
128      EnergyAnomalyStruct.hoverEnergyAnomalyStruct = undefined;
129      if (energyAnomalyRequest.isHover) {
130        let offset = 3;
131        for (let re of filter) {
132          if (
133            re.frame &&
134            energyAnomalyRequest.hoverX >= re.frame.x - offset &&
135            energyAnomalyRequest.hoverX <= re.frame.x + re.frame.width + offset
136          ) {
137            EnergyAnomalyStruct.hoverEnergyAnomalyStruct = re;
138            break;
139          }
140        }
141      } else {
142        EnergyAnomalyStruct.hoverEnergyAnomalyStruct = energyAnomalyRequest.params.hoverStruct;
143      }
144      EnergyAnomalyStruct.selectEnergyAnomalyStruct = energyAnomalyRequest.params.selectEnergyAnomalyStruct;
145      energyAnomalyRequest.context.fillStyle = ColorUtils.FUNC_COLOR[0];
146      energyAnomalyRequest.context.strokeStyle = ColorUtils.FUNC_COLOR[0];
147      for (let re of filter) {
148        EnergyAnomalyStruct.draw(energyAnomalyRequest.context, re);
149      }
150      drawLegend(energyAnomalyRequest);
151      drawSelection(energyAnomalyRequest.context, energyAnomalyRequest.params);
152      energyAnomalyRequest.context.closePath();
153      drawFlagLine(
154        energyAnomalyRequest.context,
155        energyAnomalyRequest.flagMoveInfo,
156        energyAnomalyRequest.flagSelectedInfo,
157        energyAnomalyRequest.startNS,
158        energyAnomalyRequest.endNS,
159        energyAnomalyRequest.totalNS,
160        energyAnomalyRequest.frame,
161        energyAnomalyRequest.slicesTime
162      );
163    }
164    // @ts-ignore
165    self.postMessage({
166      id: energyAnomalyRequest.id,
167      type: energyAnomalyRequest.type,
168      results: energyAnomalyRequest.canvas ? undefined : filter,
169      hover: EnergyAnomalyStruct.hoverEnergyAnomalyStruct,
170    });
171  }
172}
173
174export function drawLegend(req: any, isDark?: boolean) {
175  req.context.font = '12px Arial';
176  let text = req.context.measureText('System Abnormality');
177  req.context.fillStyle = '#E64566';
178  req.context.strokeStyle = '#E64566';
179  let textColor = isDark ? '#FFFFFF' : '#333';
180  let canvasEndX = req.context.canvas.clientWidth - EnergyAnomalyStruct.OFFSET_WIDTH;
181  let rectPadding: number;
182  let textPadding: number;
183  let textMargin: number;
184  let currentTextWidth: number;
185  let lastTextMargin: number;
186  rectPadding = 280;
187  textPadding = 270;
188  textMargin = 250;
189  currentTextWidth = canvasEndX - textMargin + text.width;
190  lastTextMargin = currentTextWidth + 12;
191  req!.context.fillRect(canvasEndX - rectPadding, 12, 8, 8);
192  req.context.globalAlpha = 1;
193  req.context.fillStyle = textColor;
194  req.context.textBaseline = 'middle';
195  req.context.fillText('System Abnormality', canvasEndX - textPadding, 18);
196  req.context.fillStyle = '#FFC880';
197  req.context.strokeStyle = '#FFC880';
198  req.context.fillRect(currentTextWidth, 12, 8, 8);
199  req.context.globalAlpha = 1;
200  req.context.fillStyle = textColor;
201  req.context.textBaseline = 'middle';
202  req.context.fillText('Application Abnormality', lastTextMargin, 18);
203  req.context.fillStyle = '#333';
204}
205
206export function anomaly(
207  arr: Array<any>,
208  res: Array<any>,
209  startNS: number,
210  endNS: number,
211  totalNS: number,
212  frame: any,
213  appName: string | undefined,
214  use: boolean
215) {
216  if (use && res.length > 0) {
217    let pns = (endNS - startNS) / frame.width;
218    let y = frame.y;
219    for (let i = 0; i < res.length; i++) {
220      let it = res[i];
221      if ((it.startNS || 0) > startNS && (it.startNS || 0) < endNS) {
222        if (!it.frame) {
223          it.frame = {};
224          it.frame.y = y;
225        }
226        it.frame.height = it.height;
227        EnergyAnomalyStruct.setAnomalyFrame(it, pns, startNS, endNS, frame);
228      } else {
229        it.frame = null;
230      }
231    }
232    return;
233  }
234
235  res.length = 0;
236  if (arr) {
237    let y = frame.y;
238    let pns = (endNS - startNS) / frame.width;
239    for (let index = 0; index < arr.length; index++) {
240      let item = arr[index];
241      if (!item.frame) {
242        item.frame = {};
243        item.frame.y = y;
244      }
245      item.frame.height = item.height;
246      if (item.startNS + 50000 > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) {
247        EnergyAnomalyStruct.setAnomalyFrame(item, pns, startNS || 0, endNS || 0, frame);
248        if (item.appKey === 'APPNAME' && item.Value.split(',').indexOf(appName) >= 0) {
249          res.push(item);
250        }
251        if (item.appKey != 'APPNAME') {
252          res.push(item);
253        }
254      }
255    }
256  }
257}
258
259export class EnergyAnomalyStruct extends BaseStruct {
260  static hoverEnergyAnomalyStruct: EnergyAnomalyStruct | undefined;
261  static selectEnergyAnomalyStruct: EnergyAnomalyStruct | undefined;
262  static SYSTEM_EXCEPTION = new Set([
263    'ANOMALY_SCREEN_OFF_ENERGY',
264    'ANOMALY_ALARM_WAKEUP',
265    'ANOMALY_KERNEL_WAKELOCK',
266    'ANOMALY_CPU_HIGH_FREQUENCY',
267    'ANOMALY_WAKEUP',
268  ]);
269  static OFFSET_WIDTH: number = 266;
270  type: number | undefined;
271  startNS: number | undefined;
272  height: number | undefined;
273  eventName: string | undefined;
274
275  static draw(ctx: CanvasRenderingContext2D, data: EnergyAnomalyStruct) {
276    if (data.frame) {
277      EnergyAnomalyStruct.drawRoundRectPath(ctx, data.frame.x - 7, 20 - 7, 12, data);
278    }
279  }
280
281  static drawRoundRectPath(
282    ctx: CanvasRenderingContext2D,
283    x: number,
284    y: number,
285    radius: number,
286    data: EnergyAnomalyStruct
287  ) {
288    ctx.beginPath();
289    ctx.arc(x + 7, y + 22, radius, 0, Math.PI * 2);
290    ctx.closePath();
291    let color = '';
292    if (EnergyAnomalyStruct.SYSTEM_EXCEPTION.has(<string>data.eventName)) {
293      color = '#E64566';
294    } else {
295      color = '#FFC880';
296    }
297    // 填充背景颜色
298    ctx.fillStyle = color;
299    ctx.fill();
300    ctx.stroke();
301    // 填充文字颜色
302    ctx.font = '12px Arial';
303    ctx.fillStyle = ColorUtils.GREY_COLOR;
304    ctx.textAlign = 'center';
305    ctx.fillText('E', x + 7, y + 23);
306  }
307
308  static setAnomalyFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) {
309    if ((node.startNS || 0) < startNS) {
310      node.frame.x = 0;
311    } else {
312      node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns);
313    }
314    if ((node.startNS || 0) > endNS) {
315      node.frame.width = frame.width - node.frame.x;
316    } else {
317      node.frame.width = Math.ceil(((node.startNS || 0) - startNS) / pns - node.frame.x);
318    }
319    if (node.frame.width < 1) {
320      node.frame.width = 1;
321    }
322  }
323}
324