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 { SelectionParam } from '../../../bean/BoxSelection'; 17import { procedurePool } from '../../../database/Procedure'; 18import { queryNativeHookResponseTypes } from '../../../database/sql/NativeHook.sql'; 19import { TraceMode } from '../../../SpApplicationPublicFunc'; 20 21export class Utils { 22 static isTransformed: boolean = false; 23 static currentSelectTrace: string | null | undefined; 24 static currentTraceMode: TraceMode = TraceMode.NORMAL; 25 static distributedTrace: string[] = []; 26 static isRangeSelectRefresh: boolean = false; 27 static currentTraceName: string = ''; 28 static DMAFENCECAT_MAP: Map< 29 number, 30 { 31 id: number; 32 cat: string; 33 seqno: number; 34 driver: string; 35 context: string 36 }> = new Map< 37 number, 38 { 39 id: number; 40 cat: string; 41 seqno: number; 42 driver: string; 43 context: string 44 } 45 >(); 46 private static statusMap: Map<string, string> = new Map<string, string>(); 47 private static instance: Utils | null = null; 48 private trace1CpuCount: number = 1; 49 private trace1WinCpuCount: number = 1; 50 private trace2CpuCount: number = 1; 51 private trace2WinCpuCount: number = 1; 52 trace1RecordStartNS: number = 1; 53 trace2RecordStartNS: number = 1; 54 trace1RecordEndNS: number = 1; 55 trace2RecordEndNS: number = 1; 56 totalNS: number = 1; 57 private trace1ThreadMap: Map<number, string> = new Map<number, string>(); 58 private trace1ProcessMap: Map<number, string> = new Map<number, string>(); 59 sysCallEventTidsMap: Map<number, { tid: number; pid: number, itid: number, ipid: number }> = new Map(); 60 private trace1SchedSliceMap: Map< 61 string, 62 { 63 endState: string; 64 priority: number; 65 } 66 > = new Map< 67 string, 68 { 69 endState: string; 70 priority: number; 71 } 72 >(); 73 private trace2ThreadMap: Map<number, string> = new Map<number, string>(); 74 private trace2ProcessMap: Map<number, string> = new Map<number, string>(); 75 private trace2SchedSliceMap: Map< 76 string, 77 { 78 endState: string; 79 priority: number; 80 } 81 > = new Map< 82 string, 83 { 84 endState: string; 85 priority: number; 86 } 87 >(); 88 private callStackMap: Map<number | string, string> = new Map<number | string, string>(); 89 90 constructor() { 91 Utils.statusMap.set('D', 'Uninterruptible Sleep'); 92 Utils.statusMap.set('D-NIO', 'Uninterruptible Sleep(non-IO)'); 93 Utils.statusMap.set('D-IO', 'Uninterruptible Sleep(IO)'); 94 Utils.statusMap.set('DK', 'Uninterruptible Sleep + Wake Kill'); 95 Utils.statusMap.set('DK-NIO', 'Uninterruptible Sleep(non-IO) + Wake Kill'); 96 Utils.statusMap.set('DK-IO', 'Uninterruptible Sleep(IO) + Wake Kill'); 97 Utils.statusMap.set('S', 'Sleeping'); 98 Utils.statusMap.set('R', 'Runnable'); 99 Utils.statusMap.set('Running', 'Running'); 100 Utils.statusMap.set('R+', 'Runnable (Preempted)'); 101 Utils.statusMap.set('R-B', 'Runnable (Binder)'); 102 Utils.statusMap.set('I', 'Task Dead'); 103 Utils.statusMap.set('T', 'Stopped'); 104 Utils.statusMap.set('t', 'Traced'); 105 Utils.statusMap.set('X', 'Exit (Dead)'); 106 Utils.statusMap.set('Z', 'Exit (Zombie)'); 107 Utils.statusMap.set('P', 'Parked'); 108 Utils.statusMap.set('N', 'No Load'); 109 } 110 111 public getProcessMap(traceId?: string | null): Map<number, string> { 112 if (traceId) { 113 return (traceId === '2' ? this.trace2ProcessMap : this.trace1ProcessMap); 114 } else { 115 return (Utils.currentSelectTrace === '2' ? this.trace2ProcessMap : this.trace1ProcessMap); 116 } 117 } 118 119 public getThreadMap(traceId?: string | null): Map<number, string> { 120 if (traceId) { 121 return (traceId === '2' ? this.trace2ThreadMap : this.trace1ThreadMap); 122 } else { 123 return (Utils.currentSelectTrace === '2' ? this.trace2ThreadMap : this.trace1ThreadMap); 124 } 125 } 126 127 public getCallStatckMap(): Map<number | string, string> { 128 return this.callStackMap; 129 } 130 131 public getSchedSliceMap(traceId?: string | null): Map<string, { 132 endState: string; 133 priority: number; 134 }> { 135 if (traceId) { 136 return (traceId === '2' ? this.trace2SchedSliceMap : this.trace1SchedSliceMap); 137 } else { 138 return (Utils.currentSelectTrace === '2' ? this.trace2SchedSliceMap : this.trace1SchedSliceMap); 139 } 140 } 141 142 public getCpuCount(traceId?: string | null): number { 143 if (traceId) { 144 return (traceId === '2' ? this.trace2CpuCount : this.trace1CpuCount); 145 } else { 146 return (Utils.currentSelectTrace === '2' ? this.trace2CpuCount : this.trace1CpuCount); 147 } 148 } 149 150 public setCpuCount(count: number, traceId?: string | null): void { 151 if (traceId) { 152 if (traceId === '2') { 153 this.trace2CpuCount = count; 154 } else { 155 this.trace1CpuCount = count; 156 } 157 } else { 158 if (Utils.currentSelectTrace === '2') { 159 this.trace2CpuCount = count; 160 } else { 161 this.trace1CpuCount = count; 162 } 163 } 164 } 165 166 public getWinCpuCount(traceId?: string | null): number { 167 if (traceId) { 168 return (traceId === '2' ? this.trace2WinCpuCount : this.trace1WinCpuCount); 169 } else { 170 return (Utils.currentSelectTrace === '2' ? this.trace2WinCpuCount : this.trace1WinCpuCount); 171 } 172 } 173 174 public setWinCpuCount(count: number, traceId?: string | null): void { 175 if (traceId) { 176 if (traceId === '2') { 177 this.trace2WinCpuCount = count; 178 } else { 179 this.trace1WinCpuCount = count; 180 } 181 } else { 182 if (Utils.currentSelectTrace === '2') { 183 this.trace2WinCpuCount = count; 184 } else { 185 this.trace1WinCpuCount = count; 186 } 187 } 188 } 189 190 public getRecordStartNS(traceId?: string | null): number { 191 if (traceId) { 192 return (traceId === '2' ? this.trace2RecordStartNS : this.trace1RecordStartNS); 193 } else { 194 return (Utils.currentSelectTrace === '2' ? this.trace2RecordStartNS : this.trace1RecordStartNS); 195 } 196 } 197 198 public getRecordEndNS(traceId?: string | null): number { 199 if (traceId) { 200 return (traceId === '2' ? this.trace2RecordEndNS : this.trace1RecordEndNS); 201 } else { 202 return (Utils.currentSelectTrace === '2' ? this.trace2RecordEndNS : this.trace1RecordEndNS); 203 } 204 } 205 206 public getTotalNS(traceId?: string | null): number { 207 return this.totalNS; 208 } 209 210 public static isDistributedMode(): boolean { 211 return Utils.currentTraceMode === TraceMode.DISTRIBUTED; 212 } 213 214 public static getInstance(): Utils { 215 if (Utils.instance === null) { 216 Utils.instance = new Utils(); 217 } 218 return Utils.instance; 219 } 220 221 public clearCache(): void { 222 this.trace1ProcessMap.clear(); 223 this.trace2ProcessMap.clear(); 224 this.trace1ThreadMap.clear(); 225 this.trace2ThreadMap.clear(); 226 this.trace1SchedSliceMap.clear(); 227 this.trace2SchedSliceMap.clear(); 228 this.sysCallEventTidsMap.clear(); 229 Utils.distributedTrace = []; 230 } 231 232 public static clearData(): void { 233 Utils.getInstance().clearCache(); 234 Utils.DMAFENCECAT_MAP.clear(); 235 } 236 237 public static getDistributedRowId(id: unknown): string { 238 let rowId = id; 239 if (rowId === null || rowId === undefined) { 240 rowId = ''; 241 } 242 return this.currentSelectTrace ? `${rowId}-${this.currentSelectTrace}` : `${rowId}`; 243 } 244 245 public static getEndState(state: string): string { 246 if (Utils.getInstance().getStatusMap().has(state)) { 247 return Utils.getInstance().getStatusMap().get(state) || 'Unknown State'; 248 } else { 249 if ('' === state || state === null) { 250 return ''; 251 } 252 return 'Unknown State'; 253 } 254 } 255 256 public static isBinder(data: unknown): boolean { 257 return ( 258 // @ts-ignore 259 data.funName !== null && // @ts-ignore 260 (data.funName.toLowerCase().startsWith('binder transaction async') || //binder transaction 261 // @ts-ignore 262 data.funName.toLowerCase().startsWith('binder async') || // @ts-ignore 263 data.funName.toLowerCase().startsWith('binder reply')) 264 ); 265 } 266 267 public static transferPTSTitle(ptsValue: unknown): string { 268 // @ts-ignore 269 if (ptsValue.startsWith('S-')) { 270 // @ts-ignore 271 return Utils.getEndState(ptsValue.replace('S-', '')); // @ts-ignore 272 } else if (ptsValue.startsWith('P-')) { 273 // @ts-ignore 274 let pid = ptsValue.replace('P-', ''); 275 let process = Utils.getInstance().getProcessMap(Utils.currentSelectTrace).get(parseInt(pid)) || 'Process'; 276 return `${process} [${pid}]`; // @ts-ignore 277 } else if (ptsValue.startsWith('T-')) { 278 // @ts-ignore 279 let tid = ptsValue.replace('T-', ''); 280 let thread = Utils.getInstance().getThreadMap(Utils.currentSelectTrace).get(parseInt(tid)) || 'Thread'; 281 return `${thread} [${tid}]`; 282 } else { 283 return ''; 284 } 285 } 286 287 public static transferBinderTitle(value: unknown, traceId?: string | null): string { 288 // @ts-ignore 289 if (value.startsWith('P-')) { 290 // @ts-ignore 291 let pid = value.replace('P-', ''); 292 let process = Utils.getInstance().getProcessMap(traceId).get(parseInt(pid)) || 'Process'; 293 return `${process} [${pid}]`; // @ts-ignore 294 } else if (value.startsWith('T-')) { 295 // @ts-ignore 296 let tid = value.replace('T-', ''); 297 let thread = Utils.getInstance().getThreadMap(traceId).get(parseInt(tid)) || 'Thread'; 298 return `${thread} [${tid}]`; 299 } else { 300 return ''; 301 } 302 } 303 304 public static getStateColor(state: string): string { 305 if (state === 'D-NIO' || state === 'DK-NIO') { 306 return '#795548'; 307 } else if (state === 'D-IO' || state === 'DK-IO' || state === 'D' || state === 'DK') { 308 return '#f19b38'; 309 } else if (state === 'R' || state === 'R+') { 310 return '#a0b84d'; 311 } else if (state === 'R-B') { 312 return '#87CEFA'; 313 } else if (state === 'I') { 314 return '#673ab7'; 315 } else if (state === 'Running') { 316 return '#467b3b'; 317 } else if (state === 'S') { 318 return '#e0e0e0'; 319 } else { 320 return '#ff6e40'; 321 } 322 } 323 324 public static getTimeString(ns: number): string { 325 let currentTime = ns; 326 let hour1 = 3600_000_000_000; 327 let minute1 = 60_000_000_000; 328 let second1 = 1_000_000_000; 329 let millisecond1 = 1_000_000; 330 let microsecond1 = 1_000; 331 let res = ''; 332 if (currentTime >= hour1) { 333 res += `${Math.floor(currentTime / hour1)}h `; 334 currentTime = currentTime - Math.floor(currentTime / hour1) * hour1; 335 } 336 if (currentTime >= minute1) { 337 res += `${Math.floor(currentTime / minute1)}m `; 338 currentTime = currentTime - Math.floor(ns / minute1) * minute1; 339 } 340 if (currentTime >= second1) { 341 res += `${Math.floor(currentTime / second1)}s `; 342 currentTime = currentTime - Math.floor(currentTime / second1) * second1; 343 } 344 if (currentTime >= millisecond1) { 345 res += `${Math.floor(currentTime / millisecond1)}ms `; 346 currentTime = currentTime - Math.floor(currentTime / millisecond1) * millisecond1; 347 } 348 if (currentTime >= microsecond1) { 349 res += `${Math.floor(currentTime / microsecond1)}μs `; 350 currentTime = currentTime - Math.floor(currentTime / microsecond1) * microsecond1; 351 } 352 if (currentTime > 0) { 353 res += `${currentTime}ns `; 354 } 355 if (res === '') { 356 res = `${ns}`; 357 } 358 return res; 359 } 360 361 public static getProbablyTime(timeNs: number): string { 362 let currentNs = timeNs; 363 let probablyHour = 3600_000_000_000; 364 let probablyMinute1 = 60_000_000_000; 365 let probablySecond1 = 1_000_000_000; 366 let probablyMillisecond1 = 1_000_000; 367 let probablyMicrosecond1 = 1_000; 368 let res = ''; 369 if (currentNs >= probablyHour) { 370 res += `${(currentNs / probablyHour).toFixed(2)}h `; 371 } else if (currentNs >= probablyMinute1) { 372 res += `${(currentNs / probablyMinute1).toFixed(2)}m `; 373 } else if (currentNs >= probablySecond1) { 374 res += `${(currentNs / probablySecond1).toFixed(2)}s `; 375 } else if (currentNs >= probablyMillisecond1) { 376 res += `${(currentNs / probablyMillisecond1).toFixed(2)}ms `; 377 } else if (currentNs >= probablyMicrosecond1) { 378 res += `${(currentNs / probablyMicrosecond1).toFixed(2)}μs `; 379 } else if (currentNs > 0) { 380 res += `${currentNs}ns `; 381 } else if (res === '') { 382 res = `${timeNs}`; 383 } 384 return res; 385 } 386 387 public static getTimeStringHMS(ns: number): string { 388 let currentNs = ns; 389 let hour1 = 3600_000_000_000; 390 let minute1 = 60_000_000_000; 391 let second1 = 1_000_000_000; // 1 second 392 let millisecond1 = 1_000_000; // 1 millisecond 393 let microsecond1 = 1_000; // 1 microsecond 394 let res = ''; 395 if (currentNs >= hour1) { 396 res += `${Math.floor(currentNs / hour1)}:`; 397 currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; 398 } 399 if (currentNs >= minute1) { 400 res += `${Math.floor(currentNs / minute1)}:`; 401 currentNs = currentNs - Math.floor(ns / minute1) * minute1; 402 } 403 if (currentNs >= second1) { 404 res += `${Math.floor(currentNs / second1)}:`; 405 currentNs = currentNs - Math.floor(currentNs / second1) * second1; 406 } 407 if (currentNs >= millisecond1) { 408 res += `${Math.floor(currentNs / millisecond1)}.`; 409 currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; 410 } 411 if (currentNs >= microsecond1) { 412 res += `${Math.floor(currentNs / microsecond1)}.`; 413 currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; 414 } 415 if (currentNs > 0) { 416 res += `${currentNs}`; 417 } 418 if (res === '') { 419 res = `${ns}`; 420 } 421 return res; 422 } 423 424 public static getByteWithUnit(bytes: number): string { 425 if (bytes < 0) { 426 return `-${this.getByteWithUnit(Math.abs(bytes))}`; 427 } 428 let currentByte = bytes; 429 let kb1 = 1 << 10; 430 let mb1 = (1 << 10) << 10; 431 let gb1 = ((1 << 10) << 10) << 10; // 1 gb 432 let res = ''; 433 if (currentByte > gb1) { 434 res += `${(currentByte / gb1).toFixed(2)} GB`; 435 } else if (currentByte > mb1) { 436 res += `${(currentByte / mb1).toFixed(2)} MB`; 437 } else if (currentByte > kb1) { 438 res += `${(currentByte / kb1).toFixed(2)} KB`; 439 } else { 440 res += `${Math.round(currentByte)} byte`; 441 } 442 return res; 443 } 444 445 public static timeFormat(ms: number): string { 446 let currentMsTime = ms; 447 let hours = 3600000; 448 let minute1 = 60000; 449 let second1 = 1000; 450 let res = ''; 451 if (currentMsTime >= hours) { 452 res += `${Math.floor(currentMsTime / hours)} h `; 453 currentMsTime = currentMsTime - Math.floor(currentMsTime / hours) * hours; 454 } 455 if (currentMsTime >= minute1) { 456 res += `${Math.floor(currentMsTime / minute1)} min `; 457 currentMsTime = currentMsTime - Math.floor(currentMsTime / minute1) * minute1; 458 } 459 if (currentMsTime >= second1) { 460 res += `${Math.floor(currentMsTime / second1)} s `; 461 currentMsTime = currentMsTime - Math.floor(currentMsTime / second1) * second1; 462 } 463 if (currentMsTime > 0) { 464 currentMsTime = parseFloat(currentMsTime.toFixed(2)); 465 res += `${currentMsTime} ms `; 466 } else if (res === '') { 467 res += '0 ms '; 468 } 469 return res; 470 } 471 472 public static groupByMap(array: Array<unknown>, key: string): Map<unknown, unknown> { 473 let result = new Map(); 474 array.forEach((item) => { 475 // @ts-ignore 476 let value = item[key]; 477 if (!result.has(value)) { 478 result.set(value, []); 479 } 480 result.get(value).push(item); 481 }); 482 return result; 483 } 484 485 public static groupBy(array: Array<unknown>, key: string): unknown { 486 return array.reduce((pre, current, index, arr) => { 487 // @ts-ignore 488 (pre[current[key]] = pre[current[key]] || []).push(current); 489 return pre; 490 }, {}); 491 } 492 493 public static timeMsFormat2p(ms: number): string { 494 let currentNs = ms; 495 let hour1 = 3600_000; 496 let minute1 = 60_000; 497 let second1 = 1_000; // 1 second 498 let result = ''; 499 if (currentNs >= hour1) { 500 result += `${Math.round(currentNs / hour1).toFixed(2)}h`; 501 return result; 502 } 503 if (currentNs >= minute1) { 504 result += `${Math.round(currentNs / minute1).toFixed(2)}min`; 505 return result; 506 } 507 if (currentNs >= second1) { 508 result += `${Math.round(currentNs / second1).toFixed(2)}s`; 509 return result; 510 } 511 if (currentNs > 0) { 512 result += `${currentNs.toFixed(2)}ms`; 513 return result; 514 } 515 if (result === '') { 516 result = '0s'; 517 } 518 return result; 519 } 520 521 public static uuid(): string { 522 // @ts-ignore 523 return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => 524 (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16) 525 ); 526 } 527 528 public static getBinaryKBWithUnit(kbytes: number): string { 529 if (kbytes === 0) { 530 return '0KB'; 531 } 532 let currentBytes = kbytes; 533 let mib1 = 1024; 534 let gib1 = 1024 * 1024; 535 let res = ''; 536 if (currentBytes >= gib1) { 537 res += `${(currentBytes / gib1).toFixed(2)}GB`; 538 } else if (currentBytes >= mib1) { 539 res += `${(currentBytes / mib1).toFixed(2)}MB`; 540 } else { 541 res += `${currentBytes.toFixed(2)}KB`; 542 } 543 return res; 544 } 545 546 public static getBinaryByteWithUnit(bytes: number): string { 547 if (bytes === 0) { 548 return '0Bytes'; 549 } 550 let currentBytes = bytes; 551 let kib1 = 1024; 552 let mib1 = 1024 * 1024; 553 let gib1 = 1024 * 1024 * 1024; 554 let res = ''; 555 if (bytes < 0) { 556 res = '-'; 557 currentBytes = Math.abs(currentBytes); 558 } 559 if (currentBytes >= gib1) { 560 res += `${(currentBytes / gib1).toFixed(2)}GB`; 561 } else if (currentBytes >= mib1) { 562 res += `${(currentBytes / mib1).toFixed(2)}MB`; 563 } else if (currentBytes >= kib1) { 564 res += `${(currentBytes / kib1).toFixed(2)}KB`; 565 } else { 566 res += `${currentBytes.toFixed(2)}Bytes`; 567 } 568 return res; 569 } 570 571 public static getTimeStampHMS(ns: number): string { 572 let currentNs = ns; 573 let hour1 = 3600_000_000_000; 574 let minute1 = 60_000_000_000; 575 let second1 = 1_000_000_000; // 1 second 576 let millisecond1 = 1_000_000; // 1 millisecond 577 let microsecond1 = 1_000; // 1 microsecond 578 let res = ''; 579 if (currentNs >= hour1) { 580 res += `${this.getCompletionTime(Math.floor(currentNs / hour1), 2)}:`; 581 currentNs = currentNs - Math.floor(currentNs / hour1) * hour1; 582 } 583 if (currentNs >= minute1) { 584 res += `${this.getCompletionTime(Math.floor(currentNs / minute1), 2)}:`; 585 currentNs = currentNs - Math.floor(ns / minute1) * minute1; 586 } 587 if (currentNs >= second1) { 588 res += `${this.getCompletionTime(Math.floor(currentNs / second1), 2)}:`; 589 currentNs = currentNs - Math.floor(currentNs / second1) * second1; 590 } else { 591 res += '00:'; 592 } 593 if (currentNs >= millisecond1) { 594 res += `${this.getCompletionTime(Math.floor(currentNs / millisecond1), 3)}.`; 595 currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1; 596 } else { 597 res += '000.'; 598 } 599 if (currentNs >= microsecond1) { 600 res += `${this.getCompletionTime(Math.floor(currentNs / microsecond1), 3)}.`; 601 currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1; 602 } else { 603 res += '000'; 604 } 605 if (currentNs > 0) { 606 res += this.getCompletionTime(currentNs, 3); 607 } 608 if (res === '') { 609 res = `${ns}`; 610 } 611 return res; 612 } 613 614 public static getDurString(ns: number): string { 615 let currentNs = ns; 616 let second1 = 1000000000; 617 let millisecond1 = 1000000; 618 let res = ''; 619 if (currentNs >= second1) { 620 let cu = currentNs / second1; 621 res += `${cu.toFixed(3)} s `; 622 return res; 623 } 624 if (currentNs >= millisecond1) { 625 res += `${Math.floor(currentNs / millisecond1)} ms `; 626 return res; 627 } 628 if (res === '') { 629 res = `${ns}`; 630 } 631 return res; 632 } 633 634 private static getCompletionTime(time: number, maxLength: number): string { 635 if (maxLength === 2) { 636 if (time.toString().length === 2) { 637 return `${time}`; 638 } else { 639 return `0${time}`; 640 } 641 } else if (maxLength === 3) { 642 if (time.toString().length === 3) { 643 return time.toString(); 644 } else if (time.toString().length === 2) { 645 return `0${time}`; 646 } else { 647 return `00${time}`; 648 } 649 } else { 650 return '0'; 651 } 652 } 653 654 public getStatusMap(): Map<string, string> { 655 return Utils.statusMap; 656 } 657 658 public static removeDuplicates(array1: unknown[], array2: unknown[], key: string): unknown { 659 let obj: unknown = {}; 660 return array1.concat(array2).reduce(function (total, item) { 661 // @ts-ignore 662 if (!obj[`${item[key]}-${item.pid}`]) { 663 // @ts-ignore 664 obj[`${item[key]}-${item.pid}`] = true; // @ts-ignore 665 total.push(item); 666 } 667 return total; 668 }, []); 669 } 670 671 // 线程排序去重 672 public static sortThreadRow(array1: unknown[], array2: unknown[], flag: string): unknown { 673 let total = new Array(); 674 let arr2Map = new Map(); 675 // 将array2转为map 676 for (let i = 0; i < array2.length; i++) { 677 // @ts-ignore 678 arr2Map.set(flag === 'thread' ? `${array2[i].pid}-${array2[i].tid}` : `${array2[i].pid}`, array2[i]); 679 } 680 for (let i = 0; i < array1.length; i++) { 681 // @ts-ignore 682 if (arr2Map.get(`${array1[i][0]}`)) { 683 // @ts-ignore 684 total.push(arr2Map.get(`${array1[i][0]}`)); 685 // @ts-ignore 686 arr2Map.delete(`${array1[i][0]}`); 687 } 688 }; 689 // 将map中剩余的循环加在total后 690 // @ts-ignore 691 arr2Map.forEach((v) => { 692 total.push(v); 693 }); 694 return total; 695 } 696 697 static getFrequencyWithUnit = ( 698 maxFreq: number 699 ): { 700 maxFreqName: string; 701 maxFreq: number; 702 } => { 703 let maxFreqObj = { 704 maxFreqName: ' ', 705 maxFreq: 0, 706 }; 707 let units: Array<string> = ['', 'K', 'M', 'G', 'T', 'E']; 708 let sb = ' '; 709 if (maxFreq > 0) { 710 let log10: number = Math.ceil(Math.log10(maxFreq)); 711 let pow10: number = Math.pow(10, log10); 712 let afterCeil: number = Math.ceil(maxFreq / (pow10 / 4)) * 1000; 713 let afterDivision: number = (afterCeil * ((pow10 / 4) * 1000)) / 1000000; 714 maxFreqObj.maxFreq = afterDivision; 715 let unitIndex: number = Math.floor(log10 / 3); 716 sb = `${afterDivision / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}`; 717 } 718 maxFreqObj.maxFreqName = sb.toString(); 719 return maxFreqObj; 720 }; 721 722 public static getTimeIsCross(startTime: number, endTime: number, startTime1: number, endTime1: number): boolean { 723 return Math.max(startTime, startTime1) <= Math.min(endTime, endTime1); 724 } 725 726 initResponseTypeList(val: SelectionParam): void { 727 const isStatistic = val.nativeMemoryStatistic.length > 0; 728 const selection = isStatistic ? val.nativeMemoryStatistic : val.nativeMemory; 729 let types: Array<string | number> = []; 730 if (selection.indexOf('All Heap & Anonymous VM') !== -1) { 731 if (isStatistic) { 732 types.push(0, 1); 733 } else { 734 types.push("'AllocEvent'", "'MmapEvent'"); 735 } 736 } else { 737 if (selection.indexOf('All Heap') !== -1) { 738 if (isStatistic) { 739 types.push(0); 740 } else { 741 types.push("'AllocEvent'"); 742 } 743 } 744 if (selection.indexOf('All Anonymous VM') !== -1) { 745 if (isStatistic) { 746 types.push(1); 747 } else { 748 types.push("'MmapEvent'"); 749 } 750 } 751 } 752 queryNativeHookResponseTypes(val.leftNs, val.rightNs, types, val.nativeMemoryCurrentIPid, isStatistic).then((res): void => { 753 procedurePool.submitWithName('logic0', 'native-memory-init-responseType', res, undefined, (): void => { }); 754 }); 755 } 756 757 setCurrentSelectIPid(ipid: number): void { 758 procedurePool.submitWithName('logic0', 'native-memory-set-current_ipid', ipid, undefined, (): void => { }); 759 } 760 761 public static convertJSON(arr: ArrayBuffer | Array<unknown>): unknown { 762 if (arr instanceof ArrayBuffer) { 763 let dec = new TextDecoder(); 764 let str = dec.decode(arr); 765 let jsonArray: Array<unknown> = []; 766 str = str.substring(str.indexOf('\n') + 1); 767 if (!str) { 768 } else { 769 let parse; 770 let tansStr: string; 771 try { 772 tansStr = str.replace(/[\t\r\n]/g, ''); 773 parse = JSON.parse(tansStr); 774 } catch { 775 try { 776 tansStr = tansStr!.replace(/[^\x20-\x7E]/g, '?'); //匹配乱码字 符,将其转换为? 777 parse = JSON.parse(tansStr); 778 } catch { 779 tansStr = tansStr!.replace(/\\/g, '\\\\'); 780 parse = JSON.parse(tansStr); 781 } 782 } 783 let columns = parse.columns; 784 let values = parse.values; 785 for (let i = 0; i < values.length; i++) { 786 let obj: unknown = {}; 787 for (let j = 0; j < columns.length; j++) { 788 //@ts-ignore 789 obj[columns[j]] = values[i][j]; 790 } 791 jsonArray.push(obj); 792 } 793 } 794 return jsonArray; 795 } else { 796 return arr; 797 } 798 } 799} 800