Loading libmeminfo/include/meminfo/procmeminfo.h +4 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,10 @@ class ProcMemInfo final { // Same as Maps() except, do not read the usage stats for each map. const std::vector<Vma>& MapsWithoutUsageStats(); // If MapsWithoutUsageStats was called, this function will fill in // usage stats for this single vma. bool FillInVmaStats(Vma& vma); // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a // constant reference to the vma vector after the collection is done. // Loading libmeminfo/libmeminfo_test.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,33 @@ TEST(ProcMemInfo, MapsUsageEmpty) { } } TEST(ProcMemInfo, MapsUsageFillInLater) { ProcMemInfo proc_mem(pid); const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats(); EXPECT_FALSE(maps.empty()); for (auto& map : maps) { Vma update_map(map); ASSERT_EQ(map.start, update_map.start); ASSERT_EQ(map.end, update_map.end); ASSERT_EQ(map.offset, update_map.offset); ASSERT_EQ(map.flags, update_map.flags); ASSERT_EQ(map.name, update_map.name); ASSERT_EQ(0, update_map.usage.vss); ASSERT_EQ(0, update_map.usage.rss); ASSERT_EQ(0, update_map.usage.pss); ASSERT_EQ(0, update_map.usage.uss); ASSERT_EQ(0, update_map.usage.swap); ASSERT_EQ(0, update_map.usage.swap_pss); ASSERT_EQ(0, update_map.usage.private_clean); ASSERT_EQ(0, update_map.usage.private_dirty); ASSERT_EQ(0, update_map.usage.shared_clean); ASSERT_EQ(0, update_map.usage.shared_dirty); ASSERT_TRUE(proc_mem.FillInVmaStats(update_map)); // Check that at least one usage stat was updated. ASSERT_NE(0, update_map.usage.vss); } } TEST(ProcMemInfo, PageMapPresent) { static constexpr size_t kNumPages = 20; size_t pagesize = getpagesize(); Loading libmeminfo/procmeminfo.cpp +25 −5 Original line number Diff line number Diff line Loading @@ -244,6 +244,15 @@ bool ProcMemInfo::PageMap(const Vma& vma, std::vector<uint64_t>* pagemap) { return true; } static int GetPagemapFd(pid_t pid) { std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid); int fd = TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)); if (fd == -1) { PLOG(ERROR) << "Failed to open " << pagemap_file; } return fd; } 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 Loading @@ -269,11 +278,8 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool 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))); if (pagemap_fd < 0) { PLOG(ERROR) << "Failed to open " << pagemap_file; ::android::base::unique_fd pagemap_fd(GetPagemapFd(pid_)); if (pagemap_fd == -1) { return false; } Loading @@ -290,6 +296,20 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool get_usage_stats return true; } bool ProcMemInfo::FillInVmaStats(Vma& vma) { ::android::base::unique_fd pagemap_fd(GetPagemapFd(pid_)); if (pagemap_fd == -1) { return false; } if (!ReadVmaStats(pagemap_fd.get(), vma, get_wss_, false)) { LOG(ERROR) << "Failed to read page map for vma " << vma.name << "[" << vma.start << "-" << vma.end << "]"; return false; } return true; } bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle) { PageAcct& pinfo = PageAcct::Instance(); if (get_wss && use_pageidle && !pinfo.InitPageAcct(true)) { Loading Loading
libmeminfo/include/meminfo/procmeminfo.h +4 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,10 @@ class ProcMemInfo final { // Same as Maps() except, do not read the usage stats for each map. const std::vector<Vma>& MapsWithoutUsageStats(); // If MapsWithoutUsageStats was called, this function will fill in // usage stats for this single vma. bool FillInVmaStats(Vma& vma); // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a // constant reference to the vma vector after the collection is done. // Loading
libmeminfo/libmeminfo_test.cpp +27 −0 Original line number Diff line number Diff line Loading @@ -101,6 +101,33 @@ TEST(ProcMemInfo, MapsUsageEmpty) { } } TEST(ProcMemInfo, MapsUsageFillInLater) { ProcMemInfo proc_mem(pid); const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats(); EXPECT_FALSE(maps.empty()); for (auto& map : maps) { Vma update_map(map); ASSERT_EQ(map.start, update_map.start); ASSERT_EQ(map.end, update_map.end); ASSERT_EQ(map.offset, update_map.offset); ASSERT_EQ(map.flags, update_map.flags); ASSERT_EQ(map.name, update_map.name); ASSERT_EQ(0, update_map.usage.vss); ASSERT_EQ(0, update_map.usage.rss); ASSERT_EQ(0, update_map.usage.pss); ASSERT_EQ(0, update_map.usage.uss); ASSERT_EQ(0, update_map.usage.swap); ASSERT_EQ(0, update_map.usage.swap_pss); ASSERT_EQ(0, update_map.usage.private_clean); ASSERT_EQ(0, update_map.usage.private_dirty); ASSERT_EQ(0, update_map.usage.shared_clean); ASSERT_EQ(0, update_map.usage.shared_dirty); ASSERT_TRUE(proc_mem.FillInVmaStats(update_map)); // Check that at least one usage stat was updated. ASSERT_NE(0, update_map.usage.vss); } } TEST(ProcMemInfo, PageMapPresent) { static constexpr size_t kNumPages = 20; size_t pagesize = getpagesize(); Loading
libmeminfo/procmeminfo.cpp +25 −5 Original line number Diff line number Diff line Loading @@ -244,6 +244,15 @@ bool ProcMemInfo::PageMap(const Vma& vma, std::vector<uint64_t>* pagemap) { return true; } static int GetPagemapFd(pid_t pid) { std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid); int fd = TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)); if (fd == -1) { PLOG(ERROR) << "Failed to open " << pagemap_file; } return fd; } 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 Loading @@ -269,11 +278,8 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool 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))); if (pagemap_fd < 0) { PLOG(ERROR) << "Failed to open " << pagemap_file; ::android::base::unique_fd pagemap_fd(GetPagemapFd(pid_)); if (pagemap_fd == -1) { return false; } Loading @@ -290,6 +296,20 @@ bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool get_usage_stats return true; } bool ProcMemInfo::FillInVmaStats(Vma& vma) { ::android::base::unique_fd pagemap_fd(GetPagemapFd(pid_)); if (pagemap_fd == -1) { return false; } if (!ReadVmaStats(pagemap_fd.get(), vma, get_wss_, false)) { LOG(ERROR) << "Failed to read page map for vma " << vma.name << "[" << vma.start << "-" << vma.end << "]"; return false; } return true; } bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle) { PageAcct& pinfo = PageAcct::Instance(); if (get_wss && use_pageidle && !pinfo.InitPageAcct(true)) { Loading