meminfo: Add ReadVmallocInfo()
This is to replace occurrences of get_allocated_vmalloc_memory().
Splitting into libmeminfo already found a bug with current code which
failed to account for memory allocated by modules due to addition of
the extra [%module_name%] in __builtin_return_address().
See: https://elixir.bootlin.com/linux/latest/source/kernel/kallsyms.c#L373
Also improves the performance a bit in the process.
Bug: 119639955
Bug: 111694435
Test: libmeminfo_test 1 --gtest_filter=SysMemInfoParser.TestVmallocInfo
Test: libmeminfo_benchmark --benchmark_filter=BM_VmallocInfo_*
Result:
----------------------------------------------------------------
Benchmark Time CPU Iterations
----------------------------------------------------------------
BM_VmallocInfo_old_fixed 459239 ns 457268 ns 1532
BM_VmallocInfo_new 386032 ns 384353 ns 1821
----------------------------------------------------------------
Change-Id: I1b6606ac73b5cc2dac31d24487b462ec9abfb2ef
Signed-off-by: Sandeep Patil <sspatil@google.com>
diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp
index 4ec1c99..8fd18d0 100644
--- a/libmeminfo/sysmeminfo.cpp
+++ b/libmeminfo/sysmeminfo.cpp
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <algorithm>
@@ -27,6 +28,7 @@
#include <cstdio>
#include <fstream>
#include <iterator>
+#include <sstream>
#include <string>
#include <utility>
#include <vector>
@@ -77,6 +79,38 @@
});
}
+uint64_t SysMemInfo::ReadVmallocInfo(const std::string& path) {
+ uint64_t vmalloc_total = 0;
+ auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+ if (fp == nullptr) {
+ return vmalloc_total;
+ }
+
+ char line[1024];
+ while (fgets(line, 1024, fp.get()) != nullptr) {
+ // We are looking for lines like
+ // 0x0000000000000000-0x0000000000000000 12288 drm_property_create_blob+0x44/0xec pages=2
+ // vmalloc 0x0000000000000000-0x0000000000000000 8192
+ // wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc Notice that if the caller is
+ // coming from a module, the kernel prints and extra "[module_name]" after the address and
+ // the symbol of the call site. This means we can't use the old sscanf() method of getting
+ // the # of pages.
+ char* p_start = strstr(line, "pages=");
+ if (p_start == nullptr) {
+ // we didn't find anything
+ continue;
+ }
+
+ p_start = strtok(p_start, " ");
+ long nr_pages;
+ if (sscanf(p_start, "pages=%ld", &nr_pages) == 1) {
+ vmalloc_total += (nr_pages * getpagesize());
+ }
+ }
+
+ return vmalloc_total;
+}
+
// TODO: Delete this function if it can't match up with the c-like implementation below.
// Currently, this added about 50 % extra overhead on hikey.
#if 0