• 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 { BaseStruct, Rect, Render, drawLoadingFrame, isFrameContainPoint } from './ProcedureWorkerCommon';
17import { TraceRow } from '../../component/trace/base/TraceRow';
18import { Utils } from '../../component/trace/base/Utils';
19
20import { SpSystemTrace } from '../../component/SpSystemTrace';
21export class HeapSnapshotRender extends Render {
22  renderMainThread(
23    req: {
24      context: CanvasRenderingContext2D;
25      useCache: boolean;
26      type: string;
27    },
28    row: TraceRow<HeapSnapshotStruct>
29  ): void {
30    let filter = row.dataListCache;
31    HeapSnapshot(
32      filter,
33      TraceRow.range?.startNS ?? 0,
34      TraceRow.range?.endNS ?? 0,
35      (TraceRow.range?.endNS ?? 0) - (TraceRow.range?.startNS! ?? 0), // @ts-ignore
36      row.frame
37    );
38    drawLoadingFrame(req.context, filter, row);
39    req.context!.beginPath();
40    for (let re of filter) {
41      HeapSnapshotStruct.draw(req.context, re);
42    }
43    for (let re of filter) {
44      if (re.frame && !isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
45        HeapSnapshotStruct.hoverSnapshotStruct = undefined;
46      }
47      if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
48        HeapSnapshotStruct.hoverSnapshotStruct = re;
49        break;
50      }
51    }
52    req.context!.closePath();
53  }
54}
55export function HeapSnapshot(
56  list: Array<HeapSnapshotStruct>,
57  startNS: number,
58  endNS: number,
59  totalNS: number,
60  frame: Rect
61): void {
62  for (let file of list) {
63    HeapSnapshotStruct.setFrame(file, startNS || 0, endNS || 0, totalNS || 0, frame);
64  }
65}
66const padding = 3;
67export function HeapSnapshotStructOnClick(
68  clickRowType: string,
69  sp: SpSystemTrace,
70  row: TraceRow<HeapSnapshotStruct>,
71  snapshotClickHandler: unknown
72): Promise<unknown> {
73  return new Promise((resolve, reject) => {
74    if (clickRowType === TraceRow.ROW_TYPE_HEAP_SNAPSHOT) {
75      if (row.findHoverStruct) {
76        row.findHoverStruct();
77      } else {
78        HeapSnapshotStruct.hoverSnapshotStruct = HeapSnapshotStruct.hoverSnapshotStruct || row.getHoverStruct();
79      }
80      if (HeapSnapshotStruct.hoverSnapshotStruct) {
81        HeapSnapshotStruct.selectSnapshotStruct = HeapSnapshotStruct.hoverSnapshotStruct;
82        sp.traceSheetEL?.displaySnapshotData(
83          HeapSnapshotStruct.selectSnapshotStruct!,
84          row!.dataListCache,
85          //@ts-ignore
86          snapshotClickHandler
87        );
88      }
89      reject(new Error());
90    } else {
91      resolve(null);
92    }
93  });
94}
95export class HeapSnapshotStruct extends BaseStruct {
96  startTs: number = 0;
97  endTs: number = 0;
98  id: number = 0;
99  pid: number = 0;
100  name: string | undefined;
101  textWidth: number | undefined;
102  size: number = 0;
103  static hoverSnapshotStruct: HeapSnapshotStruct | undefined;
104  static selectSnapshotStruct: HeapSnapshotStruct | undefined;
105
106  static setFrame(node: HeapSnapshotStruct, startNS: number, endNS: number, totalNS: number, frame: Rect): void {
107    node.frame = undefined;
108    if ((node.startTs - startNS || node.startTs - startNS === 0) && node.endTs - node.startTs) {
109      let rectangle: Rect = new Rect(
110        Math.floor(((node.startTs - startNS) / totalNS) * frame.width),
111        0,
112        Math.ceil(((node.endTs - node.startTs) / totalNS) * frame.width),
113        40
114      );
115      node.frame = rectangle;
116    }
117  }
118
119  static draw(ctx: CanvasRenderingContext2D, data: HeapSnapshotStruct): void {
120    if (data.frame) {
121      ctx.fillStyle = 'rgb(86,192,197)';
122      ctx!.fillRect(data.frame!.x, data.frame!.y + padding, data.frame!.width, data.frame!.height - padding * 2);
123      if (data.frame!.width > 7) {
124        ctx.globalAlpha = 1.0;
125        ctx.lineWidth = 1;
126        ctx.fillStyle = '#fff';
127        ctx.textBaseline = 'middle';
128        ctx.font = '12px sans-serif';
129        HeapSnapshotStruct.drawString(ctx, data.name || '', 3, data.frame!, data, 4);
130        HeapSnapshotStruct.drawString(ctx, Utils.getBinaryByteWithUnit(data.size) || '', 9, data.frame!, data, 2);
131      }
132      if (
133        HeapSnapshotStruct.selectSnapshotStruct &&
134        HeapSnapshotStruct.equals(HeapSnapshotStruct.selectSnapshotStruct, data)
135      ) {
136        ctx.strokeStyle = '#232c5d';
137        ctx.lineWidth = 2;
138        ctx.strokeRect(data.frame!.x, data.frame!.y + padding, data.frame!.width - 2, data.frame!.height - padding * 2);
139      }
140    }
141  }
142
143  /**
144   *
145   * @param ctx current context
146   * @param str text
147   * @param textPadding padding
148   * @param frame rectangle
149   * @param data HeapSnapshotStruct
150   * @param location the position of the string, the bigger the numerical value, the higher the position on the canvas
151   */
152  static drawString(
153    ctx: CanvasRenderingContext2D,
154    str: string,
155    textPadding: number,
156    frame: Rect,
157    HeapSnapshotdata: HeapSnapshotStruct,
158    location: number
159  ): void {
160    if (HeapSnapshotdata.textWidth === undefined) {
161      HeapSnapshotdata.textWidth = ctx.measureText(str).width;
162    }
163    let textWidth = Math.round(HeapSnapshotdata.textWidth / str.length);
164    let maxTextWidth = frame.width - textPadding * 2;
165    if (HeapSnapshotdata.textWidth < maxTextWidth) {
166      let x = Math.floor(frame.width / 2 - HeapSnapshotdata.textWidth / 2 + frame.x + textPadding);
167      ctx.fillText(str, x, Math.floor(frame.y + frame.height / location + textPadding), maxTextWidth);
168    } else {
169      if (maxTextWidth >= textWidth) {
170        let characterNum = maxTextWidth / textWidth;
171        let x = frame.x + textPadding;
172        if (characterNum < 2) {
173          ctx.fillText(
174            str.substring(0, 1),
175            x,
176            Math.floor(frame.y + frame.height / location + textPadding),
177            maxTextWidth
178          );
179        } else {
180          ctx.fillText(
181            str.substring(0, characterNum - 1) + '...',
182            x,
183            Math.floor(frame.y + frame.height / location + textPadding),
184            maxTextWidth
185          );
186        }
187      }
188    }
189  }
190
191  static equals(d1: HeapSnapshotStruct, d2: HeapSnapshotStruct): boolean {
192    return (
193      d1 &&
194      d2 &&
195      d1.name === d2.name &&
196      d1.id === d2.id &&
197      d1.pid === d2.pid &&
198      d1.startTs === d2.startTs &&
199      d1.endTs === d2.endTs
200    );
201  }
202}
203