fix(memory): Implement memory updating for pre-3.4 kernels (#410)

Since 3.4, `/proc/meminfo` contains a `MemAvailable` field, which polybar uses to determine
`(gb|mb)_free` and `(gb|mb)_used`. This commit adds a fallback for when `MemAvailable` does
not exist, allowing a fairly-accurate approximation on older kernels.

This commit also removes the reliance on the exact order fields appear in `/proc/meminfo`.
This commit is contained in:
Tudor Brindus 2017-02-04 12:19:58 -05:00 committed by Michael Carlberg
parent 9ced7dbf73
commit 107bdb91e3
1 changed files with 22 additions and 13 deletions

View File

@ -33,25 +33,34 @@ namespace modules {
bool memory_module::update() {
unsigned long long kb_total{0ULL};
unsigned long long kb_avail{0ULL};
unsigned long long kb_free{0ULL};
try {
std::ifstream in(PATH_MEMORY_INFO);
std::stringstream buffer;
string str;
std::ifstream meminfo(PATH_MEMORY_INFO);
std::map<std::string, unsigned long long int> parsed;
buffer.imbue(std::locale::classic());
std::string line;
while (std::getline(meminfo, line)) {
size_t sep_off = line.find(':');
size_t value_off = line.find_first_of("123456789", sep_off);
for (int i = 3; i > 0 && std::getline(in, str); i--) {
size_t off = str.find_first_of("1234567890", str.find(':'));
if (off != string::npos && str.size() > off) {
buffer << std::strtoull(&str[off], nullptr, 10) << std::endl;
}
if (sep_off == std::string::npos || value_off == std::string::npos) continue;
std::string id = line.substr(0, sep_off);
unsigned long long int value = std::strtoull(&line[value_off], nullptr, 10);
parsed[id] = value;
}
buffer >> kb_total;
buffer >> kb_free;
buffer >> kb_avail;
kb_total = parsed["MemTotal"];
// newer kernels (3.4+) have an accurate available memory field,
// see https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
// for details
if (parsed.count("MemAvailable")) {
kb_avail = parsed["MemAvailable"];
} else {
// old kernel; give a best-effort approximation of available memory
kb_avail = parsed["MemFree"] + parsed["Buffers"] + parsed["Cached"] + parsed["SReclaimable"] - parsed["Shmem"];
}
} catch (const std::exception& err) {
m_log.err("Failed to read memory values (what: %s)", err.what());
}