fix(memory): provide better free memory approximation on old kernels

The approximation should include SReclaimable, and subtract Shmem. To
prevent the parsing code from ballooning in size, this commit also
refactors the parsing into a map.
This commit is contained in:
Tudor Brindus 2020-03-20 17:37:22 -04:00
parent 37b1b35035
commit 19743f3085
2 changed files with 20 additions and 24 deletions

View File

@ -17,8 +17,7 @@ class Memory : public ALabel {
static inline const std::string data_dir_ = "/proc/meminfo"; static inline const std::string data_dir_ = "/proc/meminfo";
void parseMeminfo(); void parseMeminfo();
unsigned long memtotal_; std::unordered_map<std::string, unsigned long> meminfo_;
unsigned long memfree_;
util::SleeperThread thread_; util::SleeperThread thread_;
}; };

View File

@ -10,11 +10,23 @@ waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config
auto waybar::modules::Memory::update() -> void { auto waybar::modules::Memory::update() -> void {
parseMeminfo(); parseMeminfo();
if (memtotal_ > 0 && memfree_ >= 0) {
auto total_ram_gigabytes = memtotal_ / std::pow(1024, 2); unsigned long memtotal = meminfo_["MemTotal"];
int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_; unsigned long memfree;
auto used_ram_gigabytes = (memtotal_ - memfree_) / std::pow(1024, 2); if (meminfo_.count("MemAvailable")) {
auto available_ram_gigabytes = memfree_ / std::pow(1024, 2); // New kernels (3.4+) have an accurate available memory field.
memfree = meminfo_["MemAvailable"];
} else {
// Old kernel; give a best-effort approximation of available memory.
memfree = meminfo_["MemFree"] + meminfo_["Buffers"] + meminfo_["Cached"] +
meminfo_["SReclaimable"] - meminfo_["Shmem"];
}
if (memtotal > 0 && memfree >= 0) {
auto total_ram_gigabytes = memtotal / std::pow(1024, 2);
int used_ram_percentage = 100 * (memtotal - memfree) / memtotal;
auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2);
auto available_ram_gigabytes = memfree / std::pow(1024, 2);
getState(used_ram_percentage); getState(used_ram_percentage);
label_.set_markup(fmt::format(format_, label_.set_markup(fmt::format(format_,
@ -33,7 +45,6 @@ auto waybar::modules::Memory::update() -> void {
} }
void waybar::modules::Memory::parseMeminfo() { void waybar::modules::Memory::parseMeminfo() {
int64_t memfree = -1, membuffer = -1, memcache = -1, memavail = -1;
std::ifstream info(data_dir_); std::ifstream info(data_dir_);
if (!info.is_open()) { if (!info.is_open()) {
throw std::runtime_error("Can't open " + data_dir_); throw std::runtime_error("Can't open " + data_dir_);
@ -44,23 +55,9 @@ void waybar::modules::Memory::parseMeminfo() {
if (posDelim == std::string::npos) { if (posDelim == std::string::npos) {
continue; continue;
} }
std::string name = line.substr(0, posDelim); std::string name = line.substr(0, posDelim);
int64_t value = std::stol(line.substr(posDelim + 1)); int64_t value = std::stol(line.substr(posDelim + 1));
meminfo_[name] = value;
if (name.compare("MemTotal") == 0) {
memtotal_ = value;
} else if (name.compare("MemAvailable") == 0) {
memavail = value;
} else if (name.compare("MemFree") == 0) {
memfree = value;
} else if (name.compare("Buffers") == 0) {
membuffer = value;
} else if (name.compare("Cached") == 0) {
memcache = value;
} }
if (memtotal_ > 0 && (memavail >= 0 || (memfree > -1 && membuffer > -1 && memcache > -1))) {
break;
}
}
memfree_ = memavail >= 0 ? memavail : memfree + membuffer + memcache;
} }