• 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 {JanksStruct} from '../../bean/JanksStruct';
17import {ColorUtils} from '../../component/trace/base/ColorUtils';
18import {TraceRow} from '../../component/trace/base/TraceRow';
19import {
20  drawLoadingFrame,
21  drawString,
22  isFrameContainPoint,
23  ns2x,
24  Render,
25  RequestMessage,
26} from './ProcedureWorkerCommon';
27import {SpSystemTrace} from "../../component/SpSystemTrace";
28
29export class JankRender extends Render {
30  renderMainThread(
31    req: {
32      useCache: boolean;
33      context: CanvasRenderingContext2D;
34      type: string;
35    },
36    row: TraceRow<JankStruct>
37  ): void {
38    let jankList = row.dataList;
39    let jankFilter = row.dataListCache;
40    jank(
41      jankList,
42      jankFilter,
43      TraceRow.range!.startNS,
44      TraceRow.range!.endNS,
45      TraceRow.range!.totalNS,
46      row.frame,
47      req.useCache || !TraceRow.range!.refresh
48    );
49    drawLoadingFrame(req.context, row.dataListCache, row);
50    req.context.beginPath();
51    let find = false;
52    let nsScale = ((TraceRow.range!.endNS || 0) - (TraceRow.range!.startNS || 0)) / (TraceRow.range!.totalNS * 9);
53    for (let re of jankFilter) {
54      JankStruct.draw(req.context, re, nsScale);
55      if (row.isHover) {
56        if (re.dur == 0 || re.dur == null || re.dur == undefined) {
57          if (
58            re.frame &&
59            row.hoverX >= re.frame.x - 5 &&
60            row.hoverX <= re.frame.x + 5 &&
61            row.hoverY >= re.frame.y &&
62            row.hoverY <= re.frame.y + re.frame.height
63          ) {
64            JankStruct.hoverJankStruct = re;
65            find = true;
66          }
67        } else {
68          if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
69            JankStruct.hoverJankStruct = re;
70            find = true;
71          }
72        }
73      }
74    }
75    if (!find && row.isHover) JankStruct.hoverJankStruct = undefined;
76    req.context.closePath();
77  }
78
79  render(req: RequestMessage, list: Array<any>, filter: Array<any>): void {
80  }
81}
82
83export function jank(
84  jankList: Array<any>,
85  jankFilter: Array<any>,
86  startNS: number,
87  endNS: number,
88  totalNS: number,
89  frame: any,
90  use: boolean
91): void {
92  if (use && jankFilter.length > 0) {
93    for (let i = 0, len = jankFilter.length; i < len; i++) {
94      if ((jankFilter[i].ts || 0) + (jankFilter[i].dur || 0) >= startNS && (jankFilter[i].ts || 0) <= endNS) {
95        JankStruct.setJankFrame(jankFilter[i], 0, startNS, endNS, totalNS, frame);
96      } else {
97        jankFilter[i].frame = null;
98      }
99    }
100    return;
101  }
102  jankFilter.length = 0;
103  if (jankList) {
104    let groups = jankList
105      .filter((it) => (it.ts ?? 0) + (it.dur ?? 0) >= startNS && (it.ts ?? 0) <= endNS)
106      .map((it) => {
107        JankStruct.setJankFrame(it, 0, startNS, endNS, totalNS, frame);
108        return it;
109      })
110      .reduce((pre, current, index, arr) => {
111        (pre[`${current.frame.x}-${current.depth}`] = pre[`${current.frame.x}-${current.depth}`] || []).push(current);
112        return pre;
113      }, {});
114    Reflect.ownKeys(groups).map((kv) => {
115      let arr = groups[kv].sort((a: any, b: any) => b.dur - a.dur);
116      jankFilter.push(arr[0]);
117    });
118  }
119}
120
121export function JankStructOnClick(clickRowType: string, sp: SpSystemTrace, jankClickHandler: any) {
122  return new Promise((resolve, reject) => {
123    if (clickRowType === TraceRow.ROW_TYPE_JANK && JankStruct.hoverJankStruct) {
124      JankStruct.selectJankStructList.length = 0;
125      sp.removeLinkLinesByBusinessType('janks');
126      JankStruct.selectJankStruct = JankStruct.hoverJankStruct;
127      sp.timerShaftEL?.drawTriangle(JankStruct.selectJankStruct!.ts || 0, 'inverted');
128      sp.traceSheetEL?.displayJankData(
129        JankStruct.selectJankStruct,
130        (datas) => {
131          datas.forEach((data) => {
132            let endParentRow;
133            if (data.frame_type == 'frameTime') {
134              endParentRow = sp.shadowRoot?.querySelector<TraceRow<JankStruct>>(
135                `trace-row[row-id='frameTime'][row-type='janks']`
136              );
137            } else {
138              endParentRow = sp.shadowRoot?.querySelector<TraceRow<any>>(`trace-row[row-id='${data.pid}'][folder]`);
139            }
140            sp.drawJankLine(endParentRow, JankStruct.selectJankStruct!, data);
141          });
142        },
143        jankClickHandler
144      );
145      reject();
146    } else {
147      resolve(null);
148    }
149  });
150
151}
152
153export class JankStruct extends JanksStruct {
154  static hoverJankStruct: JankStruct | undefined;
155  static selectJankStruct: JankStruct | undefined;
156  static selectJankStructList: Array<JankStruct> = new Array<JankStruct>();
157
158  static setJankFrame(
159    jankNode: any,
160    padding: number,
161    startNS: number,
162    endNS: number,
163    totalNS: number,
164    frame: any
165  ): void {
166    let x1: number, x2: number;
167    if ((jankNode.ts || 0) > startNS && (jankNode.ts || 0) < endNS) {
168      x1 = ns2x(jankNode.ts || 0, startNS, endNS, totalNS, frame);
169    } else {
170      x1 = 0;
171    }
172    if ((jankNode.ts || 0) + (jankNode.dur || 0) > startNS && (jankNode.ts || 0) + (jankNode.dur || 0) < endNS) {
173      x2 = ns2x((jankNode.ts || 0) + (jankNode.dur || 0), startNS, endNS, totalNS, frame);
174    } else {
175      x2 = frame.width;
176    }
177    if (!jankNode.frame) {
178      jankNode.frame = {};
179    }
180    let getV: number = x2 - x1 < 1 ? 1 : x2 - x1;
181    jankNode.frame.x = Math.floor(x1);
182    jankNode.frame.y = jankNode.depth * 20;
183    jankNode.frame.width = Math.ceil(getV);
184    jankNode.frame.height = 20;
185  }
186
187  static draw(ctx: CanvasRenderingContext2D, data: JankStruct, nsScale: number): void {
188    if (data.frame) {
189      if (data.dur == undefined || data.dur == null || data.dur == 0) {
190      } else {
191        ctx.globalAlpha = 1;
192        ctx.fillStyle = ColorUtils.JANK_COLOR[0];
193        if (data.jank_tag === 1) {
194          ctx.fillStyle = ColorUtils.JANK_COLOR[2];
195        } else if (data.jank_tag === 3) {
196          ctx.fillStyle = ColorUtils.JANK_COLOR[3];
197        }
198        let miniHeight = 20;
199        if (
200          JankStruct.hoverJankStruct &&
201          data.name == JankStruct.hoverJankStruct.name &&
202          JankStruct.hoverJankStruct.type == data.type &&
203          JankStruct.hoverJankStruct.pid == data.pid &&
204          JankStruct.hoverJankStruct.frame_type == data.frame_type
205        ) {
206          ctx.globalAlpha = 0.7;
207        }
208        if (data.type == '0') {
209          this.drawActualFrame(ctx, data, miniHeight);
210        } else {
211          this.drawExpectedFrame(data, nsScale, ctx, miniHeight);
212        }
213        if (data.frame.width > 10) {
214          ctx.fillStyle = '#fff';
215          drawString(ctx, `${data.name || ''}`, 5, data.frame, data);
216        }
217        if (JankStruct.isSelected(data)) {
218          ctx.strokeStyle = '#000';
219          ctx.lineWidth = 2;
220          ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2);
221        }
222      }
223    }
224  }
225
226  private static drawExpectedFrame(
227    data: JankStruct,
228    nsScale: number,
229    ctx: CanvasRenderingContext2D,
230    miniHeight: number
231  ): void {
232    if (data.frame && data.frame.width * nsScale < 1.5) {
233      ctx.fillStyle = '#FFFFFF';
234      ctx.fillRect(data.frame.x, data.frame.y, data.frame.width * nsScale, miniHeight - padding * 2);
235      ctx.fillStyle = ColorUtils.JANK_COLOR[0];
236      ctx.fillRect(
237        data.frame.x + data.frame.width * nsScale,
238        data.frame.y,
239        data.frame.width - nsScale * 2,
240        miniHeight - padding * 2
241      );
242      ctx.fillStyle = '#FFFFFF';
243      ctx.fillRect(
244        data.frame.x + data.frame.width * nsScale + data.frame.width - nsScale * 2,
245        data.frame.y,
246        data.frame.width * nsScale,
247        miniHeight - padding * 2
248      );
249    } else {
250      ctx.fillStyle = ColorUtils.JANK_COLOR[0];
251      if (data.frame) {
252        ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2);
253      }
254    }
255  }
256
257  private static drawActualFrame(ctx: CanvasRenderingContext2D, data: JankStruct, miniHeight: number): void {
258    ctx.fillStyle = ColorUtils.JANK_COLOR[0];
259    if (data.jank_tag === 1) {
260      ctx.fillStyle = ColorUtils.JANK_COLOR[2];
261    } else if (data.jank_tag === 3) {
262      ctx.fillStyle = ColorUtils.JANK_COLOR[3];
263    }
264    if (data.frame) {
265      ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2);
266    }
267  }
268
269  static isSelected(data: JankStruct): boolean {
270    return (
271      JankStruct.selectJankStruct != undefined &&
272      JankStruct.selectJankStruct.ts == data.ts &&
273      JankStruct.selectJankStruct.type == data.type &&
274      JankStruct.selectJankStruct.pid == data.pid &&
275      JankStruct.selectJankStruct.frame_type == data.frame_type
276    );
277  }
278}
279
280const padding = 1;
281