• 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 */
15import { BaseStruct, Rect, Render, isFrameContainPoint, ns2x } from './ProcedureWorkerCommon.js';
16import { TraceRow } from '../../component/trace/base/TraceRow.js';
17import { Utils } from '../../component/trace/base/Utils.js';
18import { MemoryConfig } from '../../bean/MemoryConfig.js';
19
20export class SnapshotRender extends Render {
21  renderMainThread(
22    req: {
23      context: CanvasRenderingContext2D;
24      useCache: boolean;
25      type: string;
26    },
27    row: TraceRow<SnapshotStruct>
28  ): void {
29    let list = row.dataList;
30    let filter = row.dataListCache;
31    let maxValue = 0;
32    for (let item of list) {
33      maxValue = Math.max(maxValue, item.value || 0);
34    }
35    snapshot(list, filter, maxValue, TraceRow.range?.startNS ?? 0, (TraceRow.range?.endNS ?? 0) - (TraceRow.range?.startNS! ?? 0), row.frame);
36    req.context!.beginPath();
37    let find = false;
38    for (let re of filter) {
39      SnapshotStruct.draw(req.context, re);
40      if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
41        SnapshotStruct.hoverSnapshotStruct = re;
42        find = true;
43      }
44    }
45    if (!find && row.isHover) {
46      SnapshotStruct.hoverSnapshotStruct = undefined;
47    }
48    req.context!.closePath();
49  }
50}
51export function snapshot(
52  list: Array<SnapshotStruct>,
53  filter: Array<SnapshotStruct>,
54  maxValue: number,
55  startNs: number,
56  totalNs: number,
57  frame: Rect
58): void {
59  for (let file of list) {
60    SnapshotStruct.setFrame(file, maxValue, startNs || 0, totalNs || 0, frame);
61  }
62  filter.length = 0;
63  for (let i = 0, len = list.length; i < len; i++) {
64    if (list[i].frame) {
65      filter.push(list[i]);
66    }
67  }
68}
69const padding = 2;
70export class SnapshotStruct extends BaseStruct {
71  startNs: number = 0;
72  endNs: number = 0;
73  dur: number = 0;
74  name: string = '';
75  textWidth: number = 0;
76  value: number = 0;
77  type: string = '';
78  static hoverSnapshotStruct: SnapshotStruct | undefined;
79  static selectSnapshotStruct: SnapshotStruct | undefined;
80  static setFrame(node: SnapshotStruct, maxValue: number, startNs: number, totalNs: number, frame: Rect): void {
81    node.frame = undefined;
82    frame.height = 40 - padding * 2;
83    // sample_interval单位是ms,startNs和endNs单位是纳秒,每一次采样的时间按采样间隔的五分之一算
84    node.dur = MemoryConfig.getInstance().snapshotDur;
85    node.endNs = node.startNs + node.dur;
86    if ((node.startNs - startNs || node.startNs - startNs === 0) && node.endNs - node.startNs) {
87      let rectangle: Rect = new Rect(
88        Math.floor(((node.startNs - startNs) / totalNs) * frame.width),
89        Math.floor(((maxValue - node.value) / maxValue) * frame.height),
90        Math.ceil(((node.endNs - node.startNs) / totalNs) * frame.width),
91        Math.ceil((node.value / maxValue) * frame.height)
92      );
93      node.frame = rectangle;
94    }
95    if (node.value === 0) {
96      let rectangle: Rect = new Rect(
97        Math.floor(((node.startNs - startNs) / totalNs) * frame.width),
98        30,
99        Math.ceil((node.dur / totalNs) * frame.width),
100        1
101      );
102      node.frame = rectangle;
103    }
104  }
105  static draw(ctx: CanvasRenderingContext2D, data: SnapshotStruct): void {
106    if (data.frame) {
107      ctx.fillStyle = 'rgb(86,192,197)';
108      ctx!.fillRect(data.frame!.x, data.frame!.y + padding, data.frame!.width, data.frame!.height);
109      if (data.frame!.width > 7) {
110        ctx.globalAlpha = 1.0;
111        ctx.lineWidth = 1;
112        ctx.fillStyle = '#fff';
113        ctx.textBaseline = 'middle';
114        if (data.frame!.height > 10 && data.frame!.height < 25) {
115          SnapshotStruct.drawString(ctx, data.name || '', 4, data.frame!, data, 4);
116        } else if (data.frame!.height > 25) {
117          SnapshotStruct.drawString(ctx, data.name || '', 4, data.frame!, data, 4);
118          SnapshotStruct.drawString(ctx, Utils.getBinaryByteWithUnit(data.value || 0), 11, data.frame!, data, 2);
119        }
120      }
121      if (SnapshotStruct.selectSnapshotStruct && SnapshotStruct.equals(SnapshotStruct.selectSnapshotStruct, data)) {
122        ctx.strokeStyle = '#232c5d';
123        ctx.lineWidth = 2;
124        ctx.strokeRect(data.frame!.x, data.frame!.y + padding, data.frame!.width - 2, data.frame!.height);
125      }
126    }
127  }
128  /**
129   *
130   * @param ctx current context
131   * @param str text
132   * @param textPadding padding
133   * @param frame rectangle
134   * @param data PurgeableStruct
135   * @param location the position of the string, the bigger the numerical value, the higher the position on the canvas
136   */
137  static drawString(
138    ctx: CanvasRenderingContext2D,
139    str: string,
140    textPadding: number,
141    frame: Rect,
142    data: SnapshotStruct,
143    location: number
144  ): void {
145    if (data.textWidth === undefined) {
146      data.textWidth = ctx.measureText(str).width;
147    }
148    let textWidth = Math.round(data.textWidth / str.length);
149    let fillTextWidth = frame.width - textPadding * 2;
150    if (data.textWidth < fillTextWidth) {
151      let x = Math.floor(frame.width / 2 - data.textWidth / 2 + frame.x + textPadding);
152      ctx.fillText(str, x, Math.floor(frame.y + frame.height / location + textPadding), fillTextWidth);
153    } else {
154      if (fillTextWidth >= textWidth) {
155        let characterNum = fillTextWidth / textWidth;
156        let x = frame.x + textPadding;
157        if (characterNum < 2) {
158          ctx.fillText(
159            str.substring(0, 1),
160            x,
161            Math.floor(frame.y + frame.height / location + textPadding),
162            fillTextWidth
163          );
164        } else {
165          ctx.fillText(
166            `${str.substring(0, characterNum - 1)}...`,
167            x,
168            Math.floor(frame.y + frame.height / location + textPadding),
169            fillTextWidth
170          );
171        }
172      }
173    }
174  }
175  static equals(baseSnapshot: SnapshotStruct, targetSnapshot: SnapshotStruct): boolean {
176    return baseSnapshot === targetSnapshot;
177  }
178}
179