meminfo: Add API to read pagemap for a vma within a process.
.. and make sure we have some helper methods exposed to the clients to do some basic checks for the pagemap values. For example, to check if the page is present or swapped. Bug: 111694435 Test: libmeminfo_test 1 --gtest_filter=ValidateProcMemInfo.TestPageMap Test: libmeminfo_test 1 Change-Id: Ic6ae91f4214b42346f3d0b54164a43ac79d5ade1 Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
parent
380995adc7
commit
cbc8f123d8
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue