blob: e9cb763afc64669082880d40b624483055c7ec43 [file] [log] [blame]
Sandeep Patila60a7762018-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 <meminfo/sysmeminfo.h>
18
19#include <fcntl.h>
Sandeep Patil9f4028d2018-11-09 19:18:29 -080020#include <inttypes.h>
21#include <stdio.h>
Sandeep Patila60a7762018-08-29 17:10:47 -070022#include <sys/stat.h>
23#include <sys/types.h>
24
25#include <string>
26
27#include <android-base/file.h>
28#include <android-base/logging.h>
Sandeep Patil76a34f02018-12-29 14:34:20 -080029#include <android-base/stringprintf.h>
30#include <android-base/unique_fd.h>
Sandeep Patila60a7762018-08-29 17:10:47 -070031
32#include <benchmark/benchmark.h>
33
Sandeep Patile473d7e2018-12-11 09:28:38 -080034using ::android::meminfo::SysMemInfo;
35
Sandeep Patila60a7762018-08-29 17:10:47 -070036enum {
37 MEMINFO_TOTAL,
38 MEMINFO_FREE,
39 MEMINFO_BUFFERS,
40 MEMINFO_CACHED,
41 MEMINFO_SHMEM,
42 MEMINFO_SLAB,
43 MEMINFO_SLAB_RECLAIMABLE,
44 MEMINFO_SLAB_UNRECLAIMABLE,
45 MEMINFO_SWAP_TOTAL,
46 MEMINFO_SWAP_FREE,
47 MEMINFO_ZRAM_TOTAL,
48 MEMINFO_MAPPED,
49 MEMINFO_VMALLOC_USED,
50 MEMINFO_PAGE_TABLES,
51 MEMINFO_KERNEL_STACK,
52 MEMINFO_COUNT
53};
54
Sandeep Patil9f4028d2018-11-09 19:18:29 -080055static void get_mem_info(uint64_t mem[], const char* file) {
Sandeep Patila60a7762018-08-29 17:10:47 -070056 char buffer[4096];
57 unsigned int numFound = 0;
58
59 int fd = open(file, O_RDONLY);
60
61 if (fd < 0) {
62 printf("Unable to open %s: %s\n", file, strerror(errno));
63 return;
64 }
65
66 const int len = read(fd, buffer, sizeof(buffer) - 1);
67 close(fd);
68
69 if (len < 0) {
70 printf("Empty %s\n", file);
71 return;
72 }
73 buffer[len] = 0;
74
75 static const char* const tags[] = {
Sandeep Patil9f4028d2018-11-09 19:18:29 -080076 "MemTotal:", "MemFree:", "Buffers:", "Cached:", "Shmem:", "Slab:",
77 "SReclaimable:", "SUnreclaim:", "SwapTotal:", "SwapFree:", "ZRam:", "Mapped:",
Sandeep Patile473d7e2018-12-11 09:28:38 -080078 "VmallocUsed:", "PageTables:", "KernelStack:", NULL};
Sandeep Patila60a7762018-08-29 17:10:47 -070079
80 static const int tagsLen[] = {9, 8, 8, 7, 6, 5, 13, 11, 10, 9, 5, 7, 12, 11, 12, 0};
81
82 memset(mem, 0, sizeof(uint64_t) * 15);
83 char* p = buffer;
84 while (*p && (numFound < (sizeof(tagsLen) / sizeof(tagsLen[0])))) {
85 int i = 0;
86 while (tags[i]) {
Sandeep Patil9f4028d2018-11-09 19:18:29 -080087 // std::cout << "tag =" << tags[i] << " p = " << std::string(p, tagsLen[i]) <<
88 // std::endl;
Sandeep Patila60a7762018-08-29 17:10:47 -070089 if (strncmp(p, tags[i], tagsLen[i]) == 0) {
90 p += tagsLen[i];
91 while (*p == ' ') p++;
92 char* num = p;
93 while (*p >= '0' && *p <= '9') p++;
94 if (*p != 0) {
95 *p = 0;
96 p++;
97 }
98 mem[i] = atoll(num);
99 numFound++;
100 break;
101 }
102 i++;
103 }
104 while (*p && *p != '\n') {
105 p++;
106 }
107 if (*p) p++;
108 }
109}
110
Sandeep Patile473d7e2018-12-11 09:28:38 -0800111static void BM_ReadMemInfo_old(benchmark::State& state) {
Sandeep Patila60a7762018-08-29 17:10:47 -0700112 std::string meminfo = R"meminfo(MemTotal: 3019740 kB
113MemFree: 1809728 kB
114MemAvailable: 2546560 kB
115Buffers: 54736 kB
116Cached: 776052 kB
117SwapCached: 0 kB
118Active: 445856 kB
119Inactive: 459092 kB
120Active(anon): 78492 kB
121Inactive(anon): 2240 kB
122Active(file): 367364 kB
123Inactive(file): 456852 kB
124Unevictable: 3096 kB
125Mlocked: 3096 kB
126SwapTotal: 0 kB
127SwapFree: 0 kB
128Dirty: 32 kB
129Writeback: 0 kB
130AnonPages: 74988 kB
131Mapped: 62624 kB
132Shmem: 4020 kB
133Slab: 86464 kB
134SReclaimable: 44432 kB
135SUnreclaim: 42032 kB
136KernelStack: 4880 kB
137PageTables: 2900 kB
138NFS_Unstable: 0 kB
139Bounce: 0 kB
140WritebackTmp: 0 kB
141CommitLimit: 1509868 kB
142Committed_AS: 80296 kB
143VmallocTotal: 263061440 kB
144VmallocUsed: 0 kB
145VmallocChunk: 0 kB
146AnonHugePages: 6144 kB
147ShmemHugePages: 0 kB
148ShmemPmdMapped: 0 kB
149CmaTotal: 131072 kB
150CmaFree: 130380 kB
151HugePages_Total: 0
152HugePages_Free: 0
153HugePages_Rsvd: 0
154HugePages_Surp: 0
155Hugepagesize: 2048 kB)meminfo";
156
157 TemporaryFile tf;
158 ::android::base::WriteStringToFd(meminfo, tf.fd);
159
160 uint64_t mem[MEMINFO_COUNT];
161 for (auto _ : state) {
162 get_mem_info(mem, tf.path);
163 }
164}
Sandeep Patile473d7e2018-12-11 09:28:38 -0800165BENCHMARK(BM_ReadMemInfo_old);
Sandeep Patila60a7762018-08-29 17:10:47 -0700166
Sandeep Patile473d7e2018-12-11 09:28:38 -0800167static void BM_ReadMemInfo_new(benchmark::State& state) {
Sandeep Patila60a7762018-08-29 17:10:47 -0700168 std::string meminfo = R"meminfo(MemTotal: 3019740 kB
169MemFree: 1809728 kB
170MemAvailable: 2546560 kB
171Buffers: 54736 kB
172Cached: 776052 kB
173SwapCached: 0 kB
174Active: 445856 kB
175Inactive: 459092 kB
176Active(anon): 78492 kB
177Inactive(anon): 2240 kB
178Active(file): 367364 kB
179Inactive(file): 456852 kB
180Unevictable: 3096 kB
181Mlocked: 3096 kB
182SwapTotal: 0 kB
183SwapFree: 0 kB
184Dirty: 32 kB
185Writeback: 0 kB
186AnonPages: 74988 kB
187Mapped: 62624 kB
188Shmem: 4020 kB
189Slab: 86464 kB
190SReclaimable: 44432 kB
191SUnreclaim: 42032 kB
192KernelStack: 4880 kB
193PageTables: 2900 kB
194NFS_Unstable: 0 kB
195Bounce: 0 kB
196WritebackTmp: 0 kB
197CommitLimit: 1509868 kB
198Committed_AS: 80296 kB
199VmallocTotal: 263061440 kB
200VmallocUsed: 0 kB
201VmallocChunk: 0 kB
202AnonHugePages: 6144 kB
203ShmemHugePages: 0 kB
204ShmemPmdMapped: 0 kB
205CmaTotal: 131072 kB
206CmaFree: 130380 kB
207HugePages_Total: 0
208HugePages_Free: 0
209HugePages_Rsvd: 0
210HugePages_Surp: 0
211Hugepagesize: 2048 kB)meminfo";
212
213 TemporaryFile tf;
214 android::base::WriteStringToFd(meminfo, tf.fd);
215
216 std::string file = std::string(tf.path);
Sandeep Patile473d7e2018-12-11 09:28:38 -0800217 std::vector<uint64_t> mem(MEMINFO_COUNT);
218 const std::vector<std::string> tags = {
219 SysMemInfo::kMemTotal, SysMemInfo::kMemFree, SysMemInfo::kMemBuffers,
220 SysMemInfo::kMemCached, SysMemInfo::kMemShmem, SysMemInfo::kMemSlab,
221 SysMemInfo::kMemSReclaim, SysMemInfo::kMemSUnreclaim, SysMemInfo::kMemSwapTotal,
222 SysMemInfo::kMemSwapFree, SysMemInfo::kMemMapped, SysMemInfo::kMemVmallocUsed,
223 SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
224 };
225
226 SysMemInfo smi;
Sandeep Patila60a7762018-08-29 17:10:47 -0700227 for (auto _ : state) {
Sandeep Patile473d7e2018-12-11 09:28:38 -0800228 smi.ReadMemInfo(tags, &mem, file);
Sandeep Patila60a7762018-08-29 17:10:47 -0700229 }
230}
Sandeep Patile473d7e2018-12-11 09:28:38 -0800231BENCHMARK(BM_ReadMemInfo_new);
Sandeep Patila60a7762018-08-29 17:10:47 -0700232
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800233static uint64_t get_zram_mem_used(const std::string& zram_dir) {
234 FILE* f = fopen((zram_dir + "mm_stat").c_str(), "r");
235 if (f) {
236 uint64_t mem_used_total = 0;
237
238 int matched = fscanf(f, "%*d %*d %" SCNu64 " %*d %*d %*d %*d", &mem_used_total);
239 if (matched != 1)
240 fprintf(stderr, "warning: failed to parse %s\n", (zram_dir + "mm_stat").c_str());
241
242 fclose(f);
243 return mem_used_total;
244 }
245
246 f = fopen((zram_dir + "mem_used_total").c_str(), "r");
247 if (f) {
248 uint64_t mem_used_total = 0;
249
250 int matched = fscanf(f, "%" SCNu64, &mem_used_total);
251 if (matched != 1)
252 fprintf(stderr, "warning: failed to parse %s\n", (zram_dir + "mem_used_total").c_str());
253
254 fclose(f);
255 return mem_used_total;
256 }
257
258 return 0;
259}
260
Sandeep Patile473d7e2018-12-11 09:28:38 -0800261static void BM_ZramTotal_old(benchmark::State& state) {
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800262 std::string exec_dir = ::android::base::GetExecutableDirectory();
263 std::string zram_mmstat_dir = exec_dir + "/testdata1/";
264 for (auto _ : state) {
265 uint64_t zram_total __attribute__((unused)) = get_zram_mem_used(zram_mmstat_dir) / 1024;
266 }
267}
Sandeep Patile473d7e2018-12-11 09:28:38 -0800268BENCHMARK(BM_ZramTotal_old);
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800269
Sandeep Patile473d7e2018-12-11 09:28:38 -0800270static void BM_ZramTotal_new(benchmark::State& state) {
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800271 std::string exec_dir = ::android::base::GetExecutableDirectory();
272 std::string zram_mmstat_dir = exec_dir + "/testdata1/";
Sandeep Patile473d7e2018-12-11 09:28:38 -0800273 SysMemInfo smi;
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800274 for (auto _ : state) {
Sandeep Patile473d7e2018-12-11 09:28:38 -0800275 uint64_t zram_total __attribute__((unused)) = smi.mem_zram_kb(zram_mmstat_dir);
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800276 }
277}
Sandeep Patile473d7e2018-12-11 09:28:38 -0800278BENCHMARK(BM_ZramTotal_new);
279
280static void BM_MemInfoWithZram_old(benchmark::State& state) {
281 std::string meminfo = R"meminfo(MemTotal: 3019740 kB
282MemFree: 1809728 kB
283MemAvailable: 2546560 kB
284Buffers: 54736 kB
285Cached: 776052 kB
286SwapCached: 0 kB
287Active: 445856 kB
288Inactive: 459092 kB
289Active(anon): 78492 kB
290Inactive(anon): 2240 kB
291Active(file): 367364 kB
292Inactive(file): 456852 kB
293Unevictable: 3096 kB
294Mlocked: 3096 kB
295SwapTotal: 0 kB
296SwapFree: 0 kB
297Dirty: 32 kB
298Writeback: 0 kB
299AnonPages: 74988 kB
300Mapped: 62624 kB
301Shmem: 4020 kB
302Slab: 86464 kB
303SReclaimable: 44432 kB
304SUnreclaim: 42032 kB
305KernelStack: 4880 kB
306PageTables: 2900 kB
307NFS_Unstable: 0 kB
308Bounce: 0 kB
309WritebackTmp: 0 kB
310CommitLimit: 1509868 kB
311Committed_AS: 80296 kB
312VmallocTotal: 263061440 kB
313VmallocUsed: 0 kB
314VmallocChunk: 0 kB
315AnonHugePages: 6144 kB
316ShmemHugePages: 0 kB
317ShmemPmdMapped: 0 kB
318CmaTotal: 131072 kB
319CmaFree: 130380 kB
320HugePages_Total: 0
321HugePages_Free: 0
322HugePages_Rsvd: 0
323HugePages_Surp: 0
324Hugepagesize: 2048 kB)meminfo";
325
326 TemporaryFile tf;
327 ::android::base::WriteStringToFd(meminfo, tf.fd);
328 std::string exec_dir = ::android::base::GetExecutableDirectory();
329 std::string zram_mmstat_dir = exec_dir + "/testdata1/";
330 uint64_t mem[MEMINFO_COUNT];
331 for (auto _ : state) {
332 get_mem_info(mem, tf.path);
333 mem[MEMINFO_ZRAM_TOTAL] = get_zram_mem_used("/sys/block/zram0/") / 1024;
334 CHECK_EQ(mem[MEMINFO_KERNEL_STACK], 4880u);
335 }
336}
337BENCHMARK(BM_MemInfoWithZram_old);
338
339static void BM_MemInfoWithZram_new(benchmark::State& state) {
340 std::string meminfo = R"meminfo(MemTotal: 3019740 kB
341MemFree: 1809728 kB
342MemAvailable: 2546560 kB
343Buffers: 54736 kB
344Cached: 776052 kB
345SwapCached: 0 kB
346Active: 445856 kB
347Inactive: 459092 kB
348Active(anon): 78492 kB
349Inactive(anon): 2240 kB
350Active(file): 367364 kB
351Inactive(file): 456852 kB
352Unevictable: 3096 kB
353Mlocked: 3096 kB
354SwapTotal: 0 kB
355SwapFree: 0 kB
356Dirty: 32 kB
357Writeback: 0 kB
358AnonPages: 74988 kB
359Mapped: 62624 kB
360Shmem: 4020 kB
361Slab: 86464 kB
362SReclaimable: 44432 kB
363SUnreclaim: 42032 kB
364KernelStack: 4880 kB
365PageTables: 2900 kB
366NFS_Unstable: 0 kB
367Bounce: 0 kB
368WritebackTmp: 0 kB
369CommitLimit: 1509868 kB
370Committed_AS: 80296 kB
371VmallocTotal: 263061440 kB
372VmallocUsed: 0 kB
373VmallocChunk: 0 kB
374AnonHugePages: 6144 kB
375ShmemHugePages: 0 kB
376ShmemPmdMapped: 0 kB
377CmaTotal: 131072 kB
378CmaFree: 130380 kB
379HugePages_Total: 0
380HugePages_Free: 0
381HugePages_Rsvd: 0
382HugePages_Surp: 0
383Hugepagesize: 2048 kB)meminfo";
384
385 TemporaryFile tf;
386 android::base::WriteStringToFd(meminfo, tf.fd);
387
388 std::string file = std::string(tf.path);
389 std::vector<uint64_t> mem(MEMINFO_COUNT);
390 std::vector<std::string> tags(SysMemInfo::kDefaultSysMemInfoTags);
391 auto it = tags.begin();
392 tags.insert(it + MEMINFO_ZRAM_TOTAL, "Zram:");
393 SysMemInfo smi;
394
395 for (auto _ : state) {
396 smi.ReadMemInfo(tags, &mem, file);
397 CHECK_EQ(mem[MEMINFO_KERNEL_STACK], 4880u);
398 }
399}
400BENCHMARK(BM_MemInfoWithZram_new);
Sandeep Patil9f4028d2018-11-09 19:18:29 -0800401
Sandeep Patil76a34f02018-12-29 14:34:20 -0800402// Current implementation is in frameworks/base/core/jni/android_os_Debug.cpp.
403// That implementation is still buggy and it skips over vmalloc allocated memory by kernel modules.
404// This is the *fixed* version of the same implementation intended for benchmarking against the new
405// one.
406static uint64_t get_allocated_vmalloc_memory(const std::string& vm_file) {
407 char line[1024];
408
409 uint64_t vmalloc_allocated_size = 0;
410 auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(vm_file.c_str(), "re"), fclose};
411 if (fp == nullptr) {
412 return 0;
413 }
414
415 while (true) {
416 if (fgets(line, 1024, fp.get()) == NULL) {
417 break;
418 }
419
420 // check to see if there are pages mapped in vmalloc area
421 if (!strstr(line, "pages=")) {
422 continue;
423 }
424
425 long nr_pages;
426 if (sscanf(line, "%*x-%*x %*ld %*s pages=%ld", &nr_pages) == 1) {
427 vmalloc_allocated_size += (nr_pages * getpagesize());
428 } else if (sscanf(line, "%*x-%*x %*ld %*s %*s pages=%ld", &nr_pages) == 1) {
429 // The second case is for kernel modules. If allocation comes from the module,
430 // kernel puts an extra string containing the module name before "pages=" in
431 // the line.
432 // See: https://elixir.bootlin.com/linux/latest/source/kernel/kallsyms.c#L373
433 vmalloc_allocated_size += (nr_pages * getpagesize());
434 }
435 }
436 return vmalloc_allocated_size;
437}
438
439static void BM_VmallocInfo_old_fixed(benchmark::State& state) {
440 std::string exec_dir = ::android::base::GetExecutableDirectory();
441 std::string vmallocinfo =
442 ::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
443 for (auto _ : state) {
444 CHECK_EQ(get_allocated_vmalloc_memory(vmallocinfo), 29884416);
445 }
446}
447BENCHMARK(BM_VmallocInfo_old_fixed);
448
449static void BM_VmallocInfo_new(benchmark::State& state) {
450 std::string exec_dir = ::android::base::GetExecutableDirectory();
451 std::string vmallocinfo =
452 ::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
453 for (auto _ : state) {
454 SysMemInfo smi;
455 CHECK_EQ(smi.ReadVmallocInfo(vmallocinfo), 29884416);
456 }
457}
458BENCHMARK(BM_VmallocInfo_new);
459
Sandeep Patila60a7762018-08-29 17:10:47 -0700460BENCHMARK_MAIN();