• 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 { ColorUtils } from '../../component/trace/base/ColorUtils';
17import { TraceRow } from '../../component/trace/base/TraceRow';
18import {
19  BaseStruct,
20  isFrameContainPoint,
21  ns2x,
22  Rect,
23  Render,
24  RequestMessage,
25  drawString,
26  drawLoadingFrame,
27} from './ProcedureWorkerCommon';
28import { FuncStruct as BaseFuncStruct } from '../../bean/FuncStruct';
29import { FlagsConfig } from '../../component/SpFlags';
30import {TabPaneTaskFrames} from "../../component/trace/sheet/task/TabPaneTaskFrames";
31export class FuncRender extends Render {
32  renderMainThread(
33    req: {
34      useCache: boolean;
35      context: CanvasRenderingContext2D;
36      type: string;
37    },
38    row: TraceRow<FuncStruct>
39  ) {
40    let funcList = row.dataList;
41    let funcFilter = row.dataListCache;
42    func(
43      funcList,
44      funcFilter,
45      TraceRow.range!.startNS,
46      TraceRow.range!.endNS,
47      TraceRow.range!.totalNS,
48      row.frame,
49      req.useCache || !TraceRow.range!.refresh,
50      row.funcExpand
51    );
52    drawLoadingFrame(req.context, funcFilter, row, true);
53    req.context.beginPath();
54    let funcFind = false;
55    for (let re of funcFilter) {
56      FuncStruct.draw(req.context, re);
57      if (row.isHover) {
58        if (re.dur == 0 || re.dur == null || re.dur == undefined) {
59          if (
60            re.frame &&
61            row.hoverX >= re.frame.x - 5 &&
62            row.hoverX <= re.frame.x + 5 &&
63            row.hoverY >= re.frame.y &&
64            row.hoverY <= re.frame.y + re.frame.height
65          ) {
66            FuncStruct.hoverFuncStruct = re;
67            funcFind = true;
68          }
69        } else {
70          if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) {
71            FuncStruct.hoverFuncStruct = re;
72            funcFind = true;
73          }
74        }
75      }
76    }
77    if (!funcFind && row.isHover) FuncStruct.hoverFuncStruct = undefined;
78    req.context.closePath();
79  }
80
81  render(req: RequestMessage, list: Array<any>, filter: Array<any>) {}
82}
83
84export function func(
85  funcList: Array<any>,
86  funcFilter: Array<any>,
87  startNS: number,
88  endNS: number,
89  totalNS: number,
90  frame: any,
91  use: boolean,
92  expand: boolean
93) {
94  if (use && funcFilter.length > 0) {
95    for (let i = 0, len = funcFilter.length; i < len; i++) {
96      if ((funcFilter[i].startTs || 0) + (funcFilter[i].dur || 0) >= startNS && (funcFilter[i].startTs || 0) <= endNS) {
97        FuncStruct.setFuncFrame(funcFilter[i], 0, startNS, endNS, totalNS, frame);
98      } else {
99        funcFilter[i].frame = null;
100      }
101    }
102    return;
103  }
104  funcFilter.length = 0;
105  if (funcList) {
106    let groups = funcList
107      .filter(
108        (it) =>
109          (it.startTs ?? 0) + (it.dur ?? 0) >= startNS &&
110          (it.startTs ?? 0) <= endNS &&
111          ((!expand && it.depth === 0) || expand)
112      )
113      .map((it) => {
114        FuncStruct.setFuncFrame(it, 0, startNS, endNS, totalNS, frame);
115        return it;
116      })
117      .reduce((pre, current, index, arr) => {
118        (pre[`${current.frame.x}-${current.depth}`] = pre[`${current.frame.x}-${current.depth}`] || []).push(current);
119        return pre;
120      }, {});
121    Reflect.ownKeys(groups).map((kv) => {
122      let arr = groups[kv].sort((a: any, b: any) => b.dur - a.dur);
123      funcFilter.push(arr[0]);
124    });
125  }
126}
127export function FuncStructOnClick(clickRowType: string, sp:any,row:TraceRow<any>|undefined, scrollToFuncHandler: any) {
128  return new Promise((resolve, reject) => {
129    if (clickRowType === TraceRow.ROW_TYPE_FUNC && FuncStruct.hoverFuncStruct) {
130      TabPaneTaskFrames.TaskArray = [];
131      sp.removeLinkLinesByBusinessType('task');
132      FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct;
133      let hoverFuncStruct = FuncStruct.hoverFuncStruct;
134      sp.timerShaftEL?.drawTriangle(FuncStruct.selectFuncStruct!.startTs || 0, 'inverted');
135      FuncStruct.selectFuncStruct = hoverFuncStruct;
136      let flagConfig = FlagsConfig.getFlagsConfig('TaskPool');
137      let showTabArray: Array<string> = ['current-selection'];
138      if (flagConfig!.TaskPool === 'Enabled') {
139        if (FuncStruct.selectFuncStruct?.funName) {
140          if (FuncStruct.selectFuncStruct.funName.indexOf('H:Task ') >= 0) {
141            showTabArray.push('box-task-frames');
142            sp.drawTaskPollLine(row);
143          }
144        }
145      }
146      sp.traceSheetEL?.displayFuncData(showTabArray, FuncStruct.selectFuncStruct, scrollToFuncHandler);
147      sp.timerShaftEL?.modifyFlagList(undefined);
148      reject();
149    } else {
150      resolve(null);
151    }
152  });
153}
154export class FuncStruct extends BaseFuncStruct {
155  static hoverFuncStruct: FuncStruct | undefined;
156  static selectFuncStruct: FuncStruct | undefined;
157  flag: string | undefined; // 570000
158  textMetricsWidth: number | undefined;
159  static setFuncFrame(funcNode: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) {
160    let x1: number, x2: number;
161    if ((funcNode.startTs || 0) > startNS && (funcNode.startTs || 0) <= endNS) {
162      x1 = ns2x(funcNode.startTs || 0, startNS, endNS, totalNS, frame);
163    } else {
164      x1 = 0;
165    }
166    if (
167      (funcNode.startTs || 0) + (funcNode.dur || 0) > startNS &&
168      (funcNode.startTs || 0) + (funcNode.dur || 0) <= endNS
169    ) {
170      x2 = ns2x((funcNode.startTs || 0) + (funcNode.dur || 0), startNS, endNS, totalNS, frame);
171    } else {
172      x2 = frame.width;
173    }
174    if (!funcNode.frame) {
175      funcNode.frame = {};
176    }
177    let getV: number = x2 - x1 < 1 ? 1 : x2 - x1;
178    funcNode.frame.x = Math.floor(x1);
179    funcNode.frame.y = funcNode.depth * 20;
180    funcNode.frame.width = Math.ceil(getV);
181    funcNode.frame.height = 20;
182  }
183
184  static draw(ctx: CanvasRenderingContext2D, data: FuncStruct) {
185    if (data.frame) {
186      let isBinder = FuncStruct.isBinder(data);
187      if (data.dur == undefined || data.dur == null) {
188      } else {
189        ctx.globalAlpha = 1;
190        ctx.fillStyle = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)];
191        let textColor = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)];
192        let miniHeight = 20;
193        if (FuncStruct.hoverFuncStruct && data.funName == FuncStruct.hoverFuncStruct.funName) {
194          ctx.globalAlpha = 0.7;
195        }
196        ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2);
197        if (data.frame.width > 10) {
198          ctx.strokeStyle = '#fff';
199          ctx.lineWidth = 1;
200          ctx.strokeRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2);
201          ctx.fillStyle = ColorUtils.funcTextColor(textColor);
202          drawString(ctx, `${data.funName || ''}`, 5, data.frame, data);
203        }
204        if (data.callid == FuncStruct.selectFuncStruct?.callid&&
205          data.startTs == FuncStruct.selectFuncStruct?.startTs&&
206          data.depth == FuncStruct.selectFuncStruct?.depth) {
207          ctx.strokeStyle = '#000';
208          ctx.lineWidth = 2;
209          ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2);
210        }
211        let flagConfig = FlagsConfig.getFlagsConfig('TaskPool');
212        if (
213          flagConfig!.TaskPool === 'Enabled' &&
214          data.funName!.indexOf('H:Task PerformTask End:') >= 0 &&
215          data.funName!.indexOf('Successful') < 0
216        ) {
217          if (data.frame!.width < 10) {
218            FuncStruct.drawTaskPoolUnSuccessFlag(ctx, data.frame!.x, (data.depth! + 0.5) * 20, 3, data!);
219          } else {
220            FuncStruct.drawTaskPoolUnSuccessFlag(ctx, data.frame!.x, (data.depth! + 0.5) * 20, 6, data!);
221          }
222        }
223        if (flagConfig!.TaskPool === 'Enabled' && data.funName!.indexOf('H:Thread Timeout Exit') >= 0) {
224          FuncStruct.drawTaskPoolTimeOutFlag(ctx, data.frame!.x, (data.depth! + 0.5) * 20, 10, data!);
225        }
226      }
227    }
228  }
229
230  static drawTaskPoolUnSuccessFlag(
231    ctx: CanvasRenderingContext2D,
232    x: number,
233    y: number,
234    radius: number,
235    data: FuncStruct
236  ): void {
237    ctx.strokeStyle = '#FFC880';
238    ctx.lineWidth = 1;
239    ctx.beginPath();
240    ctx.arc(x + data.frame!.width, y, radius, 0, Math.PI * 2);
241    ctx.closePath();
242    ctx.fillStyle = '#E64566';
243    ctx.fill();
244    ctx.stroke();
245  }
246
247  static drawTaskPoolTimeOutFlag(
248    canvas: CanvasRenderingContext2D,
249    x: number,
250    y: number,
251    radius: number,
252    data: FuncStruct
253  ): void {
254    canvas.strokeStyle = '#FFC880';
255    canvas.lineWidth = 1;
256    canvas.beginPath();
257    canvas.arc(x + data.frame!.width + 20, y, radius, 0, Math.PI * 2);
258    canvas.closePath();
259    canvas.fillStyle = '#FFC880';
260    canvas.fill();
261    canvas.stroke();
262    canvas.font = '18px Arial';
263    canvas.fillStyle = ColorUtils.GREY_COLOR;
264    canvas.textAlign = 'center';
265    canvas.fillText('¡', x + data.frame!.width + 20, y);
266  }
267
268  static isSelected(data: FuncStruct): boolean {
269    return (
270      FuncStruct.selectFuncStruct != undefined &&
271      FuncStruct.selectFuncStruct.startTs == data.startTs &&
272      FuncStruct.selectFuncStruct.depth == data.depth
273    );
274  }
275}
276
277const padding = 1;
278