1 /*
2  * Copyright (c) 2023 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 namespace {
43 // eg: 123   ab-cd   456 789 0   -123  0
44 //     123   ab cd   0   0   0   0     0
45 const std::regex ALL_PROC_MEM1("^\\d{1,}\\s{1,}[\\w\\.\\[\\]():/>-]*(\\s{1,}\\d{1,}){3}\\s{1,}-?\\d{1,}\\s{1,}-?[01]$");
46 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]$");
47 // eg: ab.cd    12  34  567  890  123   ef   gh   ijk
48 //     Total dmabuf size of ab.cd: 12345 bytes
49 const std::regex RAW_DMA1("^[\\w\\.\\[\\]():/>-]{1,}(\\s{1,}\\d{1,}){5}(\\s{1,}\\w{1,}){3}$");
50 const std::regex RAW_DMA2("^(Total dmabuf size of )[\\w\\.\\[\\]():/>-]{1,}(: )\\d{1,}( bytes)$");
51 // eg: ab(cd):      12345 kB
52 //     ab:              - kB
53 const std::regex RAW_MEM_INFO1("^[\\w()]{1,}:\\s{1,}\\d{1,}( kB)?$");
54 const std::regex RAW_MEM_INFO2("^[\\w()]{1,}:\\s{1,}- kB$");
55 // eg: ab-cd:       12345 kB
56 //     ab-cd        12345 (0 in SwapPss) kB
57 const std::regex RAW_MEM_VIEW_INFO1("^[\\w\\s-]{1,}:?\\s{1,}\\w{1,}( kB| \\%)?$");
58 const std::regex RAW_MEM_VIEW_INFO2("^\\w{1,}[-\\.]\\w{1,}(-\\w{1,})?\\s{1,}\\d{1,} \\(\\d{1,} in SwapPss\\) (kB)$");
59 // eg: Node     0, zone     abc, type   def  0  0  0  0  0  0  0  0  0  0  0
60 //     ab  cd  efg  hi    jk     lmn  opq     rst   uvw     xyz
61 const std::string RAW_PAGE_TYPE_STR1("^(Node)\\s{1,}\\d{1,}(, zone)\\s{1,}\\w{1,}((, type)\\s{1,}\\w{1,})?");
62 const std::string RAW_PAGE_TYPE_STR2("(\\s{1,}\\d{1,}){5,} $");
63 const std::regex RAW_PAGE_TYPE_INFO1(RAW_PAGE_TYPE_STR1 + RAW_PAGE_TYPE_STR2);
64 const std::regex RAW_PAGE_TYPE_INFO2("^(\\w{1,}\\s{1,}){5,}$");
65 // eg: abc   12    34    5  678    9 : tunables    1    2    3 : slabdata      4      5      6
66 //     abc - version: 1.2
67 //     #name       <ab> <cd> <ef> <hi> <jk> : tunables <lmn> <opq> <rst> : slabdata <uv> <wx> <yz>
68 const std::string RAW_SLAB_STR1("^[\\w\\.\\[\\]():/>-]{1,}(\\s{1,}\\d{1,}){5}( : tunables)(\\s{1,}\\d{1,}){3}");
69 const std::string RAW_SLAB_STR2("( : slabdata)(\\s{1,}\\d{1,}){3,5}(\\s{1,}\\w{1,})?$");
70 const std::regex RAW_SLAB_INFO1(RAW_SLAB_STR1 + RAW_SLAB_STR2);
71 const std::string RAW_SLAB_STR3("^(\\w{1,} - version: )[\\d\\.]{1,}|# ?name\\s{1,}");
72 const std::string RAW_SLAB_STR4("( <\\w{1,}>){5} : tunables( <\\w{1,}>){3} : slabdata( <\\w{1,}>){3,5}$");
73 const std::regex RAW_SLAB_INFO2(RAW_SLAB_STR3 + RAW_SLAB_STR4);
74 
HasValidAILibrary()75 bool HasValidAILibrary()
76 {
77     const std::string libName = "libai_mnt_client.so";
78     void* handle = dlopen(libName.c_str(), RTLD_LAZY);
79     return handle != nullptr;
80 }
81 
CheckFormat(const std::string & fileName,const std::regex & reg1,const std::regex & reg2,int cnt)82 bool CheckFormat(const std::string &fileName, const std::regex &reg1, const std::regex &reg2, int cnt)
83 {
84     std::ifstream file;
85     file.open(fileName.c_str());
86     if (!file.is_open()) {
87         return false;
88     }
89     std::string line;
90     while (cnt--) {
91         getline(file, line);
92     }
93     while (getline(file, line)) {
94         if (line.size() > 0 && line[line.size() - 1] == '\r') {
95             line.erase(line.size() - 1, 1);
96         }
97         if (line.size() == 0) {
98             continue;
99         }
100         if (!(regex_match(line, reg1) || regex_match(line, reg2))) {
101             file.close();
102             return false;
103         }
104     }
105     file.close();
106     return true;
107 }
108 }
109 
110 /**
111  * @tc.name: MemoryCollectorTest001
112  * @tc.desc: used to test MemoryCollector.CollectProcessMemory
113  * @tc.type: FUNC
114 */
115 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest001, TestSize.Level1)
116 {
117     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
118     CollectResult<ProcessMemory> data = collector->CollectProcessMemory(1); // init process id
119     std::cout << "collect process memory result" << data.retCode << std::endl;
120     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
121     data = collector->CollectProcessMemory(-1); // invalid process id
122     std::cout << "collect process memory result" << data.retCode << std::endl;
123     ASSERT_TRUE(data.retCode == UcError::READ_FAILED);
124 }
125 
126 /**
127  * @tc.name: MemoryCollectorTest002
128  * @tc.desc: used to test MemoryCollector.CollectSysMemory
129  * @tc.type: FUNC
130 */
131 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest002, TestSize.Level1)
132 {
133     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
134     CollectResult<SysMemory> data = collector->CollectSysMemory();
135     std::cout << "collect system memory result" << data.retCode << std::endl;
136     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
137 }
138 
139 /**
140  * @tc.name: MemoryCollectorTest003
141  * @tc.desc: used to test MemoryCollector.CollectRawMemInfo
142  * @tc.type: FUNC
143 */
144 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest003, TestSize.Level1)
145 {
146     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
147     CollectResult<std::string> data = collector->CollectRawMemInfo();
148     std::cout << "collect raw memory info result" << data.retCode << std::endl;
149     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
150     bool flag = CheckFormat(data.data, RAW_MEM_INFO1, RAW_MEM_INFO2, 0);    // 0: don't skip the first line
151     ASSERT_TRUE(flag);
152 }
153 
154 /**
155  * @tc.name: MemoryCollectorTest004
156  * @tc.desc: used to test MemoryCollector.CollectAllProcessMemory
157  * @tc.type: FUNC
158 */
159 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest004, TestSize.Level1)
160 {
161     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
162     CollectResult<std::vector<ProcessMemory>> data = collector->CollectAllProcessMemory();
163     std::cout << "collect all process memory result" << data.retCode << std::endl;
164     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
165 }
166 
167 /**
168  * @tc.name: MemoryCollectorTest005
169  * @tc.desc: used to test MemoryCollector.ExportAllProcessMemory
170  * @tc.type: FUNC
171 */
172 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest005, TestSize.Level1)
173 {
174     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
175     CollectResult<std::string> data = collector->ExportAllProcessMemory();
176     std::cout << "export all process memory result" << data.retCode << std::endl;
177     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
178     bool flag = CheckFormat(data.data, ALL_PROC_MEM1, ALL_PROC_MEM2, 1);    // 1: skip the first line
179     ASSERT_TRUE(flag);
180 }
181 
182 /**
183  * @tc.name: MemoryCollectorTest006
184  * @tc.desc: used to test MemoryCollector.CollectRawSlabInfo
185  * @tc.type: FUNC
186 */
187 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest006, TestSize.Level1)
188 {
189     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
190     CollectResult<std::string> data = collector->CollectRawSlabInfo();
191     std::cout << "collect raw slab info result" << data.retCode << std::endl;
192     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
193     bool flag = CheckFormat(data.data, RAW_SLAB_INFO1, RAW_SLAB_INFO2, 0);    // 0: don't skip the first line
194     ASSERT_TRUE(flag);
195 }
196 
197 /**
198  * @tc.name: MemoryCollectorTest007
199  * @tc.desc: used to test MemoryCollector.CollectRawPageTypeInfo
200  * @tc.type: FUNC
201 */
202 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest007, TestSize.Level1)
203 {
204     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
205     CollectResult<std::string> data = collector->CollectRawPageTypeInfo();
206     std::cout << "collect raw pagetype info result" << data.retCode << std::endl;
207     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
208     bool flag = CheckFormat(data.data, RAW_PAGE_TYPE_INFO1, RAW_PAGE_TYPE_INFO2, 4);    // 4: skip the first four lines
209     ASSERT_TRUE(flag);
210 }
211 
212 /**
213  * @tc.name: MemoryCollectorTest008
214  * @tc.desc: used to test MemoryCollector.CollectRawDMA
215  * @tc.type: FUNC
216 */
217 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest008, TestSize.Level1)
218 {
219     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
220     CollectResult<std::string> data = collector->CollectRawDMA();
221     std::cout << "collect raw DMA result" << data.retCode << std::endl;
222     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
223     bool flag = CheckFormat(data.data, RAW_DMA1, RAW_DMA2, 2);    // 2: skip the first two lines
224     ASSERT_TRUE(flag);
225 }
226 
227 /**
228  * @tc.name: MemoryCollectorTest009
229  * @tc.desc: used to test MemoryCollector.CollectAllAIProcess
230  * @tc.type: FUNC
231 */
232 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest009, TestSize.Level1)
233 {
234     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
235     CollectResult<std::vector<AIProcessMem>> data = collector->CollectAllAIProcess();
236     std::cout << "collect all AI process result" << data.retCode << std::endl;
237     if (HasValidAILibrary()) {
238         ASSERT_TRUE(data.retCode == UcError::SUCCESS);
239     } else {
240         ASSERT_TRUE(data.retCode == UcError::READ_FAILED);
241     }
242 }
243 
244 /**
245  * @tc.name: MemoryCollectorTest010
246  * @tc.desc: used to test MemoryCollector.ExportAllAIProcess
247  * @tc.type: FUNC
248 */
249 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest010, TestSize.Level1)
250 {
251     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
252     CollectResult<std::string> data = collector->ExportAllAIProcess();
253     std::cout << "export all AI process result" << data.retCode << std::endl;
254     if (HasValidAILibrary()) {
255         ASSERT_TRUE(data.retCode == UcError::SUCCESS);
256     } else {
257         ASSERT_TRUE(data.retCode == UcError::READ_FAILED);
258     }
259 }
260 
261 /**
262  * @tc.name: MemoryCollectorTest011
263  * @tc.desc: used to test MemoryCollector.CollectRawSmaps
264  * @tc.type: FUNC
265 */
266 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest011, TestSize.Level1)
267 {
268     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
269     CollectResult<std::string> data = collector->CollectRawSmaps(1);
270     std::cout << "collect raw smaps info result" << data.retCode << std::endl;
271     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
272 }
273 
274 /**
275  * @tc.name: MemoryCollectorTest012
276  * @tc.desc: used to test MemoryCollector.CollectHprof
277  * @tc.type: FUNC
278 */
279 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest012, TestSize.Level1)
280 {
281     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
282     CollectResult<std::string> data = collector->CollectHprof(1);
283     std::cout << "collect heap snapshot result" << data.retCode << std::endl;
284     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
285 }
286 
287 /**
288  * @tc.name: MemoryCollectorTest013
289  * @tc.desc: used to test MemoryCollector.CollectProcessVss
290  * @tc.type: FUNC
291 */
292 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest013, TestSize.Level1)
293 {
294     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
295     CollectResult<uint64_t> data = collector->CollectProcessVss(1000);
296     std::cout << "collect processvss result" << data.retCode << std::endl;
297     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
298 }
299 
300 /**
301  * @tc.name: MemoryCollectorTest014
302  * @tc.desc: used to test MemoryCollector.CollectMemoryLimit
303  * @tc.type: FUNC
304 */
305 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest014, TestSize.Level1)
306 {
307     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
308     CollectResult<MemoryLimit> data = collector->CollectMemoryLimit();
309     std::cout << "collect memoryLimit result" << data.retCode << std::endl;
310     ASSERT_TRUE(data.retCode == UcError::SUCCESS);
311 }
312 
313 /**
314  * @tc.name: MemoryCollectorTest015
315  * @tc.desc: used to test MemoryCollector.ExportMemView
316  * @tc.type: FUNC
317 */
318 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest015, TestSize.Level1)
319 {
320     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
321     CollectResult<std::string> data = collector->ExportMemView();
322     std::cout << "collect raw memory view info result" << data.retCode << std::endl;
323     if (FileUtil::FileExists("/proc/memview")) {
324         ASSERT_EQ(data.retCode, UcError::SUCCESS);
325         bool flag = CheckFormat(data.data, RAW_MEM_VIEW_INFO1, RAW_MEM_VIEW_INFO2, 0); // 0: don't skip the first line
326         ASSERT_TRUE(flag);
327     } else {
328         ASSERT_EQ(data.retCode, UcError::UNSUPPORT);
329     }
330 }
331 
332 /**
333  * @tc.name: MemoryCollectorTest016
334  * @tc.desc: used to test MemoryCollector.CollectDdrFreq
335  * @tc.type: FUNC
336 */
337 HWTEST_F(MemoryCollectorTest, MemoryCollectorTest016, TestSize.Level1)
338 {
339     std::shared_ptr<MemoryCollector> collector = MemoryCollector::Create();
340     CollectResult<uint32_t> data = collector->CollectDdrFreq();
341     std::cout << "collect DDR current frequency info result" << data.retCode << std::endl;
342     if (!FileUtil::FileExists("/sys/class/devfreq/ddrfreq/cur_freq")) {
343         ASSERT_EQ(data.retCode, UcError::UNSUPPORT);
344     } else {
345         ASSERT_EQ(data.retCode, UcError::SUCCESS);
346         ASSERT_GT(data.data, 0);
347     }
348 }
349