meminfo: Add IsSmapsRollupSupported Api
Consolidate the checking of /proc/<pid>/smaps_rollup support in libmeminfo and do it in a thread safe way. Use the API in ProcMemInfo as well to eliminate the extra parameters passed to SmapsOrRollup* methods. Bug: 111694435 Test: libmeminfo_test 1 --gtest_filter=TestProcMemInfo.IsSmapsSupportedTest Test: Tested with and without the smaps_rollup support in kernel. Change-Id: I992057f06b54569025fa0cdade9618da2675d1de Merged-In: I992057f06b54569025fa0cdade9618da2675d1de Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
parent
8871e7e90f
commit
dfd34be42b
3 changed files with 52 additions and 11 deletions
|
@ -64,12 +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. The 'use_rollup' parameter decides which file is to be tried.
|
||||
// Pss.
|
||||
// Returns 'true' on success and the value of Pss in the out parameter.
|
||||
bool SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const;
|
||||
bool SmapsOrRollupPss(uint64_t* pss) const;
|
||||
|
||||
const std::vector<uint16_t>& SwapOffsets();
|
||||
|
||||
|
@ -94,6 +94,12 @@ 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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
@ -172,15 +173,15 @@ 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(bool use_rollup, uint64_t* pss) const {
|
||||
std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
|
||||
use_rollup ? "smaps_rollup" : "smaps");
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -374,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…
Reference in a new issue