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 drawFlagLine, 20 drawLines, 21 drawSelection, 22 isFrameContainPoint, 23 ns2x, 24 Render, 25 RequestMessage, 26} from './ProcedureWorkerCommon.js'; 27import { TraceRow } from '../../component/trace/base/TraceRow.js'; 28import { CpuAbilityMonitorStruct } from './ProcedureWorkerCpuAbility.js'; 29 30export class SmapsRender extends Render { 31 renderMainThread( 32 req: { 33 context: CanvasRenderingContext2D; 34 useCache: boolean; 35 type: string; 36 rowName: string; 37 maxValue: number; 38 }, 39 row: TraceRow<SmapsStruct> 40 ) { 41 let smapsList = row.dataList; 42 let smapsFilter = row.dataListCache; 43 dataFilterHandler(smapsList, smapsFilter, { 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: req.useCache || !(TraceRow.range?.refresh ?? false), 52 }); 53 req.context.beginPath(); 54 let drawColor = '#0A59F7'; 55 if (req.rowName != undefined) { 56 switch (req.rowName) { 57 case 'dirty': 58 drawColor = '#0A59F7'; 59 break; 60 case 'swapper': 61 drawColor = '#46B1E3'; 62 break; 63 case 'resident_size': 64 drawColor = '#564AF7'; 65 break; 66 } 67 } 68 let find = false; 69 for (let re of smapsFilter) { 70 SmapsStruct.draw(req.context, re, req.maxValue, drawColor, row.isHover); 71 if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 72 SmapsStruct.hoverSmapsStruct = re; 73 find = true; 74 } 75 } 76 if (!find && row.isHover) SmapsStruct.hoverSmapsStruct = undefined; 77 78 req.context.closePath(); 79 } 80 81 render(smapsReq: RequestMessage, list: Array<any>, filter: Array<any>) { 82 if (smapsReq.lazyRefresh) { 83 smaps( 84 list, 85 filter, 86 smapsReq.startNS, 87 smapsReq.endNS, 88 smapsReq.totalNS, 89 smapsReq.frame, 90 smapsReq.useCache || !smapsReq.range.refresh 91 ); 92 } else { 93 if (!smapsReq.useCache) { 94 smaps(list, filter, smapsReq.startNS, smapsReq.endNS, smapsReq.totalNS, smapsReq.frame, false); 95 } 96 } 97 if (smapsReq.canvas) { 98 smapsReq.context.clearRect(0, 0, smapsReq.frame.width, smapsReq.frame.height); 99 smapsReq.context.beginPath(); 100 let maxValue = 0; 101 let maxValueName = ''; 102 if (smapsReq.params.maxValue != undefined || smapsReq.params.maxValueName != undefined) { 103 maxValue = smapsReq.params.maxValue; 104 maxValueName = smapsReq.params.maxValueName; 105 } 106 drawLines(smapsReq.context, smapsReq.xs, smapsReq.frame.height, smapsReq.lineColor); 107 SmapsStruct.hoverSmapsStruct = undefined; 108 if (smapsReq.isHover) { 109 for (let re of filter) { 110 if ( 111 re.frame && 112 smapsReq.hoverX >= re.frame.x && 113 smapsReq.hoverX <= re.frame.x + re.frame.width && 114 smapsReq.hoverY >= re.frame.y && 115 smapsReq.hoverY <= re.frame.y + re.frame.height 116 ) { 117 SmapsStruct.hoverSmapsStruct = re; 118 break; 119 } 120 } 121 } 122 let drawColor = '#0A59F7'; 123 if (smapsReq.params.rowName != undefined) { 124 switch (smapsReq.params.rowName) { 125 case 'dirty': 126 drawColor = '#0A59F7'; 127 break; 128 case 'swapper': 129 drawColor = '#46B1E3'; 130 break; 131 case 'resident_size': 132 drawColor = '#564AF7'; 133 break; 134 } 135 } 136 SmapsStruct.selectSmapsStruct = smapsReq.params.selectSmapsStruct; 137 for (let re of filter) { 138 SmapsStruct.draw(smapsReq.context, re, maxValue, drawColor, true); 139 } 140 drawSelection(smapsReq.context, smapsReq.params); 141 smapsReq.context.closePath(); 142 drawFlagLine( 143 smapsReq.context, 144 smapsReq.flagMoveInfo, 145 smapsReq.flagSelectedInfo, 146 smapsReq.startNS, 147 smapsReq.endNS, 148 smapsReq.totalNS, 149 smapsReq.frame, 150 smapsReq.slicesTime 151 ); 152 } 153 // @ts-ignore 154 self.postMessage({ 155 id: smapsReq.id, 156 type: smapsReq.type, 157 results: smapsReq.canvas ? undefined : filter, 158 hover: SmapsStruct.hoverSmapsStruct, 159 }); 160 } 161} 162 163export function smaps( 164 smapsList: Array<any>, 165 res: Array<any>, 166 startNS: number, 167 endNS: number, 168 totalNS: number, 169 frame: any, 170 use: boolean 171) { 172 if (use && res.length > 0) { 173 for (let i = 0; i < res.length; i++) { 174 let smapsItem = res[i]; 175 if ((smapsItem.startNS || 0) + (smapsItem.dur || 0) > (startNS || 0) && (smapsItem.startNS || 0) < (endNS || 0)) { 176 SmapsStruct.setSmapsFrame(smapsItem, 5, startNS || 0, endNS || 0, totalNS || 0, frame); 177 } else { 178 smapsItem.frame = null; 179 } 180 } 181 return; 182 } 183 res.length = 0; 184 if (smapsList) { 185 for (let smapsIndex = 0; smapsIndex < smapsList.length; smapsIndex++) { 186 let item = smapsList[smapsIndex]; 187 if (smapsIndex === smapsList.length - 1) { 188 item.dur = (endNS || 0) - (item.startNS || 0); 189 } else { 190 item.dur = (smapsList[smapsIndex + 1].startNS || 0) - (item.startNS || 0); 191 } 192 if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { 193 SmapsStruct.setSmapsFrame(smapsList[smapsIndex], 5, startNS || 0, endNS || 0, totalNS || 0, frame); 194 if ( 195 smapsIndex > 0 && 196 (smapsList[smapsIndex - 1].frame?.x || 0) == (smapsList[smapsIndex].frame?.x || 0) && 197 (smapsList[smapsIndex - 1].frame?.width || 0) == (smapsList[smapsIndex].frame?.width || 0) 198 ) { 199 } else { 200 res.push(item); 201 } 202 } 203 } 204 } 205} 206 207export class SmapsStruct extends BaseStruct { 208 static maxValue: number = 0; 209 static maxValueName: string = '0 KB/S'; 210 static hoverSmapsStruct: SmapsStruct | undefined; 211 static selectSmapsStruct: SmapsStruct | undefined; 212 value: number | undefined; 213 startNS: number | undefined; 214 dur: number | undefined; 215 216 static draw( 217 smapsContext: CanvasRenderingContext2D, 218 data: SmapsStruct, 219 maxValue: number, 220 drawColor: string, 221 isHover: boolean 222 ) { 223 if (data.frame) { 224 let width = data.frame.width || 0; 225 smapsContext.fillStyle = drawColor; 226 smapsContext.strokeStyle = drawColor; 227 if (data.startNS === SmapsStruct.hoverSmapsStruct?.startNS && isHover) { 228 smapsContext.lineWidth = 1; 229 let smapsDrawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxValue); 230 smapsContext.fillRect( 231 data.frame.x, 232 data.frame.y + data.frame.height - smapsDrawHeight + 4, 233 width, 234 smapsDrawHeight 235 ); 236 smapsContext.beginPath(); 237 smapsContext.arc(data.frame.x, data.frame.y + data.frame.height - smapsDrawHeight + 4, 3, 0, 2 * Math.PI, true); 238 smapsContext.fill(); 239 smapsContext.globalAlpha = 1.0; 240 smapsContext.stroke(); 241 smapsContext.beginPath(); 242 smapsContext.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - smapsDrawHeight + 4); 243 smapsContext.lineWidth = 3; 244 smapsContext.lineTo(data.frame.x + width, data.frame.y + data.frame.height - smapsDrawHeight + 4); 245 smapsContext.stroke(); 246 } else { 247 smapsContext.lineWidth = 1; 248 let smapsDrawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxValue); 249 smapsContext.fillRect( 250 data.frame.x, 251 data.frame.y + data.frame.height - smapsDrawHeight + 4, 252 width, 253 smapsDrawHeight 254 ); 255 } 256 } 257 smapsContext.globalAlpha = 1.0; 258 smapsContext.lineWidth = 1; 259 } 260 261 static setSmapsFrame(smapsNode: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { 262 let smapsStartPointX: number, smapsEndPointX: number; 263 264 if ((smapsNode.startNS || 0) < startNS) { 265 smapsStartPointX = 0; 266 } else { 267 smapsStartPointX = ns2x(smapsNode.startNS || 0, startNS, endNS, totalNS, frame); 268 } 269 if ((smapsNode.startNS || 0) + (smapsNode.dur || 0) > endNS) { 270 smapsEndPointX = frame.width; 271 } else { 272 smapsEndPointX = ns2x((smapsNode.startNS || 0) + (smapsNode.dur || 0), startNS, endNS, totalNS, frame); 273 } 274 let frameWidth: number = smapsEndPointX - smapsStartPointX <= 1 ? 1 : smapsEndPointX - smapsStartPointX; 275 if (!smapsNode.frame) { 276 smapsNode.frame = {}; 277 } 278 smapsNode.frame.x = Math.floor(smapsStartPointX); 279 smapsNode.frame.y = frame.y + padding; 280 smapsNode.frame.width = Math.ceil(frameWidth); 281 smapsNode.frame.height = Math.floor(frame.height - padding * 2); 282 } 283} 284