Loading libmeminfo/include/meminfo/pageacct.h +12 −0 Original line number Diff line number Diff line Loading @@ -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 libmeminfo/include/meminfo/procmeminfo.h +7 −0 Original line number Diff line number Diff line Loading @@ -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: Loading libmeminfo/libmeminfo_test.cpp +17 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading libmeminfo/pageacct.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -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 libmeminfo/procmeminfo.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
libmeminfo/include/meminfo/pageacct.h +12 −0 Original line number Diff line number Diff line Loading @@ -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
libmeminfo/include/meminfo/procmeminfo.h +7 −0 Original line number Diff line number Diff line Loading @@ -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: Loading
libmeminfo/libmeminfo_test.cpp +17 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading
libmeminfo/pageacct.cpp +13 −0 Original line number Diff line number Diff line Loading @@ -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
libmeminfo/procmeminfo.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -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