blob: 22f358545573a4f9634f21091ab69313ce3c8a17 [file] [log] [blame]
Sandeep Patil54d87212018-08-29 17:10:47 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <sys/types.h>
18#include <sys/wait.h>
19#include <unistd.h>
20
21#include <gtest/gtest.h>
22
23#include <string>
24#include <vector>
25
26#include <meminfo/pageacct.h>
27#include <meminfo/procmeminfo.h>
28#include <meminfo/sysmeminfo.h>
29#include <pagemap/pagemap.h>
30
31#include <android-base/file.h>
32#include <android-base/logging.h>
33#include <android-base/test_utils.h>
34
35using namespace std;
36using namespace android::meminfo;
37
38pid_t pid = -1;
39
40class ValidateProcMemInfo : public ::testing::Test {
41 protected:
42 void SetUp() override {
43 ASSERT_EQ(0, pm_kernel_create(&ker));
44 ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
45 proc_mem = new ProcMemInfo(pid);
46 ASSERT_NE(proc_mem, nullptr);
47 }
48
49 void TearDown() override {
50 delete proc_mem;
51 pm_process_destroy(proc);
52 pm_kernel_destroy(ker);
53 }
54
55 pm_kernel_t* ker;
56 pm_process_t* proc;
57 ProcMemInfo* proc_mem;
58};
59
60TEST_F(ValidateProcMemInfo, TestMapsSize) {
61 const std::vector<Vma>& maps = proc_mem->Maps();
62 ASSERT_FALSE(maps.empty()) << "Process " << getpid() << " maps are empty";
63}
64
65TEST_F(ValidateProcMemInfo, TestMapsEquality) {
66 const std::vector<Vma>& maps = proc_mem->Maps();
67 ASSERT_EQ(proc->num_maps, maps.size());
68
69 for (size_t i = 0; i < maps.size(); ++i) {
70 EXPECT_EQ(proc->maps[i]->start, maps[i].start);
71 EXPECT_EQ(proc->maps[i]->end, maps[i].end);
72 EXPECT_EQ(proc->maps[i]->offset, maps[i].offset);
73 EXPECT_EQ(std::string(proc->maps[i]->name), maps[i].name);
74 }
75}
76
77TEST_F(ValidateProcMemInfo, TestMapsUsage) {
78 const std::vector<Vma>& maps = proc_mem->Maps();
79 ASSERT_FALSE(maps.empty());
80 ASSERT_EQ(proc->num_maps, maps.size());
81
82 pm_memusage_t map_usage, proc_usage;
83 pm_memusage_zero(&map_usage);
84 pm_memusage_zero(&proc_usage);
85 for (size_t i = 0; i < maps.size(); i++) {
86 ASSERT_EQ(0, pm_map_usage(proc->maps[i], &map_usage));
87 EXPECT_EQ(map_usage.vss, maps[i].usage.vss) << "VSS mismatch for map: " << maps[i].name;
88 EXPECT_EQ(map_usage.rss, maps[i].usage.rss) << "RSS mismatch for map: " << maps[i].name;
89 EXPECT_EQ(map_usage.pss, maps[i].usage.pss) << "PSS mismatch for map: " << maps[i].name;
90 EXPECT_EQ(map_usage.uss, maps[i].usage.uss) << "USS mismatch for map: " << maps[i].name;
91 pm_memusage_add(&proc_usage, &map_usage);
92 }
93
94 EXPECT_EQ(proc_usage.vss, proc_mem->Usage().vss);
95 EXPECT_EQ(proc_usage.rss, proc_mem->Usage().rss);
96 EXPECT_EQ(proc_usage.pss, proc_mem->Usage().pss);
97 EXPECT_EQ(proc_usage.uss, proc_mem->Usage().uss);
98}
99
100class ValidateProcMemInfoWss : public ::testing::Test {
101 protected:
102 void SetUp() override {
103 ASSERT_EQ(0, pm_kernel_create(&ker));
104 ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
105 proc_mem = new ProcMemInfo(pid, true);
106 ASSERT_NE(proc_mem, nullptr);
107 }
108
109 void TearDown() override {
110 delete proc_mem;
111 pm_process_destroy(proc);
112 pm_kernel_destroy(ker);
113 }
114
115 pm_kernel_t* ker;
116 pm_process_t* proc;
117 ProcMemInfo* proc_mem;
118};
119
120TEST_F(ValidateProcMemInfoWss, TestWorkingTestReset) {
121 // Expect reset to succeed
122 EXPECT_TRUE(proc_mem->WssReset());
123}
124
125TEST_F(ValidateProcMemInfoWss, TestWssEquality) {
126 // Read wss using libpagemap
127 pm_memusage_t wss_pagemap;
128 EXPECT_EQ(0, pm_process_workingset(proc, &wss_pagemap, 0));
129
130 // Read wss using libmeminfo
131 MemUsage wss = proc_mem->Wss();
132
133 // compare
134 EXPECT_EQ(wss_pagemap.rss, wss.rss);
135 EXPECT_EQ(wss_pagemap.pss, wss.pss);
136 EXPECT_EQ(wss_pagemap.uss, wss.uss);
137}
138
139class ValidatePageAcct : public ::testing::Test {
140 protected:
141 void SetUp() override {
142 ASSERT_EQ(0, pm_kernel_create(&ker));
143 ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
144 }
145
146 void TearDown() override {
147 pm_process_destroy(proc);
148 pm_kernel_destroy(ker);
149 }
150
151 pm_kernel_t* ker;
152 pm_process_t* proc;
153};
154
155TEST_F(ValidatePageAcct, TestPageFlags) {
156 PageAcct& pi = PageAcct::Instance();
157 pi.InitPageAcct(false);
158
159 uint64_t* pagemap;
160 size_t num_pages;
161 for (size_t i = 0; i < proc->num_maps; i++) {
162 ASSERT_EQ(0, pm_map_pagemap(proc->maps[i], &pagemap, &num_pages));
163 for (size_t j = 0; j < num_pages; j++) {
164 if (!PM_PAGEMAP_PRESENT(pagemap[j])) continue;
165
166 uint64_t pfn = PM_PAGEMAP_PFN(pagemap[j]);
167 uint64_t page_flags_pagemap, page_flags_meminfo;
168
169 ASSERT_EQ(0, pm_kernel_flags(ker, pfn, &page_flags_pagemap));
170 ASSERT_TRUE(pi.PageFlags(pfn, &page_flags_meminfo));
171 // check if page flags equal
172 EXPECT_EQ(page_flags_pagemap, page_flags_meminfo);
173 }
174 free(pagemap);
175 }
176}
177
178TEST_F(ValidatePageAcct, TestPageCounts) {
179 PageAcct& pi = PageAcct::Instance();
180 pi.InitPageAcct(false);
181
182 uint64_t* pagemap;
183 size_t num_pages;
184 for (size_t i = 0; i < proc->num_maps; i++) {
185 ASSERT_EQ(0, pm_map_pagemap(proc->maps[i], &pagemap, &num_pages));
186 for (size_t j = 0; j < num_pages; j++) {
187 uint64_t pfn = PM_PAGEMAP_PFN(pagemap[j]);
188 uint64_t map_count_pagemap, map_count_meminfo;
189
190 ASSERT_EQ(0, pm_kernel_count(ker, pfn, &map_count_pagemap));
191 ASSERT_TRUE(pi.PageMapCount(pfn, &map_count_meminfo));
192 // check if map counts are equal
193 EXPECT_EQ(map_count_pagemap, map_count_meminfo);
194 }
195 free(pagemap);
196 }
197}
198
199TEST_F(ValidatePageAcct, TestPageIdle) {
200 // skip the test if idle page tracking isn't enabled
201 if (pm_kernel_init_page_idle(ker) != 0) {
202 return;
203 }
204
205 PageAcct& pi = PageAcct::Instance();
206 ASSERT_TRUE(pi.InitPageAcct(true));
207
208 uint64_t* pagemap;
209 size_t num_pages;
210 for (size_t i = 0; i < proc->num_maps; i++) {
211 ASSERT_EQ(0, pm_map_pagemap(proc->maps[i], &pagemap, &num_pages));
212 for (size_t j = 0; j < num_pages; j++) {
213 if (!PM_PAGEMAP_PRESENT(pagemap[j])) continue;
214 uint64_t pfn = PM_PAGEMAP_PFN(pagemap[j]);
215
216 ASSERT_EQ(0, pm_kernel_mark_page_idle(ker, &pfn, 1));
217 int idle_status_pagemap = pm_kernel_get_page_idle(ker, pfn);
218 int idle_status_meminfo = pi.IsPageIdle(pfn);
219 EXPECT_EQ(idle_status_pagemap, idle_status_meminfo);
220 }
221 free(pagemap);
222 }
223}
224
225TEST(SysMemInfoParser, TestSysMemInfoFile) {
226 std::string meminfo = R"meminfo(MemTotal: 3019740 kB
227MemFree: 1809728 kB
228MemAvailable: 2546560 kB
229Buffers: 54736 kB
230Cached: 776052 kB
231SwapCached: 0 kB
232Active: 445856 kB
233Inactive: 459092 kB
234Active(anon): 78492 kB
235Inactive(anon): 2240 kB
236Active(file): 367364 kB
237Inactive(file): 456852 kB
238Unevictable: 3096 kB
239Mlocked: 3096 kB
240SwapTotal: 0 kB
241SwapFree: 0 kB
242Dirty: 32 kB
243Writeback: 0 kB
244AnonPages: 74988 kB
245Mapped: 62624 kB
246Shmem: 4020 kB
247Slab: 86464 kB
248SReclaimable: 44432 kB
249SUnreclaim: 42032 kB
250KernelStack: 4880 kB
251PageTables: 2900 kB
252NFS_Unstable: 0 kB
253Bounce: 0 kB
254WritebackTmp: 0 kB
255CommitLimit: 1509868 kB
256Committed_AS: 80296 kB
257VmallocTotal: 263061440 kB
258VmallocUsed: 0 kB
259VmallocChunk: 0 kB
260AnonHugePages: 6144 kB
261ShmemHugePages: 0 kB
262ShmemPmdMapped: 0 kB
263CmaTotal: 131072 kB
264CmaFree: 130380 kB
265HugePages_Total: 0
266HugePages_Free: 0
267HugePages_Rsvd: 0
268HugePages_Surp: 0
269Hugepagesize: 2048 kB)meminfo";
270
271 TemporaryFile tf;
272 ASSERT_TRUE(tf.fd != -1);
273 ASSERT_TRUE(::android::base::WriteStringToFd(meminfo, tf.fd));
274
275 SysMemInfo mi;
276 ASSERT_TRUE(mi.ReadMemInfo(tf.path));
277 EXPECT_EQ(mi.mem_total_kb(), 3019740);
278 EXPECT_EQ(mi.mem_page_tables_kb(), 2900);
279}
280
281TEST(SysMemInfoParser, TestEmptyFile) {
282 TemporaryFile tf;
283 std::string empty_string = "";
284 ASSERT_TRUE(tf.fd != -1);
285 ASSERT_TRUE(::android::base::WriteStringToFd(empty_string, tf.fd));
286
287 SysMemInfo mi;
288 EXPECT_TRUE(mi.ReadMemInfo(tf.path));
289 EXPECT_EQ(mi.mem_total_kb(), 0);
290}
291
292int main(int argc, char** argv) {
293 ::testing::InitGoogleTest(&argc, argv);
294 if (argc <= 1) {
295 cerr << "Pid of a permanently sleeping process must be provided." << endl;
296 exit(EXIT_FAILURE);
297 }
298 ::android::base::InitLogging(argv, android::base::StderrLogger);
299 pid = std::stoi(std::string(argv[1]));
300 return RUN_ALL_TESTS();
301}