meminsight-test-demo 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +36 -0
  3. package/docs/Build.md +68 -0
  4. package/docs/Interface.md +35 -0
  5. package/docs/UserGuide.md +332 -0
  6. package/docs/resources/analyzer.png +0 -0
  7. package/docs/resources/cfg_filter_filetype_json.png +0 -0
  8. package/docs/resources/filetype_txt.png +0 -0
  9. package/docs/resources/framework.png +0 -0
  10. package/docs/resources/output.png +0 -0
  11. package/docs/resources/process.png +0 -0
  12. package/package.json +54 -0
  13. package/packages/cfg/ArkStatCfg.json +33 -0
  14. package/packages/core/jest.config.js +8 -0
  15. package/packages/core/package.json +61 -0
  16. package/packages/core/src/Index.ts +53 -0
  17. package/packages/core/src/analyzer/AnalysisInfo.ts +298 -0
  18. package/packages/core/src/analyzer/ArkAnalyzer.ts +42 -0
  19. package/packages/core/src/analyzer/ArkCmpCfg.ts +22 -0
  20. package/packages/core/src/analyzer/ArkCompareAnalyzer.ts +173 -0
  21. package/packages/core/src/analyzer/ArkLeakAnalyzer.ts +196 -0
  22. package/packages/core/src/analyzer/ArkSerializer.ts +163 -0
  23. package/packages/core/src/analyzer/ArkStatAnalyzer.ts +191 -0
  24. package/packages/core/src/analyzer/ArkStatCfg.ts +77 -0
  25. package/packages/core/src/analyzer/ArkTracePath.ts +269 -0
  26. package/packages/core/src/analyzer/ArkTracer.ts +42 -0
  27. package/packages/core/src/analyzer/ArkXAnalyzer.ts +631 -0
  28. package/packages/core/src/analyzer/IAnalyzer.ts +27 -0
  29. package/packages/core/src/file/FileReader.ts +82 -0
  30. package/packages/core/src/file/FileService.ts +50 -0
  31. package/packages/core/src/file/FileWriter.ts +148 -0
  32. package/packages/core/src/report/Reporter.ts +81 -0
  33. package/packages/core/src/report/templates/template.ejs +101 -0
  34. package/packages/core/src/report/templates/template.ts +103 -0
  35. package/packages/core/src/shell/DeviceShell.ts +179 -0
  36. package/packages/core/src/shell/Shell.ts +99 -0
  37. package/packages/core/src/types/Constants.ts +16 -0
  38. package/packages/core/src/types/LeakTypes.ts +21 -0
  39. package/packages/core/src/types/OhosTypes.ts +115 -0
  40. package/packages/core/src/utils/Common.ts +37 -0
  41. package/packages/core/src/utils/Finder.ts +390 -0
  42. package/packages/core/src/utils/Loader.ts +53 -0
  43. package/packages/core/src/utils/Log.ts +252 -0
  44. package/packages/core/src/utils/Output.ts +271 -0
  45. package/packages/core/tsconfig.json +10 -0
  46. package/packages/exampletools/package.json +52 -0
  47. package/packages/exampletools/src/MemTest.ts +64 -0
  48. package/packages/exampletools/tsconfig.json +15 -0
  49. package/packages/meminsight/jest.config.js +8 -0
  50. package/packages/meminsight/package.json +52 -0
  51. package/packages/meminsight/src/Index.ts +4 -0
  52. package/packages/meminsight/src/Version.ts +7 -0
  53. package/packages/meminsight/src/process/ArkCompareProc.ts +160 -0
  54. package/packages/meminsight/src/process/ArkGCProc.ts +61 -0
  55. package/packages/meminsight/src/process/ArkLeakProc.ts +47 -0
  56. package/packages/meminsight/src/process/ArkStatProc.ts +320 -0
  57. package/packages/meminsight/src/process/ArkXProc.ts +73 -0
  58. package/packages/meminsight/src/process/HMemXProc.ts +50 -0
  59. package/packages/meminsight/src/process/IProcess.ts +12 -0
  60. package/packages/meminsight/tsconfig.json +15 -0
  61. package/packages/stack/README.md +31 -0
  62. package/packages/stack/libs/hstack_lib-1.0.0.tgz +0 -0
  63. package/packages/stack/libs/hstack_lib-1.0.1.tgz +0 -0
  64. package/packages/stack/libs/hstack_lib-1.0.4.tgz +0 -0
  65. package/packages/stack/libs/lib_list.json +34 -0
  66. package/packages/stack/package.json +27 -0
  67. package/packages/stack/src/Index.js +29 -0
  68. package/packages/stack/src/StackTracer.js +53 -0
  69. package/packages/templates/ArkLeaks.template +9 -0
  70. package/packages/templates/ArkNodes.template +9 -0
  71. package/packages/templates/ArkPaths.template +9 -0
  72. package/test/scripts/merge.py +145 -0
  73. package/test/scripts/stat.py +175 -0
  74. package/test/test_ark_stat_proc.sh +14 -0
  75. package/tsconfig.base.json +38 -0
  76. package/tsconfig.json +8 -0
@@ -0,0 +1,29 @@
1
+ const { StackTracer } = require("./StackTracer");
2
+
3
+ // input folders
4
+ const sourcemapFolder = require('path').resolve(__dirname, 'sourcemap');
5
+ const namecacheFolder = require('path').resolve(__dirname, 'namecache');
6
+ const libFolder = undefined;
7
+
8
+ // input one line
9
+ const line = '';
10
+ // input multi lines
11
+ const lines = [];
12
+
13
+ (async function test() {
14
+ console.log('StackTracer test start......\n');
15
+ const stackTracer = new StackTracer(sourcemapFolder, namecacheFolder, libFolder);
16
+ await stackTracer.init();
17
+ {
18
+ console.log('\n\nparseOneLine:');
19
+ let res = await stackTracer.parseOneLine(line);
20
+ console.log(res);
21
+ }
22
+ {
23
+ console.log('\n\nparseMultiLines:');
24
+ let res = await stackTracer.parseMultiLines(lines)
25
+ console.log(res.join('\n'));
26
+ }
27
+ await stackTracer.unInit();
28
+ console.log('StackTracer test end.\n');
29
+ }) ();
@@ -0,0 +1,53 @@
1
+ const { existsSync } = require("fs");
2
+ const { init, parseLine, stop } = require("hstack_lib");
3
+
4
+ /**
5
+ * Stack Tracer
6
+ */
7
+ class StackTracer {
8
+ constructor(sourcemapFolder, namecacheFolder, libFolder) {
9
+ this.sourcemapFolder = sourcemapFolder;
10
+ this.namecacheFolder = namecacheFolder;
11
+ this.libFolder = libFolder;
12
+ }
13
+
14
+ check() {
15
+ if (this.sourcemapFolder && !existsSync(this.sourcemapFolder)) {
16
+ console.log(`Error: sourcemap folder not exists: ${this.sourcemapFolder}`);
17
+ return false;
18
+ }
19
+ if (this.namecacheFolder && !existsSync(this.namecacheFolder)) {
20
+ console.log(`Error: namecache folder not exists: ${this.libFolder}`);
21
+ return false;
22
+ }
23
+ if (this.libFolder && !existsSync(this.libFolder)) {
24
+ console.log(`Error: so folder not exists: ${this.libFolder}`);
25
+ return false;
26
+ }
27
+ return true;
28
+ }
29
+
30
+ async init() {
31
+ if (!this.check()) {
32
+ return false;
33
+ }
34
+ await init(this.sourcemapFolder || '', this.libFolder || '', this.namecacheFolder || '');
35
+ return true;
36
+ }
37
+
38
+ async parseOneLine(line) {
39
+ return await parseLine(line);
40
+ }
41
+
42
+ async parseMultiLines(lines) {
43
+ let tmpLines = lines.join('\n');
44
+ let result = await parseLine(tmpLines);
45
+ return result.split('\n');
46
+ }
47
+
48
+ async unInit() {
49
+ await stop();
50
+ }
51
+ }
52
+
53
+ module.exports = { StackTracer };
@@ -0,0 +1,9 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <h>MemInsight Leaks Report</h>
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -0,0 +1,9 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <h>MemInsight Nodes Report</h>
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -0,0 +1,9 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+ <head>
5
+ <h>BitFun-MemInsight Paths Report</h>
6
+ </head>
7
+ <body>
8
+ </body>
9
+ </html>
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import argparse
5
+ import os
6
+ import sys
7
+
8
+ def merge_jemalloc_lines(input_file, output_file=None, in_place=False):
9
+ """
10
+ 将包含"jemalloc heap"的行与上一行合并
11
+
12
+ 参数:
13
+ input_file: 输入文件路径
14
+ output_file: 输出文件路径(如果为None且in_place=False,则打印到控制台)
15
+ in_place: 是否原地修改文件
16
+ """
17
+ try:
18
+ with open(input_file, 'r', encoding='utf-8') as f:
19
+ lines = f.readlines()
20
+ except UnicodeDecodeError:
21
+ try:
22
+ with open(input_file, 'r', encoding='latin-1') as f:
23
+ lines = f.readlines()
24
+ except Exception as e:
25
+ print(f"读取文件失败: {e}")
26
+ return False
27
+
28
+ # 处理行合并
29
+ merged_lines = []
30
+ i = 0
31
+ while i < len(lines):
32
+ current_line = lines[i].rstrip('\n\r')
33
+
34
+ # 检查下一行是否包含"jemalloc heap"
35
+ if i + 1 < len(lines) and "jemalloc heap" in lines[i + 1]:
36
+ next_line = lines[i + 1].rstrip('\n\r')
37
+ # 合并当前行和下一行
38
+ merged_line = current_line + " " + next_line
39
+ merged_lines.append(merged_line)
40
+ i += 2 # 跳过下一行,因为已经合并了
41
+ else:
42
+ merged_lines.append(current_line)
43
+ i += 1
44
+
45
+ # 输出结果
46
+ if in_place:
47
+ # 原地修改文件
48
+ with open(input_file, 'w', encoding='utf-8') as f:
49
+ for line in merged_lines:
50
+ f.write(line + '\n')
51
+ print(f"文件已原地修改: {input_file}")
52
+ return True
53
+ elif output_file:
54
+ # 写入到输出文件
55
+ with open(output_file, 'w', encoding='utf-8') as f:
56
+ for line in merged_lines:
57
+ f.write(line + '\n')
58
+ print(f"结果已保存到: {output_file}")
59
+ return True
60
+ else:
61
+ # 打印到控制台
62
+ for line in merged_lines:
63
+ print(line)
64
+ return True
65
+
66
+ def create_sample_file():
67
+ """创建示例文件用于测试"""
68
+ sample_content = """应用启动日志
69
+ 内存统计: {'TimeSatamp': 1756796001.230954, 'GL': 65512, 'Graph': 127596, 'ark ts heap': 176468, 'native heap': 284574, 'AnonPage other': 365126, 'FilePage other': 57091, 'Total': 12033
70
+ 55, jemalloc heap': 274040}
71
+ 用户操作日志
72
+ 内存统计: {"TimeSatamp": 1756796002.451234, "GL": 65890, "Graph": 128123, "ark ts heap": 177231, "native heap": 285672, "AnonPage other": 366543, "FilePage other": 57234, "Total": 1207890}
73
+ jemalloc heap': 275195}
74
+ 性能监控
75
+ 内存统计: {'TimeSatamp': 1756796003.789012, 'GL': 66234, 'Graph': 128567, 'ark ts heap': 178456, 'native heap': 286789, 'AnonPage other': 367890, 'FilePage other': 57456, 'Total': 1212345}
76
+ jemalloc heap': 276123}
77
+ 错误处理
78
+ 内存统计: {"TimeSatamp": 1756796004.123456, "GL": 66543, "Graph": 129012, "ark ts heap": 179234, "native heap": 287456, "AnonPage other": 368765, "FilePage other": 57678, "Total": 1216789}
79
+ jemalloc heap': 277456}"""
80
+
81
+ with open('sample_jemalloc.txt', 'w', encoding='utf-8') as f:
82
+ f.write(sample_content)
83
+
84
+ print("示例文件已创建: sample_jemalloc.txt")
85
+ return 'sample_jemalloc.txt'
86
+
87
+ def main():
88
+ parser = argparse.ArgumentParser(description='合并包含"jemalloc heap"的行与上一行')
89
+ parser.add_argument('input_file', nargs='?', help='输入文件路径')
90
+ parser.add_argument('-o', '--output', help='输出文件路径')
91
+ parser.add_argument('-i', '--in-place', action='store_true', help='原地修改文件')
92
+ parser.add_argument('--sample', action='store_true', help='创建示例文件并处理')
93
+ parser.add_argument('--verbose', action='store_true', help='显示详细信息')
94
+
95
+ args = parser.parse_args()
96
+
97
+ if args.sample:
98
+ input_file = create_sample_file()
99
+ print("\n处理示例文件:")
100
+ merge_jemalloc_lines(input_file, output_file="output_sample.txt")
101
+
102
+ # # 显示处理前后的对比
103
+ # print("\n处理前:")
104
+ # with open(input_file, 'r', encoding='utf-8') as f:
105
+ # print(f.read())
106
+
107
+ # print("\n处理后:")
108
+ # with open("output_sample.txt", 'r', encoding='utf-8') as f:
109
+ # print(f.read())
110
+
111
+ return
112
+
113
+ if not args.input_file:
114
+ print("请提供输入文件路径或使用 --sample 参数")
115
+ parser.print_help()
116
+ return
117
+
118
+ if not os.path.exists(args.input_file):
119
+ print(f"文件不存在: {args.input_file}")
120
+ return
121
+
122
+ if args.in_place and args.output:
123
+ print("错误: 不能同时使用 --in-place 和 --output 参数")
124
+ return
125
+
126
+ if args.verbose:
127
+ print(f"处理文件: {args.input_file}")
128
+ if args.in_place:
129
+ print("模式: 原地修改")
130
+ elif args.output:
131
+ print(f"输出到: {args.output}")
132
+ else:
133
+ print("模式: 输出到控制台")
134
+
135
+ success = merge_jemalloc_lines(
136
+ input_file=args.input_file,
137
+ output_file=args.output,
138
+ in_place=args.in_place
139
+ )
140
+
141
+ if success and args.verbose:
142
+ print("处理完成")
143
+
144
+ if __name__ == "__main__":
145
+ main()
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import re
5
+ import json
6
+ import ast
7
+ from collections import defaultdict
8
+ import argparse
9
+
10
+ def extract_dict_strings(text):
11
+ """
12
+ 从文本中提取所有类似字典格式的字符串
13
+ 支持多种格式:单引号、双引号、带换行符等
14
+ """
15
+ # patterns = [r"{'TimeStamp': (\d+\.\d+), 'GL': (\d+), 'Graph': (\d+), 'ark ts heap': (\d+), 'native heap': (\d+), 'AnonPage other': (\d+), 'FilePage other': (\d+), 'Total': (\d+), 'jemalloc heap': (\d+)}"]
16
+ patterns = [
17
+ # 宽松格式,匹配包含这些字段的任何字典
18
+ r"\{[^{}]*'GL'[^{}]*\}",
19
+ r"\{[^{}]*\"GL\"[^{}]*\}",
20
+ ]
21
+ all_matches = []
22
+ for pattern in patterns:
23
+ matches = re.findall(pattern, text, re.DOTALL)
24
+ all_matches.extend(matches)
25
+
26
+ return all_matches
27
+
28
+
29
+ def parse_dict_string(dict_str):
30
+ """
31
+ 将字典字符串解析为Python字典
32
+ """
33
+ try:
34
+ # 方法1: 使用ast.literal_eval (安全)
35
+ return ast.literal_eval(dict_str)
36
+ except:
37
+ try:
38
+ # 方法2: 使用json.loads (需要双引号)
39
+ # 将单引号替换为双引号
40
+ json_str = dict_str.replace("'", "\"")
41
+ return json.loads(json_str)
42
+ except:
43
+ try:
44
+ # 方法3: 使用eval (不安全,但作为备选)
45
+ # 注意:在生产环境中应避免使用eval
46
+ return eval(dict_str)
47
+ except:
48
+ print(f"无法解析字符串: {dict_str[:100]}...")
49
+ return None
50
+
51
+ def process_file(filename):
52
+ """
53
+ 处理文件并计算统计信息
54
+ """
55
+ try:
56
+ with open(filename, 'r', encoding='utf-8') as file:
57
+ content = file.read()
58
+ except UnicodeDecodeError:
59
+ # 如果UTF-8失败,尝试其他编码
60
+ try:
61
+ with open(filename, 'r', encoding='latin-1') as file:
62
+ content = file.read()
63
+ except Exception as e:
64
+ print(f"读取文件失败: {e}")
65
+ return None, None
66
+
67
+ # 提取所有字典字符串
68
+ dict_strings = extract_dict_strings(content)
69
+ print(f"找到 {len(dict_strings)} 个匹配的字典")
70
+
71
+ # 解析所有字典
72
+ data_points = []
73
+ for i, dict_str in enumerate(dict_strings):
74
+ parsed_dict = parse_dict_string(dict_str)
75
+ if parsed_dict:
76
+ data_points.append(parsed_dict)
77
+ if i < 5: # 打印前5个作为示例
78
+ print(f"示例 {i+1}: {parsed_dict}")
79
+
80
+ if not data_points:
81
+ print("未找到有效的数据点")
82
+ return None, None
83
+
84
+ # 收集所有字段的值
85
+ field_values = defaultdict(list)
86
+ for data_point in data_points:
87
+ for key, value in data_point.items():
88
+ # 只处理数值类型的值
89
+ if isinstance(value, (int, float)):
90
+ field_values[key].append(value)
91
+
92
+ # 计算统计信息
93
+ statistics = {}
94
+ for field, values in field_values.items():
95
+ if values:
96
+ statistics[field] = {
97
+ 'count': len(values),
98
+ 'mean': sum(values) / len(values),
99
+ 'max': max(values),
100
+ 'min': min(values),
101
+ 'sum': sum(values)
102
+ }
103
+
104
+ return statistics, len(data_points)
105
+
106
+ def print_statistics(statistics, total_points):
107
+ """
108
+ 打印统计结果
109
+ """
110
+ print("\n" + "="*80)
111
+ print(f"统计结果 (基于 {total_points} 个数据点)")
112
+ print("="*80)
113
+
114
+ if not statistics:
115
+ print("没有可用的统计数据")
116
+ return
117
+
118
+ # 按字段名排序
119
+ sorted_fields = sorted(statistics.keys())
120
+
121
+ print(f"{'字段名':<20} {'数据点数':<10} {'平均值':<15} {'最大值':<15} {'最小值':<15} {'总和':<15}")
122
+ print("-" * 90)
123
+
124
+ for field in sorted_fields:
125
+ stats = statistics[field]
126
+ print(f"{field:<20} {stats['count']:<10} {stats['mean']:<15.2f} {stats['max']:<15.2f} {stats['min']:<15.2f} {stats['sum']:<15.2f}")
127
+
128
+ def save_statistics(statistics, total_points, output_file):
129
+ """
130
+ 将统计结果保存到文件
131
+ """
132
+ try:
133
+ with open(output_file, 'w', encoding='utf-8') as f:
134
+ f.write(f"统计结果 (基于 {total_points} 个数据点)\n")
135
+ f.write("="*50 + "\n")
136
+
137
+ # JSON格式保存详细数据
138
+ output_data = {
139
+ 'total_data_points': total_points,
140
+ 'statistics': statistics
141
+ }
142
+ json.dump(output_data, f, indent=2, ensure_ascii=False)
143
+
144
+ print(f"\n详细统计结果已保存到: {output_file}")
145
+ except Exception as e:
146
+ print(f"保存文件失败: {e}")
147
+
148
+ def main():
149
+ parser = argparse.ArgumentParser(description='分析文本中的字典数据并计算统计信息')
150
+ parser.add_argument('filename', help='要分析的文本文件路径')
151
+ parser.add_argument('-o', '--output', help='输出结果文件路径(可选)')
152
+ parser.add_argument('-v', '--verbose', action='store_true', help='显示详细信息')
153
+
154
+ args = parser.parse_args()
155
+
156
+ if args.verbose:
157
+ print(f"开始分析文件: {args.filename}")
158
+
159
+ statistics, total_points = process_file(args.filename)
160
+
161
+ if statistics:
162
+ print_statistics(statistics, total_points)
163
+
164
+ if args.output:
165
+ save_statistics(statistics, total_points, args.output)
166
+
167
+ # 生成简单的统计摘要
168
+ print("\n" + "="*50)
169
+ print("统计摘要")
170
+ print("="*50)
171
+ for field, stats in statistics.items():
172
+ print(f"{field}:\t平均值={stats['mean']:.2f},\t最大值={stats['max']:.2f},数据点={stats['count']}")
173
+
174
+ if __name__ == "__main__":
175
+ main()
@@ -0,0 +1,14 @@
1
+ # test get detached nodes
2
+ node ../packages/meminsight/dist/Index.js ark-stat -t "${target}" -m 1 -f ${output_file}
3
+
4
+ # test get gc roots
5
+ node ../packages/meminsight/dist/Index.js ark-stat -t "${target}" -m 2 -f ${output_file}
6
+
7
+ # test get shortest path to node
8
+ node ../packages/meminsight/dist/Index.js ark-stat -t "${target}" -m 3 -i ${node_id} -f ${output_file}
9
+
10
+ # test get aggration paths
11
+ node ../packages/meminsight/dist/Index.js ark-stat -t "${target}" -m 4 -c ./packages/cfg/ArkStatCfg.json -f ${output_file}
12
+
13
+ # test get nodes by configuration
14
+ node ../packages/meminsight/dist/Index.js ark-stat -t "${target}" -m 5 -c ./packages/cfg/ArkStatCfg.json -f ${output_file}
@@ -0,0 +1,38 @@
1
+ {
2
+ "compilerOptions": {
3
+ "outDir": "./dist",
4
+ "allowJs": true,
5
+ "module": "commonjs",
6
+ "target": "es2015",
7
+ "esModuleInterop": true,
8
+ "composite": true,
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "incremental": true,
12
+ "strict": true,
13
+ "strictPropertyInitialization": false,
14
+ "noEmitOnError": true,
15
+ "moduleResolution": "node",
16
+ "types": [
17
+ "node",
18
+ "jest"
19
+ ],
20
+ "paths": {
21
+ "@meminsight/core": [
22
+ "./packages/core/src"
23
+ ],
24
+ "@meminsight/cmd": [
25
+ "./packages/meminsight/src"
26
+ ]
27
+ }
28
+ },
29
+ "include": [
30
+ "./src",
31
+ "./packages/**/src"
32
+ ],
33
+ "exclude": [
34
+ "./node_modules",
35
+ "./dist",
36
+ "./packages/**/dist"
37
+ ]
38
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ {
5
+ "path": "./packages/core",
6
+ },
7
+ ],
8
+ }