Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dfd34be4 authored by Sandeep Patil's avatar Sandeep Patil
Browse files

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: default avatarSandeep Patil <sspatil@google.com>
parent 8871e7e9
Loading
Loading
Loading
Loading
+9 −3
Original line number Original line Diff line number Diff line
@@ -64,12 +64,12 @@ class ProcMemInfo final {
    //   private_dirty
    //   private_dirty
    //   SwapPss
    //   SwapPss
    // All other fields of MemUsage are zeroed.
    // 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
    // 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.
    // 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();
    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.
// same format as /proc/<pid>/smaps. Returns 'false' if the file is malformed.
bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback);
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
// Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly
// from a file. The file MUST be in the same format as /proc/<pid>/smaps
// from a file. The file MUST be in the same format as /proc/<pid>/smaps
// or /proc/<pid>/smaps_rollup
// or /proc/<pid>/smaps_rollup
+10 −1
Original line number Original line Diff line number Diff line
@@ -284,13 +284,22 @@ TEST(TestProcMemInfo, SwapOffsetsEmpty) {
    EXPECT_EQ(swap_offsets.size(), 0);
    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) {
TEST(TestProcMemInfo, SmapsOrRollupReturn) {
    // if /proc/<pid>/smaps_rollup file exists, .SmapsRollup() must return true;
    // if /proc/<pid>/smaps_rollup file exists, .SmapsRollup() must return true;
    // false otherwise
    // false otherwise
    std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid);
    std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid);
    ProcMemInfo proc_mem(pid);
    ProcMemInfo proc_mem(pid);
    MemUsage stats;
    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) {
TEST(TestProcMemInfo, SmapsOrRollupTest) {
+33 −7
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>


#include <atomic>
#include <fstream>
#include <fstream>
#include <iostream>
#include <iostream>
#include <memory>
#include <memory>
@@ -172,15 +173,15 @@ bool ProcMemInfo::ForEachVma(const VmaCallback& callback) {
    return ForEachVmaFromFile(path, callback);
    return ForEachVmaFromFile(path, callback);
}
}


bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const {
bool ProcMemInfo::SmapsOrRollup(MemUsage* stats) const {
    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
    std::string path = ::android::base::StringPrintf(
                                                     use_rollup ? "smaps_rollup" : "smaps");
            "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps");
    return SmapsOrRollupFromFile(path, stats);
    return SmapsOrRollupFromFile(path, stats);
};
}


bool ProcMemInfo::SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const {
bool ProcMemInfo::SmapsOrRollupPss(uint64_t* pss) const {
    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
    std::string path = ::android::base::StringPrintf(
                                                     use_rollup ? "smaps_rollup" : "smaps");
            "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps");
    return SmapsOrRollupPssFromFile(path, pss);
    return SmapsOrRollupPssFromFile(path, pss);
}
}


@@ -374,6 +375,31 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) {
    return true;
    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) {
bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) {
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    if (fp == nullptr) {
    if (fp == nullptr) {