• 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  drawFlagLine,
19  drawLines,
20  drawLoading,
21  drawLoadingFrame,
22  drawSelection,
23  PerfRender,
24  Rect,
25  RequestMessage,
26} from './ProcedureWorkerCommon';
27import { TraceRow } from '../../component/trace/base/TraceRow';
28
29export class EBPFRender extends PerfRender {
30  renderMainThread(
31    req: {
32      context: CanvasRenderingContext2D;
33      useCache: boolean;
34      type: string;
35      chartColor: string;
36    },
37    eBPFtemRow: TraceRow<EBPFChartStruct>
38  ): void {
39    let filter = eBPFtemRow.dataListCache;
40    let groupBy10MS = (TraceRow.range?.scale || 50) > 40_000_000;
41    let isDiskIO: boolean = req.type.includes('disk-io');
42    eBPFChart(
43      filter,
44      TraceRow.range?.startNS ?? 0,
45      TraceRow.range?.endNS ?? 0,
46      TraceRow.range?.totalNS ?? 0,
47      eBPFtemRow.frame,
48      groupBy10MS,
49      isDiskIO,
50      req.useCache || (TraceRow.range?.refresh ?? false)
51    );
52    drawLoadingFrame(req.context, filter, eBPFtemRow);
53    drawEBPF(req, filter, groupBy10MS, eBPFtemRow);
54  }
55
56  render(eBPFRequest: RequestMessage, list: Array<any>, filter: Array<any>, dataList2: Array<any>): void {}
57}
58
59function drawEBPF(
60  req: {
61    context: CanvasRenderingContext2D;
62    useCache: boolean;
63    type: string;
64    chartColor: string;
65  },
66  filter: any[],
67  groupBy10MS: boolean,
68  eBPFtemRow: TraceRow<EBPFChartStruct>
69) {
70  req.context.beginPath();
71  let find = false;
72  let hoverRect: EBPFChartStruct | undefined = undefined;
73  for (let re of filter) {
74    re.group10Ms = groupBy10MS;
75    if (
76      eBPFtemRow.isHover &&
77      re.frame &&
78      eBPFtemRow.hoverX >= re.frame.x &&
79      eBPFtemRow.hoverX <= re.frame.x + re.frame.width
80    ) {
81      if (hoverRect == undefined || re.size! > hoverRect.size!) {
82        hoverRect = re;
83        find = true;
84      }
85    }
86    if (re.frame && re.frame!.x > eBPFtemRow.hoverX + 3) {
87      break;
88    }
89  }
90  if (hoverRect) {
91    EBPFChartStruct.hoverEBPFStruct = hoverRect;
92  }
93
94  for (let re of filter) {
95    EBPFChartStruct.draw(req.context, re, req.chartColor);
96  }
97  if (!find && eBPFtemRow.isHover) {
98    EBPFChartStruct.hoverEBPFStruct = undefined;
99  }
100  req.context.closePath();
101}
102
103export function eBPFChart(
104  eBPFFilters: Array<any>,
105  startNS: number,
106  endNS: number,
107  totalNS: number,
108  frame: Rect,
109  groupBy10MS: boolean,
110  isDiskIO: boolean,
111  use: boolean
112): void {
113  if (use && eBPFFilters.length > 0 && groupBy10MS) {
114    setFrameGroupBy10MS(eBPFFilters, startNS, endNS, frame);
115    return;
116  }
117  if (!groupBy10MS && eBPFFilters[0] && eBPFFilters[0].dur && eBPFFilters[0].endNS) {
118    setFrameByArr(eBPFFilters, startNS, endNS, frame, totalNS, isDiskIO);
119  }
120}
121
122function setFrameGroupBy10MS(eBPFFilters: Array<any>, startNS: number, endNS: number, frame: Rect) {
123  let pns = (endNS - startNS) / frame.width;
124  let y = frame.y;
125  for (let i = 0; i < eBPFFilters.length; i++) {
126    let it = eBPFFilters[i];
127    if ((it.startNS || 0) + (it.size || 0) > startNS && (it.startNS || 0) < endNS) {
128      if (!it.frame) {
129        it.frame = {};
130        it.frame.y = y;
131      }
132      it.frame.height = it.height;
133      EBPFChartStruct.setFrame(it, pns, startNS, endNS, frame, true);
134    } else {
135      it.frame = null;
136    }
137  }
138}
139
140function setFrameByArr(
141  eBPFFilters: Array<any>,
142  startNS: number,
143  endNS: number,
144  frame: Rect,
145  totalNS: number,
146  isDiskIO: boolean
147) {
148  let list: Array<any> = [];
149  let pns = (endNS - startNS) / frame.width;
150  let y = frame.y;
151  let filter: any[] = [];
152  for (let index = 0; index < eBPFFilters.length; index++) {
153    if (eBPFFilters[index].endNS > startNS && (eBPFFilters[index].startNS || 0) < endNS && eBPFFilters[index].dur > 0) {
154      if (index >= 1 && eBPFFilters[index - 1].endNS === eBPFFilters[index].startNS) {
155        continue;
156      } else {
157        eBPFFilters[index].size = 0;
158        filter.push(eBPFFilters[index]);
159      }
160    }
161  }
162  eBPFFilters.length = 0;
163  list = isDiskIO
164    ? EBPFChartStruct.computeHeightNoGroupLatency(filter, totalNS)
165    : EBPFChartStruct.computeHeightNoGroup(filter, totalNS);
166  list.map((it) => {
167    if (!it.frame) {
168      it.frame = {};
169      it.frame.y = y;
170    }
171    EBPFChartStruct.setFrame(it, pns, startNS, endNS, frame, false);
172    eBPFFilters.push(it);
173  });
174}
175
176export class EBPFChartStruct extends BaseStruct {
177  static hoverEBPFStruct: EBPFChartStruct | undefined;
178  startNS: number | undefined;
179  endNS: number | undefined;
180  dur: number | undefined;
181  size: number | undefined;
182  height: number | undefined;
183  group10Ms: boolean | undefined;
184
185  static draw(ctx: CanvasRenderingContext2D, data: EBPFChartStruct, chartColor: string): void {
186    if (data.frame) {
187      ctx.fillStyle = chartColor;
188      ctx.strokeStyle = chartColor;
189      ctx.fillRect(data.frame.x, 40 - (data.height || 0), data.frame.width, data.height || 0);
190    }
191  }
192
193  static setFrame(
194    eBPFtemNode: any,
195    pns: number,
196    startNS: number,
197    endNS: number,
198    frame: any,
199    groupBy10MS: boolean
200  ): void {
201    if ((eBPFtemNode.startNS || 0) < startNS) {
202      eBPFtemNode.frame.x = 0;
203    } else {
204      eBPFtemNode.frame.x = Math.floor(((eBPFtemNode.startNS || 0) - startNS) / pns);
205    }
206    if ((eBPFtemNode.startNS || 0) + (eBPFtemNode.dur || 0) > endNS) {
207      eBPFtemNode.frame.width = frame.width - eBPFtemNode.frame.x;
208    } else {
209      if (groupBy10MS) {
210        eBPFtemNode.frame.width = Math.ceil(((eBPFtemNode.endNS || 0) - (eBPFtemNode.startNS || 0)) / pns);
211      } else {
212        eBPFtemNode.frame.width = Math.ceil(
213          ((eBPFtemNode.startNS || 0) + (eBPFtemNode.dur || 0) - startNS) / pns - eBPFtemNode.frame.x
214        );
215      }
216    }
217    if (eBPFtemNode.frame.width < 1) {
218      eBPFtemNode.frame.width = 1;
219    }
220  }
221
222  static computeHeightNoGroup(array: Array<any>, totalNS: number): Array<any> {
223    if (array.length > 0) {
224      let time: Array<{ time: number; type: number }> = [];
225      array.map((item) => {
226        time.push({ time: item.startNS, type: 1 });
227        time.push({ time: item.endNS || totalNS, type: -1 });
228      });
229      time = time.sort((a, b) => a.time - b.time);
230      let arr: Array<any> = [];
231      let first = {
232        startNS: time[0].time ?? 0,
233        dur: 0,
234        size: 1,
235        group10Ms: false,
236        height: 1,
237      };
238      arr.push(first);
239      let max = 2;
240      for (let i = 1, len = time.length; i < len; i++) {
241        let heap = {
242          startNS: time[i].time,
243          dur: 0,
244          size: 0,
245          group10Ms: false,
246          height: 0,
247        };
248        arr[i - 1].dur = heap.startNS - arr[i - 1].startNS;
249        if (i == len - 1) {
250          heap.dur = totalNS - heap.startNS;
251        }
252        heap.size = arr[i - 1].size + time[i].type;
253        heap.height = Math.floor((heap.size / 6) * 36);
254        max = max > heap.size ? max : heap.size;
255        arr.push(heap);
256      }
257      arr.map((it) => (it.height = Math.floor((it.size / max) * 36)));
258      return arr;
259    } else {
260      return [];
261    }
262  }
263
264  static computeHeightNoGroupLatency(array: Array<any>, totalNS: number): Array<any> {
265    if (array.length > 0) {
266      let max = 0;
267      let arr: Array<any> = [];
268      for (let io of array) {
269        let ioItem = {
270          startNS: io.startNS,
271          dur: io.endNS > totalNS ? totalNS - io.startNS : io.endNS - io.startNS,
272          size: io.dur,
273          group10Ms: false,
274          height: 0,
275        };
276        max = max > ioItem.size ? max : ioItem.size;
277        arr.push(ioItem);
278      }
279      arr.map((it) => {
280        let height = Math.floor((it.size / max) * 36);
281        it.height = height < 1 ? 1 : height;
282      });
283      return arr;
284    } else {
285      return [];
286    }
287  }
288}
289