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, 18 dataFilterHandler, 19 drawLoadingFrame, 20 ns2x, 21 PerfRender, 22 Rect, 23 RequestMessage, 24} from '../ProcedureWorkerCommon'; 25import { TraceRow } from '../../../component/trace/base/TraceRow'; 26import { ColorUtils } from '../../../component/trace/base/ColorUtils'; 27import { SpSystemTrace } from '../../../component/SpSystemTrace'; 28 29export class CpuStateRender extends PerfRender { 30 renderMainThread( 31 req: { 32 useCache: boolean; 33 cpuStateContext: CanvasRenderingContext2D; 34 type: string; 35 cpu: number; 36 }, 37 cpuStateRow: TraceRow<CpuStateStruct> 38 ): void { 39 let list = cpuStateRow.dataList; 40 let filter = cpuStateRow.dataListCache; 41 dataFilterHandler(list, filter, { 42 startKey: 'startTs', 43 durKey: 'dur', 44 startNS: TraceRow.range?.startNS ?? 0, 45 endNS: TraceRow.range?.endNS ?? 0, 46 totalNS: TraceRow.range?.totalNS ?? 0, 47 frame: cpuStateRow.frame, 48 paddingTop: 5, 49 useCache: req.useCache || !(TraceRow.range?.refresh ?? false), 50 }); 51 drawLoadingFrame(req.cpuStateContext, filter, cpuStateRow); 52 let path = new Path2D(); 53 let find = false; 54 let offset = 3; 55 let heights = [4, 8, 12, 16, 20, 24, 28, 32]; 56 for (let re of filter) { 57 //@ts-ignore 58 re.height = heights[re.value]; 59 CpuStateStruct.draw(req.cpuStateContext, path, re); 60 if (cpuStateRow.isHover) { 61 if ( 62 re.frame && 63 cpuStateRow.hoverX >= re.frame.x - offset && 64 cpuStateRow.hoverX <= re.frame.x + re.frame.width + offset 65 ) { 66 CpuStateStruct.hoverStateStruct = re; 67 find = true; 68 } 69 } 70 } 71 if (!find && cpuStateRow.isHover) { 72 CpuStateStruct.hoverStateStruct = undefined; 73 } 74 req.cpuStateContext.fill(path); 75 } 76 77 render( 78 cpuStateReq: RequestMessage, 79 list: Array<CpuStateStruct>, 80 filter: Array<CpuStateStruct>, 81 dataList2: Array<CpuStateStruct> 82 ): void { } 83 84 setFrameByArr( 85 cpuStateRes: CpuStateStruct[], 86 startNS: number, 87 endNS: number, 88 totalNS: number, 89 frame: Rect, 90 arr2: CpuStateStruct[] 91 ): void { 92 let list: CpuStateStruct[] = arr2; 93 cpuStateRes.length = 0; 94 let pns = (endNS - startNS) / frame.width; 95 let y = frame.y + 5; 96 let frameHeight = frame.height - 10; 97 let left = 0; 98 let right = 0; 99 for (let i = 0, j = list.length - 1, ib = true, jb = true; i < list.length, j >= 0; i++, j--) { 100 if (list[j].startTs! <= endNS && jb) { 101 right = j; 102 jb = false; 103 } 104 if (list[i].startTs! + list[i].dur! >= startNS && ib) { 105 left = i; 106 ib = false; 107 } 108 if (!ib && !jb) { 109 break; 110 } 111 } 112 let slice = list.slice(left, right + 1); 113 let sum = 0; 114 for (let i = 0; i < slice.length; i++) { 115 if (!slice[i].frame) { 116 slice[i].frame = new Rect(0, 0, 0, 0); 117 slice[i].frame!.y = y; 118 slice[i].frame!.height = frameHeight; 119 } 120 if (slice[i].dur! >= pns) { 121 //@ts-ignore 122 slice[i].v = true; 123 CpuStateStruct.setFrame(slice[i], 5, startNS, endNS, totalNS, frame); 124 } else { 125 if (i > 0) { 126 //@ts-ignore 127 let c = slice[i].startTs - slice[i - 1].startTs - slice[i - 1].dur; 128 if (c < pns && sum < pns) { 129 //@ts-ignore 130 sum += c + slice[i - 1].dur; 131 //@ts-ignore 132 slice[i].v = false; 133 } else { 134 //@ts-ignore 135 slice[i].v = true; 136 CpuStateStruct.setFrame(slice[i], 5, startNS, endNS, totalNS, frame); 137 sum = 0; 138 } 139 } 140 } 141 } 142 //@ts-ignore 143 cpuStateRes.push(...slice.filter((it) => it.v)); 144 } 145 146 setFrameByFilter(cpuStateRes: CpuStateStruct[], startNS: number, endNS: number, totalNS: number, frame: Rect): void { 147 for (let i = 0, len = cpuStateRes.length; i < len; i++) { 148 if ( 149 (cpuStateRes[i].startTs || 0) + (cpuStateRes[i].dur || 0) >= startNS && 150 (cpuStateRes[i].startTs || 0) <= endNS 151 ) { 152 CpuStateStruct.setFrame(cpuStateRes[i], 5, startNS, endNS, totalNS, frame); 153 } else { 154 cpuStateRes[i].frame = undefined; 155 } 156 } 157 } 158 159 cpuState( 160 arr: CpuStateStruct[], 161 arr2: CpuStateStruct[], 162 type: string, 163 cpuStateRes: CpuStateStruct[], 164 cpu: number, 165 startNS: number, 166 endNS: number, 167 totalNS: number, 168 frame: Rect, 169 use: boolean 170 ): void { 171 if (use && cpuStateRes.length > 0) { 172 this.setFrameByFilter(cpuStateRes, startNS, endNS, totalNS, frame); 173 return; 174 } 175 cpuStateRes.length = 0; 176 if (arr) { 177 this.setFrameByArr(cpuStateRes, startNS, endNS, totalNS, frame, arr2); 178 } 179 } 180} 181export function CpuStateStructOnClick( 182 clickRowType: string, 183 sp: SpSystemTrace, 184 entry?: CpuStateStruct, 185): Promise<unknown> { 186 return new Promise((resolve, reject) => { 187 if (clickRowType === TraceRow.ROW_TYPE_CPU_STATE && (CpuStateStruct.hoverStateStruct || entry)) { 188 CpuStateStruct.selectStateStruct = entry || CpuStateStruct.hoverStateStruct; 189 sp.traceSheetEL?.displayCpuStateData(); 190 sp.timerShaftEL?.modifyFlagList(undefined); 191 reject(new Error()); 192 } else { 193 resolve(null); 194 } 195 }); 196} 197export class CpuStateStruct extends BaseStruct { 198 static hoverStateStruct: CpuStateStruct | undefined; 199 static selectStateStruct: CpuStateStruct | undefined; 200 dur: number | undefined; 201 value: string | undefined; 202 startTs: number | undefined; 203 height: number | undefined; 204 cpu: number | undefined; 205 206 static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: CpuStateStruct): void { 207 if (data.frame) { 208 let chartColor = ColorUtils.colorForTid(data.cpu!); 209 ctx.font = '11px sans-serif'; 210 ctx.fillStyle = chartColor; 211 ctx.strokeStyle = chartColor; 212 ctx.globalAlpha = 0.6; 213 if (data === CpuStateStruct.hoverStateStruct || data === CpuStateStruct.selectStateStruct) { 214 path.rect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0); 215 ctx.lineWidth = 1; 216 ctx.globalAlpha = 1.0; 217 ctx.beginPath(); 218 ctx.arc(data.frame.x, 35 - (data.height || 0), 3, 0, 2 * Math.PI, true); 219 ctx.stroke(); 220 ctx.beginPath(); 221 ctx.moveTo(data.frame.x + 3, 35 - (data.height || 0)); 222 ctx.lineWidth = 3; 223 ctx.lineTo(data.frame.x + data.frame.width, 35 - (data.height || 0)); 224 ctx.stroke(); 225 ctx.lineWidth = 1; 226 ctx.globalAlpha = 0.6; 227 ctx.fillRect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0); 228 } else { 229 ctx.globalAlpha = 0.6; 230 ctx.fillRect(data.frame.x, 35 - (data.height || 0), data.frame.width, data.height || 0); 231 } 232 } 233 } 234 235 static setCpuFrame(cpuStateNode: CpuStateStruct, pns: number, startNS: number, endNS: number, frame: Rect): void { 236 if (!cpuStateNode.frame) { 237 return; 238 } 239 //@ts-ignore 240 if ((cpuStateNode.startTime || 0) < startNS) { 241 cpuStateNode.frame.x = 0; 242 } else { 243 cpuStateNode.frame.x = Math.floor(((cpuStateNode.startTs || 0) - startNS) / pns); 244 } 245 //@ts-ignore 246 if ((cpuStateNode.startTime || 0) + (cpuStateNode.dur || 0) > endNS) { 247 cpuStateNode.frame.width = frame.width - cpuStateNode.frame.x; 248 } else { 249 cpuStateNode.frame.width = Math.ceil( 250 ((cpuStateNode.startTs || 0) + (cpuStateNode.dur || 0) - startNS) / pns - cpuStateNode.frame.x 251 ); 252 } 253 if (cpuStateNode.frame.width < 1) { 254 cpuStateNode.frame.width = 1; 255 } 256 } 257 static setFrame( 258 cpuStateNode: CpuStateStruct, 259 padding: number, 260 startNS: number, 261 endNS: number, 262 totalNS: number, 263 frame: Rect 264 ): void { 265 let x1: number; 266 let x2: number; 267 if ((cpuStateNode.startTs || 0) < startNS) { 268 x1 = 0; 269 } else { 270 x1 = ns2x(cpuStateNode.startTs || 0, startNS, endNS, totalNS, frame); 271 } 272 if ((cpuStateNode.startTs || 0) + (cpuStateNode.dur || 0) > endNS) { 273 x2 = frame.width; 274 } else { 275 x2 = ns2x((cpuStateNode.startTs || 0) + (cpuStateNode.dur || 0), startNS, endNS, totalNS, frame); 276 } 277 let cpuStateGetV: number = x2 - x1 <= 1 ? 1 : x2 - x1; 278 if (!cpuStateNode.frame) { 279 cpuStateNode.frame = new Rect(0, 0, 0, 0); 280 } 281 cpuStateNode.frame.x = Math.ceil(x1); 282 cpuStateNode.frame.y = frame.y + padding; 283 cpuStateNode.frame.width = Math.floor(cpuStateGetV); 284 cpuStateNode.frame.height = cpuStateNode.height!; 285 } 286} 287