libmeminfo: Add SmapsRollup

This adds the tests and SmapsRollup() parsing function in
ProcMemInfo. Adds tests to check the return value as well as
the correctness.

Bug: 111694435
Test: libmeminfo_test 1 --gtest_filter=TestProcMemInfo.*
Test: libmeminfo_benchmark --benchmark_filter=BM_SmapsRollup_
Result:
----------------------------------------------------------
Benchmark                   Time           CPU Iterations
----------------------------------------------------------
BM_SmapsRollup_old       4751 ns       4730 ns     149458
BM_SmapsRollup_new       4858 ns       4837 ns     144636
----------------------------------------------------------

Change-Id: Ia051fe53a7622e3091502ff7166efafae35e7935
Signed-off-by: Sandeep Patil <sspatil@google.com>
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index 8867e14..1daff1e 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -30,6 +30,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <procinfo/process_map.h>
 
@@ -102,6 +103,12 @@
     return wss_;
 }
 
+bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const {
+    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
+                                                     use_rollup ? "smaps_rollup" : "smaps");
+    return SmapsOrRollupFromFile(path, stats);
+};
+
 const std::vector<uint16_t>& ProcMemInfo::SwapOffsets() {
     if (get_wss_) {
         LOG(WARNING) << "Trying to read process swap offsets for " << pid_
@@ -252,5 +259,50 @@
     return true;
 }
 
+// Public APIs
+bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) {
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (fp == nullptr) {
+        return false;
+    }
+
+    char line[1024];
+    stats->clear();
+    while (fgets(line, sizeof(line), fp.get()) != nullptr) {
+        switch (line[0]) {
+            case 'P':
+                if (strncmp(line, "Pss:", 4) == 0) {
+                    char* c = line + 4;
+                    stats->pss += strtoull(c, nullptr, 10);
+                } else if (strncmp(line, "Private_Clean:", 14) == 0) {
+                    char* c = line + 14;
+                    uint64_t prcl = strtoull(c, nullptr, 10);
+                    stats->private_clean += prcl;
+                    stats->uss += prcl;
+                } else if (strncmp(line, "Private_Dirty:", 14) == 0) {
+                    char* c = line + 14;
+                    uint64_t prdi = strtoull(c, nullptr, 10);
+                    stats->private_dirty += prdi;
+                    stats->uss += prdi;
+                }
+                break;
+            case 'R':
+                if (strncmp(line, "Rss:", 4) == 0) {
+                    char* c = line + 4;
+                    stats->rss += strtoull(c, nullptr, 10);
+                }
+                break;
+            case 'S':
+                if (strncmp(line, "SwapPss:", 8) == 0) {
+                    char* c = line + 8;
+                    stats->swap_pss += strtoull(c, nullptr, 10);
+                }
+                break;
+        }
+    }
+
+    return true;
+}
+
 }  // namespace meminfo
 }  // namespace android