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

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

meminfo: Add ReadVmallocInfo()

This is to replace occurrences of get_allocated_vmalloc_memory().
Splitting into libmeminfo already found a bug with current code which
failed to account for memory allocated by modules due to addition of
the extra [%module_name%] in __builtin_return_address().

  See: https://elixir.bootlin.com/linux/latest/source/kernel/kallsyms.c#L373



Also improves the performance a bit in the process.

Bug: 119639955
Bug: 111694435
Test: libmeminfo_test 1 --gtest_filter=SysMemInfoParser.TestVmallocInfo
Test: libmeminfo_benchmark --benchmark_filter=BM_VmallocInfo_*
Result:
----------------------------------------------------------------
Benchmark                         Time           CPU Iterations
----------------------------------------------------------------
BM_VmallocInfo_old_fixed     459239 ns     457268 ns       1532
BM_VmallocInfo_new           386032 ns     384353 ns       1821
----------------------------------------------------------------

Change-Id: I1b6606ac73b5cc2dac31d24487b462ec9abfb2ef
Signed-off-by: default avatarSandeep Patil <sspatil@google.com>
parent 3009be5c
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -50,12 +50,16 @@ class SysMemInfo final {


    // Parse /proc/meminfo and read values that are needed
    // Parse /proc/meminfo and read values that are needed
    bool ReadMemInfo(const std::string& path = "/proc/meminfo");
    bool ReadMemInfo(const std::string& path = "/proc/meminfo");
    bool ReadMemInfo(const std::vector<std::string>& tags,
                     const std::string& path = "/proc/meminfo");
    bool ReadMemInfo(const std::vector<std::string>& tags, std::vector<uint64_t>* out,
    bool ReadMemInfo(const std::vector<std::string>& tags, std::vector<uint64_t>* out,
                     const std::string& path = "/proc/meminfo");
                     const std::string& path = "/proc/meminfo");
    bool ReadMemInfo(std::vector<uint64_t>* out, const std::string& path = "/proc/meminfo");
    bool ReadMemInfo(std::vector<uint64_t>* out, const std::string& path = "/proc/meminfo");


    // Parse /proc/vmallocinfo and return total physical memory mapped
    // in vmalloc area by the kernel.
    // Note that this deliberately ignores binder buffers. They are _always_
    // mapped in a process and are counted for in each process.
    uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");

    // getters
    // getters
    uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; }
    uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; }
    uint64_t mem_free_kb() { return mem_in_kb_[kMemFree]; }
    uint64_t mem_free_kb() { return mem_in_kb_[kMemFree]; }
+60 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@


#include <android-base/file.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>


#include <benchmark/benchmark.h>
#include <benchmark/benchmark.h>


@@ -397,4 +399,62 @@ Hugepagesize: 2048 kB)meminfo";
}
}
BENCHMARK(BM_MemInfoWithZram_new);
BENCHMARK(BM_MemInfoWithZram_new);


// Current implementation is in frameworks/base/core/jni/android_os_Debug.cpp.
// That implementation is still buggy and it skips over vmalloc allocated memory by kernel modules.
// This is the *fixed* version of the same implementation intended for benchmarking against the new
// one.
static uint64_t get_allocated_vmalloc_memory(const std::string& vm_file) {
    char line[1024];

    uint64_t vmalloc_allocated_size = 0;
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(vm_file.c_str(), "re"), fclose};
    if (fp == nullptr) {
        return 0;
    }

    while (true) {
        if (fgets(line, 1024, fp.get()) == NULL) {
            break;
        }

        // check to see if there are pages mapped in vmalloc area
        if (!strstr(line, "pages=")) {
            continue;
        }

        long nr_pages;
        if (sscanf(line, "%*x-%*x %*ld %*s pages=%ld", &nr_pages) == 1) {
            vmalloc_allocated_size += (nr_pages * getpagesize());
        } else if (sscanf(line, "%*x-%*x %*ld %*s %*s pages=%ld", &nr_pages) == 1) {
            // The second case is for kernel modules. If allocation comes from the module,
            // kernel puts an extra string containing the module name before "pages=" in
            // the line.
            //    See: https://elixir.bootlin.com/linux/latest/source/kernel/kallsyms.c#L373
            vmalloc_allocated_size += (nr_pages * getpagesize());
        }
    }
    return vmalloc_allocated_size;
}

static void BM_VmallocInfo_old_fixed(benchmark::State& state) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();
    std::string vmallocinfo =
            ::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
    for (auto _ : state) {
        CHECK_EQ(get_allocated_vmalloc_memory(vmallocinfo), 29884416);
    }
}
BENCHMARK(BM_VmallocInfo_old_fixed);

static void BM_VmallocInfo_new(benchmark::State& state) {
    std::string exec_dir = ::android::base::GetExecutableDirectory();
    std::string vmallocinfo =
            ::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
    for (auto _ : state) {
        SysMemInfo smi;
        CHECK_EQ(smi.ReadVmallocInfo(vmallocinfo), 29884416);
    }
}
BENCHMARK(BM_VmallocInfo_new);

BENCHMARK_MAIN();
BENCHMARK_MAIN();
+61 −0
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@


#include <android-base/file.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>


using namespace std;
using namespace std;
using namespace android::meminfo;
using namespace android::meminfo;
@@ -516,6 +517,66 @@ Hugepagesize: 2048 kB)meminfo";
    EXPECT_EQ(mem[MEMINFO_KERNEL_STACK], 4880);
    EXPECT_EQ(mem[MEMINFO_KERNEL_STACK], 4880);
}
}


TEST(SysMemInfoParser, TestVmallocInfoNoMemory) {
    std::string vmallocinfo =
            R"vmallocinfo(0x0000000000000000-0x0000000000000000   69632 of_iomap+0x78/0xb0 phys=17a00000 ioremap
0x0000000000000000-0x0000000000000000    8192 of_iomap+0x78/0xb0 phys=b220000 ioremap
0x0000000000000000-0x0000000000000000    8192 of_iomap+0x78/0xb0 phys=17c90000 ioremap
0x0000000000000000-0x0000000000000000    8192 of_iomap+0x78/0xb0 phys=17ca0000 ioremap)vmallocinfo";

    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
    std::string file = std::string(tf.path);

    SysMemInfo smi;
    EXPECT_EQ(smi.ReadVmallocInfo(file), 0);
}

TEST(SysMemInfoParser, TestVmallocInfoKernel) {
    std::string vmallocinfo =
            R"vmallocinfo(0x0000000000000000-0x0000000000000000    8192 drm_property_create_blob+0x44/0xec pages=1 vmalloc)vmallocinfo";

    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
    std::string file = std::string(tf.path);

    SysMemInfo smi;
    EXPECT_EQ(smi.ReadVmallocInfo(file), getpagesize());
}

TEST(SysMemInfoParser, TestVmallocInfoModule) {
    std::string vmallocinfo =
            R"vmallocinfo(0x0000000000000000-0x0000000000000000   28672 pktlog_alloc_buf+0xc4/0x15c [wlan] pages=6 vmalloc)vmallocinfo";

    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
    std::string file = std::string(tf.path);

    SysMemInfo smi;
    EXPECT_EQ(smi.ReadVmallocInfo(file), 6 * getpagesize());
}

TEST(SysMemInfoParser, TestVmallocInfoAll) {
    std::string vmallocinfo =
            R"vmallocinfo(0x0000000000000000-0x0000000000000000   69632 of_iomap+0x78/0xb0 phys=17a00000 ioremap
0x0000000000000000-0x0000000000000000    8192 of_iomap+0x78/0xb0 phys=b220000 ioremap
0x0000000000000000-0x0000000000000000    8192 of_iomap+0x78/0xb0 phys=17c90000 ioremap
0x0000000000000000-0x0000000000000000    8192 of_iomap+0x78/0xb0 phys=17ca0000 ioremap
0x0000000000000000-0x0000000000000000    8192 drm_property_create_blob+0x44/0xec pages=1 vmalloc
0x0000000000000000-0x0000000000000000   28672 pktlog_alloc_buf+0xc4/0x15c [wlan] pages=6 vmalloc)vmallocinfo";

    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
    std::string file = std::string(tf.path);

    SysMemInfo smi;
    EXPECT_EQ(smi.ReadVmallocInfo(file), 7 * getpagesize());
}

int main(int argc, char** argv) {
int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    ::testing::InitGoogleTest(&argc, argv);
    if (argc <= 1) {
    if (argc <= 1) {
+34 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
#include <inttypes.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <unistd.h>


#include <algorithm>
#include <algorithm>
@@ -27,6 +28,7 @@
#include <cstdio>
#include <cstdio>
#include <fstream>
#include <fstream>
#include <iterator>
#include <iterator>
#include <sstream>
#include <string>
#include <string>
#include <utility>
#include <utility>
#include <vector>
#include <vector>
@@ -77,6 +79,38 @@ bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, std::vector<u
    });
    });
}
}


uint64_t SysMemInfo::ReadVmallocInfo(const std::string& path) {
    uint64_t vmalloc_total = 0;
    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
    if (fp == nullptr) {
        return vmalloc_total;
    }

    char line[1024];
    while (fgets(line, 1024, fp.get()) != nullptr) {
        // We are looking for lines like
        // 0x0000000000000000-0x0000000000000000   12288 drm_property_create_blob+0x44/0xec pages=2
        // vmalloc 0x0000000000000000-0x0000000000000000    8192
        // wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc Notice that if the caller is
        // coming from a module, the kernel prints and extra "[module_name]" after the address and
        // the symbol of the call site. This means we can't use the old sscanf() method of getting
        // the # of pages.
        char* p_start = strstr(line, "pages=");
        if (p_start == nullptr) {
            // we didn't find anything
            continue;
        }

        p_start = strtok(p_start, " ");
        long nr_pages;
        if (sscanf(p_start, "pages=%ld", &nr_pages) == 1) {
            vmalloc_total += (nr_pages * getpagesize());
        }
    }

    return vmalloc_total;
}

// TODO: Delete this function if it can't match up with the c-like implementation below.
// TODO: Delete this function if it can't match up with the c-like implementation below.
// Currently, this added about 50 % extra overhead on hikey.
// Currently, this added about 50 % extra overhead on hikey.
#if 0
#if 0
+1774 −0

File added.

Preview size limit exceeded, changes collapsed.