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 { TraceRow } from '../../component/trace/base/TraceRow.js'; 18import { 19 BaseStruct, 20 isFrameContainPoint, 21 ns2x, 22 Render, 23 RequestMessage, 24 drawString, 25} from './ProcedureWorkerCommon.js'; 26 27export class SoRender extends Render { 28 renderMainThread( 29 req: { 30 useCache: boolean; 31 context: CanvasRenderingContext2D; 32 type: string; 33 }, 34 row: TraceRow<SoStruct> 35 ): void { 36 let soList = row.dataList; 37 let soFilter = row.dataListCache; 38 soDataFilter( 39 soList, 40 soFilter, 41 TraceRow.range!.startNS, 42 TraceRow.range!.endNS, 43 TraceRow.range!.totalNS, 44 row.frame, 45 req.useCache || !TraceRow.range!.refresh 46 ); 47 req.context.beginPath(); 48 let soFind = false; 49 for (let so of soFilter) { 50 SoStruct.draw(req.context, so); 51 if (row.isHover) { 52 if (so.dur === 0 || so.dur === null || so.dur === undefined) { 53 if ( 54 so.frame && 55 row.hoverX >= so.frame.x - 5 && 56 row.hoverX <= so.frame.x + 5 && 57 row.hoverY >= so.frame.y && 58 row.hoverY <= so.frame.y + so.frame.height 59 ) { 60 SoStruct.hoverSoStruct = so; 61 soFind = true; 62 } 63 } else { 64 if (so.frame && isFrameContainPoint(so.frame, row.hoverX, row.hoverY)) { 65 SoStruct.hoverSoStruct = so; 66 soFind = true; 67 } 68 } 69 } 70 } 71 if (!soFind && row.isHover) SoStruct.hoverSoStruct = undefined; 72 req.context.closePath(); 73 } 74 75 render(req: RequestMessage, list: Array<any>, filter: Array<any>): void {} 76} 77 78export function soDataFilter( 79 soList: Array<SoStruct>, 80 soFilter: Array<SoStruct>, 81 startNS: number, 82 endNS: number, 83 totalNS: number, 84 frame: any, 85 use: boolean 86): void { 87 if (use && soFilter.length > 0) { 88 for (let i = 0, len = soFilter.length ; i < len ; i++) { 89 if ((soFilter[i].startTs || 0) + (soFilter[i].dur || 0) >= startNS && (soFilter[i].startTs || 0) <= endNS) { 90 SoStruct.setSoFrame(soFilter[i], 0, startNS, endNS, totalNS, frame); 91 } else { 92 soFilter[i].frame = undefined; 93 } 94 } 95 return; 96 } 97 soFilter.length = 0; 98 if (soList) { 99 let groups = soList 100 .filter((it) => (it.startTs ?? 0) + (it.dur ?? 0) >= startNS && (it.startTs ?? 0) <= endNS) 101 .map((it) => { 102 SoStruct.setSoFrame(it, 0, startNS, endNS, totalNS, frame); 103 return it; 104 }) 105 .reduce((pre: any, current, index, arr) => { 106 if (current.frame) { 107 (pre[`${ current.frame.x }-${ current.depth }`] = pre[`${ current.frame.x }-${ current.depth }`] || []).push(current); 108 } 109 return pre; 110 }, {}); 111 Reflect.ownKeys(groups).map((kv) => { 112 let arr = groups[kv].sort((a: any, b: any) => b.dur - a.dur); 113 soFilter.push(arr[0]); 114 }); 115 } 116} 117 118export class SoStruct extends BaseStruct { 119 static hoverSoStruct: SoStruct | undefined; 120 static selectSoStruct: SoStruct | undefined; 121 textMetricsWidth: number | undefined; 122 depth: number | undefined; 123 dur: number | undefined; 124 soName: string | undefined; 125 process: string | undefined; 126 startTs: number | undefined; 127 tid: number | undefined; 128 pid: number | undefined; 129 itid: number | undefined; 130 131 static setSoFrame(soNode: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any): void { 132 let x1: number; 133 let x2: number; 134 if ((soNode.startTs || 0) > startNS && (soNode.startTs || 0) < endNS) { 135 x1 = ns2x(soNode.startTs || 0, startNS, endNS, totalNS, frame); 136 } else { 137 x1 = 0; 138 } 139 if ( 140 (soNode.startTs || 0) + (soNode.dur || 0) > startNS && 141 (soNode.startTs || 0) + (soNode.dur || 0) < endNS 142 ) { 143 x2 = ns2x((soNode.startTs || 0) + (soNode.dur || 0), startNS, endNS, totalNS, frame); 144 } else { 145 x2 = frame.width; 146 } 147 if (!soNode.frame) { 148 soNode.frame = {}; 149 } 150 let getV: number = x2 - x1 < 1 ? 1 : x2 - x1; 151 soNode.frame.x = Math.floor(x1); 152 soNode.frame.y = soNode.depth * 20; 153 soNode.frame.width = Math.ceil(getV); 154 soNode.frame.height = 20; 155 } 156 157 static draw(ctx: CanvasRenderingContext2D, data: SoStruct): void { 158 if (data.frame) { 159 if (data.dur === undefined || data.dur === null) { 160 } else { 161 162 ctx.globalAlpha = 1; 163 ctx.fillStyle = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.soName || '', 0, ColorUtils.FUNC_COLOR.length)]; 164 let textColor = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.soName || '', 0, ColorUtils.FUNC_COLOR.length)]; 165 let miniHeight = 20; 166 if (SoStruct.hoverSoStruct && data.soName === SoStruct.hoverSoStruct.soName) { 167 ctx.globalAlpha = 0.7; 168 } 169 ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); 170 if (data.frame.width > 10) { 171 ctx.strokeStyle = '#fff'; 172 ctx.lineWidth = 1; 173 ctx.strokeRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2); 174 ctx.fillStyle = ColorUtils.funcTextColor(textColor); 175 drawString(ctx, `${ data.soName || '' }`, 5, data.frame, data); 176 } 177 if (data === SoStruct.selectSoStruct) { 178 ctx.strokeStyle = '#000'; 179 ctx.lineWidth = 2; 180 ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2); 181 } 182 } 183 } 184 } 185 186} 187 188const padding = 1; 189