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 {
18  BaseStruct,
19  isFrameContainPoint,
20  ns2x,
21  Render,
22  dataFilterHandler,
23  drawLoadingFrame,
24  Rect,
25} from './ProcedureWorkerCommon';
26import { TraceRow } from '../../component/trace/base/TraceRow';
27
28export class DiskIoAbilityRender extends Render {
29  renderMainThread(
30    req: {
31      context: CanvasRenderingContext2D;
32      useCache: boolean;
33      type: string;
34      maxDiskRate: number;
35      maxDiskRateName: string;
36    },
37    diskIoAbilityRow: TraceRow<DiskAbilityMonitorStruct>
38  ): void {
39    let diskIoAbilityList = diskIoAbilityRow.dataList;
40    let diskIoFilter = diskIoAbilityRow.dataListCache;
41    dataFilterHandler(diskIoAbilityList, diskIoFilter, {
42      startKey: 'startNS',
43      durKey: 'dur',
44      startNS: TraceRow.range?.startNS ?? 0,
45      endNS: TraceRow.range?.endNS ?? 0,
46      totalNS: TraceRow.range?.totalNS ?? 0,
47      frame: diskIoAbilityRow.frame,
48      paddingTop: 5,
49      useCache: req.useCache || !(TraceRow.range?.refresh ?? false),
50    });
51    drawLoadingFrame(req.context, diskIoAbilityRow.dataListCache, diskIoAbilityRow);
52    req.context.beginPath();
53    let find = false;
54    for (let re of diskIoFilter) {
55      DiskAbilityMonitorStruct.draw(req.context, re, req.maxDiskRate, diskIoAbilityRow.isHover);
56      if (
57        diskIoAbilityRow.isHover &&
58        re.frame &&
59        isFrameContainPoint(re.frame, diskIoAbilityRow.hoverX, diskIoAbilityRow.hoverY)
60      ) {
61        DiskAbilityMonitorStruct.hoverDiskAbilityStruct = re;
62        find = true;
63      }
64    }
65    if (!find && diskIoAbilityRow.isHover) {
66      DiskAbilityMonitorStruct.hoverDiskAbilityStruct = undefined;
67    }
68    req.context.closePath();
69    let textMetrics = req.context.measureText(req.maxDiskRateName);
70    req.context.globalAlpha = 0.8;
71    req.context.fillStyle = '#f0f0f0';
72    req.context.fillRect(0, 5, textMetrics.width + 8, 18);
73    req.context.globalAlpha = 1;
74    req.context.fillStyle = '#333';
75    req.context.textBaseline = 'middle';
76    req.context.fillText(req.maxDiskRateName, 4, 5 + 9);
77  }
78}
79
80export function diskIoAbility(
81  diskIoAbilityList: Array<DiskAbilityMonitorStruct>,
82  res: Array<DiskAbilityMonitorStruct>,
83  startNS: number,
84  endNS: number,
85  totalNS: number,
86  frame: Rect,
87  use: boolean
88): void {
89  if (use && res.length > 0) {
90    for (let i = 0; i < res.length; i++) {
91      let diskIoAbilityItem = res[i];
92      if (
93        (diskIoAbilityItem.startNS || 0) + (diskIoAbilityItem.dur || 0) > (startNS || 0) &&
94        (diskIoAbilityItem.startNS || 0) < (endNS || 0)
95      ) {
96        DiskAbilityMonitorStruct.setDiskIOFrame(diskIoAbilityItem, 5, startNS || 0, endNS || 0, totalNS || 0, frame);
97      } else {
98        diskIoAbilityItem.frame = undefined;
99      }
100    }
101    return;
102  }
103  res.length = 0;
104  setDiskIoAbilityFilter(diskIoAbilityList, res, startNS || 0, endNS || 0, totalNS || 0, frame);
105}
106function setDiskIoAbilityFilter(
107  diskIoAbilityList: Array<DiskAbilityMonitorStruct>,
108  res: Array<DiskAbilityMonitorStruct>,
109  startNS: number,
110  endNS: number,
111  totalNS: number,
112  frame: Rect
113): void {
114  if (diskIoAbilityList) {
115    for (let index = 0; index < diskIoAbilityList.length; index++) {
116      let item = diskIoAbilityList[index];
117      item.dur =
118        index === diskIoAbilityList.length - 1
119          ? endNS - (item.startNS || 0)
120          : (diskIoAbilityList[index + 1].startNS || 0) - (item.startNS || 0);
121      if ((item.startNS || 0) + (item.dur || 0) > startNS && (item.startNS || 0) < endNS) {
122        DiskAbilityMonitorStruct.setDiskIOFrame(diskIoAbilityList[index], 5, startNS, endNS, totalNS, frame);
123        if (
124          !(
125            index > 0 &&
126            (diskIoAbilityList[index - 1].frame!.x || 0) === (diskIoAbilityList[index].frame!.x || 0) &&
127            (diskIoAbilityList[index - 1].frame!.width || 0) === (diskIoAbilityList[index].frame!.width || 0)
128          )
129        ) {
130          res.push(item);
131        }
132      }
133    }
134  }
135}
136export class DiskAbilityMonitorStruct extends BaseStruct {
137  static maxDiskRate: number = 0;
138  static maxDiskRateName: string = '0 KB/S';
139  static hoverDiskAbilityStruct: DiskAbilityMonitorStruct | undefined;
140  static selectDiskAbilityStruct: DiskAbilityMonitorStruct | undefined;
141  value: number | undefined;
142  startNS: number | undefined;
143  dur: number | undefined; //自补充,数据库没有返回
144
145  static draw(
146    diskIoAbilityContext: CanvasRenderingContext2D,
147    diskIoAbilityData: DiskAbilityMonitorStruct,
148    maxDiskRate: number,
149    isHover: boolean
150  ): void {
151    if (diskIoAbilityData.frame) {
152      let width = diskIoAbilityData.frame.width || 0;
153      let index = 2;
154      diskIoAbilityContext.fillStyle = ColorUtils.colorForTid(index);
155      diskIoAbilityContext.strokeStyle = ColorUtils.colorForTid(index);
156      if (diskIoAbilityData.startNS === DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.startNS && isHover) {
157        diskIoAbilityContext.lineWidth = 1;
158        diskIoAbilityContext.globalAlpha = 0.6;
159        let drawHeight: number = Math.floor(
160          ((diskIoAbilityData.value || 0) * (diskIoAbilityData.frame.height || 0) * 1.0) / maxDiskRate
161        );
162        let y = diskIoAbilityData.frame.y + diskIoAbilityData.frame.height - drawHeight + 4;
163        diskIoAbilityContext.fillRect(diskIoAbilityData.frame.x, y, width, drawHeight);
164        diskIoAbilityContext.beginPath();
165        diskIoAbilityContext.arc(diskIoAbilityData.frame.x, y, 3, 0, 2 * Math.PI, true);
166        diskIoAbilityContext.fill();
167        diskIoAbilityContext.globalAlpha = 1.0;
168        diskIoAbilityContext.stroke();
169        diskIoAbilityContext.beginPath();
170        diskIoAbilityContext.moveTo(diskIoAbilityData.frame.x + 3, y);
171        diskIoAbilityContext.lineWidth = 3;
172        diskIoAbilityContext.lineTo(diskIoAbilityData.frame.x + width, y);
173        diskIoAbilityContext.stroke();
174      } else {
175        diskIoAbilityContext.globalAlpha = 0.6;
176        diskIoAbilityContext.lineWidth = 1;
177        let drawHeight: number = Math.floor(
178          ((diskIoAbilityData.value || 0) * (diskIoAbilityData.frame.height || 0)) / maxDiskRate
179        );
180        let y = diskIoAbilityData.frame.y + diskIoAbilityData.frame.height - drawHeight + 4;
181        diskIoAbilityContext.fillRect(diskIoAbilityData.frame.x, y, width, drawHeight);
182      }
183    }
184    diskIoAbilityContext.globalAlpha = 1.0;
185    diskIoAbilityContext.lineWidth = 1;
186  }
187
188  static setDiskIOFrame(
189    diskIONode: DiskAbilityMonitorStruct,
190    padding: number,
191    startNS: number,
192    endNS: number,
193    totalNS: number,
194    frame: Rect
195  ): void {
196    let diskIOStartPointX: number;
197    let diskIOEndPointX: number;
198
199    if ((diskIONode.startNS || 0) < startNS) {
200      diskIOStartPointX = 0;
201    } else {
202      diskIOStartPointX = ns2x(diskIONode.startNS || 0, startNS, endNS, totalNS, frame);
203    }
204    if ((diskIONode.startNS || 0) + (diskIONode.dur || 0) > endNS) {
205      diskIOEndPointX = frame.width;
206    } else {
207      diskIOEndPointX = ns2x((diskIONode.startNS || 0) + (diskIONode.dur || 0), startNS, endNS, totalNS, frame);
208    }
209    let frameWidth: number = diskIOEndPointX - diskIOStartPointX <= 1 ? 1 : diskIOEndPointX - diskIOStartPointX;
210    if (!diskIONode.frame) {
211      diskIONode.frame = new Rect(0, 0, 0, 0);
212    }
213    diskIONode.frame.x = Math.floor(diskIOStartPointX);
214    diskIONode.frame.y = frame.y + padding;
215    diskIONode.frame.width = Math.ceil(frameWidth);
216    diskIONode.frame.height = Math.floor(frame.height - padding * 2);
217  }
218}
219