Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split cpu module #2114

Merged
merged 12 commits into from
Oct 17, 2023
3 changes: 3 additions & 0 deletions include/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
#endif
#if defined(HAVE_CPU_LINUX) || defined(HAVE_CPU_BSD)
#include "modules/cpu.hpp"
#include "modules/cpu_frequency.hpp"
#include "modules/cpu_usage.hpp"
#include "modules/load.hpp"
#endif
#include "modules/idle_inhibitor.hpp"
#if defined(HAVE_MEMORY_LINUX) || defined(HAVE_MEMORY_BSD)
Expand Down
6 changes: 0 additions & 6 deletions include/modules/cpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ class Cpu : public ALabel {
auto update() -> void override;

private:
double getCpuLoad();
std::tuple<std::vector<uint16_t>, std::string> getCpuUsage();
std::tuple<float, float, float> getCpuFrequency();
std::vector<std::tuple<size_t, size_t>> parseCpuinfo();
std::vector<float> parseCpuFrequencies();

std::vector<std::tuple<size_t, size_t>> prev_times_;

util::SleeperThread thread_;
Expand Down
32 changes: 32 additions & 0 deletions include/modules/cpu_frequency.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include <fmt/format.h>

#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"

namespace waybar::modules {

class CpuFrequency : public ALabel {
public:
CpuFrequency(const std::string&, const Json::Value&);
virtual ~CpuFrequency() = default;
auto update() -> void override;

// This is a static member because it is also used by the cpu module.
static std::tuple<float, float, float> getCpuFrequency();

private:
static std::vector<float> parseCpuFrequencies();

util::SleeperThread thread_;
};

} // namespace waybar::modules
34 changes: 34 additions & 0 deletions include/modules/cpu_usage.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <fmt/format.h>

#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"

namespace waybar::modules {

class CpuUsage : public ALabel {
public:
CpuUsage(const std::string&, const Json::Value&);
virtual ~CpuUsage() = default;
auto update() -> void override;

// This is a static member because it is also used by the cpu module.
static std::tuple<std::vector<uint16_t>, std::string> getCpuUsage(std::vector<std::tuple<size_t, size_t>>&);

private:
static std::vector<std::tuple<size_t, size_t>> parseCpuinfo();

std::vector<std::tuple<size_t, size_t>> prev_times_;

util::SleeperThread thread_;
};

} // namespace waybar::modules
31 changes: 31 additions & 0 deletions include/modules/load.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <fmt/format.h>

#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"

namespace waybar::modules {

class Load : public ALabel {
public:
Load(const std::string&, const Json::Value&);
virtual ~Load() = default;
auto update() -> void override;

// This is a static member because it is also used by the cpu module.
static std::tuple<double, double, double> getLoad();

private:

util::SleeperThread thread_;
};

} // namespace waybar::modules
15 changes: 11 additions & 4 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ src_files = files(
'src/modules/disk.cpp',
'src/modules/idle_inhibitor.cpp',
'src/modules/image.cpp',
'src/modules/load.cpp',
'src/modules/temperature.cpp',
'src/modules/user.cpp',
'src/main.cpp',
Expand All @@ -187,17 +188,23 @@ if is_linux
add_project_arguments('-DHAVE_MEMORY_LINUX', language: 'cpp')
src_files += files(
'src/modules/battery.cpp',
'src/modules/cpu/common.cpp',
'src/modules/cpu/linux.cpp',
'src/modules/cpu.cpp',
'src/modules/cpu_frequency/common.cpp',
'src/modules/cpu_frequency/linux.cpp',
'src/modules/cpu_usage/common.cpp',
'src/modules/cpu_usage/linux.cpp',
'src/modules/memory/common.cpp',
'src/modules/memory/linux.cpp',
)
elif is_dragonfly or is_freebsd or is_netbsd or is_openbsd
add_project_arguments('-DHAVE_CPU_BSD', language: 'cpp')
add_project_arguments('-DHAVE_MEMORY_BSD', language: 'cpp')
src_files += files(
'src/modules/cpu/bsd.cpp',
'src/modules/cpu/common.cpp',
'src/modules/cpu.cpp',
'src/modules/cpu_frequency/bsd.cpp',
'src/modules/cpu_frequency/common.cpp',
'src/modules/cpu_usage/bsd.cpp',
'src/modules/cpu_usage/common.cpp',
'src/modules/memory/bsd.cpp',
'src/modules/memory/common.cpp',
)
Expand Down
11 changes: 11 additions & 0 deletions src/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "cpu") {
return new waybar::modules::Cpu(id, config_[name]);
}
#if defined(HAVE_CPU_LINUX)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove the conditional as the module code is still compiled in. cpu is like a superset, so cpu_frequency printing different warning is confusing:

 $ waybar
 [...]
-[2023-10-04 09:23:30.090] [warning] cpu_frequency: not implemented on BSDs, expect garbage in {*_frequency}
+[2023-10-04 10:05:32.888] [warning] module cpu_frequency: Unknown module: cpu_frequency

if (ref == "cpu_frequency") {
return new waybar::modules::CpuFrequency(id, config_[name]);
}
#endif
if (ref == "cpu_usage") {
return new waybar::modules::CpuUsage(id, config_[name]);
}
if (ref == "load") {
return new waybar::modules::Load(id, config_[name]);
}
#endif
if (ref == "clock") {
return new waybar::modules::Clock(id, config_[name]);
Expand Down
63 changes: 63 additions & 0 deletions src/modules/cpu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "modules/cpu.hpp"

#include "modules/cpu_frequency.hpp"
#include "modules/cpu_usage.hpp"
#include "modules/load.hpp"

// In the 80000 version of fmt library authors decided to optimize imports
// and moved declarations required for fmt::dynamic_format_arg_store in new
// header fmt/args.h
#if (FMT_VERSION >= 80000)
#include <fmt/args.h>
#else
#include <fmt/core.h>
#endif

waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu", id, "{usage}%", 10) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
};
}

auto waybar::modules::Cpu::update() -> void {
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
auto [load1, load5, load15] = Load::getLoad();
auto [cpu_usage, tooltip] = CpuUsage::getCpuUsage(prev_times_);
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
if (tooltipEnabled()) {
label_.set_tooltip_text(tooltip);
}
auto format = format_;
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
auto state = getState(total_usage);
if (!state.empty() && config_["format-" + state].isString()) {
format = config_["format-" + state].asString();
}

if (format.empty()) {
event_box_.hide();
} else {
event_box_.show();
auto icons = std::vector<std::string>{state};
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("load", load1));
store.push_back(fmt::arg("usage", total_usage));
store.push_back(fmt::arg("icon", getIcon(total_usage, icons)));
store.push_back(fmt::arg("max_frequency", max_frequency));
store.push_back(fmt::arg("min_frequency", min_frequency));
store.push_back(fmt::arg("avg_frequency", avg_frequency));
for (size_t i = 1; i < cpu_usage.size(); ++i) {
auto core_i = i - 1;
auto core_format = fmt::format("usage{}", core_i);
store.push_back(fmt::arg(core_format.c_str(), cpu_usage[i]));
auto icon_format = fmt::format("icon{}", core_i);
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
}
label_.set_markup(fmt::vformat(format, store));
}

// Call parent update
ALabel::update();
}
15 changes: 15 additions & 0 deletions src/modules/cpu_frequency/bsd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <spdlog/spdlog.h>

#include <cmath> // NAN

#include "modules/cpu_frequency.hpp"

std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
static std::vector<float> frequencies;
if (frequencies.empty()) {
spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chase module rename and maybe slightly deduplicate wording

Suggested change
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
"cpu_frequency: not implemented on BSDs, expect garbage in {*_frequency}");

frequencies.push_back(NAN);
}
return frequencies;
}
67 changes: 67 additions & 0 deletions src/modules/cpu_frequency/common.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "modules/cpu_frequency.hpp"

// In the 80000 version of fmt library authors decided to optimize imports
// and moved declarations required for fmt::dynamic_format_arg_store in new
// header fmt/args.h
#if (FMT_VERSION >= 80000)
#include <fmt/args.h>
#else
#include <fmt/core.h>
#endif

waybar::modules::CpuFrequency::CpuFrequency(const std::string& id, const Json::Value& config)
: ALabel(config, "cpu_frequency", id, "{avg_frequency}", 10) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
};
}

auto waybar::modules::CpuFrequency::update() -> void {
// TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both
auto [max_frequency, min_frequency, avg_frequency] = CpuFrequency::getCpuFrequency();
if (tooltipEnabled()) {
auto tooltip =
fmt::format("Minimum frequency: {}\nAverage frequency: {}\nMaximum frequency: {}\n",
min_frequency, avg_frequency, max_frequency);
label_.set_tooltip_text(tooltip);
}
auto format = format_;
auto state = getState(avg_frequency);
if (!state.empty() && config_["format-" + state].isString()) {
format = config_["format-" + state].asString();
}

if (format.empty()) {
event_box_.hide();
} else {
event_box_.show();
auto icons = std::vector<std::string>{state};
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("icon", getIcon(avg_frequency, icons)));
store.push_back(fmt::arg("max_frequency", max_frequency));
store.push_back(fmt::arg("min_frequency", min_frequency));
store.push_back(fmt::arg("avg_frequency", avg_frequency));
label_.set_markup(fmt::vformat(format, store));
}

// Call parent update
ALabel::update();
}

std::tuple<float, float, float> waybar::modules::CpuFrequency::getCpuFrequency() {
std::vector<float> frequencies = CpuFrequency::parseCpuFrequencies();
if (frequencies.empty()) {
return {0.f, 0.f, 0.f};
}
auto [min, max] = std::minmax_element(std::begin(frequencies), std::end(frequencies));
float avg_frequency =
std::accumulate(std::begin(frequencies), std::end(frequencies), 0.0) / frequencies.size();

// Round frequencies with double decimal precision to get GHz
float max_frequency = std::ceil(*max / 10.0) / 100.0;
float min_frequency = std::ceil(*min / 10.0) / 100.0;
avg_frequency = std::ceil(avg_frequency / 10.0) / 100.0;

return {max_frequency, min_frequency, avg_frequency};
}
32 changes: 2 additions & 30 deletions src/modules/cpu/linux.cpp → src/modules/cpu_frequency/linux.cpp
Original file line number Diff line number Diff line change
@@ -1,36 +1,8 @@
#include <filesystem>

#include "modules/cpu.hpp"
#include "modules/cpu_frequency.hpp"

std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
const std::string data_dir_ = "/proc/stat";
std::ifstream info(data_dir_);
if (!info.is_open()) {
throw std::runtime_error("Can't open " + data_dir_);
}
std::vector<std::tuple<size_t, size_t>> cpuinfo;
std::string line;
while (getline(info, line)) {
if (line.substr(0, 3).compare("cpu") != 0) {
break;
}
std::stringstream sline(line.substr(5));
std::vector<size_t> times;
for (size_t time = 0; sline >> time; times.push_back(time))
;

size_t idle_time = 0;
size_t total_time = 0;
if (times.size() >= 4) {
idle_time = times[3];
total_time = std::accumulate(times.begin(), times.end(), 0);
}
cpuinfo.emplace_back(idle_time, total_time);
}
return cpuinfo;
}

std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
std::vector<float> waybar::modules::CpuFrequency::parseCpuFrequencies() {
const std::string file_path_ = "/proc/cpuinfo";
std::ifstream info(file_path_);
if (!info.is_open()) {
Expand Down
14 changes: 2 additions & 12 deletions src/modules/cpu/bsd.cpp → src/modules/cpu_usage/bsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include <cmath> // NAN
#include <cstdlib> // malloc

#include "modules/cpu.hpp"
#include "modules/cpu_usage.hpp"

#if defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sched.h>
Expand All @@ -27,7 +27,7 @@ typedef uint64_t pcp_time_t;
typedef long pcp_time_t;
#endif

std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
std::vector<std::tuple<size_t, size_t>> waybar::modules::CpuUsage::parseCpuinfo() {
cp_time_t sum_cp_time[CPUSTATES];
size_t sum_sz = sizeof(sum_cp_time);
int ncpu = sysconf(_SC_NPROCESSORS_CONF);
Expand Down Expand Up @@ -100,13 +100,3 @@ std::vector<std::tuple<size_t, size_t>> waybar::modules::Cpu::parseCpuinfo() {
free(cp_time);
return cpuinfo;
}

std::vector<float> waybar::modules::Cpu::parseCpuFrequencies() {
static std::vector<float> frequencies;
if (frequencies.empty()) {
spdlog::warn(
"cpu/bsd: parseCpuFrequencies is not implemented, expect garbage in {*_frequency}");
frequencies.push_back(NAN);
}
return frequencies;
}
Loading