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