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,82 @@
1
+ import * as fse from 'fs-extra';
2
+ import { Log, ILoggable } from '../utils/Log';
3
+
4
+ /**
5
+ * interface of reader
6
+ */
7
+ export interface IReader {
8
+ getType(): string;
9
+ readFromFile<T>(filepath: string, encoding: BufferEncoding): Promise<T | undefined>;
10
+ }
11
+
12
+ /**
13
+ * base reader
14
+ */
15
+ export abstract class BaseReader implements ILoggable, IReader {
16
+ public readonly DOMAIN: string;
17
+ public readonly TAG: string;
18
+ protected type: string;
19
+ /**
20
+ * get type
21
+ * @returns type
22
+ */
23
+ public getType(): string {
24
+ return this.type;
25
+ }
26
+
27
+ /**
28
+ * write to file
29
+ * @param file filepath
30
+ * @param data data
31
+ * @returns T | undefined
32
+ */
33
+ public async readFromFile<T>(
34
+ filepath: string,
35
+ encoding: BufferEncoding = 'utf-8'): Promise<T | undefined> {
36
+ return undefined;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * JsonReader
42
+ */
43
+ export class JsonReader extends BaseReader {
44
+ public readonly DOMAIN: string;
45
+ public readonly TAG: string;
46
+ protected type: string;
47
+ private static _instance: JsonReader;
48
+
49
+ constructor() {
50
+ super()
51
+ this.DOMAIN = 'meminsight';
52
+ this.TAG = JsonReader.name;
53
+ this.type = JsonReader.name;
54
+ }
55
+
56
+ /**
57
+ * JsonReader instance
58
+ * @returns instance
59
+ */
60
+ public static instance(): JsonReader {
61
+ if (!JsonReader._instance) {
62
+ JsonReader._instance = new JsonReader();
63
+ }
64
+ return JsonReader._instance;
65
+ }
66
+
67
+ /**
68
+ * read json file
69
+ * @param filepath json file path
70
+ * @param encode encoding, default is utf-
71
+ * @returns T | undefined
72
+ */
73
+ public async readFromFile<T>(filepath: string,
74
+ encoding: BufferEncoding = 'utf-8') : Promise<T | undefined> {
75
+ try {
76
+ return fse.readJSONSync(filepath, encoding) as T;
77
+ } catch (error) {
78
+ Log.errorX(this, `Failed to read json from file, Status Code: ${error}`)
79
+ return undefined;
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,50 @@
1
+ import { createWriteStream } from 'fs';
2
+ import axios from 'axios';
3
+ import { Log, ILoggable } from '../utils/Log';
4
+
5
+ /**
6
+ * File Service
7
+ */
8
+ export class FileService implements ILoggable {
9
+ public readonly DOMAIN = 'meminsight';
10
+ public readonly TAG = FileService.name;
11
+ private static _instance: FileService;
12
+ private constructor() {}
13
+
14
+ /**
15
+ * FileService instance
16
+ * @returns FileService instance
17
+ */
18
+ public static instance(): FileService {
19
+ if (!FileService._instance) {
20
+ FileService._instance = new FileService();
21
+ }
22
+ return FileService._instance;
23
+ }
24
+
25
+ /**
26
+ *
27
+ * @param url file url
28
+ * @param filepath filepath
29
+ * @returns
30
+ */
31
+ public async download(url: string, filepath: string): Promise<void> {
32
+ const response = await axios({
33
+ url,
34
+ method: 'GET',
35
+ responseType: 'stream'
36
+ });
37
+ const fileWriter = createWriteStream(filepath);
38
+ response.data.pipe(fileWriter);
39
+ return new Promise((resolve, reject) => {
40
+ fileWriter.on('finish', () => {
41
+ Log.infoX(this, `File ${url} downloaded to ${filepath} successfully`);
42
+ resolve();
43
+ });
44
+ fileWriter.on('error', (err) => {
45
+ Log.errorX(this, `Failed to download file ${url}, Status code: ${err}`);
46
+ reject(err);
47
+ });
48
+ });
49
+ }
50
+ }
@@ -0,0 +1,148 @@
1
+
2
+ import * as fse from 'fs-extra';
3
+ import { ILoggable } from '../utils/Log';
4
+
5
+ /**
6
+ * writer interface
7
+ */
8
+ export interface IWriter {
9
+ /**
10
+ * get type of writer
11
+ */
12
+ getType(): string;
13
+
14
+ /**
15
+ * write to file
16
+ * @param file filepath
17
+ * @param data data
18
+ * @param encode encode, default is utf-8
19
+ */
20
+ writeToFile(filepath: string, data: any, encode: BufferEncoding): Promise<void>;
21
+ }
22
+
23
+ /**
24
+ * base writer
25
+ */
26
+ export class BaseWriter implements ILoggable, IWriter {
27
+ public readonly DOMAIN: string;
28
+ public readonly TAG: string;
29
+ protected type: string;
30
+
31
+ /**
32
+ * get type
33
+ * @returns type
34
+ */
35
+ public getType(): string {
36
+ return this.type;
37
+ }
38
+
39
+ /**
40
+ * write to file
41
+ * @param file filepath
42
+ * @param data data
43
+ * @param encoding encoding, default is utf-8
44
+ */
45
+ public async writeToFile(filepath: string, data: any, encoding: BufferEncoding): Promise<void> {
46
+ const buf = Buffer.isBuffer(data) ? data : Buffer.from(data, encoding);
47
+ fse.outputFileSync(filepath, buf);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * text writer
53
+ */
54
+ export class TextWriter extends BaseWriter {
55
+ public readonly DOMAIN: string;
56
+ public readonly TAG: string;
57
+ protected type: string;
58
+ protected static _instance: IWriter;
59
+
60
+ public static instance(): IWriter {
61
+ if (this._instance == null) {
62
+ this._instance = new TextWriter();
63
+ }
64
+ return this._instance;
65
+ }
66
+
67
+ constructor() {
68
+ super();
69
+ this.DOMAIN = 'meminsight';
70
+ this.TAG = TextWriter.name;
71
+ this.type = TextWriter.name;
72
+ }
73
+
74
+ public async writeToFile(filepath: string, data: any, encoding: BufferEncoding): Promise<void> {
75
+ super.writeToFile(filepath, data, encoding);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * json writer
81
+ */
82
+ export class JsonWriter extends BaseWriter {
83
+ public readonly DOMAIN: string;
84
+ public readonly TAG: string;
85
+ protected type: string;
86
+ protected static _instance: IWriter;
87
+
88
+ public static instance(): IWriter {
89
+ if (this._instance == null) {
90
+ this._instance = new JsonWriter();
91
+ }
92
+ return this._instance;
93
+ }
94
+
95
+ constructor() {
96
+ super();
97
+ this.DOMAIN = 'meminsight';
98
+ this.TAG = JsonWriter.name;
99
+ this.type = JsonWriter.name;
100
+ }
101
+
102
+ public async writeToFile(filepath: string, data: any, encoding: BufferEncoding): Promise<void> {
103
+ fse.outputJSONSync(filepath, data, { encoding: encoding, spaces: 4 });
104
+ }
105
+ }
106
+
107
+ /**
108
+ * html writer
109
+ */
110
+ export class HtmlWriter extends BaseWriter {
111
+ public readonly DOMAIN: string;
112
+ public readonly TAG: string;
113
+ protected type: string;
114
+ protected static _instance: IWriter;
115
+
116
+ public static instance(): IWriter {
117
+ if (this._instance == null) {
118
+ this._instance = new HtmlWriter();
119
+ }
120
+ return this._instance;
121
+ }
122
+
123
+ constructor() {
124
+ super();
125
+ this.DOMAIN = 'meminsight';
126
+ this.TAG = HtmlWriter.name;
127
+ this.type = HtmlWriter.name;
128
+ }
129
+
130
+ public async writeToFile(filepath: string, data: any, encoding: BufferEncoding): Promise<void> {
131
+ super.writeToFile(filepath, data, encoding);
132
+ }
133
+
134
+ /**
135
+ * 从template读取数据并将data插入模板数据中
136
+ * @param template 模板路径
137
+ * @param data 待插入数据
138
+ * @param delimiter 分隔符
139
+ * @return 插入data后的模板数据
140
+ */
141
+ public getDataByTemplate(template: string, data: string, delimiter: string): string {
142
+ const templateStrs = fse.readFileSync(template, 'utf-8').split(delimiter);
143
+ if (templateStrs.length !== 2) {
144
+ return '';
145
+ }
146
+ return templateStrs[0] + delimiter + data + templateStrs[1];
147
+ }
148
+ }
@@ -0,0 +1,81 @@
1
+ import ejs from 'ejs';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { formatDate } from '../utils/Common'
5
+ import { TEMPLATE_CTX } from './templates/template';
6
+
7
+ export interface ReportConfig {
8
+ fileName: string;
9
+ fileTitle: string;
10
+ createTime: string;
11
+ data: ReportData[];
12
+ }
13
+
14
+ export interface ReportTable {
15
+ [key: string]: any;
16
+ }
17
+
18
+ export interface ReportData {
19
+ feature: string;
20
+ messages: string[];
21
+ columns: Map<string, string>;
22
+ data: ReportTable;
23
+ }
24
+
25
+ export class ReporterHTML {
26
+ /**
27
+ * 生成HTML
28
+ */
29
+ private static generate(config: ReportConfig): string {
30
+ const templateData = {
31
+ title: config.fileTitle,
32
+ time: config.createTime,
33
+ data: config.data
34
+ };
35
+
36
+ return ejs.render(TEMPLATE_CTX, templateData);
37
+ }
38
+
39
+ /**
40
+ * 生成并保存HTML
41
+ */
42
+ private static generateAndSave(config: ReportConfig, outputDir?: string): string {
43
+ const html = this.generate(config);
44
+
45
+ // 确定输出目录
46
+ const dir = outputDir || path.join(process.cwd(), 'output');
47
+ if (!fs.existsSync(dir)) {
48
+ fs.mkdirSync(dir, { recursive: true });
49
+ }
50
+
51
+ // 确定文件名
52
+ const fileName = config.fileName || `${config.fileTitle.replace(/\s+/g, '-')}.html`;
53
+ const filePath = path.join(dir, fileName);
54
+
55
+ // 保存文件
56
+ fs.writeFileSync(filePath, html, 'utf-8');
57
+
58
+ return filePath;
59
+ }
60
+
61
+ public static generateByTemplate(datas: ReportData[], fileName?: string) {
62
+ let generateTime = formatDate(new Date());
63
+ let fileConfig: ReportConfig = {
64
+ fileName: `${fileName ? fileName.split('.')[0] : 'report'}-${generateTime}.html`,
65
+ fileTitle: `${fileName || ''} 内存分析报告`,
66
+ createTime: generateTime,
67
+ data: datas
68
+ };
69
+ try {
70
+ const filePath = ReporterHTML.generateAndSave(fileConfig);
71
+ console.log('🎉 报告生成成功!');
72
+ console.log(`📁 文件: ${filePath}`);
73
+ console.log('🔗 用浏览器打开查看结果');
74
+ } catch (error) {
75
+ console.error('❌ 出错了:', error);
76
+ }
77
+ }
78
+ }
79
+
80
+ // 生成报告
81
+
@@ -0,0 +1,101 @@
1
+
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title><%= title %></title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ margin: 20px;
11
+ line-height: 1.6;
12
+ }
13
+ h1 { color: #333; }
14
+ .info {
15
+ color: #666;
16
+ margin-bottom: 20px;
17
+ padding: 10px;
18
+ background: #f5f5f5;
19
+ border-radius: 5px;
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: start;
23
+ }
24
+ table {
25
+ width: 100%;
26
+ border-collapse: collapse;
27
+ margin-top: 20px;
28
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
29
+ font-size: 14px;
30
+ }
31
+ th {
32
+ background-color: #4CAF50;
33
+ color: white;
34
+ padding: 12px;
35
+ text-align: left;
36
+ }
37
+ td {
38
+ padding: 10px;
39
+ border-bottom: 1px solid #ddd;
40
+ max-width: 300px;
41
+ word-break: break-word;
42
+ }
43
+ tr:hover {
44
+ background-color: #f5f5f5;
45
+ }
46
+ tr:nth-child(even) {
47
+ background-color: #f9f9f9;
48
+ }
49
+ .empty {
50
+ text-align: center;
51
+ color: #999;
52
+ padding: 20px;
53
+ }
54
+ .analyze-container {
55
+ display: flex;
56
+ flex-direction: column;
57
+ align-items: start;
58
+ }
59
+ </style>
60
+ </head>
61
+ <body>
62
+ <h1><%= title %></h1>
63
+ <div class="info">
64
+ 生成时间: <%= time %> | 共 <%= data.length %> 个功能
65
+ </div>
66
+ <% if (data.length === 0) { %>
67
+ <div class="empty">暂无数据</div>
68
+ <% } else { %>
69
+ <% data.forEach(function(analyze) { %>
70
+ <div class="analyze-container">
71
+ <h2><%= analyze.feature %></h2>
72
+ <div class="info">
73
+ <% analyze.messages.forEach(function(mes) { %>
74
+ <div>
75
+ <%= mes %>
76
+ </div>
77
+ <% }) %>
78
+ </div>
79
+ <table>
80
+ <thead>
81
+ <tr>
82
+ <% analyze.columns.forEach(function(value, key) { %>
83
+ <th><%= value %></th>
84
+ <% }); %>
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ <% analyze.data.forEach(function(row, index) { %>
89
+ <tr>
90
+ <% analyze.columns.forEach(function(value, col) { %>
91
+ <td><%= row[col] !== undefined ? row[col] : '-' %></td>
92
+ <% }); %>
93
+ </tr>
94
+ <% }); %>
95
+ </tbody>
96
+ </table>
97
+ </div>
98
+ <% }) %>
99
+ <% } %>
100
+ </body>
101
+ </html>
@@ -0,0 +1,103 @@
1
+ const TEMPLATE_CTX = `
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title><%= title %></title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ margin: 20px;
11
+ line-height: 1.6;
12
+ }
13
+ h1 { color: #333; }
14
+ .info {
15
+ color: #666;
16
+ margin-bottom: 20px;
17
+ padding: 10px;
18
+ background: #f5f5f5;
19
+ border-radius: 5px;
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: start;
23
+ }
24
+ table {
25
+ width: 100%;
26
+ border-collapse: collapse;
27
+ margin-top: 20px;
28
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
29
+ font-size: 14px;
30
+ }
31
+ th {
32
+ background-color: #4CAF50;
33
+ color: white;
34
+ padding: 12px;
35
+ text-align: left;
36
+ }
37
+ td {
38
+ padding: 10px;
39
+ border-bottom: 1px solid #ddd;
40
+ max-width: 300px;
41
+ word-break: break-word;
42
+ }
43
+ tr:hover {
44
+ background-color: #f5f5f5;
45
+ }
46
+ tr:nth-child(even) {
47
+ background-color: #f9f9f9;
48
+ }
49
+ .empty {
50
+ text-align: center;
51
+ color: #999;
52
+ padding: 20px;
53
+ }
54
+ .analyze-container {
55
+ display: flex;
56
+ flex-direction: column;
57
+ align-items: start;
58
+ }
59
+ </style>
60
+ </head>
61
+ <body>
62
+ <h1><%= title %></h1>
63
+ <div class="info">
64
+ 生成时间: <%= time %> | 共 <%= data.length %> 个功能
65
+ </div>
66
+ <% if (data.length === 0) { %>
67
+ <div class="empty">暂无数据</div>
68
+ <% } else { %>
69
+ <% data.forEach(function(analyze) { %>
70
+ <div class="analyze-container">
71
+ <h2><%= analyze.feature %></h2>
72
+ <div class="info">
73
+ <% analyze.messages.forEach(function(mes) { %>
74
+ <div>
75
+ <%= mes %>
76
+ </div>
77
+ <% }) %>
78
+ </div>
79
+ <table>
80
+ <thead>
81
+ <tr>
82
+ <% analyze.columns.forEach(function(value, key) { %>
83
+ <th><%= value %></th>
84
+ <% }); %>
85
+ </tr>
86
+ </thead>
87
+ <tbody>
88
+ <% analyze.data.forEach(function(row, index) { %>
89
+ <tr>
90
+ <% analyze.columns.forEach(function(value, col) { %>
91
+ <td><%= row[col] !== undefined ? row[col] : '-' %></td>
92
+ <% }); %>
93
+ </tr>
94
+ <% }); %>
95
+ </tbody>
96
+ </table>
97
+ </div>
98
+ <% }) %>
99
+ <% } %>
100
+ </body>
101
+ </html>
102
+ `
103
+ export { TEMPLATE_CTX }