Optimize code that only uses PageMap call.

Some code only wants to use PageMap to determine whether pages are
mapped in to memory. Modify the code to optimize this path.

Changes:
- Add a function that doesn't read all of usage stats data for every
  map. This operation is extremely expensive, and some code doesn't
  care about it.
- Optimize the PageMap call to do a single read instead of a single
  read per page.
- Add unit tests for these changes.

Bug: 136245508

Test: Ran new unit tests.
Test: Ran procrank and verified data looks good.
Test: Ran DexDiag art tests.
Change-Id: I37d03f2584551d26cb20be3abacdb958111d4eca
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index a8b43c1..6f68ab4 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -130,6 +130,14 @@
     return maps_;
 }
 
+const std::vector<Vma>& ProcMemInfo::MapsWithoutUsageStats() {
+    if (maps_.empty() && !ReadMaps(get_wss_, false, false)) {
+        LOG(ERROR) << "Failed to read maps for Process " << pid_;
+    }
+
+    return maps_;
+}
+
 const std::vector<Vma>& ProcMemInfo::Smaps(const std::string& path) {
     if (!maps_.empty()) {
         return maps_;
@@ -213,29 +221,30 @@
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (pagemap_fd < 0) {
+    if (pagemap_fd == -1) {
         PLOG(ERROR) << "Failed to open " << pagemap_file;
         return false;
     }
 
     uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
-    pagemap->reserve(nr_pages);
+    pagemap->resize(nr_pages);
 
-    uint64_t idx = vma.start / getpagesize();
-    uint64_t last = idx + nr_pages;
-    uint64_t val;
-    for (; idx < last; idx++) {
-        if (pread64(pagemap_fd, &val, sizeof(uint64_t), idx * sizeof(uint64_t)) < 0) {
-            PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
-            return false;
-        }
-        pagemap->emplace_back(val);
+    size_t bytes_to_read = sizeof(uint64_t) * nr_pages;
+    off64_t start_addr = (vma.start / getpagesize()) * sizeof(uint64_t);
+    ssize_t bytes_read = pread64(pagemap_fd, pagemap->data(), bytes_to_read, start_addr);
+    if (bytes_read == -1) {
+        PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+        return false;
+    } else if (static_cast<size_t>(bytes_read) != bytes_to_read) {
+        LOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_
+                   << ": read bytes " << bytes_read << " expected bytes " << bytes_to_read;
+        return false;
     }
 
     return true;
 }
 
-bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) {
+bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool get_usage_stats) {
     // Each object reads /proc/<pid>/maps only once. This is done to make sure programs that are
     // running for the lifetime of the system can recycle the objects and don't have to
     // unnecessarily retain and update this object in memory (which can get significantly large).
@@ -256,6 +265,10 @@
         return false;
     }
 
+    if (!get_usage_stats) {
+        return true;
+    }
+
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));