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: Sandeep Patil <sspatil@google.com>
This commit is contained in:
Sandeep Patil 2018-11-09 19:18:29 -08:00
parent 2259fdf7df
commit 70fa72dd01
7 changed files with 152 additions and 12 deletions

View file

@ -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/*",
],
}

View file

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

View file

@ -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;
@ -67,9 +69,10 @@ void get_mem_info(uint64_t mem[], const char* file) {
buffer[len] = 0;
static const char* const tags[] = {
"MemTotal:", "MemFree:", "Buffers:", "Cached:", "Shmem:", "Slab:",
"SReclaimable:", "SUnreclaim:", "SwapTotal:", "SwapFree:", "ZRam:", "Mapped:",
"VmallocUsed:", "PageTables:", "KernelStack:", NULL};
"MemTotal:", "MemFree:", "Buffers:", "Cached:", "Shmem:", "Slab:",
"SReclaimable:", "SUnreclaim:", "SwapTotal:", "SwapFree:", "ZRam:", "Mapped:",
"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();

View file

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

View file

@ -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"
@ -37,11 +41,11 @@ namespace android {
namespace meminfo {
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::kMemTotal, SysMemInfo::kMemFree, SysMemInfo::kMemBuffers,
SysMemInfo::kMemCached, SysMemInfo::kMemShmem, SysMemInfo::kMemSlab,
SysMemInfo::kMemSReclaim, SysMemInfo::kMemSUnreclaim, SysMemInfo::kMemSwapTotal,
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

View file

@ -0,0 +1 @@
145674240 26801454 31236096 0 45772800 3042 1887 517

View file

@ -0,0 +1 @@
31236096