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 { SpApplication } from '../SpApplication.js'; 17import { BaseStruct } from './BaseStruct.js'; 18import { Rect } from '../component/trace/timer-shaft/Rect.js'; 19import { info, warn } from '../../log/Log.js'; 20import { drawString } from '../database/ui-worker/ProcedureWorkerCommon.js'; 21 22const padding: number = 1; 23const lightBlue = { 24 r: 82, 25 g: 145, 26 b: 255, 27 a: 0.9, 28}; 29 30export class ChartStruct extends BaseStruct { 31 static hoverFuncStruct: ChartStruct | undefined; 32 static selectFuncStruct: ChartStruct | undefined; 33 static lastSelectFuncStruct: ChartStruct | undefined; 34 needShow = false; 35 isDraw = false; 36 depth: number = 0; 37 symbol: string = ''; 38 lib: string = ''; 39 size: number = 0; 40 count: number = 0; 41 dur: number = 0; 42 drawSize: number = 0; 43 drawCount: number = 0; 44 drawDur: number = 0; 45 parent: ChartStruct | undefined; 46 children: Array<ChartStruct> = []; 47 percent: number = 0; 48 addr: string = ''; 49 isSearch: boolean = false; 50 textMetricsWidth: number | undefined; 51} 52 53export enum ChartMode { 54 Byte, // Native Memory 55 Count, // Perf 56 Duration, // eBpf 57} 58 59export function setFuncFrame(node: ChartStruct, canvas_frame: Rect, total: number, mode: ChartMode) { 60 if (!node.frame) { 61 node.frame = new Rect(0, 0, 0, 0); 62 } 63 // filter depth is 0 64 if (node.parent) { 65 let idx = node.parent.children.indexOf(node); 66 if (idx == 0) { 67 node.frame!.x = node.parent.frame!.x; 68 } else { 69 // set x by left frame. left frame is parent.children[idx - 1] 70 node.frame.x = node.parent.children[idx - 1].frame!.x + node.parent.children[idx - 1].frame!.width; 71 } 72 switch (mode) { 73 case ChartMode.Byte: 74 node.frame!.width = Math.floor(((node.drawSize || node.size) / total) * canvas_frame.width); 75 break; 76 case ChartMode.Count: 77 node.frame!.width = Math.floor(((node.drawCount || node.count) / total) * canvas_frame.width); 78 break; 79 case ChartMode.Duration: 80 node.frame!.width = Math.floor(((node.drawDur || node.dur) / total) * canvas_frame.width); 81 break; 82 default: 83 warn('not match ChartMode'); 84 } 85 node.frame!.y = node.parent.frame!.y + 20; 86 node.frame!.height = 20; 87 } 88} 89 90/** 91 * draw rect 92 * @param frameChartBeanCanvasCtx CanvasRenderingContext2D 93 * @param frameChartBeanData rect which is need draw 94 * @param percent function size or count / total size or count 95 */ 96export function draw(frameChartBeanCanvasCtx: CanvasRenderingContext2D, frameChartBeanData: ChartStruct) { 97 let spApplication = <SpApplication>document.getElementsByTagName('sp-application')[0]; 98 if (frameChartBeanData.frame) { 99 // draw rect 100 let frameChartMiniHeight = 20; 101 if (isSelected(frameChartBeanData)) { 102 frameChartBeanCanvasCtx.fillStyle = `rgba(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b}, ${lightBlue.a})`; 103 } else { 104 let color = getHeatColor(frameChartBeanData.percent); 105 frameChartBeanCanvasCtx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, 0.9)`; 106 } 107 frameChartBeanCanvasCtx.fillRect(frameChartBeanData.frame.x, frameChartBeanData.frame.y, frameChartBeanData.frame.width, frameChartMiniHeight - padding * 2); 108 //draw border 109 frameChartBeanCanvasCtx.lineWidth = 0.4; 110 if (isHover(frameChartBeanData)) { 111 if (spApplication.dark) { 112 frameChartBeanCanvasCtx.strokeStyle = '#fff'; 113 } else { 114 frameChartBeanCanvasCtx.strokeStyle = '#000'; 115 } 116 } else { 117 if (spApplication.dark) { 118 frameChartBeanCanvasCtx.strokeStyle = '#000'; 119 } else { 120 frameChartBeanCanvasCtx.strokeStyle = '#fff'; 121 } 122 if (frameChartBeanData.isSearch) { 123 frameChartBeanCanvasCtx.strokeStyle = `rgb(${lightBlue.r}, ${lightBlue.g}, ${lightBlue.b})`; 124 frameChartBeanCanvasCtx.lineWidth = 1; 125 } 126 } 127 frameChartBeanCanvasCtx.strokeRect(frameChartBeanData.frame.x, frameChartBeanData.frame.y, frameChartBeanData.frame.width, frameChartMiniHeight - padding * 2); 128 129 //draw symbol name 130 if (frameChartBeanData.frame.width > 10) { 131 if (frameChartBeanData.percent > 0.6 || isSelected(frameChartBeanData)) { 132 frameChartBeanCanvasCtx.fillStyle = '#fff'; 133 } else { 134 frameChartBeanCanvasCtx.fillStyle = '#000'; 135 } 136 drawString(frameChartBeanCanvasCtx, frameChartBeanData.symbol || '', 5, frameChartBeanData.frame, frameChartBeanData); 137 } 138 frameChartBeanData.isDraw = true; 139 } 140} 141 142/** 143 * get frame chart color by percent 144 * @param widthPercentage proportion of function 145 * @returns rbg 146 */ 147function getHeatColor(widthPercentage: number) { 148 return { 149 r: Math.floor(245 + 10 * (1 - widthPercentage)), 150 g: Math.floor(110 + 105 * (1 - widthPercentage)), 151 b: 100, 152 }; 153} 154 155function isHover(data: ChartStruct): boolean { 156 return ChartStruct.hoverFuncStruct == data; 157} 158 159function isSelected(data: ChartStruct): boolean { 160 return ChartStruct.lastSelectFuncStruct == data; 161} 162