• 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 { BaseStruct, drawLoadingFrame, isFrameContainPoint, ns2x, Rect, Render } from './ProcedureWorkerCommon';
17import { TraceRow } from '../../component/trace/base/TraceRow';
18import { ColorUtils } from '../../component/trace/base/ColorUtils';
19import { THREAD_ENERGY, THREAD_LOAD } from '../../component/chart/SpXpowerChart';
20import { SpSystemTrace } from '../../component/SpSystemTrace';
21
22export class XpowerThreadInfoRender extends Render {
23  renderMainThread(
24    xpowerReq: {
25      context: CanvasRenderingContext2D;
26      useCache: boolean;
27      type: string;
28    },
29    row: TraceRow<XpowerThreadInfoStruct>
30  ): void {
31    let xpowerThreadInfoList = row.dataList;
32    let xpowerThreadInfoFilter = row.dataListCache;
33    threadInfo(
34      xpowerThreadInfoList,
35      xpowerThreadInfoFilter,
36      TraceRow.range!.startNS,
37      TraceRow.range!.endNS,
38      TraceRow.range!.totalNS,
39      row.frame,
40      xpowerReq.useCache || !TraceRow.range!.refresh
41    );
42    drawLoadingFrame(xpowerReq.context, xpowerThreadInfoFilter, row);
43    xpowerReq.context.beginPath();
44    let find = false;
45    let maxValue = 0;
46    let maxValueStr = '';
47    if (xpowerReq.type === THREAD_ENERGY) {
48      maxValue = XpowerThreadInfoStruct.energyMaxValue;
49      maxValueStr = String(maxValue) + ' mAh';
50    } else if (xpowerReq.type === THREAD_LOAD) {
51      maxValue = XpowerThreadInfoStruct.loadMaxValue;
52      maxValueStr = String(maxValue) + ' %';
53    }
54    for (let i = 0; i < xpowerThreadInfoFilter.length; i++) {
55      XpowerThreadInfoStruct.draw(xpowerReq, xpowerThreadInfoFilter[i], maxValue, row);
56      if (
57        row.isHover &&
58        xpowerThreadInfoFilter[i].frame &&
59        isFrameContainPoint(xpowerThreadInfoFilter[i].frame!, row.hoverX, row.hoverY)
60      ) {
61        XpowerThreadInfoStruct.hoverXpowerStruct = xpowerThreadInfoFilter[i];
62        XpowerThreadInfoStruct.drawStroke(xpowerReq, xpowerThreadInfoFilter[i], row);
63        find = true;
64      }
65    }
66    if (!find) {
67      XpowerThreadInfoStruct.hoverXpowerStruct = undefined;
68    }
69    drawMaxValue(xpowerReq, maxValueStr);
70  }
71}
72
73export function threadInfo(
74  list: Array<XpowerThreadInfoStruct>,
75  res: Array<XpowerThreadInfoStruct>,
76  startNS: number,
77  endNS: number,
78  totalNS: number,
79  frame: Rect,
80  use: boolean
81): void {
82  list.length = 0;
83  if (use && res.length > 0) {
84    for (let index = 0; index < res.length; index++) {
85      let item = res[index];
86      XpowerThreadInfoStruct.setThreadInfoFrame(item, 5, startNS || 0, endNS || 0, totalNS || 0, frame);
87    }
88  }
89}
90
91export function drawMaxValue(
92  xpowerReq: {
93    context: CanvasRenderingContext2D;
94    useCache: boolean;
95    type: string;
96  },
97  maxValueStr: string
98): void {
99  xpowerReq.context.closePath();
100  let textMetrics = xpowerReq.context.measureText(maxValueStr);
101  xpowerReq.context.globalAlpha = 0.8;
102  xpowerReq.context.fillStyle = '#f0f0f0';
103  xpowerReq.context.fillRect(0, 5, textMetrics.width + 8, 18);
104  xpowerReq.context.globalAlpha = 1;
105  xpowerReq.context.fillStyle = '#333';
106  xpowerReq.context.textBaseline = 'middle';
107  xpowerReq.context.fillText(maxValueStr, 4, 5 + 9);
108}
109
110export function XpowerThreadInfoStructOnClick(
111  clickRowType: string,
112  sp: SpSystemTrace,
113  entry?: XpowerThreadInfoStruct
114): Promise<unknown> {
115  return new Promise((resolve, reject) => {
116    if (clickRowType === TraceRow.ROW_TYPE_XPOWER_THREAD_INFO && (XpowerThreadInfoStruct.hoverXpowerStruct || entry)) {
117      XpowerThreadInfoStruct.selectXpowerStruct = entry || XpowerThreadInfoStruct.hoverXpowerStruct;
118      let startNs = XpowerThreadInfoStruct.selectXpowerStruct!.startNS;
119      let map = new Map();
120      if (XpowerThreadInfoStruct.selectXpowerStruct?.valueType === THREAD_ENERGY) {
121        map = XpowerThreadInfoStruct.threadEnergyStructMap;
122      } else if (XpowerThreadInfoStruct.selectXpowerStruct?.valueType === THREAD_LOAD) {
123        map = XpowerThreadInfoStruct.threadLoadStructMap;
124      }
125      sp.traceSheetEL?.displayXpowerThreadInfoData(map.get(startNs) || []);
126      sp.timerShaftEL?.modifyFlagList(undefined);
127      reject(new Error());
128    } else {
129      resolve(null);
130    }
131  });
132}
133
134export class XpowerThreadInfoStruct extends BaseStruct {
135  static energyMaxValue: number = 0;
136  static loadMaxValue: number = 0;
137  static hoverXpowerStruct: XpowerThreadInfoStruct | undefined;
138  static selectXpowerStruct: XpowerThreadInfoStruct | undefined;
139  static histogramHeightMap = new Map<string, number>();
140  static threadEnergyStructMap = new Map<number, Array<XpowerThreadInfoStruct>>();
141  static threadLoadStructMap = new Map<number, Array<XpowerThreadInfoStruct>>();
142  static rowHeight: number = 200;
143  static flagTime: number = -1;
144  static flagType: string = '';
145  static height: number = -1;
146  static drawY: number = 0;
147  value: number = 0;
148  startNS: number = 0;
149  startMS: number = 0;
150  dur: number = 0;
151  threadTime: number = 0;
152  threadName: string = '';
153  threadNameId: number = -1;
154  valueType: string = '';
155
156  static setThreadInfoFrame(
157    powerNode: XpowerThreadInfoStruct,
158    padding: number,
159    startNS: number,
160    endNS: number,
161    totalNS: number,
162    frame: Rect
163  ): void {
164    let startPointX: number;
165    let endPointX: number;
166    //@ts-ignore
167    if ((powerNode.startNS || 0) < startNS) {
168      startPointX = 0;
169    } else {
170      startPointX = ns2x(powerNode.startNS || 0, startNS, endNS, totalNS, frame);
171    }
172    //@ts-ignore
173    if (powerNode.startNS + 3000000000 > endNS) {
174      //@ts-ignore
175      endPointX = frame.width;
176    } else {
177      //@ts-ignore
178      endPointX = ns2x(powerNode.startNS + 3000000000, startNS, endNS, totalNS, frame);
179    }
180    let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
181    //@ts-ignore
182    if (!powerNode.frame) {
183      //@ts-ignore
184      powerNode.frame = {};
185    }
186    //@ts-ignore
187    powerNode.frame.x = Math.floor(startPointX);
188    //@ts-ignore
189    powerNode.frame.y = frame.y + padding;
190    //@ts-ignore
191    powerNode.frame.width = Math.ceil(frameWidth);
192    //@ts-ignore
193    powerNode.frame.height = Math.floor(frame.height - padding * 2);
194  }
195
196  static draw(
197    req: { useCache: boolean; context: CanvasRenderingContext2D },
198    data: XpowerThreadInfoStruct,
199    maxValue: number,
200    row: TraceRow<XpowerThreadInfoStruct>
201  ): void {
202    if (data.frame) {
203      req!.context.globalAlpha = 0.8;
204      if (data.startNS !== XpowerThreadInfoStruct.flagTime) {
205        this.height = -1;
206        if (XpowerThreadInfoStruct.flagTime > -1) {
207          this.histogramHeightMap.set(XpowerThreadInfoStruct.flagTime + this.flagType, this.rowHeight - this.drawY);
208        }
209      } else {
210        this.height = this.drawY;
211      }
212      XpowerThreadInfoStruct.flagTime = data.startNS;
213      this.flagType = data.valueType;
214      this.drawY = this.drawHistogram(req, data, maxValue, row);
215      XpowerThreadInfoStruct.drawStroke(req, data, row);
216    }
217  }
218
219  static drawStroke(
220    req: { useCache: boolean; context: CanvasRenderingContext2D },
221    data: XpowerThreadInfoStruct,
222    row: TraceRow<XpowerThreadInfoStruct>
223  ): void {
224    let startNS = TraceRow.range!.startNS;
225    let endNS = TraceRow.range!.endNS;
226    let totalNS = TraceRow.range!.totalNS;
227    if (
228      (XpowerThreadInfoStruct.hoverXpowerStruct &&
229        XpowerThreadInfoStruct.equals(XpowerThreadInfoStruct.hoverXpowerStruct!, data)) ||
230      (XpowerThreadInfoStruct.selectXpowerStruct &&
231        XpowerThreadInfoStruct.equals(XpowerThreadInfoStruct.selectXpowerStruct!, data))
232    ) {
233      let startPointX = ns2x(data.startNS || 0, startNS, endNS, totalNS, row.frame);
234      let endPointX = ns2x((data.startNS || 0) + 3000000000, startNS, endNS, totalNS, row.frame);
235      let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
236      req!.context.lineWidth = 1;
237      req!.context.strokeStyle = '#9899a0';
238      let height = this.histogramHeightMap.get(data.startNS + data.valueType) || 0;
239      req!.context.strokeRect(startPointX, this.rowHeight - height - 1, Math.floor(frameWidth), height);
240    }
241  }
242
243  static drawHistogram(
244    req: { useCache: boolean; context: CanvasRenderingContext2D },
245    data: XpowerThreadInfoStruct,
246    maxValue: number,
247    row: TraceRow<XpowerThreadInfoStruct>
248  ): number {
249    let endPointX = ns2x(
250      (data.startNS || 0) + 3000000000,
251      TraceRow.range!.startNS,
252      TraceRow.range!.endNS,
253      TraceRow.range!.totalNS,
254      row.frame
255    );
256    let startPointX = ns2x(
257      data.startNS || 0,
258      TraceRow.range!.startNS,
259      TraceRow.range!.endNS,
260      TraceRow.range!.totalNS,
261      row.frame
262    );
263    let frameWidth = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX;
264    let histogramColor = ColorUtils.colorForTid(data.threadNameId);
265    req!.context.fillStyle = histogramColor;
266    let drawStartY = 0;
267    let dataHeight: number = ((data.value || 0) * (this.rowHeight - 28)) / maxValue;
268    if (data.value !== 0 && dataHeight < 1) {
269      dataHeight = 1;
270    }
271    data.frame!.x = startPointX;
272    data.frame!.width = frameWidth;
273    data.frame!.height = dataHeight;
274    if (this.height === -1) {
275      drawStartY = this.rowHeight - dataHeight;
276      data.frame!.y = drawStartY;
277      req!.context.fillRect(startPointX, drawStartY, frameWidth, dataHeight);
278      return drawStartY;
279    } else {
280      drawStartY = this.height - dataHeight;
281      data.frame!.y = drawStartY;
282      req!.context.fillRect(startPointX, drawStartY, frameWidth, dataHeight);
283      return drawStartY;
284    }
285  }
286
287  static isHover(xpower: XpowerThreadInfoStruct): boolean {
288    return xpower === XpowerThreadInfoStruct.hoverXpowerStruct || xpower === XpowerThreadInfoStruct.selectXpowerStruct;
289  }
290
291  static equals(baseStruct: XpowerThreadInfoStruct, targetStruct: XpowerThreadInfoStruct): boolean {
292    return baseStruct === targetStruct;
293  }
294}
295