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}