• 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, ColorUtils, ns2x, Rect} from "./ProcedureWorkerCommon.js";
17
18export function func(list: Array<any>, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any, use: boolean) {
19    if (use && res.length > 0) {
20        for (let i = 0, len = res.length; i < len; i++) {
21            if ((res[i].startTs || 0) + (res[i].dur || 0) >= startNS && (res[i].startTs || 0) <= endNS) {
22                FuncStruct.setFuncFrame(res[i], 0, startNS, endNS, totalNS, frame)
23            }else{
24                res[i].frame = null;
25            }
26        }
27        return;
28    }
29    res.length = 0;
30    if (list) {
31        let groups = list.filter(it => (it.startTs || 0) + (it.dur || 0) >= startNS && (it.startTs || 0) <= endNS).map(it => {
32            FuncStruct.setFuncFrame(it, 0, startNS, endNS, totalNS, frame)
33            return it;
34        }).reduce((pre, current, index, arr) => {
35            (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current);
36            return pre;
37        }, {});
38        Reflect.ownKeys(groups).map((kv => {
39            let arr = (groups[kv].sort((a: any, b: any) => b.dur - a.dur));
40            res.push(arr[0]);
41        }));
42    }
43}
44
45export class FuncStruct extends BaseStruct {
46    static hoverFuncStruct: FuncStruct | undefined;
47    static selectFuncStruct: FuncStruct | undefined;
48    argsetid: number | undefined // 53161
49    depth: number | undefined // 0
50    dur: number | undefined // 570000
51    funName: string | undefined //"binder transaction"
52    id: number | undefined // 92749
53    is_main_thread: number | undefined // 0
54    parent_id: number | undefined // null
55    startTs: number | undefined // 9729867000
56    threadName: string | undefined // "Thread-15"
57    tid: number | undefined // 2785
58    identify: number | undefined
59    track_id: number | undefined // 414
60
61    static setFuncFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) {
62        let x1: number, x2: number;
63        if ((node.startTs || 0) > startNS && (node.startTs || 0) < endNS) {
64            x1 = ns2x((node.startTs || 0), startNS, endNS, totalNS, frame);
65        } else {
66            x1 = 0;
67        }
68        if ((node.startTs || 0) + (node.dur || 0) > startNS && (node.startTs || 0) + (node.dur || 0) < endNS) {
69            x2 = ns2x((node.startTs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame);
70        } else {
71            x2 = frame.width;
72        }
73        if (!node.frame) {
74            node.frame = {};
75        }
76        let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1;
77        node.frame.x = Math.floor(x1);
78        node.frame.y = 0;
79        node.frame.width = Math.floor(getV);
80        node.frame.height = 20;
81    }
82
83    static getInt(data: FuncStruct): number {
84        let str = data.funName || "";
85        let sum = 0;
86        for (let i = 0; i < str.length; i++) {
87            sum += str.charCodeAt(i)
88        }
89        return (sum + (data?.depth || 0)) % ColorUtils.FUNC_COLOR.length;
90    }
91
92    static draw(ctx: CanvasRenderingContext2D, data: FuncStruct, totalNS: number) {
93        if (data.frame) {
94            let isBinder = FuncStruct.isBinder(data);
95            if (data.dur == undefined || data.dur == null || data.dur == 0) {
96            } else {
97                ctx.fillStyle = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)];//data.depth ||
98                let miniHeight = 20
99                ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2)
100                if (data.frame.width > 10) {
101                    ctx.fillStyle = "#fff"
102                    FuncStruct.drawString(ctx, `${data.funName || ''}`, 5, data.frame)
103                }
104                if (FuncStruct.isSelected(data)) {
105                    ctx.strokeStyle = "#000"
106                    ctx.lineWidth = 2
107                    ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2)
108                }
109            }
110        }
111    }
112
113    static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect): boolean {
114        let textMetrics = ctx.measureText(str);
115        let charWidth = Math.round(textMetrics.width / str.length)
116        if (textMetrics.width < frame.width - textPadding * 2) {
117            let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding)
118            ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2)
119            return true;
120        }
121        if (frame.width - textPadding * 2 > charWidth * 4) {
122            let chatNum = (frame.width - textPadding * 2) / charWidth;
123            let x1 = frame.x + textPadding
124            ctx.fillText(str.substring(0, chatNum - 4) + '...', x1, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2)
125            return true;
126        }
127        return false;
128    }
129
130    static isSelected(data: FuncStruct): boolean {
131        return (FuncStruct.selectFuncStruct != undefined &&
132            FuncStruct.selectFuncStruct.startTs == data.startTs &&
133            FuncStruct.selectFuncStruct.depth == data.depth)
134    }
135
136    static isBinder(data: FuncStruct): boolean {
137        if (data.funName != null &&
138            (
139                data.funName.toLowerCase().startsWith("binder transaction async")
140                || data.funName.toLowerCase().startsWith("binder async")
141                || data.funName.toLowerCase().startsWith("binder reply")
142            )
143        ) {
144            return true;
145        } else {
146            return false;
147        }
148    }
149}
150
151const padding = 1;
152
153