• 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.js";
17import {
18    BaseStruct,
19    drawFlagLine,
20    drawLines,
21    drawLoading,
22    drawSelection, PerfRender,
23    RequestMessage
24} from "./ProcedureWorkerCommon.js";
25
26
27export class HiperfEventRender  extends PerfRender{
28    render(req: RequestMessage, list: Array<any>, filter: Array<any>, dataList2: Array<any>) {
29        let groupBy10MS = req.scale > 100_000_000;
30        if (req.lazyRefresh) {
31            HiPerfEvent(list, dataList2, req.type!, filter, req.startNS, req.endNS, req.totalNS, req.frame, groupBy10MS, req.intervalPerf, req.useCache || !req.range.refresh);
32        } else {
33            if (!req.useCache) {
34                HiPerfEvent(list, dataList2, req.type!, filter, req.startNS, req.endNS, req.totalNS, req.frame, groupBy10MS, req.intervalPerf, false);
35            }
36        }
37        if (req.canvas) {
38            req.context.clearRect(0, 0, req.frame.width, req.frame.height);
39            let arr = filter;
40            if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) {
41                drawLoading(req.context, req.startNS, req.endNS, req.totalNS, req.frame, arr[0].startNS, arr[arr.length - 1].startNS + arr[arr.length - 1].dur)
42            }
43            drawLines(req.context, req.xs, req.frame.height, req.lineColor)
44            req.context.stroke();
45            req.context.beginPath();
46            HiPerfEventStruct.hoverStruct = undefined;
47            req.context.fillStyle = ColorUtils.FUNC_COLOR[0];
48            req.context.strokeStyle = ColorUtils.FUNC_COLOR[0];
49            if (req.isHover) {
50                let offset = groupBy10MS ? 0 : 3;
51                for (let re of filter) {
52                    if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) {//&& req.hoverY >= re.frame.y && req.hoverY <= re.frame.y + re.frame.height
53                        HiPerfEventStruct.hoverStruct = re;
54                        break;
55                    }
56                }
57            } else {
58                HiPerfEventStruct.hoverStruct = req.params.hoverStruct;
59            }
60            HiPerfEventStruct.selectStruct = req.params.selectStruct;
61            let path = new Path2D();
62            for (let re of filter) {
63                HiPerfEventStruct.draw(req.context, path, re, groupBy10MS);
64            }
65            groupBy10MS ? req.context.fill(path) : req.context.stroke(path);
66            drawSelection(req.context, req.params);
67            let maxEvent = HiPerfEventStruct.maxEvent!.get(req.type!) || 0;
68            let textMetrics = req.context.measureText(maxEvent);
69            req.context.globalAlpha = 0.8
70            req.context.fillStyle = "#f0f0f0"
71            req.context.fillRect(0, 5, textMetrics.width + 8, 18)
72            req.context.globalAlpha = 1
73            req.context.fillStyle = "#333"
74            req.context.textBaseline = "middle"
75            req.context.fillText(maxEvent, 4, 5 + 9);
76            req.context.stroke();
77            req.context.closePath();
78            drawFlagLine(req.context, req.flagMoveInfo, req.flagSelectedInfo, req.startNS, req.endNS, req.totalNS, req.frame, req.slicesTime);
79        }
80        // @ts-ignore
81        self.postMessage({
82            id: req.id,
83            type: req.type,
84            results: req.canvas ? undefined : filter,
85            hover: HiPerfEventStruct.hoverStruct
86        });
87    }
88}
89export function HiPerfEvent(arr: Array<any>, arr2: any, type: string, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any, groupBy10MS: boolean, intervalPerf: number, use: boolean) {
90    if (use && res.length > 0) {
91        let pns = (endNS - startNS) / frame.width;
92        let y = frame.y;
93        for (let i = 0; i < res.length; i++) {
94            let it = res[i];
95            if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) {
96                if (!it.frame) {
97                    it.frame = {};
98                    it.frame.y = y;
99                }
100                it.frame.height = it.height;
101                HiPerfEventStruct.setFrame(it, pns, startNS, endNS, frame);
102            } else {
103                it.frame = null;
104            }
105        }
106        return;
107    }
108    res.length = 0;
109    if (arr) {
110        let list: Array<any>;
111        if (groupBy10MS) {
112            if (arr2[type] && arr2[type].length > 0) {
113                list = arr2[type];
114            } else {
115                list = HiPerfEventStruct.groupBy10MS(arr, intervalPerf, type);
116                arr2[type] = list;
117            }
118        } else {
119            HiPerfEventStruct.groupBy10MS(arr, intervalPerf, type);
120            list = arr;
121        }
122        let pns = (endNS - startNS) / frame.width;
123        let y = frame.y;
124
125        let groups = list.filter(it => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS).map(it => {
126            if (!it.frame) {
127                it.frame = {};
128                it.frame.y = y;
129            }
130            it.frame.height = it.height;
131            HiPerfEventStruct.setFrame(it, pns, startNS, endNS, frame);
132            return it;
133        }).reduce((pre, current, index, arr) => {
134            if (!pre[`${current.frame.x}`]) {
135                pre[`${current.frame.x}`] = [];
136                pre[`${current.frame.x}`].push(current);
137                if (groupBy10MS) {
138                    res.push(current);
139                } else {
140                    if (res.length == 0) {
141                        res.push(current);
142                    }
143                    if (res[res.length - 1] && Math.abs(current.frame.x - res[res.length - 1].frame.x) > 4) {
144                        res.push(current);
145                    }
146                }
147            }
148            return pre;
149        }, {});
150    }
151}
152
153export class HiPerfEventStruct extends BaseStruct {
154    static hoverStruct: HiPerfEventStruct | undefined;
155    static selectStruct: HiPerfEventStruct | undefined;
156    static path = new Path2D('M 100,100 h 50 v 50 h 50');
157    id: number | undefined;
158    callchain_id: number | undefined;
159    timestamp: number | undefined;
160    thread_id: number | undefined;
161    event_count: number | undefined;
162    event_type_id: number | undefined;
163    cpu_id: number | undefined;
164    thread_state: string | undefined;
165    startNS: number | undefined;
166    endNS: number | undefined;
167    dur: number | undefined;
168    height: number | undefined;
169    cpu: number | undefined;
170    static maxEvent: Map<string, number> | undefined = new Map();
171    sum: number | undefined;
172    max: number | undefined;
173
174    static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfEventStruct, groupBy10MS: boolean) {
175        if (data.frame) {
176            if (groupBy10MS) {
177                let width = data.frame.width;
178                path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0)
179            } else {
180                path.moveTo(data.frame.x + 7, 20);
181                HiPerfEventStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3)
182                path.moveTo(data.frame.x, 27);
183                path.lineTo(data.frame.x, 33);
184            }
185        }
186    }
187
188    static drawRoundRectPath(cxt: Path2D, x: number, y: number, width: number, height: number, radius: number) {
189        cxt.arc(x + width - radius, y + height - radius, radius, 0, Math.PI / 2);
190        cxt.lineTo(x + radius, y + height);
191        cxt.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI);
192        cxt.lineTo(x + 0, y + radius);
193        cxt.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
194        cxt.lineTo(x + width - radius, y + 0);
195        cxt.arc(x + width - radius, y + radius, radius, Math.PI * 3 / 2, Math.PI * 2);
196        cxt.lineTo(x + width, y + height - radius);
197        cxt.moveTo(x + width / 3, y + height / 5);
198        cxt.lineTo(x + width / 3, y + height / 5 * 4);
199        cxt.moveTo(x + width / 3, y + height / 5);
200        cxt.bezierCurveTo(x + width / 3 + 7, y + height / 5 - 2, x + width / 3 + 7, y + height / 5 + 6, x + width / 3, y + height / 5 + 4);
201    }
202
203    static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) {
204        if ((node.startNS || 0) < startNS) {
205            node.frame.x = 0;
206        } else {
207            node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns);
208        }
209        if ((node.startNS || 0) + (node.dur || 0) > endNS) {
210            node.frame.width = frame.width - node.frame.x;
211        } else {
212            node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x);
213        }
214        if (node.frame.width < 1) {
215            node.frame.width = 1;
216        }
217    }
218
219    static groupBy10MS(array: Array<any>, intervalPerf: number, type: string): Array<any> {
220        let obj = array.map(it => {
221            it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0;
222            return it;
223        }).reduce((pre, current) => {
224            (pre[current["timestamp_group"]] = pre[current["timestamp_group"]] || []).push(current);
225            return pre;
226        }, {});
227        let arr: any[] = [];
228        let max = 0;
229        for (let aKey in obj) {
230            let sum = obj[aKey].reduce((pre: any, cur: any) => {
231                return pre + cur.event_count
232            }, 0)
233            if (sum > max) max = sum;
234            let ns = parseInt(aKey);
235            arr.push({
236                startNS: ns,
237                dur: 1_000_000_0,
238                height: 0,
239                sum: sum,
240            })
241        }
242        if (typeof (HiPerfEventStruct.maxEvent!.get(type)) === "undefined") {
243            HiPerfEventStruct.maxEvent!.set(type, max);
244        }
245        arr.map(it => {
246            it.height = Math.floor(40 * it.sum / max);
247            it.max = max;
248            return it;
249        })
250        return arr;
251    }
252}
253