1fb726d48Sopenharmony_ci/*
2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd.
3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb726d48Sopenharmony_ci * You may obtain a copy of the License at
6fb726d48Sopenharmony_ci *
7fb726d48Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb726d48Sopenharmony_ci *
9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and
13fb726d48Sopenharmony_ci * limitations under the License.
14fb726d48Sopenharmony_ci */
15fb726d48Sopenharmony_ci
16fb726d48Sopenharmony_ciimport { SpApplication } from '../SpApplication';
17fb726d48Sopenharmony_ciimport { Rect } from '../component/trace/timer-shaft/Rect';
18fb726d48Sopenharmony_ciimport { warn } from '../../log/Log';
19fb726d48Sopenharmony_ciimport { BaseStruct, drawString } from '../database/ui-worker/ProcedureWorkerCommon';
20fb726d48Sopenharmony_ci
21fb726d48Sopenharmony_ciconst padding: number = 1;
22fb726d48Sopenharmony_ciconst rectHeight = 20;
23fb726d48Sopenharmony_ciconst lightBlue = {
24fb726d48Sopenharmony_ci  r: 82,
25fb726d48Sopenharmony_ci  g: 145,
26fb726d48Sopenharmony_ci  b: 255,
27fb726d48Sopenharmony_ci  a: 0.9,
28fb726d48Sopenharmony_ci};
29fb726d48Sopenharmony_ciconst lightGreen = {
30fb726d48Sopenharmony_ci  r: 132,
31fb726d48Sopenharmony_ci  g: 200,
32fb726d48Sopenharmony_ci  b: 112,
33fb726d48Sopenharmony_ci  a: 0.9,
34fb726d48Sopenharmony_ci};
35fb726d48Sopenharmony_ci
36fb726d48Sopenharmony_ciexport class ChartStruct extends BaseStruct {
37fb726d48Sopenharmony_ci  static hoverFuncStruct: ChartStruct | undefined;
38fb726d48Sopenharmony_ci  static selectFuncStruct: ChartStruct | undefined;
39fb726d48Sopenharmony_ci  static lastSelectFuncStruct: ChartStruct | undefined;
40fb726d48Sopenharmony_ci  isDraw = false; // 是否绘制,太小的不绘制
41fb726d48Sopenharmony_ci  depth: number = 0;
42fb726d48Sopenharmony_ci  symbol: string = '';
43fb726d48Sopenharmony_ci  lib: string = '';
44fb726d48Sopenharmony_ci
45fb726d48Sopenharmony_ci  id?: string;
46fb726d48Sopenharmony_ci  eventType?: string;
47fb726d48Sopenharmony_ci  parentId?: string;
48fb726d48Sopenharmony_ci  self?: string; // only perf
49fb726d48Sopenharmony_ci  eventPercent?: string; // only perf
50fb726d48Sopenharmony_ci  title?: string;
51fb726d48Sopenharmony_ci
52fb726d48Sopenharmony_ci  size: number = 0; // 实际size
53fb726d48Sopenharmony_ci  count: number = 0; // 实际count
54fb726d48Sopenharmony_ci  eventCount: number = 0;
55fb726d48Sopenharmony_ci  dur: number = 0; // 实际dur
56fb726d48Sopenharmony_ci  //搜索后会根据搜索匹配的函数的值赋值给parent
57fb726d48Sopenharmony_ci  searchSize: number = 0; //
58fb726d48Sopenharmony_ci  searchCount: number = 0;
59fb726d48Sopenharmony_ci  searchDur: number = 0;
60fb726d48Sopenharmony_ci  searchEventCount: number = 0;
61fb726d48Sopenharmony_ci  //点击绘制的size在搜索的基础上,赋值给parent
62fb726d48Sopenharmony_ci  drawSize: number = 0;
63fb726d48Sopenharmony_ci  drawCount: number = 0;
64fb726d48Sopenharmony_ci  drawDur: number = 0;
65fb726d48Sopenharmony_ci  drawEventCount: number = 0;
66fb726d48Sopenharmony_ci
67fb726d48Sopenharmony_ci  parent: ChartStruct | undefined;
68fb726d48Sopenharmony_ci  children: Array<ChartStruct> = [];
69fb726d48Sopenharmony_ci  percent: number = 0; // 0 - 1 该node所占整体的百分比
70fb726d48Sopenharmony_ci  addr: string = '';
71fb726d48Sopenharmony_ci  isSearch: boolean = false;
72fb726d48Sopenharmony_ci  isChartSelect: boolean = false; // 是否为点选的调用链
73fb726d48Sopenharmony_ci  isChartSelectParent: boolean = false; // 用来显示灰色
74fb726d48Sopenharmony_ci  tsArray: Array<number> = [];
75fb726d48Sopenharmony_ci  countArray: Array<number> = [];
76fb726d48Sopenharmony_ci  durArray: Array<number> = [];
77fb726d48Sopenharmony_ci  isThread: boolean = false;
78fb726d48Sopenharmony_ci  isProcess: boolean = false;
79fb726d48Sopenharmony_ci  isJsStack: boolean = false;
80fb726d48Sopenharmony_ci}
81fb726d48Sopenharmony_ci
82fb726d48Sopenharmony_ciexport enum ChartMode {
83fb726d48Sopenharmony_ci  Byte, // Native Memory
84fb726d48Sopenharmony_ci  Count, // Perf
85fb726d48Sopenharmony_ci  Duration, // eBpf
86fb726d48Sopenharmony_ci  EventCount, //cycles
87fb726d48Sopenharmony_ci}
88fb726d48Sopenharmony_ci
89fb726d48Sopenharmony_ciexport function setFuncFrame(node: ChartStruct, canvasFrame: Rect, total: number, mode: ChartMode): void {
90fb726d48Sopenharmony_ci  if (!node.frame) {
91fb726d48Sopenharmony_ci    node.frame = new Rect(0, 0, 0, 0);
92fb726d48Sopenharmony_ci  }
93fb726d48Sopenharmony_ci  // filter depth is 0
94fb726d48Sopenharmony_ci  if (node.parent) {
95fb726d48Sopenharmony_ci    let idx = node.parent.children.indexOf(node);
96fb726d48Sopenharmony_ci    if (idx === 0) {
97fb726d48Sopenharmony_ci      node.frame!.x = node.parent.frame!.x;
98fb726d48Sopenharmony_ci    } else {
99fb726d48Sopenharmony_ci      // set x by left frame. left frame is parent.children[idx - 1]
100fb726d48Sopenharmony_ci      node.frame.x = node.parent.children[idx - 1].frame!.x + node.parent.children[idx - 1].frame!.width;
101fb726d48Sopenharmony_ci    }
102fb726d48Sopenharmony_ci    if (node.parent?.isChartSelect && !node.isChartSelect) {
103fb726d48Sopenharmony_ci      node.frame!.width = 0;
104fb726d48Sopenharmony_ci    } else {
105fb726d48Sopenharmony_ci      switch (mode) {
106fb726d48Sopenharmony_ci        case ChartMode.Byte:
107fb726d48Sopenharmony_ci          node.frame!.width = Math.floor(((node.drawSize || node.size) / total) * canvasFrame.width);
108fb726d48Sopenharmony_ci          break;
109fb726d48Sopenharmony_ci        case ChartMode.Count:
110fb726d48Sopenharmony_ci          node.frame!.width = Math.floor(((node.drawCount || node.count) / total) * canvasFrame.width);
111fb726d48Sopenharmony_ci          break;
112fb726d48Sopenharmony_ci        case ChartMode.Duration:
113fb726d48Sopenharmony_ci          node.frame!.width = Math.floor(((node.drawDur || node.dur) / total) * canvasFrame.width);
114fb726d48Sopenharmony_ci          break;
115fb726d48Sopenharmony_ci        case ChartMode.EventCount:
116fb726d48Sopenharmony_ci          node.frame!.width = Math.floor(((node.drawEventCount || node.eventCount) / total) * canvasFrame.width);
117fb726d48Sopenharmony_ci          break;
118fb726d48Sopenharmony_ci        default:
119fb726d48Sopenharmony_ci          warn('not match ChartMode');
120fb726d48Sopenharmony_ci      }
121fb726d48Sopenharmony_ci    }
122fb726d48Sopenharmony_ci
123fb726d48Sopenharmony_ci    node.frame!.y = node.parent.frame!.y + rectHeight;
124fb726d48Sopenharmony_ci    node.frame!.height = rectHeight;
125fb726d48Sopenharmony_ci  }
126fb726d48Sopenharmony_ci}
127fb726d48Sopenharmony_ci
128fb726d48Sopenharmony_ci/**
129fb726d48Sopenharmony_ci * draw rect
130fb726d48Sopenharmony_ci * @param canvasCtx CanvasRenderingContext2D
131fb726d48Sopenharmony_ci * @param node rect which is need draw
132fb726d48Sopenharmony_ci * @param percent function size or count / total size or count
133fb726d48Sopenharmony_ci */
134fb726d48Sopenharmony_ciexport function draw(canvasCtx: CanvasRenderingContext2D, node: ChartStruct): void {
135fb726d48Sopenharmony_ci  let spApplication = <SpApplication>document.getElementsByTagName('sp-application')[0];
136fb726d48Sopenharmony_ci  if (!node.frame) {
137fb726d48Sopenharmony_ci    return;
138fb726d48Sopenharmony_ci  }
139fb726d48Sopenharmony_ci  //主体
140fb726d48Sopenharmony_ci  const drawHeight = rectHeight - padding * 2; //绘制方块上下留一个像素
141fb726d48Sopenharmony_ci  if (node.depth === 0 || (node.isChartSelectParent && node !== ChartStruct.selectFuncStruct)) {
142fb726d48Sopenharmony_ci    canvasCtx.fillStyle = `rgba(${lightBlue.g}, ${lightBlue.g}, ${lightBlue.g}, ${lightBlue.a})`;
143fb726d48Sopenharmony_ci  } else {
144fb726d48Sopenharmony_ci    if (node.isSearch) {
145fb726d48Sopenharmony_ci      canvasCtx.fillStyle = `rgba(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b}, ${lightBlue.a})`;
146fb726d48Sopenharmony_ci    } else {
147fb726d48Sopenharmony_ci      if (node.isJsStack) {
148fb726d48Sopenharmony_ci        canvasCtx.fillStyle = `rgba(${lightGreen.r}, ${lightGreen.g}, ${lightGreen.b}, ${lightGreen.a})`;
149fb726d48Sopenharmony_ci      } else {
150fb726d48Sopenharmony_ci        canvasCtx.fillStyle = getHeatColor(node.percent);
151fb726d48Sopenharmony_ci      }
152fb726d48Sopenharmony_ci    }
153fb726d48Sopenharmony_ci  }
154fb726d48Sopenharmony_ci  canvasCtx.fillRect(node.frame.x, node.frame.y, node.frame.width, drawHeight);
155fb726d48Sopenharmony_ci  //边框
156fb726d48Sopenharmony_ci  canvasCtx.lineWidth = 0.4;
157fb726d48Sopenharmony_ci  if (isHover(node)) {
158fb726d48Sopenharmony_ci    if (spApplication.dark) {
159fb726d48Sopenharmony_ci      canvasCtx.strokeStyle = '#fff';
160fb726d48Sopenharmony_ci    } else {
161fb726d48Sopenharmony_ci      canvasCtx.strokeStyle = '#000';
162fb726d48Sopenharmony_ci    }
163fb726d48Sopenharmony_ci  } else {
164fb726d48Sopenharmony_ci    if (spApplication.dark) {
165fb726d48Sopenharmony_ci      canvasCtx.strokeStyle = '#000';
166fb726d48Sopenharmony_ci    } else {
167fb726d48Sopenharmony_ci      canvasCtx.strokeStyle = '#fff';
168fb726d48Sopenharmony_ci    }
169fb726d48Sopenharmony_ci  }
170fb726d48Sopenharmony_ci  canvasCtx.strokeRect(node.frame.x, node.frame.y, node.frame.width - canvasCtx.lineWidth, drawHeight);
171fb726d48Sopenharmony_ci  //文字
172fb726d48Sopenharmony_ci  if (node.frame.width > 10) {
173fb726d48Sopenharmony_ci    if (node.percent > 0.6 || node.isSearch) {
174fb726d48Sopenharmony_ci      canvasCtx.fillStyle = '#fff';
175fb726d48Sopenharmony_ci    } else {
176fb726d48Sopenharmony_ci      canvasCtx.fillStyle = '#000';
177fb726d48Sopenharmony_ci    }
178fb726d48Sopenharmony_ci    drawString(canvasCtx, splitSymbol(node), 5, node.frame, node);
179fb726d48Sopenharmony_ci  }
180fb726d48Sopenharmony_ci  node.isDraw = true;
181fb726d48Sopenharmony_ci}
182fb726d48Sopenharmony_ci
183fb726d48Sopenharmony_cifunction splitSymbol(node: ChartStruct): string {
184fb726d48Sopenharmony_ci  if (node.depth === 0 || node.isProcess || node.isThread) {
185fb726d48Sopenharmony_ci    return node.symbol;
186fb726d48Sopenharmony_ci  }
187fb726d48Sopenharmony_ci  return node.symbol.split(' (')[0];
188fb726d48Sopenharmony_ci}
189fb726d48Sopenharmony_ci
190fb726d48Sopenharmony_ci/**
191fb726d48Sopenharmony_ci * 火焰图颜色计算,根据每个node占总大小的百分比调整
192fb726d48Sopenharmony_ci * @param widthPercentage 百分比
193fb726d48Sopenharmony_ci * @returns rbg
194fb726d48Sopenharmony_ci */
195fb726d48Sopenharmony_cifunction getHeatColor(widthPercentage: number): string {
196fb726d48Sopenharmony_ci  return `rgba(
197fb726d48Sopenharmony_ci    ${Math.floor(245 + 10 * (1 - widthPercentage))},
198fb726d48Sopenharmony_ci    ${Math.floor(110 + 105 * (1 - widthPercentage))},
199fb726d48Sopenharmony_ci    ${100},
200fb726d48Sopenharmony_ci    0.9)`;
201fb726d48Sopenharmony_ci}
202fb726d48Sopenharmony_ci
203fb726d48Sopenharmony_cifunction isHover(data: ChartStruct): boolean {
204fb726d48Sopenharmony_ci  return ChartStruct.hoverFuncStruct === data;
205fb726d48Sopenharmony_ci}
206