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