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 drawFlagLine, 19 drawLines, 20 drawLoading, 21 drawLoadingFrame, 22 drawSelection, 23 PerfRender, 24 Rect, 25 RequestMessage, 26} from './ProcedureWorkerCommon'; 27import { TraceRow } from '../../component/trace/base/TraceRow'; 28 29export class EBPFRender extends PerfRender { 30 renderMainThread( 31 req: { 32 context: CanvasRenderingContext2D; 33 useCache: boolean; 34 type: string; 35 chartColor: string; 36 }, 37 eBPFtemRow: TraceRow<EBPFChartStruct> 38 ): void { 39 let filter = eBPFtemRow.dataListCache; 40 let groupBy10MS = (TraceRow.range?.scale || 50) > 40_000_000; 41 let isDiskIO: boolean = req.type.includes('disk-io'); 42 eBPFChart( 43 filter, 44 TraceRow.range?.startNS ?? 0, 45 TraceRow.range?.endNS ?? 0, 46 TraceRow.range?.totalNS ?? 0, 47 eBPFtemRow.frame, 48 groupBy10MS, 49 isDiskIO, 50 req.useCache || (TraceRow.range?.refresh ?? false) 51 ); 52 drawLoadingFrame(req.context, filter, eBPFtemRow); 53 drawEBPF(req, filter, groupBy10MS, eBPFtemRow); 54 } 55 56 render(eBPFRequest: RequestMessage, list: Array<any>, filter: Array<any>, dataList2: Array<any>): void {} 57} 58 59function drawEBPF( 60 req: { 61 context: CanvasRenderingContext2D; 62 useCache: boolean; 63 type: string; 64 chartColor: string; 65 }, 66 filter: any[], 67 groupBy10MS: boolean, 68 eBPFtemRow: TraceRow<EBPFChartStruct> 69) { 70 req.context.beginPath(); 71 let find = false; 72 let hoverRect: EBPFChartStruct | undefined = undefined; 73 for (let re of filter) { 74 re.group10Ms = groupBy10MS; 75 if ( 76 eBPFtemRow.isHover && 77 re.frame && 78 eBPFtemRow.hoverX >= re.frame.x && 79 eBPFtemRow.hoverX <= re.frame.x + re.frame.width 80 ) { 81 if (hoverRect == undefined || re.size! > hoverRect.size!) { 82 hoverRect = re; 83 find = true; 84 } 85 } 86 if (re.frame && re.frame!.x > eBPFtemRow.hoverX + 3) { 87 break; 88 } 89 } 90 if (hoverRect) { 91 EBPFChartStruct.hoverEBPFStruct = hoverRect; 92 } 93 94 for (let re of filter) { 95 EBPFChartStruct.draw(req.context, re, req.chartColor); 96 } 97 if (!find && eBPFtemRow.isHover) { 98 EBPFChartStruct.hoverEBPFStruct = undefined; 99 } 100 req.context.closePath(); 101} 102 103export function eBPFChart( 104 eBPFFilters: Array<any>, 105 startNS: number, 106 endNS: number, 107 totalNS: number, 108 frame: Rect, 109 groupBy10MS: boolean, 110 isDiskIO: boolean, 111 use: boolean 112): void { 113 if (use && eBPFFilters.length > 0 && groupBy10MS) { 114 setFrameGroupBy10MS(eBPFFilters, startNS, endNS, frame); 115 return; 116 } 117 if (!groupBy10MS && eBPFFilters[0] && eBPFFilters[0].dur && eBPFFilters[0].endNS) { 118 setFrameByArr(eBPFFilters, startNS, endNS, frame, totalNS, isDiskIO); 119 } 120} 121 122function setFrameGroupBy10MS(eBPFFilters: Array<any>, startNS: number, endNS: number, frame: Rect) { 123 let pns = (endNS - startNS) / frame.width; 124 let y = frame.y; 125 for (let i = 0; i < eBPFFilters.length; i++) { 126 let it = eBPFFilters[i]; 127 if ((it.startNS || 0) + (it.size || 0) > startNS && (it.startNS || 0) < endNS) { 128 if (!it.frame) { 129 it.frame = {}; 130 it.frame.y = y; 131 } 132 it.frame.height = it.height; 133 EBPFChartStruct.setFrame(it, pns, startNS, endNS, frame, true); 134 } else { 135 it.frame = null; 136 } 137 } 138} 139 140function setFrameByArr( 141 eBPFFilters: Array<any>, 142 startNS: number, 143 endNS: number, 144 frame: Rect, 145 totalNS: number, 146 isDiskIO: boolean 147) { 148 let list: Array<any> = []; 149 let pns = (endNS - startNS) / frame.width; 150 let y = frame.y; 151 let filter: any[] = []; 152 for (let index = 0; index < eBPFFilters.length; index++) { 153 if (eBPFFilters[index].endNS > startNS && (eBPFFilters[index].startNS || 0) < endNS && eBPFFilters[index].dur > 0) { 154 if (index >= 1 && eBPFFilters[index - 1].endNS === eBPFFilters[index].startNS) { 155 continue; 156 } else { 157 eBPFFilters[index].size = 0; 158 filter.push(eBPFFilters[index]); 159 } 160 } 161 } 162 eBPFFilters.length = 0; 163 list = isDiskIO 164 ? EBPFChartStruct.computeHeightNoGroupLatency(filter, totalNS) 165 : EBPFChartStruct.computeHeightNoGroup(filter, totalNS); 166 list.map((it) => { 167 if (!it.frame) { 168 it.frame = {}; 169 it.frame.y = y; 170 } 171 EBPFChartStruct.setFrame(it, pns, startNS, endNS, frame, false); 172 eBPFFilters.push(it); 173 }); 174} 175 176export class EBPFChartStruct extends BaseStruct { 177 static hoverEBPFStruct: EBPFChartStruct | undefined; 178 startNS: number | undefined; 179 endNS: number | undefined; 180 dur: number | undefined; 181 size: number | undefined; 182 height: number | undefined; 183 group10Ms: boolean | undefined; 184 185 static draw(ctx: CanvasRenderingContext2D, data: EBPFChartStruct, chartColor: string): void { 186 if (data.frame) { 187 ctx.fillStyle = chartColor; 188 ctx.strokeStyle = chartColor; 189 ctx.fillRect(data.frame.x, 40 - (data.height || 0), data.frame.width, data.height || 0); 190 } 191 } 192 193 static setFrame( 194 eBPFtemNode: any, 195 pns: number, 196 startNS: number, 197 endNS: number, 198 frame: any, 199 groupBy10MS: boolean 200 ): void { 201 if ((eBPFtemNode.startNS || 0) < startNS) { 202 eBPFtemNode.frame.x = 0; 203 } else { 204 eBPFtemNode.frame.x = Math.floor(((eBPFtemNode.startNS || 0) - startNS) / pns); 205 } 206 if ((eBPFtemNode.startNS || 0) + (eBPFtemNode.dur || 0) > endNS) { 207 eBPFtemNode.frame.width = frame.width - eBPFtemNode.frame.x; 208 } else { 209 if (groupBy10MS) { 210 eBPFtemNode.frame.width = Math.ceil(((eBPFtemNode.endNS || 0) - (eBPFtemNode.startNS || 0)) / pns); 211 } else { 212 eBPFtemNode.frame.width = Math.ceil( 213 ((eBPFtemNode.startNS || 0) + (eBPFtemNode.dur || 0) - startNS) / pns - eBPFtemNode.frame.x 214 ); 215 } 216 } 217 if (eBPFtemNode.frame.width < 1) { 218 eBPFtemNode.frame.width = 1; 219 } 220 } 221 222 static computeHeightNoGroup(array: Array<any>, totalNS: number): Array<any> { 223 if (array.length > 0) { 224 let time: Array<{ time: number; type: number }> = []; 225 array.map((item) => { 226 time.push({ time: item.startNS, type: 1 }); 227 time.push({ time: item.endNS || totalNS, type: -1 }); 228 }); 229 time = time.sort((a, b) => a.time - b.time); 230 let arr: Array<any> = []; 231 let first = { 232 startNS: time[0].time ?? 0, 233 dur: 0, 234 size: 1, 235 group10Ms: false, 236 height: 1, 237 }; 238 arr.push(first); 239 let max = 2; 240 for (let i = 1, len = time.length; i < len; i++) { 241 let heap = { 242 startNS: time[i].time, 243 dur: 0, 244 size: 0, 245 group10Ms: false, 246 height: 0, 247 }; 248 arr[i - 1].dur = heap.startNS - arr[i - 1].startNS; 249 if (i == len - 1) { 250 heap.dur = totalNS - heap.startNS; 251 } 252 heap.size = arr[i - 1].size + time[i].type; 253 heap.height = Math.floor((heap.size / 6) * 36); 254 max = max > heap.size ? max : heap.size; 255 arr.push(heap); 256 } 257 arr.map((it) => (it.height = Math.floor((it.size / max) * 36))); 258 return arr; 259 } else { 260 return []; 261 } 262 } 263 264 static computeHeightNoGroupLatency(array: Array<any>, totalNS: number): Array<any> { 265 if (array.length > 0) { 266 let max = 0; 267 let arr: Array<any> = []; 268 for (let io of array) { 269 let ioItem = { 270 startNS: io.startNS, 271 dur: io.endNS > totalNS ? totalNS - io.startNS : io.endNS - io.startNS, 272 size: io.dur, 273 group10Ms: false, 274 height: 0, 275 }; 276 max = max > ioItem.size ? max : ioItem.size; 277 arr.push(ioItem); 278 } 279 arr.map((it) => { 280 let height = Math.floor((it.size / max) * 36); 281 it.height = height < 1 ? 1 : height; 282 }); 283 return arr; 284 } else { 285 return []; 286 } 287 } 288} 289