Merge "Add method to get usage stats for a single map."
This commit is contained in:
commit
d1cb35bdef
3 changed files with 56 additions and 5 deletions
|
@ -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.
|
||||
//
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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…
Reference in a new issue