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

Commit 70fa72dd authored by Sandeep Patil's avatar Sandeep Patil
Browse files

libmeminfo: Add support to read zram memory consumption



Bug: 114325007
Bug: 111694435
Test: libmeminfo_test 1 --gtest_filter=SysMemInfoParse.TestZramTotal
Benchmark: libmeminfo_benchmark --benchmark_filter=BM_.*ZramTotal
Benchmark Result on Blueline:
-----------------------------------------------------------
Benchmark                    Time           CPU Iterations
-----------------------------------------------------------
BM_OldReadZramTotal       3857 ns       3839 ns     134096
BM_NewReadZramTotal       4461 ns       4440 ns     157341

Change-Id: I5220fa17b101981ef859179960fe78fe68e84852
Signed-off-by: default avatarSandeep Patil <sspatil@google.com>
parent 2259fdf7
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -54,6 +54,11 @@ cc_test {
    srcs: [
        "libmeminfo_test.cpp"
    ],

    data: [
        "testdata1/*",
        "testdata2/*"
    ],
}

cc_benchmark {
@@ -67,4 +72,8 @@ cc_benchmark {
        "libmeminfo",
        "libprocinfo",
    ],

    data: [
        "testdata1/*",
    ],
}
+2 −2
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ class SysMemInfo final {
    static constexpr const char* kMemSUnreclaim = "SUnreclaim:";
    static constexpr const char* kMemSwapTotal = "SwapTotal:";
    static constexpr const char* kMemSwapFree = "SwapFree:";
    static constexpr const char* kMemZram = "Zram:";
    static constexpr const char* kMemMapped = "Mapped:";
    static constexpr const char* kMemVmallocUsed = "VmallocUsed:";
    static constexpr const char* kMemPageTables = "PageTables:";
@@ -64,14 +63,15 @@ class SysMemInfo final {
    uint64_t mem_slab_unreclaimable_kb() { return mem_in_kb_[kMemSUnreclaim]; }
    uint64_t mem_swap_kb() { return mem_in_kb_[kMemSwapTotal]; }
    uint64_t mem_swap_free_kb() { return mem_in_kb_[kMemSwapFree]; }
    uint64_t mem_zram_kb() { return mem_in_kb_[kMemZram]; }
    uint64_t mem_mapped_kb() { return mem_in_kb_[kMemMapped]; }
    uint64_t mem_vmalloc_used_kb() { return mem_in_kb_[kMemVmallocUsed]; }
    uint64_t mem_page_tables_kb() { return mem_in_kb_[kMemPageTables]; }
    uint64_t mem_kernel_stack_kb() { return mem_in_kb_[kMemPageTables]; }
    uint64_t mem_zram_kb(const std::string& zram_dev = "");

  private:
    std::map<std::string, uint64_t> mem_in_kb_;
    bool MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev);
};

}  // namespace meminfo
+56 −5
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#include <meminfo/sysmeminfo.h>

#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>

@@ -46,7 +48,7 @@ enum {
    MEMINFO_COUNT
};

void get_mem_info(uint64_t mem[], const char* file) {
static void get_mem_info(uint64_t mem[], const char* file) {
    char buffer[4096];
    unsigned int numFound = 0;

@@ -69,7 +71,8 @@ void get_mem_info(uint64_t mem[], const char* file) {
    static const char* const tags[] = {
            "MemTotal:",     "MemFree:",    "Buffers:",     "Cached:",   "Shmem:", "Slab:",
            "SReclaimable:", "SUnreclaim:", "SwapTotal:",   "SwapFree:", "ZRam:",  "Mapped:",
            "VmallocUsed:",  "PageTables:", "KernelStack:", NULL};
            "VmallocUsed:",  "PageTables:", "KernelStack:", NULL
    };

    static const int tagsLen[] = {9, 8, 8, 7, 6, 5, 13, 11, 10, 9, 5, 7, 12, 11, 12, 0};

@@ -78,7 +81,8 @@ void get_mem_info(uint64_t mem[], const char* file) {
    while (*p && (numFound < (sizeof(tagsLen) / sizeof(tagsLen[0])))) {
        int i = 0;
        while (tags[i]) {
            //std::cout << "tag =" << tags[i] << " p = " << std::string(p, tagsLen[i]) << std::endl;
            // std::cout << "tag =" << tags[i] << " p = " << std::string(p, tagsLen[i]) <<
            // std::endl;
            if (strncmp(p, tags[i], tagsLen[i]) == 0) {
                p += tagsLen[i];
                while (*p == ' ') p++;
@@ -214,4 +218,51 @@ Hugepagesize: 2048 kB)meminfo";
}
BENCHMARK(BM_ReadMemInfo);

static uint64_t get_zram_mem_used(const std::string& zram_dir) {
    FILE* f = fopen((zram_dir + "mm_stat").c_str(), "r");
    if (f) {
        uint64_t mem_used_total = 0;

        int matched = fscanf(f, "%*d %*d %" SCNu64 " %*d %*d %*d %*d", &mem_used_total);
        if (matched != 1)
            fprintf(stderr, "warning: failed to parse %s\n", (zram_dir + "mm_stat").c_str());

        fclose(f);
        return mem_used_total;
    }

    f = fopen((zram_dir + "mem_used_total").c_str(), "r");
    if (f) {
        uint64_t mem_used_total = 0;

        int matched = fscanf(f, "%" SCNu64, &mem_used_total);
        if (matched != 1)
            fprintf(stderr, "warning: failed to parse %s\n", (zram_dir + "mem_used_total").c_str());

        fclose(f);
        return mem_used_total;
    }

    return 0;
}

static void BM_OldReadZramTotal(benchmark::State& state) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();
    std::string zram_mmstat_dir = exec_dir + "/testdata1/";
    for (auto _ : state) {
        uint64_t zram_total __attribute__((unused)) = get_zram_mem_used(zram_mmstat_dir) / 1024;
    }
}
BENCHMARK(BM_OldReadZramTotal);

static void BM_NewReadZramTotal(benchmark::State& state) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();
    std::string zram_mmstat_dir = exec_dir + "/testdata1/";
    ::android::meminfo::SysMemInfo mi;
    for (auto _ : state) {
        uint64_t zram_total __attribute__((unused)) = mi.mem_zram_kb(zram_mmstat_dir);
    }
}
BENCHMARK(BM_NewReadZramTotal);

BENCHMARK_MAIN();
+11 −0
Original line number Diff line number Diff line
@@ -312,6 +312,17 @@ TEST(SysMemInfoParser, TestEmptyFile) {
    EXPECT_EQ(mi.mem_total_kb(), 0);
}

TEST(SysMemInfoParse, TestZramTotal) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();

    SysMemInfo mi;
    std::string zram_mmstat_dir = exec_dir + "/testdata1/";
    EXPECT_EQ(mi.mem_zram_kb(zram_mmstat_dir), 30504);

    std::string zram_memused_dir = exec_dir + "/testdata2/";
    EXPECT_EQ(mi.mem_zram_kb(zram_memused_dir), 30504);
}

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    if (argc <= 1) {
+72 −5
Original line number Diff line number Diff line
@@ -17,10 +17,12 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdlib.h>
#include <unistd.h>

#include <cctype>
#include <cstdio>
#include <fstream>
#include <string>
#include <utility>
@@ -29,7 +31,9 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>

#include "meminfo_private.h"

@@ -40,8 +44,8 @@ const std::vector<std::string> SysMemInfo::kDefaultSysMemInfoTags = {
        SysMemInfo::kMemTotal,      SysMemInfo::kMemFree,        SysMemInfo::kMemBuffers,
        SysMemInfo::kMemCached,     SysMemInfo::kMemShmem,       SysMemInfo::kMemSlab,
        SysMemInfo::kMemSReclaim,   SysMemInfo::kMemSUnreclaim,  SysMemInfo::kMemSwapTotal,
        SysMemInfo::kMemSwapFree,    SysMemInfo::kMemZram,       SysMemInfo::kMemMapped,
        SysMemInfo::kMemVmallocUsed, SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
        SysMemInfo::kMemSwapFree,   SysMemInfo::kMemMapped,      SysMemInfo::kMemVmallocUsed,
        SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
};

bool SysMemInfo::ReadMemInfo(const std::string& path) {
@@ -129,5 +133,68 @@ bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::st
}
#endif

uint64_t SysMemInfo::mem_zram_kb(const std::string& zram_dev) {
    uint64_t mem_zram_total = 0;
    if (!zram_dev.empty()) {
        if (!MemZramDevice(zram_dev, &mem_zram_total)) {
            return 0;
        }
        return mem_zram_total / 1024;
    }

    constexpr uint32_t kMaxZramDevices = 256;
    for (uint32_t i = 0; i < kMaxZramDevices; i++) {
        std::string zram_dev = ::android::base::StringPrintf("/sys/block/zram%u/", i);
        if (access(zram_dev.c_str(), F_OK)) {
            // We assume zram devices appear in range 0-255 and appear always in sequence
            // under /sys/block. So, stop looking for them once we find one is missing.
            break;
        }

        uint64_t mem_zram_dev;
        if (!MemZramDevice(zram_dev, &mem_zram_dev)) {
            return 0;
        }

        mem_zram_total += mem_zram_dev;
    }

    return mem_zram_total / 1024;
}

bool SysMemInfo::MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev) {
    std::string content;
    if (android::base::ReadFileToString(zram_dev + "mm_stat", &content)) {
        std::vector<std::string> values = ::android::base::Split(content, " ");
        if (values.size() < 3) {
            LOG(ERROR) << "Malformed mm_stat file for zram dev: " << zram_dev
                       << " content: " << content;
            return false;
        }

        if (!::android::base::ParseUint(values[2], mem_zram_dev)) {
            LOG(ERROR) << "Malformed mm_stat file for zram dev: " << zram_dev
                       << " value: " << values[2];
            return false;
        }

        return true;
    }

    if (::android::base::ReadFileToString(zram_dev + "mem_used_total", &content)) {
        *mem_zram_dev = strtoull(content.c_str(), NULL, 10);
        if (*mem_zram_dev == ULLONG_MAX) {
            PLOG(ERROR) << "Malformed mem_used_total file for zram dev: " << zram_dev
                        << " content: " << content;
            return false;
        }

        return true;
    }

    LOG(ERROR) << "Can't find memory status under: " << zram_dev;
    return false;
}

}  // namespace meminfo
}  // namespace android
Loading