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