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 { 17 convertJSON, getByteWithUnit, 18 getProbablyTime, 19 getTimeString, 20 LogicHandler, 21 MerageBean, 22 merageBeanDataSplit, 23 postMessage, 24 setFileName 25} from "./ProcedureLogicWorkerCommon.js"; 26 27export let FILE_TYPE_MAP = { 28 '0': 'OPEN', 29 '1': 'CLOSE', 30 '2': 'READ', 31 '3': 'WRITE', 32}; 33 34export let DISKIO_TYPE_MAP = { 35 '0': 'OPEN', 36 '1': 'CLOSE', 37 '2': 'READ', 38 '3': 'WRITE', 39}; 40 41export let VM_TYPE_MAP = { 42 '1': 'File Backed In', 43 '2': 'Page Cache Hit', 44 '3': 'Swap From Zram', 45 '4': 'Swap From Disk', 46 '5': 'Zero Fill Page', 47 '6': 'Zero FAKE Page', 48 '7': 'Copy On Write', 49}; 50 51export class ProcedureLogicWorkerFileSystem extends LogicHandler { 52 tab:string = ""; 53 data_dict: Map<number, string> = new Map<number, string>(); 54 currentEventId: string = "" 55 currentTreeMapData: any = {} 56 samplesData: FileSample[] = [] 57 splitMapData: any = {} 58 currentTreeList: any[] = [] 59 searchValue: string = "" 60 callChainsMap: Map<number, FileCallChain[]> = new Map<number, FileCallChain[]>() 61 allProcess: FileMerageBean[] = [] 62 dataSource: FileMerageBean[] = [] 63 currentDataType:string = "" 64 65 handle(data: any): void { 66 this.currentEventId = data.id 67 if (data && data.type) { 68 switch (data.type) { 69 case "fileSystem-init": 70 this.data_dict = data.params as Map<number, string> 71 this.initCallchains(); 72 break 73 case "fileSystem-queryCallchains": 74 let callChains = convertJSON(data.params.list) || []; 75 this.initCallChainTopDown(callChains) 76 // @ts-ignore 77 self.postMessage({id: data.id, action: data.action, results: []}); 78 break; 79 case "fileSystem-queryFileSamples": 80 case "fileSystem-queryIoSamples": 81 case "fileSystem-queryVirtualMemorySamples": 82 this.currentDataType = data.type 83 this.samplesData = convertJSON(data.params.list) || [] 84 self.postMessage({ 85 id: data.id, action: data.action, results: this.resolvingAction([{ 86 funcName: "getCallChainsBySampleIds", 87 funcArgs: [true] 88 }]) 89 }); 90 break; 91 case "fileSystem-action": 92 if (data.params) { 93 let filter = data.params.filter((item: any) => item.funcName == "getCurrentDataFromDb"); 94 if (filter.length == 0) { 95 // @ts-ignore 96 self.postMessage({ 97 id: data.id, 98 action: data.action, 99 results: this.resolvingAction(data.params) 100 }); 101 } else { 102 this.resolvingAction(data.params) 103 } 104 } 105 break; 106 case "fileSystem-queryStack": 107 let res = this.getStacksByCallchainId(data.params.callchainId) 108 self.postMessage({id: data.id, action: data.action, results: res}) 109 break; 110 case "fileSystem-queryFileSysEvents": 111 if (data.params.list) { 112 let res = convertJSON(data.params.list) || [] 113 postMessage(data.id, data.action, this.supplementFileSysEvents(res, this.tab)); 114 } else { 115 this.tab = data.params.tab; 116 this.queryFileSysEvents(data.params.leftNs, data.params.rightNs, data.params.typeArr, data.params.tab) 117 } 118 break; 119 case "fileSystem-queryVMEvents": 120 if (data.params.list) { 121 let res = convertJSON(data.params.list) || [] 122 postMessage(data.id, data.action, this.supplementVMEvents(res)); 123 } else { 124 this.queryVMEvents(data.params.leftNs, data.params.rightNs, data.params.typeArr) 125 } 126 break 127 case "fileSystem-queryIOEvents": 128 if (data.params.list) { 129 let res = convertJSON(data.params.list) || [] 130 postMessage(data.id, data.action, this.supplementIoEvents(res)); 131 } else { 132 this.queryIOEvents(data.params.leftNs, data.params.rightNs, data.params.typeArr) 133 } 134 break 135 } 136 } 137 } 138 139 queryFileSysEvents(leftNs: number, rightNs: number, typeArr: Array<number>, tab: string) { 140 let types = Array.from(typeArr).join(","); 141 let sql = ""; 142 if (tab == "events") { 143 sql = ` 144 select 145 A.callchain_id as callchainId, 146 (A.start_ts - B.start_ts) as startTs, 147 dur, 148 A.type, 149 ifnull(C.name,'Process') || '[' || C.pid || ']' as process, 150 ifnull(D.name,'Thread') || '[' || D.tid || ']' as thread, 151 first_argument as firstArg, 152 second_argument as secondArg, 153 third_argument as thirdArg, 154 fourth_argument as fourthArg, 155 return_value as returnValue, 156 error_code as error 157 from file_system_sample A,trace_range B 158 left join process C on A.ipid = C.id 159 left join thread D on A.itid = D.id 160 where A.type in (${types}) 161 and( 162 (A.end_ts - B.start_ts) between $leftNS and $rightNS 163 ) 164 order by A.end_ts; 165 ` 166 } else if (tab == "history") { 167 sql = ` 168 select 169 A.callchain_id as callchainId, 170 (A.start_ts - B.start_ts) as startTs, 171 dur, 172 fd, 173 A.type, 174 ifnull(C.name,'Process') || '[' || C.pid || ']' as process 175 from file_system_sample A,trace_range B 176 left join process C on A.ipid = C.id 177 where A.type in (${types}) 178 and fd not null 179 and( 180 (A.start_ts - B.start_ts) between $leftNS and $rightNS 181 ) 182 order by A.end_ts; 183 ` 184 } else { 185 sql = ` 186 select TB.callchain_id as callchainId, 187 (TB.start_ts - TR.start_ts) as startTs, 188 (${rightNs} - TB.start_ts) as dur, 189 TB.fd, 190 TB.type, 191 ifnull(TC.name, 'Process') || '[' || TC.pid || ']' as process 192 from ( 193 select fd, 194 max(case when type = 0 then A.end_ts else 0 end) as openTs, 195 max(case when type = 1 then A.end_ts else 0 end) as closeTs 196 from file_system_sample A 197 where type in (0, 1) and A.end_ts between $leftNS and $rightNS group by fd 198 ) TA 199 left join file_system_sample TB on TA.fd = TB.fd and TA.openTs = TB.end_ts 200 left join process TC on TB.ipid = TC.ipid 201 left join trace_range TR 202 where startTs not null and TB.fd not null and TA.closeTs < TA.openTs 203 order by TB.end_ts; ` 204 } 205 this.queryData("fileSystem-queryFileSysEvents", sql, {$leftNS: leftNs, $rightNS: rightNs}) 206 } 207 208 queryVMEvents(leftNs: number, rightNs: number, typeArr: Array<number>){ 209 let types = Array.from(typeArr).join(","); 210 let sql = `select 211 A.callchain_id as callchainId, 212 (A.start_ts - B.start_ts) as startTs, 213 dur, 214 addr as address, 215 C.pid, 216 T.tid, 217 size, 218 A.type, 219 ifnull(T.name,'Thread') || '[' || T.tid || ']' as thread, 220 ifnull(C.name,'Process') || '[' || C.pid || ']' as process 221 from virtual_memory_sample A,trace_range B 222 left join process C on A.ipid = C.id 223 left join thread T on T.id = A.itid 224 where ( 225 (A.end_ts - B.start_ts) between $leftNS and $rightNS 226 );`; 227 this.queryData("fileSystem-queryVMEvents", sql, {$leftNS: leftNs, $rightNS: rightNs}) 228 } 229 230 queryIOEvents(leftNs: number, rightNs: number, typeArr: Array<number>){ 231 let types = Array.from(typeArr).join(","); 232 let sql = `select 233 A.callchain_id as callchainId, 234 (A.start_ts - B.start_ts) as startTs, 235 latency_dur as dur, 236 path, 237 dur_per_4k as durPer4k, 238 tier, 239 size, 240 A.type, 241 block_number as blockNumber, 242 ifnull(T.name,'Thread') || '[' || T.tid || ']' as thread, 243 ifnull(C.name,'Process') || '[' || C.pid || ']' as process 244 from io_latency_sample A,trace_range B 245 left join process C on A.ipid = C.id 246 left join thread T on T.id = A.itid 247 where ( 248 (A.start_ts - B.start_ts) between $leftNS and $rightNS 249 or 250 (A.start_ts + A.latency_dur - B.start_ts) between $leftNS and $rightNS 251 );`; 252 this.queryData("fileSystem-queryIOEvents", sql, {$leftNS: leftNs, $rightNS: rightNs}) 253 } 254 255 getStacksByCallchainId(id: number) { 256 let stacks = this.callChainsMap.get(id) ?? []; 257 let arr: Array<Stack> = []; 258 for (let s of stacks) { 259 let st: Stack = new Stack() 260 st.path = (this.data_dict.get(s.pathId) ?? "Unknown Path").split("/").reverse()[0]; 261 st.symbol = `${s.symbolsId == null ? s.ip : this.data_dict.get(s.symbolsId) ?? ''} (${st.path})`; 262 st.type = (st.path.endsWith(".so.1") || st.path.endsWith(".dll") || st.path.endsWith(".so")) ? 0 : 1; 263 arr.push(st); 264 } 265 return arr; 266 } 267 268 supplementIoEvents(res: Array<IoCompletionTimes>){ 269 return res.map((event) => { 270 event.startTsStr = getTimeString(event.startTs) 271 event.durPer4kStr = getProbablyTime(event.durPer4k) 272 event.sizeStr = getByteWithUnit(event.size) 273 event.durStr = getProbablyTime(event.dur) 274 // @ts-ignore 275 event.operation = DISKIO_TYPE_MAP[`${event.type}`]||"UNKNOW" 276 let stacks = this.callChainsMap.get(event.callchainId)||[]; 277 if(stacks.length > 0){ 278 let stack = stacks[0] 279 event.backtrace = [stack.symbolsId == null ? stack.ip : this.data_dict.get(stack.symbolsId) ?? "", `(${stacks.length} other frames)`]; 280 }else { 281 event.backtrace = []; 282 } 283 return event 284 }) 285 } 286 287 supplementVMEvents(res: Array<VirtualMemoryEvent>){ 288 return res.map((event) => { 289 event.startTsStr = getTimeString(event.startTs) 290 event.sizeStr = getByteWithUnit(event.size*4096) 291 event.durStr = getProbablyTime(event.dur) 292 // @ts-ignore 293 event.operation = VM_TYPE_MAP[`${event.type}`]||"UNKNOW" 294 return event 295 }) 296 } 297 298 299 supplementFileSysEvents(res: Array<FileSysEvent>, tab: string) { 300 res.map((r) => { 301 let stacks = this.callChainsMap.get(r.callchainId); 302 r.startTsStr = getTimeString(r.startTs); 303 r.durStr = getProbablyTime(r.dur); 304 if (tab == "events") { 305 r.firstArg = r.firstArg ?? "0x0" 306 r.secondArg = r.secondArg ?? "0x0" 307 r.thirdArg = r.thirdArg ?? "0x0" 308 r.fourthArg = r.fourthArg ?? "0x0" 309 r.returnValue = r.returnValue ?? "0x0" 310 r.error = r.error ?? "0x0" 311 } 312 // @ts-ignore 313 r.typeStr = FILE_TYPE_MAP[`${r.type}`] ?? ""; 314 if (stacks && stacks.length > 0) { 315 let stack = stacks[0] 316 r.depth = stacks.length; 317 r.symbol = stack.symbolsId == null ? stack.ip : this.data_dict.get(stack.symbolsId) ?? "" 318 if (tab != "events") { 319 r.path = this.data_dict.get(stack.pathId) ?? "" 320 } 321 r.backtrace = [r.symbol, `(${r.depth} other frames)`]; 322 } else { 323 r.depth = 0; 324 r.symbol = ""; 325 r.path = ""; 326 r.backtrace = []; 327 } 328 }) 329 return res; 330 } 331 332 initCallchains() { 333 this.clearAll() 334 this.queryData("fileSystem-queryCallchains", `select callchain_id as callChainId,depth,symbols_id as symbolsId,file_path_id as pathId,ip from ebpf_callstack`, {}) 335 } 336 337 queryCallchainsSamples(selectionParam: any){ 338 if(selectionParam.queryFuncName!=undefined){ 339 switch (selectionParam.queryFuncName) { 340 case "fileSystem": 341 this.queryFileSamples(selectionParam) 342 break; 343 case "io": 344 this.queryIOSamples(selectionParam) 345 break; 346 case "virtualMemory": 347 this.queryEpbfSamples(selectionParam) 348 break; 349 } 350 } 351 } 352 353 queryFileSamples(selectionParam: any) { 354 let sql = ''; 355 if (selectionParam.fileSystemType != undefined && selectionParam.fileSystemType.length > 0) { 356 sql += " and s.type in (" 357 sql += selectionParam.fileSystemType.join(",") 358 sql += ")" 359 } 360 this.queryData("fileSystem-queryFileSamples", `select s.callchain_id as callChainId,h.tid,h.name as threadName,s.dur,s.type,p.pid,p.name as processName from file_system_sample s,trace_range t 361left join process p on p.id = s.ipid 362left join thread h on h.id = s.itid 363where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${sql} and callchain_id != -1;` 364 , {$startTime: selectionParam.leftNs, $endTime: selectionParam.rightNs}) 365 366 } 367 368 queryIOSamples(selectionParam: any){ 369 let sql = ''; 370 this.queryData("fileSystem-queryIoSamples", `select s.callchain_id as callChainId,h.tid,h.name as threadName,s.latency_dur as dur,s.type,p.pid,p.name as processName from io_latency_sample s,trace_range t 371left join process p on p.id = s.ipid 372left join thread h on h.id = s.itid 373where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${sql} and callchain_id != -1;` 374 , {$startTime: selectionParam.leftNs, $endTime: selectionParam.rightNs}) 375 } 376 377 queryEpbfSamples(selectionParam: any){ 378 let sql = ''; 379 this.queryData("fileSystem-queryVirtualMemorySamples", `select s.callchain_id as callChainId,h.tid,h.name as threadName,s.dur,s.type,p.pid,p.name as processName from virtual_memory_sample s,trace_range t 380left join process p on p.id = s.ipid 381left join thread h on h.id = s.itid 382where s.end_ts between $startTime + t.start_ts and $endTime + t.start_ts ${sql} and callchain_id != -1;` 383 , {$startTime: selectionParam.leftNs, $endTime: selectionParam.rightNs}) 384 } 385 386 initCallChainTopDown(list: any[]) { 387 list.forEach((callchain: FileCallChain) => { 388 if (this.callChainsMap.has(callchain.callChainId)) { 389 this.callChainsMap.get(callchain.callChainId)!.push(callchain) 390 } else { 391 this.callChainsMap.set(callchain.callChainId, [callchain]) 392 } 393 }) 394 } 395 396 freshCurrentCallchains(samples: FileSample[], isTopDown: boolean) { 397 this.currentTreeMapData = {} 398 this.currentTreeList = [] 399 this.allProcess = []; 400 this.dataSource = [] 401 let totalCount = 0 402 samples.forEach((sample) => { 403 totalCount += sample.dur; 404 let callChains = this.createThreadAndType(sample) 405 let topIndex = isTopDown ? 0 : (callChains.length - 1); 406 if (callChains.length > 1) { 407 let root = this.currentTreeMapData[callChains[topIndex].symbolsId + "" + callChains[topIndex].pathId + sample.pid]; 408 if (root == undefined) { 409 root = new FileMerageBean(); 410 this.currentTreeMapData[callChains[topIndex].symbolsId + "" + callChains[topIndex].pathId + sample.pid] = root; 411 this.currentTreeList.push(root) 412 } 413 FileMerageBean.merageCallChainSample(root, callChains[topIndex], sample, false); 414 this.merageChildrenByIndex(root, callChains, topIndex, sample, isTopDown); 415 } 416 }) 417 let rootMerageMap: any = {} 418 Object.values(this.currentTreeMapData).forEach((merageData: any) => { 419 if (rootMerageMap[merageData.pid] == undefined) { 420 let processMerageData = new FileMerageBean()//新增进程的节点数据 421 processMerageData.canCharge = false 422 processMerageData.symbolName = merageData.processName 423 processMerageData.symbol = processMerageData.symbolName 424 processMerageData.children.push(merageData) 425 processMerageData.initChildren.push(merageData) 426 processMerageData.dur = merageData.dur; 427 processMerageData.count = merageData.count; 428 processMerageData.total = totalCount; 429 rootMerageMap[merageData.pid] = processMerageData 430 } else { 431 rootMerageMap[merageData.pid].children.push(merageData) 432 rootMerageMap[merageData.pid].initChildren.push(merageData) 433 rootMerageMap[merageData.pid].dur += merageData.dur; 434 rootMerageMap[merageData.pid].count += merageData.count; 435 rootMerageMap[merageData.pid].total = totalCount; 436 } 437 merageData.parentNode = rootMerageMap[merageData.pid]//子节点添加父节点的引用 438 }) 439 let id = 0; 440 this.currentTreeList.forEach((node) => { 441 node.total = totalCount; 442 this.setMerageName(node) 443 if (node.id == "") { 444 node.id = id + "" 445 id++ 446 } 447 if (node.parentNode) { 448 if (node.parentNode.id == "") { 449 node.parentNode.id = id + "" 450 id++ 451 } 452 node.parentId = node.parentNode.id 453 } 454 }) 455 this.allProcess = Object.values(rootMerageMap) 456 } 457 458 createThreadAndType(sample: FileSample){ 459 let typeCallchain = new FileCallChain(); 460 typeCallchain.callChainId = sample.callChainId 461 let map:any = {} 462 if(this.currentDataType == "fileSystem-queryFileSamples"){ 463 map = FILE_TYPE_MAP 464 }else if(this.currentDataType == "fileSystem-queryIoSamples"){ 465 map = DISKIO_TYPE_MAP 466 }else if(this.currentDataType == "fileSystem-queryVirtualMemorySamples"){ 467 map = VM_TYPE_MAP 468 } 469 // @ts-ignore 470 typeCallchain.ip = map[sample.type.toString()]||""; 471 typeCallchain.symbolsId = sample.type 472 typeCallchain.pathId = -1; 473 let threadCallChain = new FileCallChain(); 474 threadCallChain.callChainId = sample.callChainId 475 threadCallChain.ip = (sample.threadName||"Thread")+`-${sample.tid}` 476 threadCallChain.symbolsId = sample.tid; 477 threadCallChain.pathId = -1; 478 return [typeCallchain,threadCallChain,...(this.callChainsMap.get(sample.callChainId)||[])] 479 } 480 481 482 merageChildrenByIndex(currentNode: FileMerageBean, callChainDataList: any[], index: number, sample: FileSample, isTopDown: boolean) { 483 isTopDown ? index++ : index--; 484 let isEnd = isTopDown ? (callChainDataList.length == index + 1) : (index == 0) 485 let node; 486 if (currentNode.initChildren.filter((child: any) => { 487 if (child.ip == callChainDataList[index]?.ip||(child.symbolsId == callChainDataList[index]?.symbolsId&&child.pathId == callChainDataList[index]?.pathId)) { 488 node = child; 489 FileMerageBean.merageCallChainSample(child, callChainDataList[index], sample, isEnd) 490 return true; 491 } 492 return false; 493 }).length == 0) { 494 node = new FileMerageBean() 495 FileMerageBean.merageCallChainSample(node, callChainDataList[index], sample, isEnd) 496 currentNode.children.push(node) 497 currentNode.initChildren.push(node) 498 this.currentTreeList.push(node) 499 node.parentNode = currentNode 500 } 501 if (node && !isEnd) this.merageChildrenByIndex(node, callChainDataList, index, sample, isTopDown) 502 } 503 504 setMerageName(currentNode: FileMerageBean) { 505 if (currentNode.pathId == -1) { 506 currentNode.canCharge = false; 507 currentNode.symbol = currentNode.ip; 508 currentNode.symbolName = currentNode.symbol; 509 currentNode.libName = ""; 510 currentNode.path = ""; 511 } else { 512 currentNode.symbol = this.data_dict.get(currentNode.symbolsId) || currentNode.ip || 'unkown' 513 currentNode.path = this.data_dict.get(currentNode.pathId) || 'unkown' 514 currentNode.libName = setFileName(currentNode.path) 515 currentNode.symbolName = `${currentNode.symbol} (${currentNode.libName})` 516 } 517 } 518 519 clearAll() { 520 this.samplesData = [] 521 this.splitMapData = {} 522 this.currentTreeMapData = {} 523 this.currentTreeList = [] 524 this.searchValue = "" 525 this.allProcess = [] 526 this.dataSource = [] 527 this.callChainsMap = new Map<number, FileCallChain[]>() 528 this.splitMapData = {} 529 this.searchValue = "" 530 this.currentDataType = "" 531 } 532 533 clearSplitMapData(symbolName: string) { 534 delete this.splitMapData[symbolName] 535 } 536 537 resolvingAction(params: any[]) { 538 if (params.length > 0) { 539 params.forEach((item) => { 540 if (item.funcName && item.funcArgs) { 541 switch (item.funcName) { 542 case "getCallChainsBySampleIds": 543 this.freshCurrentCallchains(this.samplesData, item.funcArgs[0]) 544 break 545 case "getCurrentDataFromDb": 546 this.queryCallchainsSamples(item.funcArgs[0]); 547 break 548 case "hideSystemLibrary": 549 merageBeanDataSplit.hideSystemLibrary(this.allProcess, this.splitMapData); 550 break 551 case "hideNumMaxAndMin": 552 merageBeanDataSplit.hideNumMaxAndMin(this.allProcess, this.splitMapData, item.funcArgs[0], item.funcArgs[1]) 553 break 554 case "splitAllProcess": 555 merageBeanDataSplit.splitAllProcess(this.allProcess, this.splitMapData, item.funcArgs[0]) 556 break 557 case "resetAllNode": 558 merageBeanDataSplit.resetAllNode(this.allProcess, this.currentTreeList, this.searchValue) 559 break 560 case "resotreAllNode": 561 merageBeanDataSplit.resotreAllNode(this.splitMapData, item.funcArgs[0]) 562 break 563 case "clearSplitMapData": 564 this.clearSplitMapData(item.funcArgs[0]) 565 break 566 case "splitTree": 567 merageBeanDataSplit.splitTree(this.splitMapData, this.allProcess, item.funcArgs[0], item.funcArgs[1], item.funcArgs[2], this.currentTreeList, this.searchValue); 568 break 569 case "setSearchValue": 570 this.searchValue = item.funcArgs[0] 571 break 572 } 573 } 574 }) 575 this.dataSource = this.allProcess.filter((process) => { 576 return process.children && process.children.length > 0 577 }) 578 } 579 return this.dataSource 580 } 581 582 queryData(queryName: string, sql: string, args: any) { 583 self.postMessage({ 584 id: this.currentEventId, 585 type: queryName, 586 isQuery: true, 587 args: args, 588 sql: sql 589 }) 590 } 591 592} 593 594class FileCallChain { 595 callChainId: number = 0; 596 depth: number = 0; 597 symbolsId: number = 0; 598 pathId: number = 0; 599 ip: string = "" 600} 601 602class FileSample { 603 type:number = 0 604 callChainId:number = 0; 605 dur:number = 0; 606 pid:number = 0; 607 tid:number = 0; 608 threadName:string = ""; 609 processName:string = "" 610} 611 612export class FileMerageBean extends MerageBean { 613 ip: string = "" 614 symbolsId: number = 0; 615 pathId: number = 0; 616 processName: string = ""; 617 type: number = 0 618 619 static merageCallChainSample(currentNode: FileMerageBean, callChain: FileCallChain, sample: FileSample, isEnd: boolean) { 620 if (currentNode.processName == "") { 621 currentNode.ip = callChain.ip 622 currentNode.pid = sample.pid 623 currentNode.canCharge = true 624 currentNode.pathId = callChain.pathId; 625 currentNode.symbolsId = callChain.symbolsId; 626 currentNode.processName = sample.processName || `Process(${sample.pid})` 627 } 628 if (isEnd) { 629 currentNode.selfDur += sample.dur; 630 currentNode.self = getProbablyTime(currentNode.selfDur) 631 } 632 currentNode.dur += sample.dur; 633 currentNode.count++; 634 } 635} 636 637export class Stack { 638 type: number = 0; 639 symbol: string = ""; 640 path: string = ""; 641} 642 643export class FileSysEvent { 644 isSelected:boolean = false; 645 id: number = 0; 646 callchainId: number = 0; 647 startTs: number = 0; 648 startTsStr: string = ""; 649 durStr: string = ""; 650 dur: number = 0; 651 process: string = ""; 652 thread: string = ""; 653 type: number = 0; 654 typeStr: string = ""; 655 fd: number = 0; 656 size: number = 0; 657 depth: number = 0; 658 firstArg: string = ""; 659 secondArg: string = ""; 660 thirdArg: string = ""; 661 fourthArg: string = ""; 662 returnValue: string = ""; 663 error: string = ""; 664 path: string = ""; 665 symbol: string = ""; 666 backtrace: Array<string> = []; 667} 668 669export class IoCompletionTimes{ 670 isSelected:boolean = false; 671 type:number = 0; 672 callchainId: number = 0; 673 startTs: number = 0; 674 startTsStr: string = ""; 675 durStr: string = ""; 676 dur: number = 0; 677 process: string = ""; 678 thread: string = ""; 679 path: string = ""; 680 operation: string = ""; 681 size: number = 0; 682 sizeStr:string = ""; 683 blockNumber:string = ""; 684 tier:number = 0; 685 backtrace: Array<string> = []; 686 durPer4kStr: string = "" 687 durPer4k: number = 0; 688} 689 690export class VirtualMemoryEvent{ 691 isSelected:boolean = false; 692 callchainId: number = 0; 693 startTs: number = 0; 694 startTsStr: string = ""; 695 durStr: string = ""; 696 dur: number = 0; 697 process: string = ""; 698 thread: string = ""; 699 address:string = ""; 700 size:number = 0; 701 sizeStr:string = ""; 702 type:number = 0; 703 tid:number = 0; 704 pid:number = 0; 705 operation: string = ""; 706} 707