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 isFrameContainPoint, 20 ns2x, 21 Render, 22 drawLoadingFrame, 23 Rect, 24} from '../ProcedureWorkerCommon'; 25import { ColorUtils } from '../../../component/trace/base/ColorUtils'; 26import { TraceRow } from '../../../component/trace/base/TraceRow'; 27import { SpSystemTrace } from '../../../component/SpSystemTrace'; 28 29export class CpuFreqLimitRender extends Render { 30 renderMainThread( 31 cpuFreqLimitReq: { 32 useCache: boolean; 33 context: CanvasRenderingContext2D; 34 cpu: number; 35 type: string; 36 maxFreq: number; 37 maxFreqName: string; 38 }, 39 row: TraceRow<CpuFreqLimitsStruct> 40 ): void { 41 let list = row.dataList; 42 let filter = row.dataListCache; 43 dataFilterHandler(list, filter, { 44 startKey: 'startNs', 45 durKey: 'dur', 46 startNS: TraceRow.range?.startNS ?? 0, 47 endNS: TraceRow.range?.endNS ?? 0, 48 totalNS: TraceRow.range?.totalNS ?? 0, 49 frame: row.frame, 50 paddingTop: 5, 51 useCache: cpuFreqLimitReq.useCache || !(TraceRow.range?.refresh ?? false), 52 }); 53 drawLoadingFrame(cpuFreqLimitReq.context, filter, row); 54 cpuFreqLimitReq.context.beginPath(); 55 let maxFreq = cpuFreqLimitReq.maxFreq; 56 let maxFreqName = cpuFreqLimitReq.maxFreqName; 57 if (row.isHover) { 58 for (let re of filter) { 59 if (re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 60 CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct = re; 61 break; 62 } 63 } 64 } 65 for (let re of filter) { 66 CpuFreqLimitsStruct.draw(cpuFreqLimitReq.context, re, maxFreq); 67 } 68 cpuFreqLimitReq.context.closePath(); 69 let s = maxFreqName; 70 let textMetrics = cpuFreqLimitReq.context.measureText(s); 71 cpuFreqLimitReq.context.globalAlpha = 0.8; 72 cpuFreqLimitReq.context.fillStyle = '#f0f0f0'; 73 cpuFreqLimitReq.context.fillRect(0, 5, textMetrics.width + 8, 18); 74 cpuFreqLimitReq.context.globalAlpha = 1; 75 cpuFreqLimitReq.context.fillStyle = '#333'; 76 cpuFreqLimitReq.context.textBaseline = 'middle'; 77 cpuFreqLimitReq.context.fillText(s, 4, 5 + 9); 78 } 79} 80export function CpuFreqLimitsStructOnClick( 81 clickRowType: string, 82 sp: SpSystemTrace, 83 entry?: CpuFreqLimitsStruct, 84): Promise<unknown> { 85 return new Promise((resolve, reject) => { 86 if (clickRowType === TraceRow.ROW_TYPE_CPU_FREQ_LIMIT && (CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct || entry)) { 87 CpuFreqLimitsStruct.selectCpuFreqLimitsStruct = entry || CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct; 88 sp.traceSheetEL?.displayFreqLimitData(); 89 sp.timerShaftEL?.modifyFlagList(undefined); 90 reject(new Error()); 91 } else { 92 resolve(null); 93 } 94 }); 95} 96export class CpuFreqLimitsStruct extends BaseStruct { 97 static hoverCpuFreqLimitsStruct: CpuFreqLimitsStruct | undefined; 98 static selectCpuFreqLimitsStruct: CpuFreqLimitsStruct | undefined; 99 static minAlpha = 0.4; 100 static maxAlpha = 0.8; 101 startNs: number | undefined; 102 dur: number = 0; 103 max: number | undefined; 104 min: number | undefined; 105 cpu: number = 0; 106 107 static draw(ctx: CanvasRenderingContext2D, data: CpuFreqLimitsStruct, maxFreq: number): void { 108 if (data.frame) { 109 let width = data.frame.width || 0; 110 let drawMaxHeight: number = Math.floor(((data.max || 0) * (data.frame.height || 0)) / maxFreq); 111 let drawMinHeight: number = Math.floor(((data.min || 0) * (data.frame.height || 0)) / maxFreq); 112 let index = data.cpu || 0; 113 index += 2; 114 ctx.fillStyle = ColorUtils.colorForTid(index); 115 ctx.strokeStyle = ColorUtils.colorForTid(index); 116 if ( 117 data === CpuFreqLimitsStruct.hoverCpuFreqLimitsStruct || 118 data === CpuFreqLimitsStruct.selectCpuFreqLimitsStruct 119 ) { 120 ctx.lineWidth = 1; 121 ctx.globalAlpha = this.minAlpha; 122 this.drawArcLine(ctx, data, drawMaxHeight, drawMaxHeight - drawMinHeight); 123 ctx.globalAlpha = this.maxAlpha; 124 this.drawArcLine(ctx, data, drawMinHeight, drawMinHeight); 125 } else { 126 ctx.globalAlpha = this.minAlpha; 127 ctx.lineWidth = 1; 128 ctx.fillRect( 129 data.frame.x, 130 data.frame.y + data.frame.height - drawMaxHeight, 131 width, 132 drawMaxHeight - drawMinHeight 133 ); 134 ctx.globalAlpha = this.maxAlpha; 135 ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawMinHeight, width, drawMinHeight); 136 } 137 } 138 ctx.globalAlpha = 1.0; 139 ctx.lineWidth = 1; 140 } 141 142 static drawArcLine( 143 ctx: CanvasRenderingContext2D, 144 data: CpuFreqLimitsStruct, 145 yStartHeight: number, 146 drawHeight: number 147 ): void { 148 if (data.frame) { 149 let width = data.frame.width || 0; 150 ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - yStartHeight, width, drawHeight); 151 ctx.globalAlpha = this.maxAlpha; 152 ctx.beginPath(); 153 ctx.arc(data.frame.x, data.frame.y + data.frame.height - yStartHeight, 3, 0, 2 * Math.PI, true); 154 ctx.fill(); 155 ctx.stroke(); 156 ctx.beginPath(); 157 ctx.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - yStartHeight); 158 ctx.lineWidth = 3; 159 ctx.lineTo(data.frame.x + width, data.frame.y + data.frame.height - yStartHeight); 160 ctx.stroke(); 161 } 162 } 163 164 static setFreqLimitFrame( 165 freqLimitNode: CpuFreqLimitsStruct, 166 padding: number, 167 startNS: number, 168 endNS: number, 169 totalNS: number, 170 frame: Rect 171 ): void { 172 let x1: number; 173 let x2: number; 174 if ((freqLimitNode.startNs || 0) < startNS) { 175 x1 = 0; 176 } else { 177 x1 = ns2x(freqLimitNode.startNs || 0, startNS, endNS, totalNS, frame); 178 } 179 if ((freqLimitNode.startNs || 0) + (freqLimitNode.dur || 0) > endNS) { 180 x2 = frame.width; 181 } else { 182 x2 = ns2x((freqLimitNode.startNs || 0) + (freqLimitNode.dur || 0), startNS, endNS, totalNS, frame); 183 } 184 let cpuFreqLimitsGetV: number = x2 - x1 <= 1 ? 1 : x2 - x1; 185 if (!freqLimitNode.frame) { 186 freqLimitNode.frame = new Rect(0, 0, 0, 0); 187 } 188 freqLimitNode.frame.x = Math.floor(x1); 189 freqLimitNode.frame.y = frame.y + padding; 190 freqLimitNode.frame.width = Math.ceil(cpuFreqLimitsGetV); 191 freqLimitNode.frame.height = Math.floor(frame.height - padding * 2); 192 } 193} 194