• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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';
19
20export class Utils {
21  static isTransformed: boolean = false;
22  private static statusMap: Map<string, string> = new Map<string, string>();
23  private static instance: Utils | null = null;
24  static THREAD_MAP: Map<number, string> = new Map<number, string>();
25  static PROCESS_MAP: Map<number, string> = new Map<number, string>();
26  static SCHED_SLICE_MAP: Map<
27    string,
28    {
29      endState: string;
30      priority: number;
31    }
32  > = new Map<
33    string,
34    {
35      endState: string;
36      priority: number;
37    }
38  >();
39
40  constructor() {
41    Utils.statusMap.set('D', 'Uninterruptible Sleep');
42    Utils.statusMap.set('D-NIO', 'Uninterruptible Sleep(non-IO)');
43    Utils.statusMap.set('D-IO', 'Uninterruptible Sleep(IO)');
44    Utils.statusMap.set('DK', 'Uninterruptible Sleep + Wake Kill');
45    Utils.statusMap.set('DK-NIO', 'Uninterruptible Sleep(non-IO) + Wake Kill');
46    Utils.statusMap.set('DK-IO', 'Uninterruptible Sleep(IO) + Wake Kill');
47    Utils.statusMap.set('S', 'Sleeping');
48    Utils.statusMap.set('R', 'Runnable');
49    Utils.statusMap.set('Running', 'Running');
50    Utils.statusMap.set('R+', 'Runnable (Preempted)');
51    Utils.statusMap.set('R-B', 'Runnable (Binder)');
52    Utils.statusMap.set('I', 'Task Dead');
53    Utils.statusMap.set('T', 'Stopped');
54    Utils.statusMap.set('t', 'Traced');
55    Utils.statusMap.set('X', 'Exit (Dead)');
56    Utils.statusMap.set('Z', 'Exit (Zombie)');
57    Utils.statusMap.set('P', 'Parked');
58    Utils.statusMap.set('N', 'No Load');
59  }
60
61  public static getInstance(): Utils {
62    if (Utils.instance === null) {
63      Utils.instance = new Utils();
64    }
65    return Utils.instance;
66  }
67
68  public static clearData(): void {
69    Utils.THREAD_MAP.clear();
70    Utils.PROCESS_MAP.clear();
71    Utils.SCHED_SLICE_MAP.clear();
72  }
73
74  public static getEndState(state: string): string {
75    if (Utils.getInstance().getStatusMap().has(state)) {
76      return Utils.getInstance().getStatusMap().get(state) || 'Unknown State';
77    } else {
78      if ('' === state || state === null) {
79        return '';
80      }
81      return 'Unknown State';
82    }
83  }
84
85  public static isBinder(data: unknown): boolean {
86    return (
87      // @ts-ignore
88      data.funName !== null && // @ts-ignore
89      (data.funName.toLowerCase().startsWith('binder transaction async') || //binder transaction
90        // @ts-ignore
91        data.funName.toLowerCase().startsWith('binder async') || // @ts-ignore
92        data.funName.toLowerCase().startsWith('binder reply'))
93    );
94  }
95
96  public static transferPTSTitle(ptsValue: unknown): string {
97    // @ts-ignore
98    if (ptsValue.startsWith('S-')) {
99      // @ts-ignore
100      return Utils.getEndState(ptsValue.replace('S-', '')); // @ts-ignore
101    } else if (ptsValue.startsWith('P-')) {
102      // @ts-ignore
103      let pid = ptsValue.replace('P-', ''); // @ts-ignore
104      let process = Utils.PROCESS_MAP.get(parseInt(pid)) || 'Process';
105      return `${process} [${pid}]`; // @ts-ignore
106    } else if (ptsValue.startsWith('T-')) {
107      // @ts-ignore
108      let tid = ptsValue.replace('T-', '');
109      let thread = Utils.THREAD_MAP.get(parseInt(tid)) || 'Thread';
110      return `${thread} [${tid}]`;
111    } else {
112      return '';
113    }
114  }
115
116  public static transferBinderTitle(value: unknown): string {
117    // @ts-ignore
118    if (value.startsWith('P-')) {
119      // @ts-ignore
120      let pid = value.replace('P-', '');
121      let process = Utils.PROCESS_MAP.get(parseInt(pid)) || 'Process';
122      return `${process} [${pid}]`; // @ts-ignore
123    } else if (value.startsWith('T-')) {
124      // @ts-ignore
125      let tid = value.replace('T-', '');
126      let thread = Utils.THREAD_MAP.get(parseInt(tid)) || 'Thread';
127      return `${thread} [${tid}]`;
128    } else {
129      return '';
130    }
131  }
132
133  public static getStateColor(state: string): string {
134    if (state === 'D-NIO' || state === 'DK-NIO') {
135      return '#795548';
136    } else if (state === 'D-IO' || state === 'DK-IO' || state === 'D' || state === 'DK') {
137      return '#f19b38';
138    } else if (state === 'R' || state === 'R+') {
139      return '#a0b84d';
140    } else if (state === 'R-B') {
141      return '#87CEFA';
142    } else if (state === 'I') {
143      return '#673ab7';
144    } else if (state === 'Running') {
145      return '#467b3b';
146    } else if (state === 'S') {
147      return '#e0e0e0';
148    } else {
149      return '#ff6e40';
150    }
151  }
152
153  public static getTimeString(ns: number): string {
154    let currentTime = ns;
155    let hour1 = 3600_000_000_000;
156    let minute1 = 60_000_000_000;
157    let second1 = 1_000_000_000;
158    let millisecond1 = 1_000_000;
159    let microsecond1 = 1_000;
160    let res = '';
161    if (currentTime >= hour1) {
162      res += `${Math.floor(currentTime / hour1)}h `;
163      currentTime = currentTime - Math.floor(currentTime / hour1) * hour1;
164    }
165    if (currentTime >= minute1) {
166      res += `${Math.floor(currentTime / minute1)}m `;
167      currentTime = currentTime - Math.floor(ns / minute1) * minute1;
168    }
169    if (currentTime >= second1) {
170      res += `${Math.floor(currentTime / second1)}s `;
171      currentTime = currentTime - Math.floor(currentTime / second1) * second1;
172    }
173    if (currentTime >= millisecond1) {
174      res += `${Math.floor(currentTime / millisecond1)}ms `;
175      currentTime = currentTime - Math.floor(currentTime / millisecond1) * millisecond1;
176    }
177    if (currentTime >= microsecond1) {
178      res += `${Math.floor(currentTime / microsecond1)}μs `;
179      currentTime = currentTime - Math.floor(currentTime / microsecond1) * microsecond1;
180    }
181    if (currentTime > 0) {
182      res += `${currentTime}ns `;
183    }
184    if (res === '') {
185      res = `${ns}`;
186    }
187    return res;
188  }
189
190  public static getProbablyTime(timeNs: number): string {
191    let currentNs = timeNs;
192    let probablyHour = 3600_000_000_000;
193    let probablyMinute1 = 60_000_000_000;
194    let probablySecond1 = 1_000_000_000;
195    let probablyMillisecond1 = 1_000_000;
196    let probablyMicrosecond1 = 1_000;
197    let res = '';
198    if (currentNs >= probablyHour) {
199      res += `${(currentNs / probablyHour).toFixed(2)}h `;
200    } else if (currentNs >= probablyMinute1) {
201      res += `${(currentNs / probablyMinute1).toFixed(2)}m `;
202    } else if (currentNs >= probablySecond1) {
203      res += `${(currentNs / probablySecond1).toFixed(2)}s `;
204    } else if (currentNs >= probablyMillisecond1) {
205      res += `${(currentNs / probablyMillisecond1).toFixed(2)}ms `;
206    } else if (currentNs >= probablyMicrosecond1) {
207      res += `${(currentNs / probablyMicrosecond1).toFixed(2)}μs `;
208    } else if (currentNs > 0) {
209      res += `${currentNs}ns `;
210    } else if (res === '') {
211      res = `${timeNs}`;
212    }
213    return res;
214  }
215
216  public static getTimeStringHMS(ns: number): string {
217    let currentNs = ns;
218    let hour1 = 3600_000_000_000;
219    let minute1 = 60_000_000_000;
220    let second1 = 1_000_000_000; // 1 second
221    let millisecond1 = 1_000_000; // 1 millisecond
222    let microsecond1 = 1_000; // 1 microsecond
223    let res = '';
224    if (currentNs >= hour1) {
225      res += `${Math.floor(currentNs / hour1)}:`;
226      currentNs = currentNs - Math.floor(currentNs / hour1) * hour1;
227    }
228    if (currentNs >= minute1) {
229      res += `${Math.floor(currentNs / minute1)}:`;
230      currentNs = currentNs - Math.floor(ns / minute1) * minute1;
231    }
232    if (currentNs >= second1) {
233      res += `${Math.floor(currentNs / second1)}:`;
234      currentNs = currentNs - Math.floor(currentNs / second1) * second1;
235    }
236    if (currentNs >= millisecond1) {
237      res += `${Math.floor(currentNs / millisecond1)}.`;
238      currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1;
239    }
240    if (currentNs >= microsecond1) {
241      res += `${Math.floor(currentNs / microsecond1)}.`;
242      currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1;
243    }
244    if (currentNs > 0) {
245      res += `${currentNs}`;
246    }
247    if (res === '') {
248      res = `${ns}`;
249    }
250    return res;
251  }
252
253  public static getByteWithUnit(bytes: number): string {
254    if (bytes < 0) {
255      return `-${this.getByteWithUnit(Math.abs(bytes))}`;
256    }
257    let currentByte = bytes;
258    let kb1 = 1 << 10;
259    let mb1 = (1 << 10) << 10;
260    let gb1 = ((1 << 10) << 10) << 10; // 1 gb
261    let res = '';
262    if (currentByte > gb1) {
263      res += `${(currentByte / gb1).toFixed(2)} GB`;
264    } else if (currentByte > mb1) {
265      res += `${(currentByte / mb1).toFixed(2)} MB`;
266    } else if (currentByte > kb1) {
267      res += `${(currentByte / kb1).toFixed(2)} KB`;
268    } else {
269      res += `${Math.round(currentByte)} byte`;
270    }
271    return res;
272  }
273
274  public static groupByMap(array: Array<unknown>, key: string): Map<unknown, unknown> {
275    let result = new Map();
276    array.forEach((item) => {
277      // @ts-ignore
278      let value = item[key];
279      if (!result.has(value)) {
280        result.set(value, []);
281      }
282      result.get(value).push(item);
283    });
284    return result;
285  }
286
287  public static groupBy(array: Array<unknown>, key: string): unknown {
288    return array.reduce((pre, current, index, arr) => {
289      // @ts-ignore
290      (pre[current[key]] = pre[current[key]] || []).push(current);
291      return pre;
292    }, {});
293  }
294
295  public static timeMsFormat2p(ms: number): string {
296    let currentNs = ms;
297    let hour1 = 3600_000;
298    let minute1 = 60_000;
299    let second1 = 1_000; // 1 second
300    let result = '';
301    if (currentNs >= hour1) {
302      result += `${Math.round(currentNs / hour1).toFixed(2)}h`;
303      return result;
304    }
305    if (currentNs >= minute1) {
306      result += `${Math.round(currentNs / minute1).toFixed(2)}min`;
307      return result;
308    }
309    if (currentNs >= second1) {
310      result += `${Math.round(currentNs / second1).toFixed(2)}s`;
311      return result;
312    }
313    if (currentNs > 0) {
314      result += `${currentNs.toFixed(2)}ms`;
315      return result;
316    }
317    if (result === '') {
318      result = '0s';
319    }
320    return result;
321  }
322
323  public static uuid(): string {
324    // @ts-ignore
325    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
326      (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
327    );
328  }
329
330  public static getBinaryKBWithUnit(kbytes: number): string {
331    if (kbytes === 0) {
332      return '0KB';
333    }
334    let currentBytes = kbytes;
335    let mib1 = 1024;
336    let gib1 = 1024 * 1024;
337    let res = '';
338    if (currentBytes >= gib1) {
339      res += `${(currentBytes / gib1).toFixed(2)}GB`;
340    } else if (currentBytes >= mib1) {
341      res += `${(currentBytes / mib1).toFixed(2)}MB`;
342    } else {
343      res += `${currentBytes.toFixed(2)}KB`;
344    }
345    return res;
346  }
347
348  public static getBinaryByteWithUnit(bytes: number): string {
349    if (bytes === 0) {
350      return '0Bytes';
351    }
352    let currentBytes = bytes;
353    let kib1 = 1024;
354    let mib1 = 1024 * 1024;
355    let gib1 = 1024 * 1024 * 1024;
356    let res = '';
357    if (bytes < 0) {
358      res = '-';
359      currentBytes = Math.abs(currentBytes);
360    }
361    if (currentBytes >= gib1) {
362      res += `${(currentBytes / gib1).toFixed(2)}GB`;
363    } else if (currentBytes >= mib1) {
364      res += `${(currentBytes / mib1).toFixed(2)}MB`;
365    } else if (currentBytes >= kib1) {
366      res += `${(currentBytes / kib1).toFixed(2)}KB`;
367    } else {
368      res += `${currentBytes.toFixed(2)}Bytes`;
369    }
370    return res;
371  }
372
373  public static getTimeStampHMS(ns: number): string {
374    let currentNs = ns;
375    let hour1 = 3600_000_000_000;
376    let minute1 = 60_000_000_000;
377    let second1 = 1_000_000_000; // 1 second
378    let millisecond1 = 1_000_000; // 1 millisecond
379    let microsecond1 = 1_000; // 1 microsecond
380    let res = '';
381    if (currentNs >= hour1) {
382      res += `${this.getCompletionTime(Math.floor(currentNs / hour1), 2)}:`;
383      currentNs = currentNs - Math.floor(currentNs / hour1) * hour1;
384    }
385    if (currentNs >= minute1) {
386      res += `${this.getCompletionTime(Math.floor(currentNs / minute1), 2)}:`;
387      currentNs = currentNs - Math.floor(ns / minute1) * minute1;
388    }
389    if (currentNs >= second1) {
390      res += `${this.getCompletionTime(Math.floor(currentNs / second1), 2)}:`;
391      currentNs = currentNs - Math.floor(currentNs / second1) * second1;
392    } else {
393      res += '00:';
394    }
395    if (currentNs >= millisecond1) {
396      res += `${this.getCompletionTime(Math.floor(currentNs / millisecond1), 3)}.`;
397      currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1;
398    } else {
399      res += '000.';
400    }
401    if (currentNs >= microsecond1) {
402      res += `${this.getCompletionTime(Math.floor(currentNs / microsecond1), 3)}.`;
403      currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1;
404    } else {
405      res += '000';
406    }
407    if (currentNs > 0) {
408      res += this.getCompletionTime(currentNs, 3);
409    }
410    if (res === '') {
411      res = `${ns}`;
412    }
413    return res;
414  }
415
416  public static getDurString(ns: number): string {
417    let currentNs = ns;
418    let second1 = 1000000000;
419    let millisecond1 = 1000000;
420    let res = '';
421    if (currentNs >= second1) {
422      let cu = currentNs / second1;
423      res += `${cu.toFixed(3)} s `;
424      return res;
425    }
426    if (currentNs >= millisecond1) {
427      res += `${Math.floor(currentNs / millisecond1)} ms `;
428      return res;
429    }
430    if (res === '') {
431      res = `${ns}`;
432    }
433    return res;
434  }
435
436  private static getCompletionTime(time: number, maxLength: number): string {
437    if (maxLength === 2) {
438      if (time.toString().length === 2) {
439        return `${time}`;
440      } else {
441        return `0${time}`;
442      }
443    } else if (maxLength === 3) {
444      if (time.toString().length === 3) {
445        return time.toString();
446      } else if (time.toString().length === 2) {
447        return `0${time}`;
448      } else {
449        return `00${time}`;
450      }
451    } else {
452      return '0';
453    }
454  }
455
456  public getStatusMap(): Map<string, string> {
457    return Utils.statusMap;
458  }
459
460  public static removeDuplicates(array1: unknown[], array2: unknown[], key: string): unknown {
461    let obj: unknown = {};
462    return array1.concat(array2).reduce(function (total, item) {
463      // @ts-ignore
464      if (!obj[`${item[key]}-${item.pid}`]) {
465        // @ts-ignore
466        obj[`${item[key]}-${item.pid}`] = true; // @ts-ignore
467        total.push(item);
468      }
469      return total;
470    }, []);
471  }
472
473  static getFrequencyWithUnit = (
474    maxFreq: number
475  ): {
476    maxFreqName: string;
477    maxFreq: number;
478  } => {
479    let maxFreqObj = {
480      maxFreqName: ' ',
481      maxFreq: 0,
482    };
483    let units: Array<string> = ['', 'K', 'M', 'G', 'T', 'E'];
484    let sb = ' ';
485    if (maxFreq > 0) {
486      let log10: number = Math.ceil(Math.log10(maxFreq));
487      let pow10: number = Math.pow(10, log10);
488      let afterCeil: number = Math.ceil(maxFreq / (pow10 / 4)) * (pow10 / 4);
489      maxFreqObj.maxFreq = afterCeil;
490      let unitIndex: number = Math.floor(log10 / 3);
491      sb = `${afterCeil / Math.pow(10, unitIndex * 3)}${units[unitIndex + 1]}`;
492    }
493    maxFreqObj.maxFreqName = sb.toString();
494    return maxFreqObj;
495  };
496
497  public static getTimeIsCross(startTime: number, endTime: number, startTime1: number, endTime1: number): boolean {
498    return Math.max(startTime, startTime1) <= Math.min(endTime, endTime1);
499  }
500
501  initResponseTypeList(val: SelectionParam): void {
502    const isStatistic = val.nativeMemoryStatistic.length > 0;
503    const selection = isStatistic ? val.nativeMemoryStatistic : val.nativeMemory;
504    let types: Array<string | number> = [];
505    if (selection.indexOf('All Heap & Anonymous VM') !== -1) {
506      if (isStatistic) {
507        types.push(0, 1);
508      } else {
509        types.push("'AllocEvent'", "'MmapEvent'");
510      }
511    } else {
512      if (selection.indexOf('All Heap') !== -1) {
513        if (isStatistic) {
514          types.push(0);
515        } else {
516          types.push("'AllocEvent'");
517        }
518      }
519      if (selection.indexOf('All Anonymous VM') !== -1) {
520        if (isStatistic) {
521          types.push(1);
522        } else {
523          types.push("'MmapEvent'");
524        }
525      }
526    }
527    queryNativeHookResponseTypes(val.leftNs, val.rightNs, types, isStatistic).then((res): void => {
528      procedurePool.submitWithName('logic0', 'native-memory-init-responseType', res, undefined, (): void => {});
529    });
530  }
531
532  setCurrentSelectIPid(ipid: number): void {
533    procedurePool.submitWithName('logic0', 'native-memory-set-current_ipid', ipid, undefined, (): void => {});
534  }
535}
536