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