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 { BaseStruct, drawLoadingFrame, ns2x, Rect, Render } from './ProcedureWorkerCommon';
18import { TraceRow } from '../../component/trace/base/TraceRow';
19import { Utils } from '../../component/trace/base/Utils';
20
21export class ProcessRender extends Render {
22  renderMainThread(req: unknown, row: TraceRow<ProcessStruct>): void {
23    if (row.expansion) {
24      return;
25    }
26    let list = row.dataList;
27    let filter = row.dataListCache;
28    proc(
29      list,
30      filter,
31      TraceRow.range!.startNS || 0,
32      TraceRow.range!.endNS || 0,
33      TraceRow.range!.totalNS || 0,
34      row.frame,
35      //@ts-ignore
36      req.useCache || !TraceRow.range!.refresh
37    );
38    //@ts-ignore
39    drawLoadingFrame(req.context, filter, row, true);
40    //@ts-ignore
41    req.context.beginPath();
42    let path = new Path2D();
43    let miniHeight = Math.round((row.frame.height - Utils.getInstance().getCpuCount() * 2) /
44      Utils.getInstance().getCpuCount());
45    //@ts-ignore
46    req.context.fillStyle = ColorUtils.colorForTid(req.pid || 0);
47    for (let re of filter) {
48      //@ts-ignore
49      ProcessStruct.draw(req.context, path, re, miniHeight);
50    }
51    //@ts-ignore
52    req.context.fill(path);
53    //@ts-ignore
54    req.context.closePath();
55  }
56}
57export function proc(
58  list: Array<unknown>,
59  res: Array<unknown>,
60  startNS: number,
61  endNS: number,
62  totalNS: number,
63  frame: Rect,
64  use: boolean
65): void {
66  if (use && res.length > 0) {
67    //@ts-ignore
68    res.forEach((it) => ProcessStruct.setProcessFrame(it, 5, startNS, endNS, totalNS, frame));
69    return;
70  }
71  res.length = 0;
72  if (list) {
73    for (let i = 0, len = list.length; i < len; i++) {
74      let it = list[i];
75      //@ts-ignore
76      if ((it.startTime || 0) + (it.dur || 0) > startNS && (it.startTime || 0) < endNS) {
77        //@ts-ignore
78        ProcessStruct.setProcessFrame(list[i], 5, startNS, endNS, totalNS, frame);
79        if (
80          !(
81            i > 0 &&
82            //@ts-ignore
83            (list[i - 1].frame.x || 0) === (list[i].frame.x || 0) &&
84            //@ts-ignore
85            (list[i - 1].frame.width || 0) === (list[i].frame.width || 0)
86          )
87        ) {
88          res.push(list[i]);
89        }
90      }
91    }
92  }
93}
94
95const padding = 1;
96
97export class ProcessStruct extends BaseStruct {
98  cpu: number | undefined;
99  dur: number | undefined;
100  id: number | undefined;
101  pid: number | undefined;
102  process: string | undefined;
103  startTime: number | undefined;
104  state: string | undefined;
105  thread: string | undefined;
106  tid: number | undefined;
107  ts: number | undefined;
108  type: string | undefined;
109  utid: number | undefined;
110
111  static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: ProcessStruct, miniHeight: number): void {
112    if (data.frame) {
113      path.rect(data.frame.x, data.frame.y + (data.cpu || 0) * miniHeight + padding, data.frame.width, miniHeight);
114    }
115  }
116
117  static setFrame(processNode: ProcessStruct, pns: number, startNS: number, endNS: number, frame: Rect): void {
118    if ((processNode.startTime || 0) < startNS) {
119      processNode.frame!.x = 0;
120    } else {
121      processNode.frame!.x = Math.floor(((processNode.startTime || 0) - startNS) / pns);
122    }
123    if ((processNode.startTime || 0) + (processNode.dur || 0) > endNS) {
124      processNode.frame!.width = frame.width - processNode.frame!.x;
125    } else {
126      processNode.frame!.width = Math.ceil(
127        ((processNode.startTime || 0) + (processNode.dur || 0) - startNS) / pns - processNode.frame!.x
128      );
129    }
130    if (processNode.frame!.width < 1) {
131      processNode.frame!.width = 1;
132    }
133  }
134
135  static setProcessFrame(
136    processNode: ProcessStruct,
137    padding: number,
138    startNS: number,
139    endNS: number,
140    totalNS: number,
141    frame: Rect
142  ): void {
143    let x1: number;
144    let x2: number;
145    if ((processNode.startTime || 0) < startNS) {
146      x1 = 0;
147    } else {
148      x1 = ns2x(processNode.startTime || 0, startNS, endNS, totalNS, frame);
149    }
150    if ((processNode.startTime || 0) + (processNode.dur || 0) > endNS) {
151      x2 = frame.width;
152    } else {
153      x2 = ns2x((processNode.startTime || 0) + (processNode.dur || 0), startNS, endNS, totalNS, frame);
154    }
155    let processGetV: number = x2 - x1 <= 1 ? 1 : x2 - x1;
156    if (!processNode.frame) {
157      processNode.frame = new Rect(0, 0, 0, 0);
158    }
159    processNode.frame.x = Math.floor(x1);
160    processNode.frame.y = Math.floor(frame.y + 2);
161    processNode.frame.width = Math.ceil(processGetV);
162    processNode.frame.height = Math.floor(frame.height - padding * 2);
163  }
164}
165