• 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, drawWakeUp,
23    ns2x,
24    Rect, Render,
25    RequestMessage
26} from "./ProcedureWorkerCommon.js";
27
28export class FuncRender extends Render{
29    render(req: RequestMessage, list: Array<any>, filter: Array<any>) {
30        if (!req.params.isLive) {
31            self.postMessage({
32                id: req.id,
33                type: req.type,
34                results: req.canvas ? undefined : filter,
35                hover: undefined
36            });
37            return;
38        }
39        if (req.lazyRefresh) {
40            func(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh);
41        } else {
42            if (!req.useCache) {
43                func(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false);
44            }
45        }
46        if (req.canvas) {
47            if (req.canvas.height == 150) {
48                req.canvas.width = req.frame.width;
49                req.canvas.height = req.params.maxHeight;
50                req.context.scale(req.params.dpr, req.params.dpr);
51            }
52            req.context.clearRect(0, 0, req.frame.width, req.frame.height);
53            let arr = filter;
54            if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) {
55                drawLoading(req.context, req.startNS, req.endNS, req.totalNS, req.frame, arr[0].startTs, arr[arr.length - 1].startTs + arr[arr.length - 1].dur)
56            }
57            req.context.beginPath();
58            drawLines(req.context, req.xs, req.frame.height, req.lineColor)
59            FuncStruct.hoverFuncStruct = undefined;
60            if (req.isHover) {
61                for (let re of filter) {
62                    if (re.dur == 0 || re.dur == null || re.dur == undefined) {
63                        if (re.frame && req.hoverX >= re.frame.x - 5 && req.hoverX <= re.frame.x + 5 && req.hoverY >= re.frame.y + (re.depth * 20) && req.hoverY <= re.frame.y + re.frame.height + (re.depth * 20)) {
64                            FuncStruct.hoverFuncStruct = re;
65                            break;
66                        }
67                    } else {
68                        if (re.frame && req.hoverX >= re.frame.x && req.hoverX <= re.frame.x + re.frame.width && req.hoverY >= re.frame.y + (re.depth * 20) && req.hoverY <= re.frame.y + re.frame.height + (re.depth * 20)) {
69                            FuncStruct.hoverFuncStruct = re;
70                            break;
71                        }
72                    }
73                }
74            } else {
75                FuncStruct.hoverFuncStruct = req.params.hoverFuncStruct;
76            }
77            FuncStruct.selectFuncStruct = req.params.selectFuncStruct;
78            for (let re of filter) {
79                FuncStruct.draw(req.context, re, req.totalNS)
80            }
81            drawSelection(req.context, req.params);
82            drawWakeUp(req.context, req.wakeupBean, req.startNS, req.endNS, req.totalNS, req.frame);
83            req.context.closePath();
84            drawFlagLine(req.context, req.flagMoveInfo, req.flagSelectedInfo, req.startNS, req.endNS, req.totalNS, req.frame, req.slicesTime);
85        }
86        // @ts-ignore
87        self.postMessage({
88            id: req.id,
89            type: req.type,
90            results: req.canvas ? undefined : filter,
91            hover: FuncStruct.hoverFuncStruct
92        });
93    }
94}
95
96export function func(list: Array<any>, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any, use: boolean) {
97    if (use && res.length > 0) {
98        for (let i = 0, len = res.length; i < len; i++) {
99            if ((res[i].startTs || 0) + (res[i].dur || 0) >= startNS && (res[i].startTs || 0) <= endNS) {
100                FuncStruct.setFuncFrame(res[i], 0, startNS, endNS, totalNS, frame)
101            } else {
102                res[i].frame = null;
103            }
104        }
105        return;
106    }
107    res.length = 0;
108    if (list) {
109        let groups = list.filter(it => (it.startTs || 0) + (it.dur || 0) >= startNS && (it.startTs || 0) <= endNS).map(it => {
110            FuncStruct.setFuncFrame(it, 0, startNS, endNS, totalNS, frame)
111            return it;
112        }).reduce((pre, current, index, arr) => {
113            (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current);
114            return pre;
115        }, {});
116        Reflect.ownKeys(groups).map((kv => {
117            let arr = (groups[kv].sort((a: any, b: any) => b.dur - a.dur));
118            res.push(arr[0]);
119        }));
120    }
121}
122
123export class FuncStruct extends BaseStruct {
124    static hoverFuncStruct: FuncStruct | undefined;
125    static selectFuncStruct: FuncStruct | undefined;
126    argsetid: number | undefined // 53161
127    depth: number | undefined // 0
128    dur: number | undefined // 570000
129    funName: string | undefined //"binder transaction"
130    id: number | undefined // 92749
131    is_main_thread: number | undefined // 0
132    parent_id: number | undefined // null
133    startTs: number | undefined // 9729867000
134    threadName: string | undefined // "Thread-15"
135    tid: number | undefined // 2785
136    identify: number | undefined
137    track_id: number | undefined // 414
138
139    static setFuncFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) {
140        let x1: number, x2: number;
141        if ((node.startTs || 0) > startNS && (node.startTs || 0) < endNS) {
142            x1 = ns2x((node.startTs || 0), startNS, endNS, totalNS, frame);
143        } else {
144            x1 = 0;
145        }
146        if ((node.startTs || 0) + (node.dur || 0) > startNS && (node.startTs || 0) + (node.dur || 0) < endNS) {
147            x2 = ns2x((node.startTs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame);
148        } else {
149            x2 = frame.width;
150        }
151        if (!node.frame) {
152            node.frame = {};
153        }
154        let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1;
155        node.frame.x = Math.floor(x1);
156        node.frame.y = 0;
157        node.frame.width = Math.floor(getV);
158        node.frame.height = 20;
159    }
160
161    static getInt(data: FuncStruct): number {
162        let str = data.funName || "";
163        let sum = 0;
164        for (let i = 0; i < str.length; i++) {
165            sum += str.charCodeAt(i)
166        }
167        return (sum + (data?.depth || 0)) % ColorUtils.FUNC_COLOR.length;
168    }
169
170    static draw(ctx: CanvasRenderingContext2D, data: FuncStruct, totalNS: number) {
171        if (data.frame) {
172            let isBinder = FuncStruct.isBinder(data);
173            if (data.dur == undefined || data.dur == null || data.dur == 0) {
174            } else {
175                ctx.fillStyle = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)];//data.depth ||
176                let miniHeight = 20
177                ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2)
178                if (data.frame.width > 10) {
179                    ctx.fillStyle = "#fff"
180                    FuncStruct.drawString(ctx, `${data.funName || ''}`, 5, data.frame)
181                }
182                if (FuncStruct.isSelected(data)) {
183                    ctx.strokeStyle = "#000"
184                    ctx.lineWidth = 2
185                    ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2)
186                }
187            }
188        }
189    }
190
191    static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect): boolean {
192        let textMetrics = ctx.measureText(str);
193        let charWidth = Math.round(textMetrics.width / str.length)
194        if (textMetrics.width < frame.width - textPadding * 2) {
195            let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding)
196            ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2)
197            return true;
198        }
199        if (frame.width - textPadding * 2 > charWidth * 4) {
200            let chatNum = (frame.width - textPadding * 2) / charWidth;
201            let x1 = frame.x + textPadding
202            ctx.fillText(str.substring(0, chatNum - 4) + '...', x1, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2)
203            return true;
204        }
205        return false;
206    }
207
208    static isSelected(data: FuncStruct): boolean {
209        return (FuncStruct.selectFuncStruct != undefined &&
210            FuncStruct.selectFuncStruct.startTs == data.startTs &&
211            FuncStruct.selectFuncStruct.depth == data.depth)
212    }
213
214    static isBinder(data: FuncStruct): boolean {
215        if (data.funName != null &&
216            (
217                data.funName.toLowerCase().startsWith("binder transaction async")
218                || data.funName.toLowerCase().startsWith("binder async")
219            )
220        ) {
221            return true;
222        } else {
223            return false;
224        }
225    }
226}
227
228const padding = 1;
229
230