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 16export class ChartStruct { 17 depth: number = 0; 18 symbol: string = ''; 19 size: number = 0; 20 count: number = 0; 21 dur:number = 0; 22 parent: ChartStruct | undefined; 23 children: Array<ChartStruct> = []; 24} 25 26export class Msg{ 27 tag:string = ""; 28 index:number = 0; 29 data:Array<any> = []; 30} 31 32export class MerageBean extends ChartStruct{ 33 #parentNode: MerageBean | undefined = undefined 34 #total = 0 35 currentTreeParentNode: MerageBean | undefined = undefined; 36 id: string = ""; 37 parentId: string = ""; 38 symbolName: string = ""; 39 symbol: string = "" 40 libName: string = "" 41 path: string = "" 42 self: string = "0s" 43 weight: string = "" 44 weightPercent: string = "" 45 selfDur: number = 0; 46 dur: number = 0; 47 pid: number = 0; 48 canCharge:boolean = true 49 isStore = 0; 50 isSelected: boolean = false; 51 searchShow: boolean = true; 52 children: MerageBean[] = [] 53 initChildren: MerageBean[] = [] 54 type:number = 0 55 set parentNode(data: MerageBean | undefined) { 56 this.currentTreeParentNode = data; 57 this.#parentNode = data; 58 } 59 60 get parentNode() { 61 return this.#parentNode 62 } 63 64 set total(data: number) { 65 this.#total = data; 66 this.weight = `${getProbablyTime(this.dur)}` 67 this.weightPercent = `${(this.dur / data * 100).toFixed(1)}%` 68 } 69 70 get total() { 71 return this.#total; 72 } 73} 74 75class MerageBeanDataSplit{ 76 systmeRuleName = "/system/" 77 numRuleName = "/max/min/" 78 79 //所有的操作都是针对整个树结构的 不区分特定的数据 80 splitTree(splitMapData:any,data: MerageBean[], name: string, isCharge: boolean, isSymbol: boolean,currentTreeList:any[],searchValue:string) { 81 data.forEach((process) => { 82 process.children = [] 83 if (isCharge) { 84 this.recursionChargeInitTree(splitMapData,process, name, isSymbol) 85 } else { 86 this.recursionPruneInitTree(splitMapData,process, name, isSymbol) 87 } 88 }) 89 this.resetAllNode(data,currentTreeList,searchValue) 90 } 91 92 recursionChargeInitTree(splitMapData:any,node: MerageBean, symbolName: string, isSymbol: boolean) { 93 if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { 94 (splitMapData[symbolName] = splitMapData[symbolName] || []).push(node) 95 node.isStore++; 96 } 97 if (node.initChildren.length > 0) { 98 node.initChildren.forEach((child) => { 99 this.recursionChargeInitTree(splitMapData,child, symbolName, isSymbol) 100 }) 101 } 102 } 103 104 //symbol lib charge 105 recursionChargeTree(node: MerageBean, symbolName: string, isSymbol: boolean) { 106 if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { 107 node.currentTreeParentNode && node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1, ...node.children); 108 node.children.forEach((child) => { 109 child.currentTreeParentNode = node.currentTreeParentNode 110 }) 111 } 112 if (node.children.length > 0) { 113 node.children.forEach((child) => { 114 this.recursionChargeTree(child, symbolName, isSymbol) 115 }) 116 } 117 } 118 119 recursionPruneInitTree(splitMapData:any,node: MerageBean, symbolName: string, isSymbol: boolean) { 120 if (isSymbol && node.symbolName == symbolName || (!isSymbol && node.libName == symbolName)) { 121 (splitMapData[symbolName] = splitMapData[symbolName] || []).push(node) 122 node.isStore++; 123 this.pruneChildren(splitMapData,node, symbolName) 124 } else if (node.initChildren.length > 0) { 125 node.initChildren.forEach((child) => { 126 this.recursionPruneInitTree(splitMapData,child, symbolName, isSymbol) 127 }) 128 } 129 } 130 131 //symbol lib prune 132 recursionPruneTree(node: MerageBean, symbolName: string, isSymbol: boolean) { 133 if (isSymbol && node.symbolName == symbolName || (!isSymbol && node.libName == symbolName)) { 134 node.currentTreeParentNode && node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1); 135 } else { 136 node.children.forEach((child) => { 137 this.recursionPruneTree(child, symbolName, isSymbol) 138 }) 139 } 140 } 141 142 recursionChargeByRule(splitMapData:any,node: MerageBean, ruleName: string, rule: (node: MerageBean) => boolean) { 143 if (node.initChildren.length > 0) { 144 node.initChildren.forEach((child) => { 145 if (rule(child)) { 146 (splitMapData[ruleName] = splitMapData[ruleName] || []).push(child) 147 child.isStore++; 148 } 149 this.recursionChargeByRule(splitMapData,child, ruleName, rule) 150 }) 151 } 152 } 153 154 pruneChildren(splitMapData:any,node: MerageBean, symbolName: string) { 155 if (node.initChildren.length > 0) { 156 node.initChildren.forEach((child) => { 157 child.isStore++; 158 (splitMapData[symbolName] = splitMapData[symbolName] || []).push(child); 159 this.pruneChildren(splitMapData,child, symbolName) 160 }) 161 } 162 } 163 164 hideSystemLibrary(allProcess:MerageBean[],splitMapData:any){ 165 allProcess.forEach((item)=>{ 166 item.children = [] 167 this.recursionChargeByRule(splitMapData,item,this.systmeRuleName,(node)=>{ 168 return node.path.startsWith(this.systmeRuleName) 169 }) 170 }) 171 } 172 173 hideNumMaxAndMin(allProcess:MerageBean[],splitMapData:any,startNum:number,endNum:string){ 174 let max = endNum == "∞"?Number.POSITIVE_INFINITY :parseInt(endNum) 175 allProcess.forEach((item)=>{ 176 item.children = [] 177 this.recursionChargeByRule(splitMapData,item,this.numRuleName,(node)=>{ 178 return node.count < startNum || node.count > max 179 }) 180 }) 181 } 182 183 resotreAllNode(splitMapData:any,symbols: string[]) { 184 symbols.forEach((symbol) => { 185 let list = splitMapData[symbol]; 186 if (list != undefined) { 187 list.forEach((item: any) => { 188 item.isStore-- 189 }) 190 } 191 }) 192 } 193 194 resetAllNode(data: MerageBean[],currentTreeList:any[],searchValue:string) { 195 this.clearSearchNode(currentTreeList) 196 data.forEach((process) => { 197 process.searchShow = true 198 }) 199 this.resetNewAllNode(data,currentTreeList) 200 if (searchValue != "") { 201 this.findSearchNode(data, searchValue, false) 202 this.resetNewAllNode(data,currentTreeList) 203 } 204 } 205 206 resetNewAllNode(data: MerageBean[],currentTreeList:any[]) { 207 data.forEach((process) => { 208 process.children = [] 209 }) 210 let values = currentTreeList.map((item: any) => { 211 item.children = [] 212 return item 213 }) 214 values.forEach((item: any) => { 215 if (item.parentNode != undefined) { 216 if (item.isStore == 0 && item.searchShow) { 217 let parentNode = item.parentNode 218 while (parentNode != undefined && !(parentNode.isStore == 0 && parentNode.searchShow)) { 219 parentNode = parentNode.parentNode 220 } 221 if (parentNode) { 222 item.currentTreeParentNode = parentNode 223 parentNode.children.push(item) 224 } 225 } 226 } 227 }) 228 } 229 230 findSearchNode(data: MerageBean[], search: string, parentSearch: boolean) { 231 data.forEach((node) => { 232 if ((node.symbolName!=undefined&&node.symbolName.includes(search)) || parentSearch) { 233 node.searchShow = true 234 let parentNode = node.currentTreeParentNode 235 while (parentNode != undefined && !parentNode.searchShow) { 236 parentNode.searchShow = true 237 parentNode = parentNode.currentTreeParentNode 238 } 239 } else { 240 node.searchShow = false 241 } 242 if (node.children.length > 0) { 243 this.findSearchNode(node.children, search, node.searchShow) 244 } 245 }) 246 } 247 248 clearSearchNode(currentTreeList:any[]) { 249 currentTreeList.forEach((node) => { 250 node.searchShow = true 251 }) 252 } 253 254 splitAllProcess(allProcess:any[],splitMapData:any,list:any[]){ 255 list.forEach((item:any)=>{ 256 allProcess.forEach((process)=>{ 257 if(item.select == "0"){ 258 this.recursionChargeInitTree(splitMapData,process, item.name, item.type == "symbol") 259 }else { 260 this.recursionPruneInitTree(splitMapData,process, item.name, item.type == "symbol") 261 } 262 }) 263 if(!item.checked){ 264 this.resotreAllNode(splitMapData,[item.name]) 265 } 266 }) 267 } 268} 269 270export let merageBeanDataSplit = new MerageBeanDataSplit() 271 272export abstract class LogicHandler { 273 abstract handle(data:any):void 274} 275 276let dec = new TextDecoder(); 277 278export let setFileName = (path: string)=> { 279 let fileName = "" 280 if (path) { 281 let number = path.lastIndexOf("/"); 282 if (number > 0) { 283 fileName = path.substring(number + 1) 284 return fileName 285 } 286 } 287 return path 288} 289 290let pagination = (page:number, pageSize:number, source:Array<any>)=>{ 291 let offset = (page - 1) * pageSize; 292 return (offset + pageSize >= source.length) ? source.slice(offset, source.length) : source.slice(offset, offset + pageSize); 293} 294 295const PAGE_SIZE:number = 50_0000; 296export let postMessage = (id: any, action: string, results: Array<any>) => { 297 if(results.length > PAGE_SIZE){ 298 let pageCount = Math.ceil( results.length / PAGE_SIZE) 299 for (let i = 0; i < pageCount; i++) { 300 let tag = "start"; 301 if(i== 0){ 302 tag = "start" 303 }else if(i == pageCount - 1){ 304 tag = "end" 305 }else{ 306 tag = "sending" 307 } 308 let msg = new Msg(); 309 msg.tag = tag; 310 msg.index = i; 311 msg.data = pagination(i,PAGE_SIZE,results); 312 self.postMessage({id: id, action: action, isSending:msg.tag != "end",results: msg}) 313 } 314 }else{ 315 let msg = new Msg(); 316 msg.tag = "end"; 317 msg.index = 0; 318 msg.data = results; 319 self.postMessage({id: id, action: action,results: msg}) 320 } 321} 322 323export let convertJSON = (arr:ArrayBuffer)=>{ 324 if(arr instanceof ArrayBuffer) { 325 let str = dec.decode(arr); 326 let jsonArray = []; 327 str = str.substring(str.indexOf("\n") + 1); 328 if (!str) { 329 } else { 330 let parse = JSON.parse(str); 331 let columns = parse.columns; 332 let values = parse.values; 333 for (let i = 0; i < values.length; i++) { 334 let obj: any = {} 335 for (let j = 0; j < columns.length; j++) { 336 obj[columns[j]] = values[i][j] 337 } 338 jsonArray.push(obj) 339 } 340 } 341 return jsonArray; 342 } else { 343 return arr; 344 } 345} 346 347export let getByteWithUnit = (bytes: number) : string => { 348 if (bytes < 0) { 349 return "-" + getByteWithUnit(Math.abs(bytes)) 350 } 351 let currentBytes = bytes 352 let kb1 = 1 << 10; 353 let mb1 = 1 << 10 << 10; 354 let gb1 = 1 << 10 << 10 << 10; // 1 gb 355 let res = "" 356 if (currentBytes > gb1) { 357 res += (currentBytes / gb1).toFixed(2) + " Gb"; 358 } else if (currentBytes > mb1) { 359 res += (currentBytes / mb1).toFixed(2) + " Mb"; 360 } else if (currentBytes > kb1) { 361 res += (currentBytes / kb1).toFixed(2) + " Kb"; 362 } else { 363 res += Math.round(currentBytes) + " byte"; 364 } 365 return res 366} 367 368export let getTimeString = (ns: number): string =>{ 369 let currentNs = ns 370 let hour1 = 3600_000_000_000 371 let minute1 = 60_000_000_000 372 let second1 = 1_000_000_000; 373 let millisecond1 = 1_000_000; 374 let microsecond1 = 1_000; 375 let res = ""; 376 if (currentNs >= hour1) { 377 res += Math.floor(currentNs / hour1) + "h "; 378 currentNs = currentNs - Math.floor(currentNs / hour1) * hour1 379 } 380 if (currentNs >= minute1) { 381 res += Math.floor(currentNs / minute1) + "m "; 382 currentNs = currentNs - Math.floor(ns / minute1) * minute1 383 } 384 if (currentNs >= second1) { 385 res += Math.floor(currentNs / second1) + "s "; 386 currentNs = currentNs - Math.floor(currentNs / second1) * second1 387 } 388 if (currentNs >= millisecond1) { 389 res += Math.floor(currentNs / millisecond1) + "ms "; 390 currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1 391 } 392 if (currentNs >= microsecond1) { 393 res += Math.floor(currentNs / microsecond1) + "μs "; 394 currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1 395 } 396 if (currentNs > 0) { 397 res += currentNs + "ns "; 398 } 399 if (res == "") { 400 res = ns + ""; 401 } 402 return res 403} 404 405export function getProbablyTime(ns: number): string { 406 let currentNs = ns 407 let hour1 = 3600_000_000_000 408 let minute1 = 60_000_000_000 409 let second1 = 1_000_000_000; 410 let millisecond1 = 1_000_000; 411 let microsecond1 = 1_000; 412 let res = ""; 413 if (currentNs >= hour1) { 414 res += (currentNs / hour1).toFixed(2) + "h "; 415 }else if (currentNs >= minute1) { 416 res += (currentNs / minute1).toFixed(2) + "m "; 417 }else if (currentNs >= second1) { 418 res += (currentNs / second1).toFixed(2) + "s "; 419 }else if (currentNs >= millisecond1) { 420 res += (currentNs / millisecond1).toFixed(2) + "ms "; 421 }else if (currentNs >= microsecond1) { 422 res += (currentNs / microsecond1).toFixed(2) + "μs "; 423 }else if (currentNs > 0) { 424 res += currentNs + "ns "; 425 }else if (res == "") { 426 res = ns + ""; 427 } 428 return res 429} 430 431export function timeMsFormat2p(ns: number) { 432 let currentNs = ns 433 let hour1 = 3600_000 434 let minute1 = 60_000 435 let second1 = 1_000; // 1 second 436 let res = "" 437 if (currentNs >= hour1) { 438 res += Math.floor(currentNs / hour1).toFixed(2) + "h" 439 return res 440 } 441 if (currentNs >= minute1) { 442 res += Math.floor(currentNs / minute1).toFixed(2) + "min" 443 return res 444 } 445 if (currentNs >= second1) { 446 res += Math.floor(currentNs / second1).toFixed(2) + "s" 447 return res 448 } 449 if (currentNs > 0) { 450 res += currentNs.toFixed(2) + "ms"; 451 return res 452 } 453 if (res == "") { 454 res = "0s"; 455 } 456 return res 457}