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_benchmark.cpp b/libmeminfo_benchmark.cpp
index e9cb763..81fc3b3 100644
--- a/libmeminfo_benchmark.cpp
+++ b/libmeminfo_benchmark.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <meminfo/procmeminfo.h>
 #include <meminfo/sysmeminfo.h>
 
 #include <fcntl.h>
@@ -31,6 +32,9 @@
 
 #include <benchmark/benchmark.h>
 
+using ::android::meminfo::MemUsage;
+using ::android::meminfo::ProcMemInfo;
+using ::android::meminfo::SmapsOrRollupFromFile;
 using ::android::meminfo::SysMemInfo;
 
 enum {
@@ -457,4 +461,85 @@
 }
 BENCHMARK(BM_VmallocInfo_new);
 
+// This implementation is picked up as-is from frameworks/base/core/jni/android_os_Debug.cpp
+// and only slightly modified to use std:unique_ptr.
+static bool get_smaps_rollup(const std::string path, MemUsage* rollup) {
+    char lineBuffer[1024];
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (fp != nullptr) {
+        char* line;
+        while (true) {
+            if (fgets(lineBuffer, sizeof(lineBuffer), fp.get()) == NULL) {
+                break;
+            }
+            line = lineBuffer;
+
+            switch (line[0]) {
+                case 'P':
+                    if (strncmp(line, "Pss:", 4) == 0) {
+                        char* c = line + 4;
+                        while (*c != 0 && (*c < '0' || *c > '9')) {
+                            c++;
+                        }
+                        rollup->pss += atoi(c);
+                    } else if (strncmp(line, "Private_Clean:", 14) == 0 ||
+                               strncmp(line, "Private_Dirty:", 14) == 0) {
+                        char* c = line + 14;
+                        while (*c != 0 && (*c < '0' || *c > '9')) {
+                            c++;
+                        }
+                        rollup->uss += atoi(c);
+                    }
+                    break;
+                case 'R':
+                    if (strncmp(line, "Rss:", 4) == 0) {
+                        char* c = line + 4;
+                        while (*c != 0 && (*c < '0' || *c > '9')) {
+                            c++;
+                        }
+                        rollup->rss += atoi(c);
+                    }
+                    break;
+                case 'S':
+                    if (strncmp(line, "SwapPss:", 8) == 0) {
+                        char* c = line + 8;
+                        long lSwapPss;
+                        while (*c != 0 && (*c < '0' || *c > '9')) {
+                            c++;
+                        }
+                        lSwapPss = atoi(c);
+                        rollup->swap_pss += lSwapPss;
+                    }
+                    break;
+            }
+        }
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+static void BM_SmapsRollup_old(benchmark::State& state) {
+    std::string exec_dir = ::android::base::GetExecutableDirectory();
+    std::string path = ::android::base::StringPrintf("%s/testdata1/smaps", exec_dir.c_str());
+    for (auto _ : state) {
+        MemUsage stats;
+        CHECK_EQ(get_smaps_rollup(path, &stats), true);
+        CHECK_EQ(stats.pss, 108384);
+    }
+}
+BENCHMARK(BM_SmapsRollup_old);
+
+static void BM_SmapsRollup_new(benchmark::State& state) {
+    std::string exec_dir = ::android::base::GetExecutableDirectory();
+    std::string path = ::android::base::StringPrintf("%s/testdata1/smaps", exec_dir.c_str());
+    for (auto _ : state) {
+        MemUsage stats;
+        CHECK_EQ(SmapsOrRollupFromFile(path, &stats), true);
+        CHECK_EQ(stats.pss, 108384);
+    }
+}
+BENCHMARK(BM_SmapsRollup_new);
+
 BENCHMARK_MAIN();