Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f688f5b authored by Sandeep Patil's avatar Sandeep Patil Committed by android-build-merger
Browse files

Merge "meminfo: Add API to read pagemap for a vma within a process."

am: 15a3a287

Change-Id: I3dba7766030dfebd5732f6586fdcbde7245385fd
parents e8b2ac49 15a3a287
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -65,5 +65,17 @@ class PageAcct final {
    ::android::base::unique_fd pageidle_fd_;
};

// Returns if the page present bit is set in the value
// passed in.
bool page_present(uint64_t pagemap_val);

// Returns if the page swapped bit is set in the value
// passed in.
bool page_swapped(uint64_t pagemap_val);

// Returns the page frame number (physical page) from
// pagemap value
uint64_t page_pfn(uint64_t pagemap_val);

}  // namespace meminfo
}  // namespace android
+7 −0
Original line number Diff line number Diff line
@@ -73,6 +73,13 @@ class ProcMemInfo final {

    const std::vector<uint16_t>& SwapOffsets();

    // Reads /proc/<pid>/pagemap for this process for each page within
    // the 'vma' and stores that in 'pagemap'. It is assumed that the 'vma'
    // is obtained by calling Maps() or 'ForEachVma' for the same object. No special checks
    // are made to see if 'vma' is *valid*.
    // Returns false if anything goes wrong, 'true' otherwise.
    bool PageMap(const Vma& vma, std::vector<uint64_t>* pagemap);

    ~ProcMemInfo() = default;

  private:
+17 −0
Original line number Diff line number Diff line
@@ -121,6 +121,23 @@ TEST_F(ValidateProcMemInfo, TestSwapOffsets) {
    EXPECT_EQ(proc_usage.swap / getpagesize(), swap_offsets.size());
}

TEST_F(ValidateProcMemInfo, TestPageMap) {
    std::vector<uint64_t> pagemap;

    auto vma_callback = [&](const Vma& vma) {
        uint64_t* pmap_out;
        size_t len;
        ASSERT_EQ(0, pm_process_pagemap_range(proc, vma.start, vma.end, &pmap_out, &len));
        ASSERT_TRUE(proc_mem->PageMap(vma, &pagemap));

        EXPECT_EQ(len, ((vma.end - vma.start) / getpagesize()));
        for (size_t i = 0; i < len; i++) {
            EXPECT_EQ(pmap_out[i], pagemap[i]);
        }
    };
    ASSERT_TRUE(proc_mem->ForEachVma(vma_callback));
}

class ValidateProcMemInfoWss : public ::testing::Test {
  protected:
    void SetUp() override {
+13 −0
Original line number Diff line number Diff line
@@ -138,5 +138,18 @@ int PageAcct::GetPageIdle(uint64_t pfn) const {
    return !!(idle_bits & (1ULL << (pfn % 64)));
}

// Public methods
bool page_present(uint64_t pagemap_val) {
    return PAGE_PRESENT(pagemap_val);
}

bool page_swapped(uint64_t pagemap_val) {
    return PAGE_SWAPPED(pagemap_val);
}

uint64_t page_pfn(uint64_t pagemap_val) {
    return PAGE_PFN(pagemap_val);
}

}  // namespace meminfo
}  // namespace android
+27 −0
Original line number Diff line number Diff line
@@ -199,6 +199,33 @@ const std::vector<uint16_t>& ProcMemInfo::SwapOffsets() {
    return swap_offsets_;
}

bool ProcMemInfo::PageMap(const Vma& vma, std::vector<uint64_t>* pagemap) {
    pagemap->clear();
    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) {
        PLOG(ERROR) << "Failed to open " << pagemap_file;
        return false;
    }

    uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
    pagemap->reserve(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);
    }

    return true;
}

bool ProcMemInfo::ReadMaps(bool get_wss) {
    // 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