• 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, drawString, isFrameContainPoint, ns2x } from './ProcedureWorkerCommon.js';
17import { TraceRow } from '../../component/trace/base/TraceRow.js';
18import { ColorUtils } from '../../component/trace/base/ColorUtils.js';
19import { JsCpuProfilerChartFrame } from '../../bean/JsStruct.js';
20
21export class JsCpuProfilerRender extends Render {
22  renderMainThread(
23    req: {
24      useCache: boolean;
25      context: CanvasRenderingContext2D;
26      type: string;
27    },
28    jsCpuProfilerRow: TraceRow<JsCpuProfilerStruct>
29  ) {
30    let list = jsCpuProfilerRow.dataList;
31    let filter = jsCpuProfilerRow.dataListCache;
32    jsCpuProfiler(
33      list,
34      filter,
35      TraceRow.range!.startNS,
36      TraceRow.range!.endNS,
37      TraceRow.range!.totalNS,
38      jsCpuProfilerRow.frame,
39      req.useCache || !TraceRow.range!.refresh
40    );
41    req.context.beginPath();
42    let jsCpuProfilerFind = false;
43    for (let re of filter) {
44      JsCpuProfilerStruct.draw(req.context, re);
45      if (jsCpuProfilerRow.isHover) {
46        if (
47          re.endTime - re.startTime == 0 ||
48          re.endTime - re.startTime == null ||
49          re.endTime - re.startTime == undefined
50        ) {
51          if (
52            re.frame &&
53            jsCpuProfilerRow.hoverX >= re.frame.x - 5 &&
54            jsCpuProfilerRow.hoverX <= re.frame.x + 5 &&
55            jsCpuProfilerRow.hoverY >= re.frame.y &&
56            jsCpuProfilerRow.hoverY <= re.frame.y + re.frame.height
57          ) {
58            JsCpuProfilerStruct.hoverJsCpuProfilerStruct = re;
59            jsCpuProfilerFind = true;
60          }
61        } else {
62          if (re.frame && isFrameContainPoint(re.frame, jsCpuProfilerRow.hoverX, jsCpuProfilerRow.hoverY)) {
63            JsCpuProfilerStruct.hoverJsCpuProfilerStruct = re;
64            jsCpuProfilerFind = true;
65          }
66        }
67      }
68    }
69    if (!jsCpuProfilerFind && jsCpuProfilerRow.isHover) JsCpuProfilerStruct.hoverJsCpuProfilerStruct = undefined;
70    req.context.closePath();
71  }
72}
73export function jsCpuProfiler(
74  list: Array<any>,
75  filter: Array<any>,
76  startNS: number,
77  endNS: number,
78  totalNS: number,
79  frame: Rect,
80  use: boolean
81) {
82  if (use && filter.length > 0) {
83    for (let i = 0, len = filter.length; i < len; i++) {
84      if ((filter[i].startTime || 0) + (filter[i].totalTime || 0) >= startNS && (filter[i].startTime || 0) <= endNS) {
85        JsCpuProfilerStruct.setJsCpuProfilerFrame(filter[i], startNS, endNS, totalNS, frame);
86      } else {
87        filter[i].frame = null;
88      }
89    }
90    return;
91  }
92  filter.length = 0;
93  if (list) {
94    let groups = list
95      .filter((it) => (it.startTime ?? 0) + (it.totalTime ?? 0) >= startNS && (it.startTime ?? 0) <= endNS)
96      .map((it) => {
97        JsCpuProfilerStruct.setJsCpuProfilerFrame(it, startNS, endNS, totalNS, frame);
98        return it;
99      })
100      .reduce((pre, current) => {
101        (pre[`${current.frame.x}-${current.depth}`] = pre[`${current.frame.x}-${current.depth}`] || []).push(current);
102        return pre;
103      }, {});
104    Reflect.ownKeys(groups).map((kv) => {
105      let arr = groups[kv].sort((a: JsCpuProfilerChartFrame, b: JsCpuProfilerChartFrame) => b.totalTime - a.totalTime);
106      filter.push(arr[0]);
107    });
108  }
109}
110
111const padding = 1;
112export class JsCpuProfilerStruct extends BaseStruct {
113  static lastSelectJsCpuProfilerStruct: JsCpuProfilerStruct | undefined;
114  static selectJsCpuProfilerStruct: JsCpuProfilerStruct | undefined;
115  static hoverJsCpuProfilerStruct: JsCpuProfilerStruct | undefined;
116  id: number = 0;
117  name: string = '';
118  startTime: number = 0;
119  endTime: number = 0;
120  selfTime: number = 0;
121  totalTime: number = 0;
122  url: string = '';
123  depth: number = 0;
124  parentId: number = 0;
125  children!: Array<JsCpuProfilerChartFrame>;
126  isSelect: boolean = false;
127
128  static setJsCpuProfilerFrame(jsCpuProfilerNode: any, startNS: number, endNS: number, totalNS: number, frame: Rect) {
129    let x1: number, x2: number;
130    if ((jsCpuProfilerNode.startTime || 0) > startNS && (jsCpuProfilerNode.startTime || 0) < endNS) {
131      x1 = ns2x(jsCpuProfilerNode.startTime || 0, startNS, endNS, totalNS, frame);
132    } else {
133      x1 = 0;
134    }
135    if (
136      (jsCpuProfilerNode.startTime || 0) + (jsCpuProfilerNode.totalTime || 0) > startNS &&
137      (jsCpuProfilerNode.startTime || 0) + (jsCpuProfilerNode.totalTime || 0) < endNS
138    ) {
139      x2 = ns2x(
140        (jsCpuProfilerNode.startTime || 0) + (jsCpuProfilerNode.totalTime || 0),
141        startNS,
142        endNS,
143        totalNS,
144        frame
145      );
146    } else {
147      x2 = frame.width;
148    }
149    if (!jsCpuProfilerNode.frame) {
150      jsCpuProfilerNode.frame = {};
151    }
152    let getV: number = x2 - x1 < 1 ? 1 : x2 - x1;
153    jsCpuProfilerNode.frame.x = Math.floor(x1);
154    jsCpuProfilerNode.frame.y = jsCpuProfilerNode.depth * 20;
155    jsCpuProfilerNode.frame.width = Math.ceil(getV);
156    jsCpuProfilerNode.frame.height = 20;
157  }
158
159  static draw(jsCpuProfilerCtx: CanvasRenderingContext2D, data: JsCpuProfilerStruct) {
160    if (data.frame) {
161      if (data.endTime - data.startTime == undefined || data.endTime - data.startTime == null) {
162      } else {
163        jsCpuProfilerCtx.globalAlpha = 1;
164        if (data.name === '(program)') {
165          jsCpuProfilerCtx.fillStyle = '#ccc';
166        } else if (data.name === '(idle)') {
167          jsCpuProfilerCtx.fillStyle = '#f0f0f0';
168        } else {
169          jsCpuProfilerCtx.fillStyle =
170            ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.name || '', 0, ColorUtils.FUNC_COLOR.length)];
171        }
172        let miniHeight = 20;
173        if (JsCpuProfilerStruct.hoverJsCpuProfilerStruct && data == JsCpuProfilerStruct.hoverJsCpuProfilerStruct) {
174          jsCpuProfilerCtx.globalAlpha = 0.7;
175        }
176        jsCpuProfilerCtx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2);
177        if (data.frame.width > 8) {
178          jsCpuProfilerCtx.lineWidth = 1;
179          jsCpuProfilerCtx.fillStyle = '#fff';
180          jsCpuProfilerCtx.textBaseline = 'middle';
181          drawString(jsCpuProfilerCtx, `${data.name || ''}`, 4, data.frame, data);
182        }
183        if (data === JsCpuProfilerStruct.selectJsCpuProfilerStruct) {
184          jsCpuProfilerCtx.strokeStyle = '#000';
185          jsCpuProfilerCtx.lineWidth = 2;
186          jsCpuProfilerCtx.strokeRect(
187            data.frame.x + 1,
188            data.frame.y + 1,
189            data.frame.width - 2,
190            miniHeight - padding * 2 - 2
191          );
192        }
193      }
194    }
195  }
196}
197