1fb726d48Sopenharmony_ci/* 2fb726d48Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd. 3fb726d48Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fb726d48Sopenharmony_ci * you may not use this file except in compliance with the License. 5fb726d48Sopenharmony_ci * You may obtain a copy of the License at 6fb726d48Sopenharmony_ci * 7fb726d48Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fb726d48Sopenharmony_ci * 9fb726d48Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fb726d48Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fb726d48Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fb726d48Sopenharmony_ci * See the License for the specific language governing permissions and 13fb726d48Sopenharmony_ci * limitations under the License. 14fb726d48Sopenharmony_ci */ 15fb726d48Sopenharmony_ci 16fb726d48Sopenharmony_ciimport { SpApplication } from '../SpApplication'; 17fb726d48Sopenharmony_ciimport { Rect } from '../component/trace/timer-shaft/Rect'; 18fb726d48Sopenharmony_ciimport { warn } from '../../log/Log'; 19fb726d48Sopenharmony_ciimport { BaseStruct, drawString } from '../database/ui-worker/ProcedureWorkerCommon'; 20fb726d48Sopenharmony_ci 21fb726d48Sopenharmony_ciconst padding: number = 1; 22fb726d48Sopenharmony_ciconst rectHeight = 20; 23fb726d48Sopenharmony_ciconst lightBlue = { 24fb726d48Sopenharmony_ci r: 82, 25fb726d48Sopenharmony_ci g: 145, 26fb726d48Sopenharmony_ci b: 255, 27fb726d48Sopenharmony_ci a: 0.9, 28fb726d48Sopenharmony_ci}; 29fb726d48Sopenharmony_ciconst lightGreen = { 30fb726d48Sopenharmony_ci r: 132, 31fb726d48Sopenharmony_ci g: 200, 32fb726d48Sopenharmony_ci b: 112, 33fb726d48Sopenharmony_ci a: 0.9, 34fb726d48Sopenharmony_ci}; 35fb726d48Sopenharmony_ci 36fb726d48Sopenharmony_ciexport class ChartStruct extends BaseStruct { 37fb726d48Sopenharmony_ci static hoverFuncStruct: ChartStruct | undefined; 38fb726d48Sopenharmony_ci static selectFuncStruct: ChartStruct | undefined; 39fb726d48Sopenharmony_ci static lastSelectFuncStruct: ChartStruct | undefined; 40fb726d48Sopenharmony_ci isDraw = false; // 是否绘制,太小的不绘制 41fb726d48Sopenharmony_ci depth: number = 0; 42fb726d48Sopenharmony_ci symbol: string = ''; 43fb726d48Sopenharmony_ci lib: string = ''; 44fb726d48Sopenharmony_ci 45fb726d48Sopenharmony_ci id?: string; 46fb726d48Sopenharmony_ci eventType?: string; 47fb726d48Sopenharmony_ci parentId?: string; 48fb726d48Sopenharmony_ci self?: string; // only perf 49fb726d48Sopenharmony_ci eventPercent?: string; // only perf 50fb726d48Sopenharmony_ci title?: string; 51fb726d48Sopenharmony_ci 52fb726d48Sopenharmony_ci size: number = 0; // 实际size 53fb726d48Sopenharmony_ci count: number = 0; // 实际count 54fb726d48Sopenharmony_ci eventCount: number = 0; 55fb726d48Sopenharmony_ci dur: number = 0; // 实际dur 56fb726d48Sopenharmony_ci //搜索后会根据搜索匹配的函数的值赋值给parent 57fb726d48Sopenharmony_ci searchSize: number = 0; // 58fb726d48Sopenharmony_ci searchCount: number = 0; 59fb726d48Sopenharmony_ci searchDur: number = 0; 60fb726d48Sopenharmony_ci searchEventCount: number = 0; 61fb726d48Sopenharmony_ci //点击绘制的size在搜索的基础上,赋值给parent 62fb726d48Sopenharmony_ci drawSize: number = 0; 63fb726d48Sopenharmony_ci drawCount: number = 0; 64fb726d48Sopenharmony_ci drawDur: number = 0; 65fb726d48Sopenharmony_ci drawEventCount: number = 0; 66fb726d48Sopenharmony_ci 67fb726d48Sopenharmony_ci parent: ChartStruct | undefined; 68fb726d48Sopenharmony_ci children: Array<ChartStruct> = []; 69fb726d48Sopenharmony_ci percent: number = 0; // 0 - 1 该node所占整体的百分比 70fb726d48Sopenharmony_ci addr: string = ''; 71fb726d48Sopenharmony_ci isSearch: boolean = false; 72fb726d48Sopenharmony_ci isChartSelect: boolean = false; // 是否为点选的调用链 73fb726d48Sopenharmony_ci isChartSelectParent: boolean = false; // 用来显示灰色 74fb726d48Sopenharmony_ci tsArray: Array<number> = []; 75fb726d48Sopenharmony_ci countArray: Array<number> = []; 76fb726d48Sopenharmony_ci durArray: Array<number> = []; 77fb726d48Sopenharmony_ci isThread: boolean = false; 78fb726d48Sopenharmony_ci isProcess: boolean = false; 79fb726d48Sopenharmony_ci isJsStack: boolean = false; 80fb726d48Sopenharmony_ci} 81fb726d48Sopenharmony_ci 82fb726d48Sopenharmony_ciexport enum ChartMode { 83fb726d48Sopenharmony_ci Byte, // Native Memory 84fb726d48Sopenharmony_ci Count, // Perf 85fb726d48Sopenharmony_ci Duration, // eBpf 86fb726d48Sopenharmony_ci EventCount, //cycles 87fb726d48Sopenharmony_ci} 88fb726d48Sopenharmony_ci 89fb726d48Sopenharmony_ciexport function setFuncFrame(node: ChartStruct, canvasFrame: Rect, total: number, mode: ChartMode): void { 90fb726d48Sopenharmony_ci if (!node.frame) { 91fb726d48Sopenharmony_ci node.frame = new Rect(0, 0, 0, 0); 92fb726d48Sopenharmony_ci } 93fb726d48Sopenharmony_ci // filter depth is 0 94fb726d48Sopenharmony_ci if (node.parent) { 95fb726d48Sopenharmony_ci let idx = node.parent.children.indexOf(node); 96fb726d48Sopenharmony_ci if (idx === 0) { 97fb726d48Sopenharmony_ci node.frame!.x = node.parent.frame!.x; 98fb726d48Sopenharmony_ci } else { 99fb726d48Sopenharmony_ci // set x by left frame. left frame is parent.children[idx - 1] 100fb726d48Sopenharmony_ci node.frame.x = node.parent.children[idx - 1].frame!.x + node.parent.children[idx - 1].frame!.width; 101fb726d48Sopenharmony_ci } 102fb726d48Sopenharmony_ci if (node.parent?.isChartSelect && !node.isChartSelect) { 103fb726d48Sopenharmony_ci node.frame!.width = 0; 104fb726d48Sopenharmony_ci } else { 105fb726d48Sopenharmony_ci switch (mode) { 106fb726d48Sopenharmony_ci case ChartMode.Byte: 107fb726d48Sopenharmony_ci node.frame!.width = Math.floor(((node.drawSize || node.size) / total) * canvasFrame.width); 108fb726d48Sopenharmony_ci break; 109fb726d48Sopenharmony_ci case ChartMode.Count: 110fb726d48Sopenharmony_ci node.frame!.width = Math.floor(((node.drawCount || node.count) / total) * canvasFrame.width); 111fb726d48Sopenharmony_ci break; 112fb726d48Sopenharmony_ci case ChartMode.Duration: 113fb726d48Sopenharmony_ci node.frame!.width = Math.floor(((node.drawDur || node.dur) / total) * canvasFrame.width); 114fb726d48Sopenharmony_ci break; 115fb726d48Sopenharmony_ci case ChartMode.EventCount: 116fb726d48Sopenharmony_ci node.frame!.width = Math.floor(((node.drawEventCount || node.eventCount) / total) * canvasFrame.width); 117fb726d48Sopenharmony_ci break; 118fb726d48Sopenharmony_ci default: 119fb726d48Sopenharmony_ci warn('not match ChartMode'); 120fb726d48Sopenharmony_ci } 121fb726d48Sopenharmony_ci } 122fb726d48Sopenharmony_ci 123fb726d48Sopenharmony_ci node.frame!.y = node.parent.frame!.y + rectHeight; 124fb726d48Sopenharmony_ci node.frame!.height = rectHeight; 125fb726d48Sopenharmony_ci } 126fb726d48Sopenharmony_ci} 127fb726d48Sopenharmony_ci 128fb726d48Sopenharmony_ci/** 129fb726d48Sopenharmony_ci * draw rect 130fb726d48Sopenharmony_ci * @param canvasCtx CanvasRenderingContext2D 131fb726d48Sopenharmony_ci * @param node rect which is need draw 132fb726d48Sopenharmony_ci * @param percent function size or count / total size or count 133fb726d48Sopenharmony_ci */ 134fb726d48Sopenharmony_ciexport function draw(canvasCtx: CanvasRenderingContext2D, node: ChartStruct): void { 135fb726d48Sopenharmony_ci let spApplication = <SpApplication>document.getElementsByTagName('sp-application')[0]; 136fb726d48Sopenharmony_ci if (!node.frame) { 137fb726d48Sopenharmony_ci return; 138fb726d48Sopenharmony_ci } 139fb726d48Sopenharmony_ci //主体 140fb726d48Sopenharmony_ci const drawHeight = rectHeight - padding * 2; //绘制方块上下留一个像素 141fb726d48Sopenharmony_ci if (node.depth === 0 || (node.isChartSelectParent && node !== ChartStruct.selectFuncStruct)) { 142fb726d48Sopenharmony_ci canvasCtx.fillStyle = `rgba(${lightBlue.g}, ${lightBlue.g}, ${lightBlue.g}, ${lightBlue.a})`; 143fb726d48Sopenharmony_ci } else { 144fb726d48Sopenharmony_ci if (node.isSearch) { 145fb726d48Sopenharmony_ci canvasCtx.fillStyle = `rgba(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b}, ${lightBlue.a})`; 146fb726d48Sopenharmony_ci } else { 147fb726d48Sopenharmony_ci if (node.isJsStack) { 148fb726d48Sopenharmony_ci canvasCtx.fillStyle = `rgba(${lightGreen.r}, ${lightGreen.g}, ${lightGreen.b}, ${lightGreen.a})`; 149fb726d48Sopenharmony_ci } else { 150fb726d48Sopenharmony_ci canvasCtx.fillStyle = getHeatColor(node.percent); 151fb726d48Sopenharmony_ci } 152fb726d48Sopenharmony_ci } 153fb726d48Sopenharmony_ci } 154fb726d48Sopenharmony_ci canvasCtx.fillRect(node.frame.x, node.frame.y, node.frame.width, drawHeight); 155fb726d48Sopenharmony_ci //边框 156fb726d48Sopenharmony_ci canvasCtx.lineWidth = 0.4; 157fb726d48Sopenharmony_ci if (isHover(node)) { 158fb726d48Sopenharmony_ci if (spApplication.dark) { 159fb726d48Sopenharmony_ci canvasCtx.strokeStyle = '#fff'; 160fb726d48Sopenharmony_ci } else { 161fb726d48Sopenharmony_ci canvasCtx.strokeStyle = '#000'; 162fb726d48Sopenharmony_ci } 163fb726d48Sopenharmony_ci } else { 164fb726d48Sopenharmony_ci if (spApplication.dark) { 165fb726d48Sopenharmony_ci canvasCtx.strokeStyle = '#000'; 166fb726d48Sopenharmony_ci } else { 167fb726d48Sopenharmony_ci canvasCtx.strokeStyle = '#fff'; 168fb726d48Sopenharmony_ci } 169fb726d48Sopenharmony_ci } 170fb726d48Sopenharmony_ci canvasCtx.strokeRect(node.frame.x, node.frame.y, node.frame.width - canvasCtx.lineWidth, drawHeight); 171fb726d48Sopenharmony_ci //文字 172fb726d48Sopenharmony_ci if (node.frame.width > 10) { 173fb726d48Sopenharmony_ci if (node.percent > 0.6 || node.isSearch) { 174fb726d48Sopenharmony_ci canvasCtx.fillStyle = '#fff'; 175fb726d48Sopenharmony_ci } else { 176fb726d48Sopenharmony_ci canvasCtx.fillStyle = '#000'; 177fb726d48Sopenharmony_ci } 178fb726d48Sopenharmony_ci drawString(canvasCtx, splitSymbol(node), 5, node.frame, node); 179fb726d48Sopenharmony_ci } 180fb726d48Sopenharmony_ci node.isDraw = true; 181fb726d48Sopenharmony_ci} 182fb726d48Sopenharmony_ci 183fb726d48Sopenharmony_cifunction splitSymbol(node: ChartStruct): string { 184fb726d48Sopenharmony_ci if (node.depth === 0 || node.isProcess || node.isThread) { 185fb726d48Sopenharmony_ci return node.symbol; 186fb726d48Sopenharmony_ci } 187fb726d48Sopenharmony_ci return node.symbol.split(' (')[0]; 188fb726d48Sopenharmony_ci} 189fb726d48Sopenharmony_ci 190fb726d48Sopenharmony_ci/** 191fb726d48Sopenharmony_ci * 火焰图颜色计算,根据每个node占总大小的百分比调整 192fb726d48Sopenharmony_ci * @param widthPercentage 百分比 193fb726d48Sopenharmony_ci * @returns rbg 194fb726d48Sopenharmony_ci */ 195fb726d48Sopenharmony_cifunction getHeatColor(widthPercentage: number): string { 196fb726d48Sopenharmony_ci return `rgba( 197fb726d48Sopenharmony_ci ${Math.floor(245 + 10 * (1 - widthPercentage))}, 198fb726d48Sopenharmony_ci ${Math.floor(110 + 105 * (1 - widthPercentage))}, 199fb726d48Sopenharmony_ci ${100}, 200fb726d48Sopenharmony_ci 0.9)`; 201fb726d48Sopenharmony_ci} 202fb726d48Sopenharmony_ci 203fb726d48Sopenharmony_cifunction isHover(data: ChartStruct): boolean { 204fb726d48Sopenharmony_ci return ChartStruct.hoverFuncStruct === data; 205fb726d48Sopenharmony_ci} 206