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 { ColorUtils } from "../../component/trace/base/ColorUtils.js"; 17import { 18 BaseStruct, 19 drawFlagLine, 20 drawLines, 21 drawLoading, 22 drawSelection, PerfRender, 23 RequestMessage 24} from "./ProcedureWorkerCommon.js"; 25import {HiPerfCpuStruct} from "./ProcedureWorkerHiPerfCPU.js"; 26 27export class HiperfProcessRender extends PerfRender{ 28 render(req: RequestMessage, list: Array<any>, filter: Array<any>, dataList2: Array<any>) { 29 let groupBy10MS = req.scale > 100_000_000; 30 if (req.lazyRefresh) { 31 hiPerfProcess(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, groupBy10MS, req.intervalPerf, req.useCache || !req.range.refresh); 32 } else { 33 if (!req.useCache) { 34 hiPerfProcess(list, filter, req.startNS, req.endNS, req.totalNS, req.frame, groupBy10MS, req.intervalPerf, false); 35 } 36 } 37 if (req.canvas) { 38 req.context.clearRect(0, 0, req.frame.width, req.frame.height); 39 let arr = filter; 40 if (arr.length > 0 && !req.range.refresh && !req.useCache && req.lazyRefresh) { 41 drawLoading(req.context, req.startNS, req.endNS, req.totalNS, req.frame, arr[0].startNS, arr[arr.length - 1].startNS + arr[arr.length - 1].dur) 42 } 43 drawLines(req.context, req.xs, req.frame.height, req.lineColor) 44 req.context.stroke(); 45 req.context.beginPath(); 46 HiPerfProcessStruct.hoverStruct = undefined; 47 req.context.fillStyle = ColorUtils.FUNC_COLOR[0]; 48 req.context.strokeStyle = ColorUtils.FUNC_COLOR[0]; 49 if (req.isHover) { 50 let offset = groupBy10MS ? 0 : 3; 51 for (let re of filter) { 52 if (re.frame && req.hoverX >= re.frame.x - offset && req.hoverX <= re.frame.x + re.frame.width + offset) {//&& req.hoverY >= re.frame.y && req.hoverY <= re.frame.y + re.frame.height 53 HiPerfProcessStruct.hoverStruct = re; 54 break; 55 } 56 } 57 } else { 58 HiPerfProcessStruct.hoverStruct = req.params.hoverStruct; 59 } 60 HiPerfProcessStruct.selectStruct = req.params.selectStruct; 61 let path = new Path2D(); 62 for (let re of filter) { 63 HiPerfProcessStruct.draw(req.context, path, re, groupBy10MS); 64 } 65 groupBy10MS ? req.context.fill(path) : req.context.stroke(path); 66 req.context.closePath(); 67 drawSelection(req.context, req.params); 68 drawFlagLine(req.context, req.flagMoveInfo, req.flagSelectedInfo, req.startNS, req.endNS, req.totalNS, req.frame, req.slicesTime); 69 } 70 // @ts-ignore 71 self.postMessage({ 72 id: req.id, 73 type: req.type, 74 results: req.canvas ? undefined : filter, 75 hover: HiPerfProcessStruct.hoverStruct 76 }); 77 } 78} 79 80export function hiPerfProcess(arr: Array<any>, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any, groupBy10MS: boolean, intervalPerf: number, use: boolean) { 81 if (use && res.length > 0) { 82 let pns = (endNS - startNS) / frame.width; 83 let y = frame.y; 84 for (let i = 0; i < res.length; i++) { 85 let it = res[i]; 86 if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { 87 if (!it.frame) { 88 it.frame = {}; 89 it.frame.y = y; 90 } 91 it.frame.height = it.height; 92 HiPerfProcessStruct.setFrame(it, pns, startNS, endNS, frame); 93 } else { 94 it.frame = null; 95 } 96 } 97 return; 98 } 99 res.length = 0; 100 if (arr) { 101 let list = groupBy10MS ? HiPerfProcessStruct.groupBy10MS(arr, intervalPerf) : arr; 102 let pns = (endNS - startNS) / frame.width; 103 let y = frame.y; 104 for (let i = 0, len = list.length; i < len; i++) { 105 let it = list[i]; 106 if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { 107 if (!list[i].frame) { 108 list[i].frame = {}; 109 list[i].frame.y = y; 110 } 111 list[i].frame.height = it.height; 112 HiPerfProcessStruct.setFrame(list[i], pns, startNS, endNS, frame) 113 if (groupBy10MS) { 114 if (i > 0 && ((list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) 115 && ((list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0)) 116 && ((list[i - 1].frame?.height || 0) == (list[i].frame?.height || 0)) 117 )) { 118 } else { 119 res.push(list[i]) 120 } 121 } else { 122 if (i > 0 && (Math.abs((list[i - 1].frame?.x || 0) - (list[i].frame?.x || 0)) < 4)) { 123 } else { 124 res.push(list[i]) 125 } 126 } 127 128 } 129 } 130 } 131} 132 133export class HiPerfProcessStruct extends BaseStruct { 134 static hoverStruct: HiPerfProcessStruct | undefined; 135 static selectStruct: HiPerfProcessStruct | undefined; 136 id: number | undefined; 137 callchain_id: number | undefined; 138 timestamp: number | undefined; 139 thread_id: number | undefined; 140 event_count: number | undefined; 141 event_type_id: number | undefined; 142 cpu_id: number | undefined; 143 thread_state: string | undefined; 144 //------------------------------------------------------ 145 startNS: number | undefined; 146 endNS: number | undefined; 147 dur: number | undefined; 148 height: number | undefined; 149 cpu: number | undefined; 150 group: number | undefined; 151 152 static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfProcessStruct, groupBy10MS: boolean) { 153 if (data.frame) { 154 if (groupBy10MS) { 155 let width = data.frame.width; 156 path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0) 157 } else { 158 path.moveTo(data.frame.x + 7, 20); 159 HiPerfCpuStruct.drawRoundRectPath(path, data.frame.x - 7, 20 - 7, 14, 14, 3) 160 path.moveTo(data.frame.x, 27); 161 path.lineTo(data.frame.x, 33); 162 } 163 } 164 } 165 166 static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { 167 if ((node.startNS || 0) < startNS) { 168 node.frame.x = 0; 169 } else { 170 node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); 171 } 172 if ((node.startNS || 0) + (node.dur || 0) > endNS) { 173 node.frame.width = frame.width - node.frame.x; 174 } else { 175 node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); 176 } 177 if (node.frame.width < 1) { 178 node.frame.width = 1; 179 } 180 } 181 182 static groupBy10MS(array: Array<any>, intervalPerf: number): Array<any> { 183 let obj = array.map(it => { 184 it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; 185 return it; 186 }).reduce((pre, current) => { 187 (pre[current["timestamp_group"]] = pre[current["timestamp_group"]] || []).push(current); 188 return pre; 189 }, {}); 190 let arr: any[] = []; 191 for (let aKey in obj) { 192 let ns = parseInt(aKey); 193 let height: number = 0; 194 height = Math.floor(obj[aKey].length / (10 / intervalPerf) * 40); 195 arr.push({ 196 startNS: ns, 197 height: height, 198 dur: 1_000_000_0, 199 }) 200 } 201 return arr; 202 } 203} 204