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

Commit 4bdced8d authored by Sandeep Patil's avatar Sandeep Patil Committed by android-build-merger
Browse files

Merge changes from topic "meminfo-apis" am: e16c2ce6

am: fd7b2b2e

Change-Id: I89421f1fab7b6c9da570cc2195543e64ea4d4137
parents d417e5a5 fd7b2b2e
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -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
+17 −2
Original line number Diff line number Diff line
@@ -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();

@@ -82,7 +87,6 @@ class ProcMemInfo final {
    std::vector<Vma> maps_;

    MemUsage usage_;
    MemUsage wss_;
    std::vector<uint16_t> swap_offsets_;
};

@@ -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
+59 −1
Original line number Diff line number Diff line
@@ -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) {
@@ -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());
@@ -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);
@@ -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
+69 −34
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <unistd.h>

#include <atomic>
#include <fstream>
#include <iostream>
#include <memory>
@@ -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) {
@@ -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_) {
@@ -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;
}
@@ -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];
@@ -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;
}

@@ -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';

@@ -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) {
@@ -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
+6 −6
Original line number Diff line number Diff line
@@ -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;
        }
@@ -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;
    };

@@ -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