Loading libmeminfo/include/meminfo/meminfo.h +1 −6 Original line number Diff line number Diff line Loading @@ -72,15 +72,10 @@ struct Vma { : start(s), end(e), offset(off), flags(f), name(n) {} ~Vma() = default; void clear() { memset(&usage, 0, sizeof(usage)); memset(&wss, 0, sizeof(wss)); } void clear() { memset(&usage, 0, sizeof(usage)); } // Memory usage of this mapping. MemUsage usage; // Working set within this mapping. MemUsage wss; }; } // namespace meminfo Loading libmeminfo/include/meminfo/procmeminfo.h +17 −2 Original line number Diff line number Diff line Loading @@ -64,7 +64,12 @@ class ProcMemInfo final { // private_dirty // SwapPss // All other fields of MemUsage are zeroed. bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const; bool SmapsOrRollup(MemUsage* stats) const; // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's // Pss. // Returns 'true' on success and the value of Pss in the out parameter. bool SmapsOrRollupPss(uint64_t* pss) const; const std::vector<uint16_t>& SwapOffsets(); Loading @@ -82,7 +87,6 @@ class ProcMemInfo final { std::vector<Vma> maps_; MemUsage usage_; MemUsage wss_; std::vector<uint16_t> swap_offsets_; }; Loading @@ -90,10 +94,21 @@ class ProcMemInfo final { // same format as /proc/<pid>/smaps. Returns 'false' if the file is malformed. bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback); // Returns if the kernel supports /proc/<pid>/smaps_rollup. Assumes that the // calling process has access to the /proc/<pid>/smaps_rollup. // Returns 'false' if the calling process has no permission to read the file if it exists // of if the file doesn't exist. bool IsSmapsRollupSupported(pid_t pid); // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly // from a file. The file MUST be in the same format as /proc/<pid>/smaps // or /proc/<pid>/smaps_rollup bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats); // Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly // from a file and returns total Pss in kB. The file MUST be in the same format // as /proc/<pid>/smaps or /proc/<pid>/smaps_rollup bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss); } // namespace meminfo } // namespace android libmeminfo/libmeminfo_test.cpp +59 −1 Original line number Diff line number Diff line Loading @@ -284,13 +284,22 @@ TEST(TestProcMemInfo, SwapOffsetsEmpty) { EXPECT_EQ(swap_offsets.size(), 0); } TEST(TestProcMemInfo, IsSmapsSupportedTest) { std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); bool supported = IsSmapsRollupSupported(pid); EXPECT_EQ(!access(path.c_str(), F_OK | R_OK), supported); // Second call must return what the first one returned regardless of the pid parameter. // So, deliberately pass invalid pid. EXPECT_EQ(supported, IsSmapsRollupSupported(-1)); } TEST(TestProcMemInfo, SmapsOrRollupReturn) { // if /proc/<pid>/smaps_rollup file exists, .SmapsRollup() must return true; // false otherwise std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); ProcMemInfo proc_mem(pid); MemUsage stats; EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(true, &stats)); EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(&stats)); } TEST(TestProcMemInfo, SmapsOrRollupTest) { Loading Loading @@ -365,6 +374,50 @@ VmFlags: rd wr mr mw me ac EXPECT_EQ(stats.swap_pss, 70); } TEST(TestProcMemInfo, SmapsOrRollupPssRollupTest) { // This is a made up smaps for the test std::string smaps = R"smaps(12c00000-13440000 rw-p 00000000 00:00 0 [anon:dalvik-main space (region space)] Name: [anon:dalvik-main space (region space)] Size: 8448 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 2652 kB Pss: 2652 kB Shared_Clean: 840 kB Shared_Dirty: 40 kB Private_Clean: 84 kB Private_Dirty: 2652 kB Referenced: 2652 kB Anonymous: 2652 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 102 kB SwapPss: 70 kB Locked: 2652 kB VmFlags: rd wr mr mw me ac )smaps"; TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); ASSERT_TRUE(::android::base::WriteStringToFd(smaps, tf.fd)); uint64_t pss; ASSERT_EQ(SmapsOrRollupPssFromFile(tf.path, &pss), true); EXPECT_EQ(pss, 2652); } TEST(TestProcMemInfo, SmapsOrRollupPssSmapsTest) { std::string exec_dir = ::android::base::GetExecutableDirectory(); std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str()); uint64_t pss; ASSERT_EQ(SmapsOrRollupPssFromFile(path, &pss), true); EXPECT_EQ(pss, 19119); } TEST(TestProcMemInfo, ForEachVmaFromFileTest) { std::string exec_dir = ::android::base::GetExecutableDirectory(); std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str()); Loading @@ -374,6 +427,9 @@ TEST(TestProcMemInfo, ForEachVmaFromFileTest) { auto collect_vmas = [&](const Vma& v) { vmas.push_back(v); }; ASSERT_TRUE(ForEachVmaFromFile(path, collect_vmas)); // We should get a total of 6 vmas ASSERT_EQ(vmas.size(), 6); // Expect values to be equal to what we have in testdata1/smaps_short // Check for sizes first ASSERT_EQ(vmas[0].usage.vss, 32768); Loading Loading @@ -468,6 +524,8 @@ TEST(TestProcMemInfo, SmapsTest) { auto vmas = proc_mem.Smaps(path); ASSERT_FALSE(vmas.empty()); // We should get a total of 6 vmas ASSERT_EQ(vmas.size(), 6); // Expect values to be equal to what we have in testdata1/smaps_short // Check for sizes first Loading libmeminfo/procmeminfo.cpp +69 −34 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <stdio.h> #include <unistd.h> #include <atomic> #include <fstream> #include <iostream> #include <memory> Loading Loading @@ -157,14 +158,14 @@ const MemUsage& ProcMemInfo::Wss() { if (!get_wss_) { LOG(WARNING) << "Trying to read process working set for " << pid_ << " using invalid object"; return wss_; return usage_; } if (maps_.empty() && !ReadMaps(get_wss_)) { LOG(ERROR) << "Failed to get working set for Process " << pid_; } return wss_; return usage_; } bool ProcMemInfo::ForEachVma(const VmaCallback& callback) { Loading @@ -172,11 +173,17 @@ bool ProcMemInfo::ForEachVma(const VmaCallback& callback) { return ForEachVmaFromFile(path, callback); } bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const { std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_, use_rollup ? "smaps_rollup" : "smaps"); bool ProcMemInfo::SmapsOrRollup(MemUsage* stats) const { std::string path = ::android::base::StringPrintf( "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps"); return SmapsOrRollupFromFile(path, stats); }; } bool ProcMemInfo::SmapsOrRollupPss(uint64_t* pss) const { std::string path = ::android::base::StringPrintf( "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps"); return SmapsOrRollupPssFromFile(path, pss); } const std::vector<uint16_t>& ProcMemInfo::SwapOffsets() { if (get_wss_) { Loading Loading @@ -228,12 +235,8 @@ bool ProcMemInfo::ReadMaps(bool get_wss) { maps_.clear(); return false; } if (get_wss) { add_mem_usage(&wss_, vma.wss); } else { add_mem_usage(&usage_, vma.usage); } } return true; } Loading Loading @@ -300,18 +303,9 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) { // This effectively makes vss = rss for the working set is requested. // The libpagemap implementation returns vss > rss for // working set, which doesn't make sense. vma.wss.vss += pagesz; vma.wss.rss += pagesz; vma.wss.uss += is_private ? pagesz : 0; vma.wss.pss += pagesz / pg_counts[i]; if (is_private) { vma.wss.private_dirty += is_dirty ? pagesz : 0; vma.wss.private_clean += is_dirty ? 0 : pagesz; } else { vma.wss.shared_dirty += is_dirty ? pagesz : 0; vma.wss.shared_clean += is_dirty ? 0 : pagesz; vma.usage.vss += pagesz; } } else { vma.usage.rss += pagesz; vma.usage.uss += is_private ? pagesz : 0; vma.usage.pss += pagesz / pg_counts[i]; Loading @@ -323,8 +317,6 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) { vma.usage.shared_clean += is_dirty ? 0 : pagesz; } } } return true; } Loading @@ -338,8 +330,9 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) { char* line = nullptr; bool parsing_vma = false; ssize_t line_len; size_t line_alloc = 0; Vma vma; while ((line_len = getline(&line, 0, fp.get())) > 0) { while ((line_len = getline(&line, &line_alloc, fp.get())) > 0) { // Make sure the line buffer terminates like a C string for ReadMapFile line[line_len] = '\0'; Loading Loading @@ -382,6 +375,31 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) { return true; } enum smaps_rollup_support { UNTRIED, SUPPORTED, UNSUPPORTED }; static std::atomic<smaps_rollup_support> g_rollup_support = UNTRIED; bool IsSmapsRollupSupported(pid_t pid) { // Similar to OpenSmapsOrRollup checks from android_os_Debug.cpp, except // the method only checks if rollup is supported and returns the status // right away. enum smaps_rollup_support rollup_support = g_rollup_support.load(std::memory_order_relaxed); if (rollup_support != UNTRIED) { return rollup_support == SUPPORTED; } std::string rollup_file = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); if (access(rollup_file.c_str(), F_OK | R_OK)) { // No check for errno = ENOENT necessary here. The caller MUST fallback to // using /proc/<pid>/smaps instead anyway. g_rollup_support.store(UNSUPPORTED, std::memory_order_relaxed); return false; } g_rollup_support.store(SUPPORTED, std::memory_order_relaxed); LOG(INFO) << "Using smaps_rollup for pss collection"; return true; } bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) { auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose}; if (fp == nullptr) { Loading Loading @@ -426,5 +444,22 @@ bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) { return true; } bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss) { auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose}; if (fp == nullptr) { return false; } *pss = 0; char line[1024]; while (fgets(line, sizeof(line), fp.get()) != nullptr) { uint64_t v; if (sscanf(line, "Pss: %" SCNu64 " kB", &v) == 1) { *pss += v; } } return true; } } // namespace meminfo } // namespace android libmeminfo/tools/procmem.cpp +6 −6 Original line number Diff line number Diff line Loading @@ -98,7 +98,7 @@ static int show(const MemUsage& proc_stats, const std::vector<Vma>& maps) { std::stringstream ss; print_header(ss); for (auto& vma : maps) { const MemUsage& vma_stats = show_wss ? vma.wss : vma.usage; const MemUsage& vma_stats = vma.usage; if (hide_zeroes && vma_stats.rss == 0) { continue; } Loading @@ -116,14 +116,14 @@ static int show(const MemUsage& proc_stats, const std::vector<Vma>& maps) { int main(int argc, char* argv[]) { int opt; auto pss_sort = [](const Vma& a, const Vma& b) { uint64_t pss_a = show_wss ? a.wss.pss : a.usage.pss; uint64_t pss_b = show_wss ? b.wss.pss : b.usage.pss; uint64_t pss_a = a.usage.pss; uint64_t pss_b = b.usage.pss; return pss_a > pss_b; }; auto uss_sort = [](const Vma& a, const Vma& b) { uint64_t uss_a = show_wss ? a.wss.uss : a.usage.uss; uint64_t uss_b = show_wss ? b.wss.uss : b.usage.uss; uint64_t uss_a = a.usage.uss; uint64_t uss_b = b.usage.uss; return uss_a > uss_b; }; Loading Loading @@ -182,7 +182,7 @@ int main(int argc, char* argv[]) { } ProcMemInfo proc(pid, show_wss); const MemUsage& proc_stats = show_wss ? proc.Wss() : proc.Usage(); const MemUsage& proc_stats = proc.Usage(); std::vector<Vma> maps(proc.Maps()); if (sort_func != nullptr) { std::sort(maps.begin(), maps.end(), sort_func); Loading Loading
libmeminfo/include/meminfo/meminfo.h +1 −6 Original line number Diff line number Diff line Loading @@ -72,15 +72,10 @@ struct Vma { : start(s), end(e), offset(off), flags(f), name(n) {} ~Vma() = default; void clear() { memset(&usage, 0, sizeof(usage)); memset(&wss, 0, sizeof(wss)); } void clear() { memset(&usage, 0, sizeof(usage)); } // Memory usage of this mapping. MemUsage usage; // Working set within this mapping. MemUsage wss; }; } // namespace meminfo Loading
libmeminfo/include/meminfo/procmeminfo.h +17 −2 Original line number Diff line number Diff line Loading @@ -64,7 +64,12 @@ class ProcMemInfo final { // private_dirty // SwapPss // All other fields of MemUsage are zeroed. bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const; bool SmapsOrRollup(MemUsage* stats) const; // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's // Pss. // Returns 'true' on success and the value of Pss in the out parameter. bool SmapsOrRollupPss(uint64_t* pss) const; const std::vector<uint16_t>& SwapOffsets(); Loading @@ -82,7 +87,6 @@ class ProcMemInfo final { std::vector<Vma> maps_; MemUsage usage_; MemUsage wss_; std::vector<uint16_t> swap_offsets_; }; Loading @@ -90,10 +94,21 @@ class ProcMemInfo final { // same format as /proc/<pid>/smaps. Returns 'false' if the file is malformed. bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback); // Returns if the kernel supports /proc/<pid>/smaps_rollup. Assumes that the // calling process has access to the /proc/<pid>/smaps_rollup. // Returns 'false' if the calling process has no permission to read the file if it exists // of if the file doesn't exist. bool IsSmapsRollupSupported(pid_t pid); // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly // from a file. The file MUST be in the same format as /proc/<pid>/smaps // or /proc/<pid>/smaps_rollup bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats); // Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly // from a file and returns total Pss in kB. The file MUST be in the same format // as /proc/<pid>/smaps or /proc/<pid>/smaps_rollup bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss); } // namespace meminfo } // namespace android
libmeminfo/libmeminfo_test.cpp +59 −1 Original line number Diff line number Diff line Loading @@ -284,13 +284,22 @@ TEST(TestProcMemInfo, SwapOffsetsEmpty) { EXPECT_EQ(swap_offsets.size(), 0); } TEST(TestProcMemInfo, IsSmapsSupportedTest) { std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); bool supported = IsSmapsRollupSupported(pid); EXPECT_EQ(!access(path.c_str(), F_OK | R_OK), supported); // Second call must return what the first one returned regardless of the pid parameter. // So, deliberately pass invalid pid. EXPECT_EQ(supported, IsSmapsRollupSupported(-1)); } TEST(TestProcMemInfo, SmapsOrRollupReturn) { // if /proc/<pid>/smaps_rollup file exists, .SmapsRollup() must return true; // false otherwise std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); ProcMemInfo proc_mem(pid); MemUsage stats; EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(true, &stats)); EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(&stats)); } TEST(TestProcMemInfo, SmapsOrRollupTest) { Loading Loading @@ -365,6 +374,50 @@ VmFlags: rd wr mr mw me ac EXPECT_EQ(stats.swap_pss, 70); } TEST(TestProcMemInfo, SmapsOrRollupPssRollupTest) { // This is a made up smaps for the test std::string smaps = R"smaps(12c00000-13440000 rw-p 00000000 00:00 0 [anon:dalvik-main space (region space)] Name: [anon:dalvik-main space (region space)] Size: 8448 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Rss: 2652 kB Pss: 2652 kB Shared_Clean: 840 kB Shared_Dirty: 40 kB Private_Clean: 84 kB Private_Dirty: 2652 kB Referenced: 2652 kB Anonymous: 2652 kB AnonHugePages: 0 kB ShmemPmdMapped: 0 kB Shared_Hugetlb: 0 kB Private_Hugetlb: 0 kB Swap: 102 kB SwapPss: 70 kB Locked: 2652 kB VmFlags: rd wr mr mw me ac )smaps"; TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); ASSERT_TRUE(::android::base::WriteStringToFd(smaps, tf.fd)); uint64_t pss; ASSERT_EQ(SmapsOrRollupPssFromFile(tf.path, &pss), true); EXPECT_EQ(pss, 2652); } TEST(TestProcMemInfo, SmapsOrRollupPssSmapsTest) { std::string exec_dir = ::android::base::GetExecutableDirectory(); std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str()); uint64_t pss; ASSERT_EQ(SmapsOrRollupPssFromFile(path, &pss), true); EXPECT_EQ(pss, 19119); } TEST(TestProcMemInfo, ForEachVmaFromFileTest) { std::string exec_dir = ::android::base::GetExecutableDirectory(); std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str()); Loading @@ -374,6 +427,9 @@ TEST(TestProcMemInfo, ForEachVmaFromFileTest) { auto collect_vmas = [&](const Vma& v) { vmas.push_back(v); }; ASSERT_TRUE(ForEachVmaFromFile(path, collect_vmas)); // We should get a total of 6 vmas ASSERT_EQ(vmas.size(), 6); // Expect values to be equal to what we have in testdata1/smaps_short // Check for sizes first ASSERT_EQ(vmas[0].usage.vss, 32768); Loading Loading @@ -468,6 +524,8 @@ TEST(TestProcMemInfo, SmapsTest) { auto vmas = proc_mem.Smaps(path); ASSERT_FALSE(vmas.empty()); // We should get a total of 6 vmas ASSERT_EQ(vmas.size(), 6); // Expect values to be equal to what we have in testdata1/smaps_short // Check for sizes first Loading
libmeminfo/procmeminfo.cpp +69 −34 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <stdio.h> #include <unistd.h> #include <atomic> #include <fstream> #include <iostream> #include <memory> Loading Loading @@ -157,14 +158,14 @@ const MemUsage& ProcMemInfo::Wss() { if (!get_wss_) { LOG(WARNING) << "Trying to read process working set for " << pid_ << " using invalid object"; return wss_; return usage_; } if (maps_.empty() && !ReadMaps(get_wss_)) { LOG(ERROR) << "Failed to get working set for Process " << pid_; } return wss_; return usage_; } bool ProcMemInfo::ForEachVma(const VmaCallback& callback) { Loading @@ -172,11 +173,17 @@ bool ProcMemInfo::ForEachVma(const VmaCallback& callback) { return ForEachVmaFromFile(path, callback); } bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const { std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_, use_rollup ? "smaps_rollup" : "smaps"); bool ProcMemInfo::SmapsOrRollup(MemUsage* stats) const { std::string path = ::android::base::StringPrintf( "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps"); return SmapsOrRollupFromFile(path, stats); }; } bool ProcMemInfo::SmapsOrRollupPss(uint64_t* pss) const { std::string path = ::android::base::StringPrintf( "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps"); return SmapsOrRollupPssFromFile(path, pss); } const std::vector<uint16_t>& ProcMemInfo::SwapOffsets() { if (get_wss_) { Loading Loading @@ -228,12 +235,8 @@ bool ProcMemInfo::ReadMaps(bool get_wss) { maps_.clear(); return false; } if (get_wss) { add_mem_usage(&wss_, vma.wss); } else { add_mem_usage(&usage_, vma.usage); } } return true; } Loading Loading @@ -300,18 +303,9 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) { // This effectively makes vss = rss for the working set is requested. // The libpagemap implementation returns vss > rss for // working set, which doesn't make sense. vma.wss.vss += pagesz; vma.wss.rss += pagesz; vma.wss.uss += is_private ? pagesz : 0; vma.wss.pss += pagesz / pg_counts[i]; if (is_private) { vma.wss.private_dirty += is_dirty ? pagesz : 0; vma.wss.private_clean += is_dirty ? 0 : pagesz; } else { vma.wss.shared_dirty += is_dirty ? pagesz : 0; vma.wss.shared_clean += is_dirty ? 0 : pagesz; vma.usage.vss += pagesz; } } else { vma.usage.rss += pagesz; vma.usage.uss += is_private ? pagesz : 0; vma.usage.pss += pagesz / pg_counts[i]; Loading @@ -323,8 +317,6 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) { vma.usage.shared_clean += is_dirty ? 0 : pagesz; } } } return true; } Loading @@ -338,8 +330,9 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) { char* line = nullptr; bool parsing_vma = false; ssize_t line_len; size_t line_alloc = 0; Vma vma; while ((line_len = getline(&line, 0, fp.get())) > 0) { while ((line_len = getline(&line, &line_alloc, fp.get())) > 0) { // Make sure the line buffer terminates like a C string for ReadMapFile line[line_len] = '\0'; Loading Loading @@ -382,6 +375,31 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) { return true; } enum smaps_rollup_support { UNTRIED, SUPPORTED, UNSUPPORTED }; static std::atomic<smaps_rollup_support> g_rollup_support = UNTRIED; bool IsSmapsRollupSupported(pid_t pid) { // Similar to OpenSmapsOrRollup checks from android_os_Debug.cpp, except // the method only checks if rollup is supported and returns the status // right away. enum smaps_rollup_support rollup_support = g_rollup_support.load(std::memory_order_relaxed); if (rollup_support != UNTRIED) { return rollup_support == SUPPORTED; } std::string rollup_file = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); if (access(rollup_file.c_str(), F_OK | R_OK)) { // No check for errno = ENOENT necessary here. The caller MUST fallback to // using /proc/<pid>/smaps instead anyway. g_rollup_support.store(UNSUPPORTED, std::memory_order_relaxed); return false; } g_rollup_support.store(SUPPORTED, std::memory_order_relaxed); LOG(INFO) << "Using smaps_rollup for pss collection"; return true; } bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) { auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose}; if (fp == nullptr) { Loading Loading @@ -426,5 +444,22 @@ bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) { return true; } bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss) { auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose}; if (fp == nullptr) { return false; } *pss = 0; char line[1024]; while (fgets(line, sizeof(line), fp.get()) != nullptr) { uint64_t v; if (sscanf(line, "Pss: %" SCNu64 " kB", &v) == 1) { *pss += v; } } return true; } } // namespace meminfo } // namespace android
libmeminfo/tools/procmem.cpp +6 −6 Original line number Diff line number Diff line Loading @@ -98,7 +98,7 @@ static int show(const MemUsage& proc_stats, const std::vector<Vma>& maps) { std::stringstream ss; print_header(ss); for (auto& vma : maps) { const MemUsage& vma_stats = show_wss ? vma.wss : vma.usage; const MemUsage& vma_stats = vma.usage; if (hide_zeroes && vma_stats.rss == 0) { continue; } Loading @@ -116,14 +116,14 @@ static int show(const MemUsage& proc_stats, const std::vector<Vma>& maps) { int main(int argc, char* argv[]) { int opt; auto pss_sort = [](const Vma& a, const Vma& b) { uint64_t pss_a = show_wss ? a.wss.pss : a.usage.pss; uint64_t pss_b = show_wss ? b.wss.pss : b.usage.pss; uint64_t pss_a = a.usage.pss; uint64_t pss_b = b.usage.pss; return pss_a > pss_b; }; auto uss_sort = [](const Vma& a, const Vma& b) { uint64_t uss_a = show_wss ? a.wss.uss : a.usage.uss; uint64_t uss_b = show_wss ? b.wss.uss : b.usage.uss; uint64_t uss_a = a.usage.uss; uint64_t uss_b = b.usage.uss; return uss_a > uss_b; }; Loading Loading @@ -182,7 +182,7 @@ int main(int argc, char* argv[]) { } ProcMemInfo proc(pid, show_wss); const MemUsage& proc_stats = show_wss ? proc.Wss() : proc.Usage(); const MemUsage& proc_stats = proc.Usage(); std::vector<Vma> maps(proc.Maps()); if (sort_func != nullptr) { std::sort(maps.begin(), maps.end(), sort_func); Loading