From 9de0b7f8937b7f6ce990132609f0b26851b31f2b Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 3 Jan 2025 15:36:22 +0100 Subject: Monitor CPU --- MIDI.h | 11 ++++++---- Makefile | 6 +++++- UI.cpp | 17 ++++++++++++++- cpuload.cpp | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cpuload.h | 8 +++++++ debug.cpp | 3 +++ debug.h | 40 ++++++++++++++++++++++++++++++++++ main.cpp | 2 ++ 8 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 cpuload.cpp create mode 100644 cpuload.h create mode 100644 debug.cpp create mode 100644 debug.h diff --git a/MIDI.h b/MIDI.h index f0175bc..5ce050e 100644 --- a/MIDI.h +++ b/MIDI.h @@ -1,9 +1,12 @@ #pragma once #include "config.h" +#include "debug.h" #include +#include + #include class MIDI @@ -119,7 +122,7 @@ public: if((ev->type == SND_SEQ_EVENT_NOTEON) ||(ev->type == SND_SEQ_EVENT_NOTEOFF)) { const char *type = (ev->type == SND_SEQ_EVENT_NOTEON) ? "on " : "off"; - printf("[%d] Note %s: %2x vel(%2x), ch %2x\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, + debug_cout << fmt::format("[{}] Note {}: {:2x} vel({:2x}), ch {:2x}\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, type, ev->data.note.note, ev->data.note.velocity, @@ -132,17 +135,17 @@ public: } else if(ev->type == SND_SEQ_EVENT_CONTROLLER) { - printf("[%d] Control: %2x val(%2x)\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, + debug_cout << fmt::format("[{}] Control: {:2x} val({:2x})\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick, ev->data.control.param, ev->data.control.value); } else if(ev->type == SND_SEQ_EVENT_CLOCK) { - printf("[%d] Clock\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick); + debug_cout << fmt::format("[{}] Clock\n", ((ev->flags & SND_SEQ_TIME_STAMP_MASK) == SND_SEQ_TIME_STAMP_REAL) ? ev->time.time.tv_sec : ev->time.tick) << std::endl;; } else { - printf("[%d] Unknown: Unhandled Event Received\n", ev->time.tick); + debug_cout << fmt::format("[{}] Unknown: Unhandled Event Received\n", ev->time.tick) << std::endl;; } } diff --git a/Makefile b/Makefile index 8ef3555..1fc0bbd 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,11 @@ SRCS= \ ClickStream.cpp \ config.cpp \ UI.cpp \ - Timer.cpp + Timer.cpp \ + debug.cpp \ + cpuload.cpp + +HEADERS=$(SRCS:.cpp=.h) OBJS=$(SRCS:.cpp=.o) diff --git a/UI.cpp b/UI.cpp index f0eb0c3..e1d33c9 100644 --- a/UI.cpp +++ b/UI.cpp @@ -1,15 +1,30 @@ #include "UI.h" +#include "cpuload.h" + +#include #include +#include + +#include void UI::draw() { + std::vector cpuloads = get_cpu_loads(); + std::cout << std::endl; std::cout << "- -- BPM +" << std::endl; std::cout << "Mode: Click __/__ (Clock Internal)" << std::endl; std::cout << "Status:" << std::endl; std::cout << " Alive/not alive" << std::endl; - std::cout << " CPU: --% --% ..." << std::endl; + + std::cout << " CPU:"; + for (auto& i: cpuloads) { + std::cout << fmt::format(" {:2}%", i); + } + int max = *std::max_element(cpuloads.begin(), cpuloads.end()); + std::cout << fmt::format(", max. {:2}%", max) << std::endl; + std::cout << " Notes/Channels: -- -- -- ... (Choose)" << std::endl; std::cout << " Timestamp: ------" << std::endl; std::cout << " Active sensing: ---" << std::endl; diff --git a/cpuload.cpp b/cpuload.cpp new file mode 100644 index 0000000..77abc3e --- /dev/null +++ b/cpuload.cpp @@ -0,0 +1,71 @@ +#include "cpuload.h" + +#include +#include + +#include +#include + +int get_number_of_cpus() +{ + int result{}; + std::string stat = Reichwein::File::getFile("/proc/stat"); + std::vector lines = Reichwein::Stringhelper::split(stat, "\n"); + for (const auto& line: lines) { + std::vector words = Reichwein::Stringhelper::split(line, " "); + // /proc/stat line, e.g.: cpu0 1132 34 1441 11311718 3675 127 438 + if (words.size() >= 8) { + if (words[0].size() > 3 && words[0].substr(0, 3) == "cpu") { + ++result; + } + } + } + return result; +} + +// returns empty vector if no data is available yet +// Note: to be called several times, because data is generated differentially from /proc/stat +std::vector get_cpu_loads() +{ + using clock_type = std::chrono::high_resolution_clock; + static int number_of_cpus = get_number_of_cpus(); + static std::vector stat_cpus_sum(number_of_cpus); + static std::vector stat_cpus_idle(number_of_cpus); + static std::chrono::time_point timestamp{}; + + std::string stat = Reichwein::File::getFile("/proc/stat"); + + std::vector lines = Reichwein::Stringhelper::split(stat, "\n"); + + std::vector result; + + int i = 0; + for (const auto& line: lines) { + std::vector words = Reichwein::Stringhelper::split(line, " "); + // /proc/stat line, e.g.: cpu0 1132 34 1441 11311718 3675 127 438 + // idle value is at index 4 + if (words.size() >= 8) { + if (words[0].size() > 3 && words[0].substr(0, 3) == "cpu") { + uint64_t sum = std::accumulate(words.begin() + 1, words.end(), uint64_t{}, [](uint64_t sum, const std::string& s){return sum + std::stoull(s);}); + uint64_t idle = std::stoull(words[4]); + + // previous data available + if (timestamp == std::chrono::time_point{}) + { + uint64_t sum_diff = sum - stat_cpus_sum[i]; + uint64_t idle_diff = idle - stat_cpus_idle[i]; + int percentage = (sum_diff == 0) ? 0 : ((sum_diff - idle_diff) * 100 / sum_diff); + result.push_back(percentage); + } + + stat_cpus_sum[i] = sum; + stat_cpus_idle[i] = idle; + + ++i; + } + } + } + + return result; +} + diff --git a/cpuload.h b/cpuload.h new file mode 100644 index 0000000..ae98071 --- /dev/null +++ b/cpuload.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +int get_number_of_cpus(); + +// returns percentages of cpu load, for all cores +std::vector get_cpu_loads(); diff --git a/debug.cpp b/debug.cpp new file mode 100644 index 0000000..09c9fcc --- /dev/null +++ b/debug.cpp @@ -0,0 +1,3 @@ +#include "debug.h" + +debug_ostream debug_cout; diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..1965de0 --- /dev/null +++ b/debug.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +class debug_ostream +{ +public: + debug_ostream(): m_active(false) {} + + void activate() + { + m_active = true; + } + + void deactivate() + { + m_active = false; + } + + template + debug_ostream& operator<<(const T& arg) { + if (m_active) + std::cout << arg; + return *this; + } + + debug_ostream& operator<<( + std::basic_ostream& (*func) + (std::basic_ostream&) ) { + if (m_active) + std::cout << *func; + return *this; + } + +private: + bool m_active; +}; + +extern debug_ostream debug_cout; diff --git a/main.cpp b/main.cpp index 53e2947..19cf681 100644 --- a/main.cpp +++ b/main.cpp @@ -31,6 +31,8 @@ double diff_timespec(const struct timespec *time1, const struct timespec *time0) int main(void) { try { + //debug_cout.activate(); + MIDI midi; ClickStream stream; PCM pcm{stream}; -- cgit v1.2.3