• 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 {
17  BaseStruct,
18  dataFilterHandler,
19  drawFlagLine,
20  drawLines,
21  drawLoading,
22  drawSelection,
23  drawWakeUp,
24  ns2x,
25  PerfRender,
26  Render,
27  RequestMessage,
28} from './ProcedureWorkerCommon.js';
29import { TraceRow } from '../../component/trace/base/TraceRow.js';
30import { ColorUtils } from '../../component/trace/base/ColorUtils.js';
31import { convertJSON } from '../logic-worker/ProcedureLogicWorkerCommon.js';
32
33export class CpuStateRender extends PerfRender {
34  renderMainThread(
35    req: {
36      useCache: boolean;
37      context: CanvasRenderingContext2D;
38      type: string;
39      cpu: number;
40    },
41    row: TraceRow<CpuStateStruct>
42  ) {
43    let list = row.dataList;
44    let filter = row.dataListCache;
45    let chartColor = ColorUtils.colorForTid(req.cpu);
46    dataFilterHandler(list, filter, {
47      startKey: 'startTs',
48      durKey: 'dur',
49      startNS: TraceRow.range?.startNS ?? 0,
50      endNS: TraceRow.range?.endNS ?? 0,
51      totalNS: TraceRow.range?.totalNS ?? 0,
52      frame: row.frame,
53      paddingTop: 5,
54      useCache: req.useCache || !(TraceRow.range?.refresh ?? false),
55    });
56    req.context.beginPath();
57    req.context.font = '11px sans-serif';
58    req.context.fillStyle = chartColor;
59    req.context.strokeStyle = chartColor;
60    req.context.globalAlpha = 0.6;
61    let path = new Path2D();
62    let find = false;
63    let offset = 3;
64    let heights = [4, 12, 21, 30];
65    for (let re of filter) {
66      re.height = heights[(re as any).value];
67      CpuStateStruct.draw(req.context, path, re);
68      if (row.isHover) {
69        if (re.frame && row.hoverX >= re.frame.x - offset && row.hoverX <= re.frame.x + re.frame.width + offset) {
70          CpuStateStruct.hoverStateStruct = re;
71          find = true;
72        }
73      }
74    }
75    if (!find && row.isHover) CpuStateStruct.hoverStateStruct = undefined;
76    req.context.fill(path);
77  }
78
79  render(cpuStateReq: RequestMessage, list: Array<any>, filter: Array<any>, dataList2: Array<any>) {
80    if (cpuStateReq.lazyRefresh) {
81      this.cpuState(
82        list,
83        dataList2,
84        cpuStateReq.type!,
85        filter,
86        cpuStateReq.params.cpu,
87        cpuStateReq.startNS,
88        cpuStateReq.endNS,
89        cpuStateReq.totalNS,
90        cpuStateReq.frame,
91        cpuStateReq.useCache || !cpuStateReq.range.refresh
92      );
93    } else {
94      if (!cpuStateReq.useCache) {
95        this.cpuState(
96          list,
97          dataList2,
98          cpuStateReq.type!,
99          filter,
100          cpuStateReq.params.cpu,
101          cpuStateReq.startNS,
102          cpuStateReq.endNS,
103          cpuStateReq.totalNS,
104          cpuStateReq.frame,
105          false
106        );
107      }
108    }
109    CpuStateStruct.hoverStateStruct = undefined;
110    if (cpuStateReq.canvas) {
111      cpuStateReq.context.clearRect(0, 0, cpuStateReq.frame.width, cpuStateReq.frame.height);
112      if (filter.length > 0 && !cpuStateReq.range.refresh && !cpuStateReq.useCache && cpuStateReq.lazyRefresh) {
113        drawLoading(
114          cpuStateReq.context,
115          cpuStateReq.startNS,
116          cpuStateReq.endNS,
117          cpuStateReq.totalNS,
118          cpuStateReq.frame,
119          filter[0].startTs,
120          filter[filter.length - 1].startTs + filter[filter.length - 1].dur
121        );
122      }
123      cpuStateReq.context.beginPath();
124      drawLines(cpuStateReq.context, cpuStateReq.xs, cpuStateReq.frame.height, cpuStateReq.lineColor);
125      if (cpuStateReq.isHover) {
126        let offset = 3;
127        for (let re of filter) {
128          if (
129            re.frame &&
130            cpuStateReq.hoverX >= re.frame.x - offset &&
131            cpuStateReq.hoverX <= re.frame.x + re.frame.width + offset
132          ) {
133            CpuStateStruct.hoverStateStruct = re;
134            break;
135          }
136        }
137      }
138      CpuStateStruct.selectStateStruct = cpuStateReq.params.selectStateStruct;
139      cpuStateReq.context.font = '11px sans-serif';
140      cpuStateReq.context.fillStyle = cpuStateReq.chartColor;
141      cpuStateReq.context.strokeStyle = cpuStateReq.chartColor;
142      cpuStateReq.context.globalAlpha = 0.6;
143      let path = new Path2D();
144      for (let re of filter) {
145        CpuStateStruct.draw(cpuStateReq.context, path, re);
146      }
147      cpuStateReq.context.fill(path);
148      drawSelection(cpuStateReq.context, cpuStateReq.params);
149      drawFlagLine(
150        cpuStateReq.context,
151        cpuStateReq.flagMoveInfo,
152        cpuStateReq.flagSelectedInfo,
153        cpuStateReq.startNS,
154        cpuStateReq.endNS,
155        cpuStateReq.totalNS,
156        cpuStateReq.frame,
157        cpuStateReq.slicesTime
158      );
159    }
160    let msg = {
161      id: cpuStateReq.id,
162      type: cpuStateReq.type,
163      results: cpuStateReq.canvas ? undefined : filter,
164      hover: CpuStateStruct.hoverStateStruct,
165    };
166    self.postMessage(msg);
167  }
168
169  cpuState(
170    arr: Array<any>,
171    arr2: Array<any>,
172    type: string,
173    cpuStateRes: Array<any>,
174    cpu: number,
175    startNS: number,
176    endNS: number,
177    totalNS: number,
178    frame: any,
179    use: boolean
180  ) {
181    if (use && cpuStateRes.length > 0) {
182      for (let i = 0, len = cpuStateRes.length; i < len; i++) {
183        if (
184          (cpuStateRes[i].startTs || 0) + (cpuStateRes[i].dur || 0) >= startNS &&
185          (cpuStateRes[i].startTs || 0) <= endNS
186        ) {
187          CpuStateStruct.setFrame(cpuStateRes[i], 5, startNS, endNS, totalNS, frame);
188        } else {
189          cpuStateRes[i].frame = null;
190        }
191      }
192      return;
193    }
194    cpuStateRes.length = 0;
195    if (arr) {
196      let list: Array<any> = arr2;
197      cpuStateRes.length = 0;
198      let pns = (endNS - startNS) / frame.width; //每个像素多少ns
199      let y = frame.y + 5;
200      let frameHeight = frame.height - 10;
201      let left = 0,
202        right = 0;
203      for (let i = 0, j = list.length - 1, ib = true, jb = true; i < list.length, j >= 0; i++, j--) {
204        if (list[j].startTs <= endNS && jb) {
205          right = j;
206          jb = false;
207        }
208        if (list[i].startTs + list[i].dur >= startNS && ib) {
209          left = i;
210          ib = false;
211        }
212        if (!ib && !jb) {
213          break;
214        }
215      }
216      let slice = list.slice(left, right + 1);
217      let sum = 0;
218      for (let i = 0; i < slice.length; i++) {
219        if (!slice[i].frame) {
220          slice[i].frame = {};
221          slice[i].frame.y = y;
222          slice[i].frame.height = frameHeight;
223        }
224        if (slice[i].dur >= pns) {
225          slice[i].v = true;
226          CpuStateStruct.setFrame(slice[i], 5, startNS, endNS, totalNS, frame);
227        } else {
228          if (i > 0) {
229            let c = slice[i].startTs - slice[i - 1].startTs - slice[i - 1].dur;
230            if (c < pns && sum < pns) {
231              sum += c + slice[i - 1].dur;
232              slice[i].v = false;
233            } else {
234              slice[i].v = true;
235              CpuStateStruct.setFrame(slice[i], 5, startNS, endNS, totalNS, frame);
236              sum = 0;
237            }
238          }
239        }
240      }
241      cpuStateRes.push(...slice.filter((it) => it.v));
242    }
243  }
244}
245
246export class CpuStateStruct extends BaseStruct {
247  static hoverStateStruct: CpuStateStruct | undefined;
248  static selectStateStruct: CpuStateStruct | undefined;
249  dur: number | undefined;
250  value: string | undefined;
251  startTs: number | undefined;
252  height: number | undefined;
253  cpu: number | undefined;
254
255  static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: CpuStateStruct) {
256    if (data.frame) {
257      if (data === CpuStateStruct.hoverStateStruct || data === CpuStateStruct.selectStateStruct) {
258        path.rect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0);
259        ctx.lineWidth = 1;
260        ctx.globalAlpha = 1.0;
261        ctx.beginPath();
262        ctx.arc(data.frame.x, 35 - (data.height || 0), 3, 0, 2 * Math.PI, true);
263        ctx.stroke();
264        ctx.beginPath();
265        ctx.moveTo(data.frame.x + 3, 35 - (data.height || 0));
266        ctx.lineWidth = 3;
267        ctx.lineTo(data.frame.x + data.frame.width, 35 - (data.height || 0));
268        ctx.stroke();
269        ctx.lineWidth = 1;
270        ctx.globalAlpha = 0.6;
271        ctx.fillRect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0);
272      } else {
273        ctx.globalAlpha = 0.6;
274        path.rect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0);
275      }
276    }
277  }
278
279  static setCpuFrame(cpuStateNode: any, pns: number, startNS: number, endNS: number, frame: any) {
280    if ((cpuStateNode.startTime || 0) < startNS) {
281      cpuStateNode.frame.x = 0;
282    } else {
283      cpuStateNode.frame.x = Math.floor(((cpuStateNode.startTs || 0) - startNS) / pns);
284    }
285    if ((cpuStateNode.startTime || 0) + (cpuStateNode.dur || 0) > endNS) {
286      cpuStateNode.frame.width = frame.width - cpuStateNode.frame.x;
287    } else {
288      cpuStateNode.frame.width = Math.ceil(
289        ((cpuStateNode.startTs || 0) + (cpuStateNode.dur || 0) - startNS) / pns - cpuStateNode.frame.x
290      );
291    }
292    if (cpuStateNode.frame.width < 1) {
293      cpuStateNode.frame.width = 1;
294    }
295  }
296  static setFrame(cpuStateNode: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) {
297    let x1: number, x2: number;
298    if ((cpuStateNode.startTs || 0) < startNS) {
299      x1 = 0;
300    } else {
301      x1 = ns2x(cpuStateNode.startTs || 0, startNS, endNS, totalNS, frame);
302    }
303    if ((cpuStateNode.startTs || 0) + (cpuStateNode.dur || 0) > endNS) {
304      x2 = frame.width;
305    } else {
306      x2 = ns2x((cpuStateNode.startTs || 0) + (cpuStateNode.dur || 0), startNS, endNS, totalNS, frame);
307    }
308    let cpuStateGetV: number = x2 - x1 <= 1 ? 1 : x2 - x1;
309    if (!cpuStateNode.frame) {
310      cpuStateNode.frame = {};
311    }
312    cpuStateNode.frame.x = Math.ceil(x1);
313    cpuStateNode.frame.y = frame.y + padding;
314    cpuStateNode.frame.width = Math.floor(cpuStateGetV);
315    cpuStateNode.frame.height = cpuStateNode.height;
316  }
317}
318