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:
parent
2259fdf7df
commit
70fa72dd01
7 changed files with 152 additions and 12 deletions
|
@ -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/*",
|
||||
],
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
1
libmeminfo/testdata1/mm_stat
Normal file
1
libmeminfo/testdata1/mm_stat
Normal file
|
@ -0,0 +1 @@
|
|||
145674240 26801454 31236096 0 45772800 3042 1887 517
|
1
libmeminfo/testdata2/mem_used_total
Normal file
1
libmeminfo/testdata2/mem_used_total
Normal file
|
@ -0,0 +1 @@
|
|||
31236096
|
Loading…
Reference in a new issue