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