• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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