1 /*
2 * Copyright (c) 2023-2024 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 #include <dlfcn.h>
16 #include <fcntl.h>
17 #include <fstream>
18 #include <iostream>
19 #include <regex>
20 #include <string>
21
22 #include "common_utils.h"
23 #include "file_util.h"
24 #include "string_util.h"
25 #include "memory_collector.h"
26
27 #include <gtest/gtest.h>
28
29 using namespace testing::ext;
30 using namespace OHOS::HiviewDFX;
31 using namespace OHOS::HiviewDFX::UCollectUtil;
32 using namespace OHOS::HiviewDFX::UCollect;
33
34 class MemoryCollectorTest : public testing::Test {
35 public:
SetUp()36 void SetUp() {};
TearDown()37 void TearDown() {};
SetUpTestCase()38 static void SetUpTestCase() {};
TearDownTestCase()39 static void TearDownTestCase() {};
40 };
41
42 #ifdef UNIFIED_COLLECTOR_MEMORY_ENABLE
43 namespace {
44 // eg: 123 ab-cd 456 789 0 -123 0
45 // 123 ab cd 0 0 0 0 0
46 const std::regex ALL_PROC_MEM1("^\\d{1,}\\s{1,}[\\w\\.\\[\\]():/>-]*(\\s{1,}\\d{1,}){3}\\s{1,}-?\\d{1,}\\s{1,}-?[01]$");
47 const std::regex ALL_PROC_MEM2("^\\d{1,}\\s{1,}\\w{1,}( \\w{1,}){1,}(\\s{1,}\\d{1,}){3}\\s{1,}-?\\d{1,}\\s{1,}-?[01]$");
48 // eg: ab.cd 12 34 567 890 123 ef gh ijk
49 // Total dmabuf size of ab.cd: 12345 bytes
50 const std::string RAW_DMA1_STR1("^[\\w\\.\\[\\]():/>-]{1,}(\\s{1,}\\d{1,}){5}(\\s{1,}\\w{1,}){3}");
51 const std::string RAW_DMA1_STR2("(\\s{1,}\\d{1,}){0,2}(\\s{1,}\\w{1,}\\s{1,})?$");
52 const std::regex RAW_DMA1(RAW_DMA1_STR1 + RAW_DMA1_STR2);
53 const std::regex RAW_DMA2("^(Total dmabuf size of )[\\w\\.\\[\\]():/>-]{1,}(: )\\d{1,}( bytes)$");
54 // eg: ab(cd): 12345 kB
55 // ab: - kB
56 const std::regex RAW_MEM_INFO1("^[\\w()]{1,}:\\s{1,}\\d{1,}( kB)?$");
57 const std::regex RAW_MEM_INFO2("^[\\w()]{1,}:\\s{1,}- kB$");
58 // eg: ab-cd: 12345 kB
59 // ab-cd 12345 (0 in SwapPss) kB
60 const std::regex RAW_MEM_VIEW_INFO1("^[\\w\\s()-]{1,}:?\\s{1,}\\w{1,}( kB| \\%)?$");
61 const std::regex RAW_MEM_VIEW_INFO2("^\\w{1,}[-\\.]\\w{1,}(-\\w{1,})?\\s{1,}\\d{1,} \\(\\d{1,} in SwapPss\\) (kB)$");
62 // eg: Node 0, zone abc, type def 0 0 0 0 0 0 0 0 0 0 0
63 // ab cd efg hi jk lmn opq rst uvw xyz
64 const std::string RAW_PAGE_TYPE_STR1("^(Node)\\s{1,}\\d{1,}(, zone)\\s{1,}\\w{1,}((, type)\\s{1,}\\w{1,})?");
65 const std::string RAW_PAGE_TYPE_STR2("(\\s{1,}\\d{1,}){5,} $");
66 const std::regex RAW_PAGE_TYPE_INFO1(RAW_PAGE_TYPE_STR1 + RAW_PAGE_TYPE_STR2);
67 const std::regex RAW_PAGE_TYPE_INFO2("^(\\w{1,}\\s{1,}){5,}$");
68 // eg: abc 12 34 5 678 9 : tunables 1 2 3 : slabdata 4 5 6
69 // abc - version: 1.2
70 // #name <ab> <cd> <ef> <hi> <jk> : tunables <lmn> <opq> <rst> : slabdata <uv> <wx> <yz>
71 const std::string RAW_SLAB_STR1("^[\\w\\.\\[\\]():/>-]{1,}(\\s{1,}\\d{1,}){5}( : tunables)(\\s{1,}\\d{1,}){3}");
72 const std::string RAW_SLAB_STR2("( : slabdata)(\\s{1,}\\d{1,}){3,5}(\\s{1,}\\w{1,})?$");
73 const std::regex RAW_SLAB_INFO1(RAW_SLAB_STR1 + RAW_SLAB_STR2);
74 const std::string RAW_SLAB_STR3("^(\\w{1,} - version: )[\\d\\.]{1,}|# ?name\\s{1,}");
75 const std::string RAW_SLAB_STR4("( <\\w{1,}>){5} : tunables( <\\w{1,}>){3} : slabdata( <\\w{1,}>){3,5}$");
76 const std::regex RAW_SLAB_INFO2(RAW_SLAB_STR3 + RAW_SLAB_STR4);
77 const std::regex RAW_SLAB_INFO3("-{52}");
78
HasValidAILibrary()79 bool HasValidAILibrary()
80 {
81 const std::string libName = "libai_mnt_client.so";
82 void* handle = dlopen(libName.c_str(), RTLD_LAZY);
83 return handle != nullptr;
84 }
85
CheckFormat(const std::string & fileName,const std::vector<std::regex> & regexs,int cnt)86 bool CheckFormat(const std::string &fileName, const std::vector<std::regex>& regexs, int cnt)
87 {
88 std::ifstream file;
89 file.open(fileName.c_str());
90 if (!file.is_open()) {
91 return false;
92 }
93 std::string line;
94 while (cnt--) {
95 getline(file, line);
96 }
97 while (getline(file, line)) {
98 if (line.size() > 0 && line[line.size() - 1] == '\r') {
99 line.erase(line.size() - 1, 1);
100 }
101 if (line.size() == 0) {
102 continue;
103 }
104
105 bool isMatch = false;
106 for (const auto& reg : regexs) {
107 if (regex_match(line, reg)) {
108 isMatch = true;
109 break;
110 }
111 }
112 if (!isMatch) {
113 file.close();
114 return false;
115 }
116 }
117 file.close();
118 return true;
119 }
120 }
121
122 /**
123 * @tc.name: MemoryCollectorTest001
124 * @tc.desc: used to test MemoryCollector.CollectProcessMemory
125 * @tc.type: FUNC
126 */
127 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest001, TestSize.Level1)
128 {
129 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
130 CollectResult<ProcessMemory> data = collector->CollectProcessMemory(1); // init process id
131 std::cout << "collect process memory result" << data.retCode << std::endl;
132 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
133 data = collector->CollectProcessMemory(-1); // invalid process id
134 std::cout << "collect process memory result" << data.retCode << std::endl;
135 ASSERT_TRUE(data.retCode == UcError::READ_FAILED);
136 }
137
138 /**
139 * @tc.name: MemoryCollectorTest002
140 * @tc.desc: used to test MemoryCollector.CollectSysMemory
141 * @tc.type: FUNC
142 */
143 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest002, TestSize.Level1)
144 {
145 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
146 CollectResult<SysMemory> data = collector->CollectSysMemory();
147 std::cout << "collect system memory result" << data.retCode << std::endl;
148 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
149 }
150
151 /**
152 * @tc.name: MemoryCollectorTest003
153 * @tc.desc: used to test MemoryCollector.CollectRawMemInfo
154 * @tc.type: FUNC
155 */
156 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest003, TestSize.Level1)
157 {
158 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
159 CollectResult<std::string> data = collector->CollectRawMemInfo();
160 std::cout << "collect raw memory info result" << data.retCode << std::endl;
161 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
162 bool flag = CheckFormat(data.data, {RAW_MEM_INFO1, RAW_MEM_INFO2}, 0); // 0: don't skip the first line
163 ASSERT_TRUE(flag);
164 }
165
166 /**
167 * @tc.name: MemoryCollectorTest004
168 * @tc.desc: used to test MemoryCollector.CollectAllProcessMemory
169 * @tc.type: FUNC
170 */
171 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest004, TestSize.Level1)
172 {
173 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
174 CollectResult<std::vector<ProcessMemory>> data = collector->CollectAllProcessMemory();
175 std::cout << "collect all process memory result" << data.retCode << std::endl;
176 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
177 }
178
179 /**
180 * @tc.name: MemoryCollectorTest005
181 * @tc.desc: used to test MemoryCollector.ExportAllProcessMemory
182 * @tc.type: FUNC
183 */
184 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest005, TestSize.Level1)
185 {
186 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
187 CollectResult<std::string> data = collector->ExportAllProcessMemory();
188 std::cout << "export all process memory result" << data.retCode << std::endl;
189 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
190 bool flag = CheckFormat(data.data, {ALL_PROC_MEM1, ALL_PROC_MEM2}, 1); // 1: skip the first line
191 ASSERT_TRUE(flag);
192 }
193
194 /**
195 * @tc.name: MemoryCollectorTest006
196 * @tc.desc: used to test MemoryCollector.CollectRawSlabInfo
197 * @tc.type: FUNC
198 */
199 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest006, TestSize.Level1)
200 {
201 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
202 CollectResult<std::string> data = collector->CollectRawSlabInfo();
203 std::cout << "collect raw slab info result" << data.retCode << std::endl;
204 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
205 bool flag = CheckFormat(data.data,
206 {RAW_SLAB_INFO1, RAW_SLAB_INFO2, RAW_SLAB_INFO3}, 0); // 0: don't skip the first line
207 ASSERT_TRUE(flag);
208 }
209
210 /**
211 * @tc.name: MemoryCollectorTest007
212 * @tc.desc: used to test MemoryCollector.CollectRawPageTypeInfo
213 * @tc.type: FUNC
214 */
215 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest007, TestSize.Level1)
216 {
217 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
218 CollectResult<std::string> data = collector->CollectRawPageTypeInfo();
219 std::cout << "collect raw pagetype info result" << data.retCode << std::endl;
220 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
221 bool flag = CheckFormat(data.data, {RAW_PAGE_TYPE_INFO1, RAW_PAGE_TYPE_INFO2}, 4); // 4: skip the first four lines
222 ASSERT_TRUE(flag);
223 }
224
225 /**
226 * @tc.name: MemoryCollectorTest008
227 * @tc.desc: used to test MemoryCollector.CollectRawDMA
228 * @tc.type: FUNC
229 */
230 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest008, TestSize.Level1)
231 {
232 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
233 CollectResult<std::string> data = collector->CollectRawDMA();
234 std::cout << "collect raw DMA result" << data.retCode << std::endl;
235 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
236 bool flag = CheckFormat(data.data, {RAW_DMA1, RAW_DMA2}, 2); // 2: skip the first two lines
237 ASSERT_TRUE(flag);
238 }
239
240 /**
241 * @tc.name: MemoryCollectorTest009
242 * @tc.desc: used to test MemoryCollector.CollectAllAIProcess
243 * @tc.type: FUNC
244 */
245 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest009, TestSize.Level1)
246 {
247 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
248 CollectResult<std::vector<AIProcessMem>> data = collector->CollectAllAIProcess();
249 std::cout << "collect all AI process result" << data.retCode << std::endl;
250 if (HasValidAILibrary()) {
251 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
252 } else {
253 ASSERT_TRUE(data.retCode == UcError::READ_FAILED);
254 }
255 }
256
257 /**
258 * @tc.name: MemoryCollectorTest010
259 * @tc.desc: used to test MemoryCollector.ExportAllAIProcess
260 * @tc.type: FUNC
261 */
262 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest010, TestSize.Level1)
263 {
264 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
265 CollectResult<std::string> data = collector->ExportAllAIProcess();
266 std::cout << "export all AI process result" << data.retCode << std::endl;
267 if (HasValidAILibrary()) {
268 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
269 } else {
270 ASSERT_TRUE(data.retCode == UcError::READ_FAILED);
271 }
272 }
273
274 /**
275 * @tc.name: MemoryCollectorTest011
276 * @tc.desc: used to test MemoryCollector.CollectRawSmaps
277 * @tc.type: FUNC
278 */
279 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest011, TestSize.Level1)
280 {
281 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
282 CollectResult<std::string> data = collector->CollectRawSmaps(1);
283 std::cout << "collect raw smaps info result" << data.retCode << std::endl;
284 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
285 }
286
287 /**
288 * @tc.name: MemoryCollectorTest012
289 * @tc.desc: used to test MemoryCollector.CollectHprof
290 * @tc.type: FUNC
291 */
292 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest012, TestSize.Level1)
293 {
294 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
295 CollectResult<std::string> data = collector->CollectHprof(1);
296 std::cout << "collect heap snapshot result" << data.retCode << std::endl;
297 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
298 }
299
300 /**
301 * @tc.name: MemoryCollectorTest013
302 * @tc.desc: used to test MemoryCollector.CollectProcessVss
303 * @tc.type: FUNC
304 */
305 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest013, TestSize.Level1)
306 {
307 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
308 CollectResult<uint64_t> data = collector->CollectProcessVss(1000);
309 std::cout << "collect processvss result" << data.retCode << std::endl;
310 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
311 }
312
313 /**
314 * @tc.name: MemoryCollectorTest014
315 * @tc.desc: used to test MemoryCollector.CollectMemoryLimit
316 * @tc.type: FUNC
317 */
318 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest014, TestSize.Level1)
319 {
320 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
321 CollectResult<MemoryLimit> data = collector->CollectMemoryLimit();
322 std::cout << "collect memoryLimit result" << data.retCode << std::endl;
323 ASSERT_TRUE(data.retCode == UcError::SUCCESS);
324 }
325
326 /**
327 * @tc.name: MemoryCollectorTest015
328 * @tc.desc: used to test MemoryCollector.ExportMemView
329 * @tc.type: FUNC
330 */
331 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest015, TestSize.Level1)
332 {
333 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
334 CollectResult<std::string> data = collector->ExportMemView();
335 std::cout << "collect raw memory view info result" << data.retCode << std::endl;
336 if (FileUtil::FileExists("/proc/memview")) {
337 ASSERT_EQ(data.retCode, UcError::SUCCESS);
338 bool flag = CheckFormat(data.data, {RAW_MEM_VIEW_INFO1, RAW_MEM_VIEW_INFO2}, 0); // 0: don't skip the first line
339 ASSERT_TRUE(flag);
340 } else {
341 ASSERT_EQ(data.retCode, UcError::UNSUPPORT);
342 }
343 }
344
345 /**
346 * @tc.name: MemoryCollectorTest016
347 * @tc.desc: used to test MemoryCollector.CollectDdrFreq
348 * @tc.type: FUNC
349 */
350 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest016, TestSize.Level1)
351 {
352 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
353 CollectResult<uint32_t> data = collector->CollectDdrFreq();
354 std::cout << "collect DDR current frequency info result" << data.retCode << std::endl;
355 if (!FileUtil::FileExists("/sys/class/devfreq/ddrfreq/cur_freq")) {
356 ASSERT_EQ(data.retCode, UcError::UNSUPPORT);
357 } else {
358 ASSERT_EQ(data.retCode, UcError::SUCCESS);
359 ASSERT_GT(data.data, 0);
360 }
361 }
362
363 /**
364 * @tc.name: MemoryCollectorTest017
365 * @tc.desc: used to test MemoryCollector.CollectDdrFreq
366 * @tc.type: FUNC
367 */
368 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest017, TestSize.Level1)
369 {
370 std::cout << "MemoryCollector test" << std::endl;
371 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
372 auto data = collector->CollectProcessMemoryDetail(1, false);
373 std::cout << "collect processMemoryDetail result" << data.retCode << std::endl;
374 ASSERT_EQ(data.data.name, "init");
375 ASSERT_GT(data.data.totalPss, 0);
376 ASSERT_GT(data.data.details.size(), 0);
377 auto data2 = collector->CollectProcessMemoryDetail(1, true);
378 ASSERT_EQ(data2.retCode, UcError::SUCCESS);
379 auto data3 = collector->CollectProcessMemoryDetail(1, true);
380 ASSERT_EQ(data3.retCode, UcError::SUCCESS);
381 }
382 #else
383 /**
384 * @tc.name: MemoryCollectorTest001
385 * @tc.desc: used to test empty MemoryCollector
386 * @tc.type: FUNC
387 */
388 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest001, TestSize.Level1)
389 {
390 std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
391 auto ret1 = collector->CollectProcessMemory(0);
392 ASSERT_EQ(ret1.retCode, UcError::FEATURE_CLOSED);
393
394 auto ret2 = collector->CollectSysMemory();
395 ASSERT_EQ(ret2.retCode, UcError::FEATURE_CLOSED);
396
397 auto ret3 = collector->CollectRawMemInfo();
398 ASSERT_EQ(ret3.retCode, UcError::FEATURE_CLOSED);
399
400 auto ret4 = collector->ExportMemView();
401 ASSERT_EQ(ret4.retCode, UcError::FEATURE_CLOSED);
402
403 auto ret5 = collector->CollectAllProcessMemory();
404 ASSERT_EQ(ret5.retCode, UcError::FEATURE_CLOSED);
405
406 auto ret6 = collector->ExportAllProcessMemory();
407 ASSERT_EQ(ret6.retCode, UcError::FEATURE_CLOSED);
408
409 auto ret7 = collector->CollectRawSlabInfo();
410 ASSERT_EQ(ret7.retCode, UcError::FEATURE_CLOSED);
411
412 auto ret8 = collector->CollectRawPageTypeInfo();
413 ASSERT_EQ(ret8.retCode, UcError::FEATURE_CLOSED);
414
415 auto ret9 = collector->CollectRawDMA();
416 ASSERT_EQ(ret9.retCode, UcError::FEATURE_CLOSED);
417
418 auto ret10 = collector->CollectAllAIProcess();
419 ASSERT_EQ(ret10.retCode, UcError::FEATURE_CLOSED);
420
421 auto ret11 = collector->ExportAllAIProcess();
422 ASSERT_EQ(ret11.retCode, UcError::FEATURE_CLOSED);
423
424 auto ret12 = collector->CollectRawSmaps(0);
425 ASSERT_EQ(ret12.retCode, UcError::FEATURE_CLOSED);
426
427 auto ret13 = collector->CollectHprof(0);
428 ASSERT_EQ(ret13.retCode, UcError::FEATURE_CLOSED);
429
430 auto ret14 = collector->CollectProcessVss(0);
431 ASSERT_EQ(ret14.retCode, UcError::FEATURE_CLOSED);
432
433 auto ret15 = collector->CollectMemoryLimit();
434 ASSERT_EQ(ret15.retCode, UcError::FEATURE_CLOSED);
435
436 auto ret16 = collector->CollectDdrFreq();
437 ASSERT_EQ(ret16.retCode, UcError::FEATURE_CLOSED);
438
439 auto ret17 = collector->CollectProcessMemoryDetail(0);
440 ASSERT_EQ(ret17.retCode, UcError::FEATURE_CLOSED);
441 }
442 #endif
443