• 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 {
17    BaseStruct, drawFlagLine,
18    drawLines,
19    drawLoading,
20    drawSelection, drawWakeUp,
21    ns2x,
22    Rect, Render,
23    RequestMessage
24} from "./ProcedureWorkerCommon.js";
25export class ThreadRender extends Render{
26    render(req: RequestMessage, list: Array<any>, filter: Array<any>) {
27        if (req.lazyRefresh) {
28            thread(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, req.useCache || !req.range.refresh);
29        } else {
30            if (!req.useCache) {
31                thread(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, false);
32            }
33        }
34        if (req.canvas) {
35            req.context.clearRect(0, 0, req.frame.width, req.frame.height);
36            let arr = filter;
37            if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) {
38                drawLoading(req.context, req.startNS, req.endNS, req.totalNS, req.frame, arr[0].startTime, arr[arr.length - 1].startTime + arr[arr.length - 1].dur)
39            }
40            req.context.beginPath();
41            drawLines(req.context, req.xs, req.frame.height, req.lineColor)
42            ThreadStruct.hoverThreadStruct = undefined;
43            if (req.isHover) {
44                for (let re of filter) {
45                    if (re.frame && req.hoverX >= re.frame.x && req.hoverX <= re.frame.x + re.frame.width && req.hoverY >= re.frame.y && req.hoverY <= re.frame.y + re.frame.height) {
46                        ThreadStruct.hoverThreadStruct = re;
47                        break;
48                    }
49                }
50            } else {
51                ThreadStruct.hoverThreadStruct = req.params.hoverThreadStruct;
52            }
53            ThreadStruct.selectThreadStruct = req.params.selectThreadStruct;
54            for (let re of filter) {
55                ThreadStruct.draw(req.context, re)
56            }
57            drawSelection(req.context, req.params);
58            drawWakeUp(req.context, req.wakeupBean, req.startNS, req.endNS, req.totalNS, req.frame);
59            req.context.closePath();
60            drawFlagLine(req.context, req.flagMoveInfo, req.flagSelectedInfo, req.startNS, req.endNS, req.totalNS, req.frame, req.slicesTime);
61        }
62        // @ts-ignore
63        self.postMessage({
64            id: req.id,
65            type: req.type,
66            results: req.canvas ? undefined : filter,
67            hover: ThreadStruct.hoverThreadStruct
68        });
69    }
70}
71export function thread(list: Array<any>, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any,use:boolean) {
72    if(use && res.length > 0){
73        for (let i = 0; i < res.length; i++) {
74            let it = res[i];
75            if((it.startTime || 0) + (it.dur || 0) > startNS && (it.startTime || 0) < endNS){
76                ThreadStruct.setThreadFrame(it, 5, startNS, endNS, totalNS, frame)
77            }else{
78                it.frame = null;
79            }
80        }
81        return;
82    }
83    res.length = 0;
84    if (list) {
85        let groups = list.filter(it => (it.startTime || 0) + (it.dur || 0) > startNS && (it.startTime || 0) < endNS).map(it => {
86            ThreadStruct.setThreadFrame(it, 5, startNS, endNS, totalNS, frame)
87            return it;
88        }).reduce((pre, current, index, arr) => {
89            (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current);
90            return pre;
91        }, {});
92        Reflect.ownKeys(groups).map((kv => {
93            let arr = (groups[kv].sort((a: any, b: any) => b.frame.width - a.frame.width));
94            if (arr.length > 1) {
95                let idx = arr.findIndex((it: any) => it.state != "S")
96                if (idx != -1) {
97                    res.push(arr[idx]);
98                } else {
99                    res.push(arr[0]);
100                }
101            } else {
102                res.push(arr[0]);
103            }
104        }));
105    }
106}
107
108const padding = 3;
109
110export class ThreadStruct extends BaseStruct {
111    static runningColor: string = "#467b3b";
112    static rColor = "#a0b84d";
113    static otherColor = "#673ab7";
114    static uninterruptibleSleepColor = "#f19d38";
115    static traceColor = "#0d47a1";
116    static sColor = "#FBFBFB";
117    static hoverThreadStruct: ThreadStruct | undefined;
118    static selectThreadStruct: ThreadStruct | undefined;
119    static statusMap: any = {
120        "D": "Uninterruptible Sleep",
121        "S": "Sleeping",
122        "R": "Runnable",
123        "Running": "Running",
124        "R+": "Runnable (Preempted)",
125        "DK": "Uninterruptible Sleep + Wake Kill",
126        "I": "Task Dead",
127        "T": "Traced",
128        "t": "Traced",
129        "X": "Exit (Dead)",
130        "Z": "Exit (Zombie)",
131        "K": "Wake Kill",
132        "W": "Waking",
133        "P": "Parked",
134        "N": "No Load"
135    }
136    hasSched: number | undefined;// 14724852000
137    pid: number | undefined// 2519
138    processName: string | undefined //null
139    threadName: string | undefined//"ACCS0"
140    tid: number | undefined //2716
141    upid: number | undefined // 1
142    utid: number | undefined // 1
143    cpu: number | undefined // null
144    dur: number | undefined // 405000
145    end_ts: number | undefined // null
146    id: number | undefined // 1
147    is_main_thread: number | undefined // 0
148    name: string | undefined // "ACCS0"
149    startTime: number | undefined // 58000
150    start_ts: number | undefined // null
151    state: string | undefined // "S"
152    type: string | undefined // "thread"
153
154    static setThreadFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) {
155        let x1: number;
156        let x2: number;
157        if ((node.startTime || 0) < startNS) {
158            x1 = 0;
159        } else {
160            x1 = ns2x((node.startTime || 0), startNS, endNS, totalNS, frame);
161        }
162        if ((node.startTime || 0) + (node.dur || 0) > endNS) {
163            x2 = frame.width;
164        } else {
165            x2 = ns2x((node.startTime || 0) + (node.dur || 0), startNS, endNS, totalNS, frame);
166        }
167        let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1;
168        if (!node.frame) {
169            node.frame = {};
170        }
171        node.frame.x = Math.floor(x1);
172        node.frame.y = frame.y + padding;
173        node.frame.width = Math.ceil(getV);
174        node.frame.height = 30 - padding * 2;
175    }
176
177    static draw(ctx: CanvasRenderingContext2D, data: ThreadStruct) {
178        if (data.frame) {
179            ctx.globalAlpha = 1
180            let stateText = data.state || '';
181            if ("S" == data.state) {
182                ctx.fillStyle = ThreadStruct.sColor;
183                ctx.globalAlpha = 0.2; // transparency
184                ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2)
185                ctx.globalAlpha = 1; // transparency
186            } else if ("R" == data.state || "R+" == data.state) {
187                ctx.fillStyle = ThreadStruct.rColor;
188                ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2)
189                ctx.fillStyle = "#fff";
190                data.frame.width > 4 && ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
191            } else if ("D" == data.state) {
192                ctx.fillStyle = ThreadStruct.uninterruptibleSleepColor;
193                ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2)
194                ctx.fillStyle = "#fff";
195                data.frame.width > 4 && ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
196            } else if ("Running" == data.state) {
197                ctx.fillStyle = ThreadStruct.runningColor;
198                ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2)
199                ctx.fillStyle = "#fff";
200                data.frame.width > 4 && ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
201            } else if ("T" == data.state || "t" == data.state) {
202                ctx.fillStyle = ThreadStruct.traceColor;
203                ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2)
204                ctx.fillStyle = "#fff";
205                ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
206            } else {
207                ctx.fillStyle = ThreadStruct.otherColor;
208                ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2)
209                ctx.fillStyle = "#fff";
210                data.frame.width > 4 && ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
211            }
212            if (ThreadStruct.selectThreadStruct && ThreadStruct.equals(ThreadStruct.selectThreadStruct, data) && ThreadStruct.selectThreadStruct.state != "S") {
213                ctx.strokeStyle = '#232c5d'
214                ctx.lineWidth = 2
215                ctx.strokeRect(data.frame.x, data.frame.y + padding, data.frame.width - 2, data.frame.height - padding * 2)
216            }
217        }
218    }
219
220    static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect) {
221        let textMetrics = ctx.measureText(str);
222        let charWidth = Math.round(textMetrics.width / str.length)
223        if (textMetrics.width < frame.width - textPadding * 2) {
224            let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding)
225            ctx.textBaseline = "middle"
226            ctx.font = "8px sans-serif";
227            ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2), frame.width - textPadding * 2)
228            return;
229        }
230        if (frame.width - textPadding * 2 > charWidth * 4) {
231            let chatNum = (frame.width - textPadding * 2) / charWidth;
232            let x1 = frame.x + textPadding
233            ctx.textBaseline = "middle"
234            ctx.font = "8px sans-serif";
235            ctx.fillText(str.substring(0, chatNum - 4) + '...', x1, Math.floor(frame.y + frame.height / 2), frame.width - textPadding * 2)
236            return;
237        }
238    }
239
240    static getEndState(state: string): string {
241        let statusMapElement = ThreadStruct.statusMap[state];
242        if (statusMapElement) {
243            return statusMapElement
244        } else {
245            if ("" == statusMapElement || statusMapElement == null) {
246                return "";
247            }
248            return "Unknown State";
249        }
250    }
251
252    static equals(d1: ThreadStruct, d2: ThreadStruct): boolean {
253        if (d1 && d2 && d1.cpu == d2.cpu &&
254            d1.tid == d2.tid &&
255            d1.state == d2.state &&
256            d1.startTime == d2.startTime &&
257            d1.dur == d2.dur) {
258            return true;
259        } else {
260            return false;
261        }
262    }
263}