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 {BaseStruct, ColorUtils, ns2x, Rect} from "./ProcedureWorkerCommon.js"; 17 18export function func(list: Array<any>, res: Array<any>, startNS: number, endNS: number, totalNS: number, frame: any, use: boolean) { 19 if (use && res.length > 0) { 20 for (let i = 0, len = res.length; i < len; i++) { 21 if ((res[i].startTs || 0) + (res[i].dur || 0) >= startNS && (res[i].startTs || 0) <= endNS) { 22 FuncStruct.setFuncFrame(res[i], 0, startNS, endNS, totalNS, frame) 23 }else{ 24 res[i].frame = null; 25 } 26 } 27 return; 28 } 29 res.length = 0; 30 if (list) { 31 let groups = list.filter(it => (it.startTs || 0) + (it.dur || 0) >= startNS && (it.startTs || 0) <= endNS).map(it => { 32 FuncStruct.setFuncFrame(it, 0, startNS, endNS, totalNS, frame) 33 return it; 34 }).reduce((pre, current, index, arr) => { 35 (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current); 36 return pre; 37 }, {}); 38 Reflect.ownKeys(groups).map((kv => { 39 let arr = (groups[kv].sort((a: any, b: any) => b.dur - a.dur)); 40 res.push(arr[0]); 41 })); 42 } 43} 44 45export class FuncStruct extends BaseStruct { 46 static hoverFuncStruct: FuncStruct | undefined; 47 static selectFuncStruct: FuncStruct | undefined; 48 argsetid: number | undefined // 53161 49 depth: number | undefined // 0 50 dur: number | undefined // 570000 51 funName: string | undefined //"binder transaction" 52 id: number | undefined // 92749 53 is_main_thread: number | undefined // 0 54 parent_id: number | undefined // null 55 startTs: number | undefined // 9729867000 56 threadName: string | undefined // "Thread-15" 57 tid: number | undefined // 2785 58 identify: number | undefined 59 track_id: number | undefined // 414 60 61 static setFuncFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { 62 let x1: number, x2: number; 63 if ((node.startTs || 0) > startNS && (node.startTs || 0) < endNS) { 64 x1 = ns2x((node.startTs || 0), startNS, endNS, totalNS, frame); 65 } else { 66 x1 = 0; 67 } 68 if ((node.startTs || 0) + (node.dur || 0) > startNS && (node.startTs || 0) + (node.dur || 0) < endNS) { 69 x2 = ns2x((node.startTs || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); 70 } else { 71 x2 = frame.width; 72 } 73 if (!node.frame) { 74 node.frame = {}; 75 } 76 let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; 77 node.frame.x = Math.floor(x1); 78 node.frame.y = 0; 79 node.frame.width = Math.floor(getV); 80 node.frame.height = 20; 81 } 82 83 static getInt(data: FuncStruct): number { 84 let str = data.funName || ""; 85 let sum = 0; 86 for (let i = 0; i < str.length; i++) { 87 sum += str.charCodeAt(i) 88 } 89 return (sum + (data?.depth || 0)) % ColorUtils.FUNC_COLOR.length; 90 } 91 92 static draw(ctx: CanvasRenderingContext2D, data: FuncStruct, totalNS: number) { 93 if (data.frame) { 94 let isBinder = FuncStruct.isBinder(data); 95 if (data.dur == undefined || data.dur == null || data.dur == 0) { 96 } else { 97 ctx.fillStyle = ColorUtils.FUNC_COLOR[ColorUtils.hashFunc(data.funName || '', 0, ColorUtils.FUNC_COLOR.length)];//data.depth || 98 let miniHeight = 20 99 ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2) 100 if (data.frame.width > 10) { 101 ctx.fillStyle = "#fff" 102 FuncStruct.drawString(ctx, `${data.funName || ''}`, 5, data.frame) 103 } 104 if (FuncStruct.isSelected(data)) { 105 ctx.strokeStyle = "#000" 106 ctx.lineWidth = 2 107 ctx.strokeRect(data.frame.x, data.frame.y + 1, data.frame.width, miniHeight - padding * 2 - 2) 108 } 109 } 110 } 111 } 112 113 static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect): boolean { 114 let textMetrics = ctx.measureText(str); 115 let charWidth = Math.round(textMetrics.width / str.length) 116 if (textMetrics.width < frame.width - textPadding * 2) { 117 let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding) 118 ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2) 119 return true; 120 } 121 if (frame.width - textPadding * 2 > charWidth * 4) { 122 let chatNum = (frame.width - textPadding * 2) / charWidth; 123 let x1 = frame.x + textPadding 124 ctx.fillText(str.substring(0, chatNum - 4) + '...', x1, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2) 125 return true; 126 } 127 return false; 128 } 129 130 static isSelected(data: FuncStruct): boolean { 131 return (FuncStruct.selectFuncStruct != undefined && 132 FuncStruct.selectFuncStruct.startTs == data.startTs && 133 FuncStruct.selectFuncStruct.depth == data.depth) 134 } 135 136 static isBinder(data: FuncStruct): boolean { 137 if (data.funName != null && 138 ( 139 data.funName.toLowerCase().startsWith("binder transaction async") 140 || data.funName.toLowerCase().startsWith("binder async") 141 || data.funName.toLowerCase().startsWith("binder reply") 142 ) 143 ) { 144 return true; 145 } else { 146 return false; 147 } 148 } 149} 150 151const padding = 1; 152 153