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'; 17import { 18 BaseStruct, 19 Render, 20 ns2x, 21 Rect, 22 drawString, 23 isFrameContainPoint, 24 drawLoadingFrame, 25} from './ProcedureWorkerCommon'; 26import { TraceRow } from '../../component/trace/base/TraceRow'; 27import { SpSystemTrace } from '../../component/SpSystemTrace'; 28import { SpUserFileChart } from '../../component/chart/SpUserPluginChart'; 29 30const SAMPLE_STRUCT_HEIGHT = 20; 31const Y_PADDING = 2; 32 33export class SampleRender extends Render { 34 renderMainThread( 35 req: { 36 context: CanvasRenderingContext2D; 37 useCache: boolean; 38 type: string; 39 start_ts: number; 40 uniqueProperty: Array<unknown>; 41 flattenTreeArray: Array<SampleStruct>; 42 }, 43 row: TraceRow<SampleStruct> 44 ): void { 45 let startTs = req.start_ts; 46 let sampleList = row.dataList; 47 let sampleFilter = row.dataListCache; 48 SampleStruct.reqProperty = req; 49 func( 50 sampleList, 51 sampleFilter, 52 TraceRow.range!.startNS, 53 TraceRow.range!.endNS, 54 TraceRow.range!.totalNS, 55 startTs, 56 row.frame, 57 req.useCache || TraceRow.range!.refresh 58 ); 59 drawLoadingFrame(req.context, sampleFilter, row, true); 60 req.context.beginPath(); 61 let find = false; 62 for (let re of sampleFilter) { 63 SampleStruct.draw(req.context, re); 64 if (row.isHover && re.frame && isFrameContainPoint(re.frame, row.hoverX, row.hoverY)) { 65 SampleStruct.hoverSampleStruct = re; 66 find = true; 67 } 68 } 69 if (!find && row.isHover) { 70 SampleStruct.hoverSampleStruct = undefined; 71 } 72 req.context.closePath(); 73 } 74} 75 76export function func( 77 sampleList: Array<SampleStruct>, 78 sampleFilter: Array<SampleStruct>, 79 startNS: number, 80 endNS: number, 81 totalNS: number, 82 startTS: number, 83 frame: Rect, 84 use: boolean 85): void { 86 if (use && sampleFilter.length > 0) { 87 for (let i = 0, len = sampleFilter.length; i < len; i++) { 88 //@ts-ignore 89 if ((sampleFilter[i].end - startTS || 0) >= startNS && (sampleFilter[i].begin - startTS || 0) <= endNS) { 90 SampleStruct.setSampleFrame(sampleFilter[i], 0, startNS, endNS, totalNS, startTS, frame); 91 } else { 92 sampleFilter[i].frame = undefined; 93 } 94 } 95 return; 96 } 97 sampleFilter.length = 0; 98 setSampleFilter(sampleList, sampleFilter, startNS, startTS, endNS, totalNS, frame); 99} 100 101function setSampleFilter( 102 sampleList: Array<SampleStruct>, 103 sampleFilter: Array<SampleStruct>, 104 startNS: number, 105 startTS: number, 106 endNS: number, 107 totalNS: number, 108 frame: Rect 109): void { 110 if (sampleList) { 111 sampleList.forEach((func) => { 112 let funcProperty: Array<unknown> = func.property!; 113 let groups = funcProperty 114 //@ts-ignore 115 .filter((it) => (it.end - startTS ?? 0) >= startNS && (it.begin - startTS ?? 0) <= endNS) 116 .map((it) => { 117 //@ts-ignore 118 SampleStruct.setSampleFrame(it, 0, startNS, endNS, totalNS, startTS, frame); 119 return it; 120 }) 121 .reduce((pre, current) => { 122 //@ts-ignore 123 (pre[`${current.frame.x}-${current.depth}`] = pre[`${current.frame.x}-${current.depth}`] || []).push(current); 124 return pre; 125 }, {}); 126 //@ts-ignore 127 Reflect.ownKeys(groups).map((kv) => { 128 //@ts-ignore 129 let arr = groups[kv].sort((a: unknown, b: unknown) => b.end - b.start - (a.end - a.start)); 130 sampleFilter.push(arr[0]); 131 }); 132 }); 133 } 134} 135 136export function sampleStructOnClick( 137 clickRowType: string, 138 sp: SpSystemTrace, 139 row: TraceRow<SampleStruct> | undefined, 140 entry?: SampleStruct, 141): Promise<unknown> { 142 return new Promise((resolve, reject) => { 143 if (clickRowType === TraceRow.ROW_TYPE_SAMPLE && (SampleStruct.hoverSampleStruct || entry)) { 144 SampleStruct.selectSampleStruct = entry || SampleStruct.hoverSampleStruct; 145 if (row?.rowId === 'userPlugin') { 146 SpUserFileChart.userPluginData!.map((v: unknown) => { 147 //@ts-ignore 148 if (v.func_name === SampleStruct.selectSampleStruct!.name && 149 //@ts-ignore 150 v.begin === SampleStruct.selectSampleStruct?.begin) { 151 sp.traceSheetEL?.displayUserPlugin(v) 152 } 153 }) 154 } else { 155 sp.traceSheetEL?.displaySampleData(SampleStruct.selectSampleStruct!, SampleStruct.reqProperty); 156 sp.timerShaftEL?.modifyFlagList(undefined); 157 } 158 reject(new Error()); 159 } else { 160 resolve(null); 161 } 162 }); 163} 164 165export class SampleStruct extends BaseStruct { 166 static hoverSampleStruct: SampleStruct | undefined; 167 static selectSampleStruct: SampleStruct | undefined; 168 static reqProperty: unknown | undefined; 169 name: string | undefined; 170 detail: string | undefined; 171 property: Array<unknown> | undefined; 172 begin: number | undefined; 173 end: number | undefined; 174 depth: number | undefined; 175 startTs: number | undefined; 176 instructions: number | undefined; 177 cycles: number | undefined; 178 static setSampleFrame( 179 sampleNode: SampleStruct, 180 padding: number, 181 startNS: number, 182 endNS: number, 183 totalNS: number, 184 startTS: number, 185 frame: Rect 186 ): void { 187 let x1: number, x2: number; 188 if ((sampleNode.begin! - startTS || 0) > startNS && (sampleNode.begin! - startTS || 0) < endNS) { 189 x1 = ns2x(sampleNode.begin! - startTS || 0, startNS, endNS, totalNS, frame); 190 } else { 191 x1 = 0; 192 } 193 if ((sampleNode.end! - startTS || 0) > startNS && (sampleNode.end! - startTS || 0) < endNS) { 194 x2 = ns2x(sampleNode.end! - startTS || 0, startNS, endNS, totalNS, frame); 195 } else { 196 x2 = frame.width; 197 } 198 if (!sampleNode.frame) { 199 sampleNode.frame! = new Rect(0, 0, 0, 0); 200 } 201 let getV: number = x2 - x1 < 1 ? 1 : x2 - x1; 202 sampleNode.frame!.x = Math.floor(x1); 203 sampleNode.frame!.y = sampleNode.depth! * SAMPLE_STRUCT_HEIGHT; 204 sampleNode.frame!.width = Math.ceil(getV); 205 sampleNode.frame!.height = SAMPLE_STRUCT_HEIGHT; 206 sampleNode.startTs = startTS; 207 } 208 static draw(ctx: CanvasRenderingContext2D, data: SampleStruct): void { 209 if (data.depth === undefined || data.depth === null) { 210 return; 211 } 212 if (data.frame) { 213 ctx.globalAlpha = 1; 214 ctx.fillStyle = 215 ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.name || '', data.depth, ColorUtils.FUNC_COLOR.length)]; 216 const textColor = 217 ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.name || '', data.depth, ColorUtils.FUNC_COLOR.length)]; 218 if (SampleStruct.hoverSampleStruct && data.name === SampleStruct.hoverSampleStruct.name) { 219 ctx.globalAlpha = 0.7; 220 } 221 ctx.strokeStyle = '#fff'; 222 ctx.lineWidth = 1; 223 ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, SAMPLE_STRUCT_HEIGHT - Y_PADDING); 224 ctx.fillStyle = ColorUtils.funcTextColor(textColor); 225 drawString(ctx, `${data.detail + '(' + data.name + ')' || ''}`, 5, data.frame, data); 226 if (data === SampleStruct.selectSampleStruct) { 227 ctx.strokeStyle = '#000'; 228 ctx.lineWidth = 2; 229 ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, SAMPLE_STRUCT_HEIGHT - Y_PADDING - 2); 230 } 231 } 232 } 233 static equals(d1: SampleStruct, d2: SampleStruct): boolean { 234 return d1 && d2 && d1.name === d2.name && d1.begin === d2.begin; 235 } 236} 237