diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5104ea2..4f1e05b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,20 +2,24 @@ name: CI
on:
push:
- branches: [ main ]
+ branches: [ main, linux_dev ]
pull_request:
- branches: [ main ]
+ branches: [ main, linux_dev ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
- os: [windows-latest]
+ os: [windows-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v4
+ - name: Install dependencies
+ if: matrix.os == 'ubuntu-latest'
+ run: sudo apt-get update && sudo apt-get install -y build-essential cmake
+
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 001af5b..578f976 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,6 +13,10 @@ target_include_directories(SysMood PRIVATE
${CMAKE_SOURCE_DIR}/include
)
+if(WIN32)
+ target_link_libraries(SysMood PRIVATE Iphlpapi)
+endif()
+
# Enable testing (used later)
include(CTest)
enable_testing()
diff --git a/README.md b/README.md
index efd2090..eded8bf 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# SysMood
+[](https://github.com/RayBreeze/SysMood/actions/workflows/ci.yml)
Hey there, the lone wonderer here!
**SysMood** is a fun little console program for Windows that checks your CPU and memory usage, then tells you how your system is "feeling"—with some quirky moods and a splash of ASCII art.
@@ -19,6 +20,8 @@ Hey there, the lone wonderer here!
- **ASCII Art Banner:**
Because every program deserves a cool entrance.
+ and many more....
+
---
## How to Use
@@ -53,7 +56,7 @@ g++ -Iinclude src/main.cpp -o SysMood.exe
winget install SysMood
```
-## What You’ll See
+## What You’ll See [This is Demo of Release 1.0.0, future versions might differ...]
```sh
________ ___ ___ ________ _____ ______ ________ ________ ________
@@ -93,7 +96,7 @@ So much free memory! I could host a party in here!
## What You Need
-- Windows (Linux folks—coming soon don't worry!)
+- OS [ Windows or Linux ]
- C++17 or newer (tested with g++ and MSVC)
---
@@ -106,7 +109,17 @@ MIT License. See [LICENSE](LICENSE) for the legal stuff.
## Who Made This?
-Made with ☕ and curiosity by [Samman Das (RayBreeze)](https://github.com/RayBreeze)
+Made with ☕ and curiosity by [Samman Das (RayBreeze)](https://github.com/RayBreeze) and with the help of fellow Contributors across the Globe
+
+---
+
+## Contributors
+
+
+
+
+
+Made with [contrib.rocks](https://contrib.rocks).
---
diff --git a/SysMood.exe b/SysMood.exe
new file mode 100644
index 0000000..1465fc8
Binary files /dev/null and b/SysMood.exe differ
diff --git a/bin/sysMood b/bin/sysMood
new file mode 100755
index 0000000..2b93353
Binary files /dev/null and b/bin/sysMood differ
diff --git a/include/cpu_monitor.h b/include/cpu_monitor.h
index 4247a3e..a67375c 100644
--- a/include/cpu_monitor.h
+++ b/include/cpu_monitor.h
@@ -21,48 +21,176 @@
// - this file is mostly chill, unless your system's on fire 🔥
// - not responsible if your computer gets feelings 🥲
// - if you find a bug, please report it to me on github
-//
+//
#define _WIN32_WINNT 0x0602
#include
#include
-#include
#include
-uint64_t FromFileTime( const FILETIME& ft ) {
- ULARGE_INTEGER uli = { 0 };
+#ifdef _WIN32
+#include
+#elif __linux__
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#ifdef _WIN32
+uint64_t FromFileTime(const FILETIME &ft)
+{
+ ULARGE_INTEGER uli = {0};
uli.LowPart = ft.dwLowDateTime;
uli.HighPart = ft.dwHighDateTime;
return uli.QuadPart;
}
+#elif __linux__
+struct CpuTimes
+{
+ uint64_t user, nice, system, idle, iowait, irq, softirq, steal;
+ uint64_t getTotalTime() const
+ {
+ return user + nice + system + idle + iowait + irq + softirq + steal;
+ }
+ uint64_t getIdleTime() const
+ {
+ return idle + iowait;
+ }
+};
+
+struct CPUStats
+{
+ uint64_t ctxt;
+ uint64_t btime;
+ uint64_t processes;
+ uint64_t procs_running;
+ uint64_t procs_blocked;
+};
+
+CpuTimes getCpuTimes()
+{
+ std::ifstream file("/proc/stat");
+ if (!file.is_open())
+ {
+ std::cerr << "Could not open /proc/stat" << std::endl;
+ return CpuTimes{0};
+ }
+ std::string line;
+ std::getline(file, line);
+
+ std::istringstream ss(line);
+ std::string cpu_label;
+ CpuTimes times = {0};
+
+ ss >> cpu_label >> times.user >> times.nice >> times.system >> times.idle >> times.iowait >> times.irq >> times.softirq >> times.steal;
+
+ return times;
+}
+
+CPUStats getCPUstats()
+{
+ std::ifstream file("/proc/stat");
+ CPUStats stats = {0};
+ if (!file.is_open())
+ {
+ std::cerr << "Could not open /proc/stat" << std::endl;
+ return stats;
+ }
+ std::string line;
+ while (std::getline(file, line))
+ {
+ std::istringstream ss(line);
+ std::string key;
+ ss >> key;
+ if (key == "ctxt")
+ {
+ ss >> stats.ctxt;
+ }
+ else if (key == "btime")
+ {
+ ss >> stats.btime;
+ }
+ else if (key == "processes")
+ {
+ ss >> stats.processes;
+ }
+ else if (key == "procs_running")
+ {
+ ss >> stats.procs_running;
+ }
+ else if (key == "procs_blocked")
+ {
+ ss >> stats.procs_blocked;
+ }
+ }
+ return stats;
+}
+#endif
- class Processor{};
+class Processor
+{
+};
- class Usage: public Processor
+class Usage : public Processor
+{
+public:
+#ifdef _WIN32
+ uint64_t FromFileTime(const FILETIME &ft)
{
- public:
+ ULARGE_INTEGER uli = {0};
+ uli.LowPart = ft.dwLowDateTime;
+ uli.HighPart = ft.dwHighDateTime;
+ return uli.QuadPart;
+ }
- int now(){
- FILETIME i0, i1, k0, k1, u0, u1;
- GetSystemTimes(&i0, &k0, &u0);
- SleepEx(1000, false);
- GetSystemTimes(&i1, &k1, &u1);
+ int now()
+ {
+ FILETIME i0, i1, k0, k1, u0, u1;
+ GetSystemTimes(&i0, &k0, &u0);
+ SleepEx(1000, false);
+ GetSystemTimes(&i1, &k1, &u1);
+ uint64_t idle0 = FromFileTime(i0);
+ uint64_t idle1 = FromFileTime(i1);
+ uint64_t kernel0 = FromFileTime(k0);
+ uint64_t kernel1 = FromFileTime(k1);
+ uint64_t user0 = FromFileTime(u0);
+ uint64_t user1 = FromFileTime(u1);
- uint64_t idle0 = FromFileTime(i0);
- uint64_t idle1 = FromFileTime(i1);
- uint64_t kernel0 = FromFileTime(k0);
- uint64_t kernel1 = FromFileTime(k1);
- uint64_t user0 = FromFileTime(u0);
- uint64_t user1 = FromFileTime(u1);
+ uint64_t idle = idle1 - idle0;
+ uint64_t kernel = kernel1 - kernel0;
+ uint64_t user = user1 - user0;
- uint64_t idle = idle1 - idle0;
- uint64_t kernel = kernel1 - kernel0;
- uint64_t user = user1 - user0;
- uint64_t total = (kernel + user) - idle;
+ double cpu = (1.0 - (double)idle / (kernel + user)) * 100.0;
+ return static_cast(cpu);
+ }
- double cpu = (1.0 - (double)idle / (kernel + user)) * 100.0;
+#elif __linux__
+ int now()
+ {
+ CpuTimes times1 = getCpuTimes();
+ sleep(1);
+ CpuTimes times2 = getCpuTimes();
- return static_cast(cpu);
+ uint64_t idle1 = times1.getIdleTime();
+ uint64_t idle2 = times2.getIdleTime();
+ uint64_t total1 = times1.getTotalTime();
+ uint64_t total2 = times2.getTotalTime();
- }
+ uint64_t idle_diff = idle2 - idle1;
+ uint64_t total_diff = total2 - total1;
+
+ if (total_diff == 0)
+ return 0; // Avoid division by zero
+
+ double cpu = (double)(total_diff - idle_diff) / total_diff * 100.0;
+ return static_cast(cpu);
+ }
+ CPUStats getCPUstats()
+ {
+ return ::getCPUstats();
+ }
- };
+#endif
+};
diff --git a/include/memory_monitor.h b/include/memory_monitor.h
index 28ef439..8c895cc 100644
--- a/include/memory_monitor.h
+++ b/include/memory_monitor.h
@@ -24,36 +24,43 @@
//
#include
#include
-#include
#include
+
+#ifdef _WIN32
+#include
#define DIV 1024
+#elif __linux__
+#include
+#include
+#include
+#include
+#define DIV 1024
+#endif
+
+class Memory {
+public:
+#ifdef _WIN32
int memory_percent(){
MEMORYSTATUSEX statusex;
-
statusex.dwLength = sizeof(statusex);
-
GlobalMemoryStatusEx(&statusex);
- long long percent = statusex.dwMemoryLoad;
-
- return percent;
+ return statusex.dwMemoryLoad;
}
+
int memory_available(){
MEMORYSTATUSEX statusex;
-
statusex.dwLength = sizeof(statusex);
-
GlobalMemoryStatusEx(&statusex);
- long long available = statusex.ullAvailPhys / DIV / DIV;
-
- return available;
+ return statusex.ullAvailPhys / DIV / DIV;
}
+
int memory_total(){
MEMORYSTATUSEX statusex;
statusex.dwLength = sizeof(statusex);
GlobalMemoryStatusEx(&statusex);
- long long total = statusex.ullTotalPhys / DIV / DIV;
- return total;
+ return statusex.ullTotalPhys / DIV / DIV;
}
+
int memory_used(){
MEMORYSTATUSEX statusex;
statusex.dwLength = sizeof(statusex);
@@ -61,3 +68,60 @@
long long used = statusex.ullTotalPhys - statusex.ullAvailPhys;
return used / DIV / DIV;
}
+
+#elif __linux__
+private:
+ struct MemInfo {
+ long long total;
+ long long free;
+ long long available;
+ long long buffers;
+ long long cached;
+ };
+
+ MemInfo getMemInfo() {
+ MemInfo info = {0};
+ std::ifstream file("/proc/meminfo");
+ std::string line;
+
+ while (std::getline(file, line)) {
+ std::istringstream iss(line);
+ std::string key;
+ long long value;
+ std::string unit;
+
+ if (iss >> key >> value >> unit) {
+ if (key == "MemTotal:") info.total = value;
+ else if (key == "MemFree:") info.free = value;
+ else if (key == "MemAvailable:") info.available = value;
+ else if (key == "Buffers:") info.buffers = value;
+ else if (key == "Cached:") info.cached = value;
+ }
+ }
+ return info;
+ }
+
+public:
+ int memory_percent(){
+ MemInfo info = getMemInfo();
+ if (info.total == 0) return 0;
+ long long used = info.total - info.available;
+ return (used * 100) / info.total;
+ }
+
+ int memory_available(){
+ MemInfo info = getMemInfo();
+ return info.available / DIV;
+ }
+
+ int memory_total(){
+ MemInfo info = getMemInfo();
+ return info.total / DIV;
+ }
+
+ int memory_used(){
+ MemInfo info = getMemInfo();
+ return (info.total - info.available) / DIV;
+ }
+#endif
+};
diff --git a/include/network_monitor.h b/include/network_monitor.h
new file mode 100644
index 0000000..19d5349
--- /dev/null
+++ b/include/network_monitor.h
@@ -0,0 +1,109 @@
+#ifndef NETWORK_MONITOR_H
+#define NETWORK_MONITOR_H
+
+// Written by: Anderson Yu-Hong Cai (https://github.com/AndersonTsaiTW)
+// Written on: 2025-10-11
+// License: MIT
+// Version: 2.0
+//
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0602
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+// Note: linking still required for iphlpapi when using g++: -liphlpapi
+
+static bool collect_if_counters(uint64_t &out_sent, uint64_t &out_recv) {
+ out_sent = 0;
+ out_recv = 0;
+
+ // Fallback to GetIfTable which is widely available (MinGW). We'll
+ // allocate the table buffer dynamically as required.
+ MIB_IFTABLE *pIfTable = NULL;
+ DWORD dwSize = 0;
+ DWORD dwRetVal = GetIfTable(NULL, &dwSize, FALSE);
+ if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
+ return false;
+ }
+
+ pIfTable = (MIB_IFTABLE*)malloc(dwSize);
+ if (pIfTable == NULL) return false;
+
+ dwRetVal = GetIfTable(pIfTable, &dwSize, FALSE);
+ if (dwRetVal != NO_ERROR) {
+ free(pIfTable);
+ return false;
+ }
+
+ std::set seenIndexes;
+ for (DWORD i = 0; i < pIfTable->dwNumEntries; ++i) {
+ MIB_IFROW &row = pIfTable->table[i];
+
+ // De-duplicate by dwIndex (if available). Some stacks list
+ // virtual/alias rows that may duplicate counters.
+ if (seenIndexes.find(row.dwIndex) != seenIndexes.end()) continue;
+ seenIndexes.insert(row.dwIndex);
+
+ // Heuristic: include an interface if it shows any octets OR has a
+ // non-zero oper status. This avoids summing unused loopback/host
+ // entries while still counting active interfaces.
+ uint64_t outOct = (uint64_t)row.dwOutOctets;
+ uint64_t inOct = (uint64_t)row.dwInOctets;
+ if (outOct == 0 && inOct == 0 && row.dwOperStatus == 0) {
+ continue;
+ }
+
+ out_sent += outOct;
+ out_recv += inOct;
+ }
+
+ free(pIfTable);
+ return true;
+}
+
+// Helper: compute difference with 64-bit wrap-around handling
+static inline uint64_t counter_diff(uint64_t end, uint64_t start) {
+ if (end >= start) return end - start;
+ // wrapped
+ return (UINT64_MAX - start) + end + 1ULL;
+}
+
+// Public API: samples counters for ~1s and returns KB/s
+static void get_network_stats(double &sent_rate_kbps, double &received_rate_kbps) {
+ uint64_t sent0 = 0, recv0 = 0;
+ uint64_t sent1 = 0, recv1 = 0;
+
+ if (!collect_if_counters(sent0, recv0)) {
+ sent_rate_kbps = 0.0;
+ received_rate_kbps = 0.0;
+ return;
+ }
+
+ ULONGLONG t0 = GetTickCount64();
+ Sleep(3000); // 3-second interval
+
+ if (!collect_if_counters(sent1, recv1)) {
+ sent_rate_kbps = 0.0;
+ received_rate_kbps = 0.0;
+ return;
+ }
+
+ ULONGLONG t1 = GetTickCount64();
+
+ double elapsed_s = (double)(t1 - t0) / 1000.0;
+ if (elapsed_s <= 0.0) elapsed_s = 1.0; // safety
+
+ uint64_t ds = counter_diff(sent1, sent0);
+ uint64_t dr = counter_diff(recv1, recv0);
+
+ // convert to KB/s
+ sent_rate_kbps = ((double)ds / 1024.0) / elapsed_s;
+ received_rate_kbps = ((double)dr / 1024.0) / elapsed_s;
+}
+
+#endif // NETWORK_MONITOR_H
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index a528335..5fc0474 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,19 +24,28 @@
// - if you find a bug, please report it to me on github
//
#include
+#include
#include "cpu_monitor.h"
#include "memory_monitor.h"
+#include "network_monitor.h"
-int main() {
+int main()
+{
Usage cpu;
-
+ Memory memory;
int cpu_percent = cpu.now();
- int mem_percent = memory_percent();
- int mem_available = memory_available();
- int mem_total = memory_total();
- int mem_used = memory_used();
- std::cout <<
-R"(________ ___ ___ ________ _____ ______ ________ ________ ________
+#ifdef __linux__
+ CPUStats stats = cpu.getCPUstats();
+#endif
+ int mem_percent = memory.memory_percent();
+ int mem_available = memory.memory_available();
+ int mem_total = memory.memory_total();
+ int mem_used = memory.memory_used();
+ double sent_rate_kbps, received_rate_kbps;
+ get_network_stats(sent_rate_kbps, received_rate_kbps);
+ double sum_rate_kbs = sent_rate_kbps + received_rate_kbps;
+ std::cout <<
+ R"(________ ___ ___ ________ _____ ______ ________ ________ ________
|\ ____\ |\ \ / /|\ ____\|\ _ \ _ \|\ __ \|\ __ \|\ ___ \
\ \ \___|_ \ \ \/ / | \ \___|\ \ \\\__\ \ \ \ \|\ \ \ \|\ \ \ \_|\ \
\ \_____ \ \ \ / / \ \_____ \ \ \\|__| \ \ \ \\\ \ \ \\\ \ \ \ \\ \
@@ -46,33 +55,73 @@ R"(________ ___ ___ ________ _____ ______ ________ ________ ______
\|_________\|___|/ \|_________|
)" << std::endl;
-
- std::cout << "Sysmood: Your system is feeling. It also has moods." << std::endl;
- std::cout << "========================System Stats======================= " << std::endl;
- std::cout << "CPU Usage: " << cpu_percent << "%" << std::endl;
- std::cout << "Memory Usage: " << mem_percent << "%" << std::endl;
- std::cout << "Memory Available: " << mem_available << " MB" << std::endl;
- std::cout << "Memory Total: " << mem_total << " MB" << std::endl;
- std::cout << "Memory Used: " << mem_used << " MB" << std::endl;
- std::cout << "=========================================================== " << std::endl;
-
- std::cout << "========================System Mood======================== " << std::endl;
- if (cpu_percent > 80) {
- std::cout << "I am getting fried here helpppppp :o" << std::endl;
- } else if (cpu_percent > 50) {
- std::cout << "Well I am working here, cool :)" << std::endl;
- } else {
- std::cout << "Yeah I am chilling here, toally chillll ;)" << std::endl;
+
+ std::cout << "Sysmood: Your system is feeling. It also has moods." << '\n';
+ std::cout << "========================System Stats======================= " << '\n';
+ std::cout << "CPU Usage: " << cpu_percent << "%" << '\n';
+#ifdef __linux__
+ std::cout << "Context Switches: " << stats.ctxt << '\n';
+ std::cout << "Boot Time: " << std::ctime(reinterpret_cast(&stats.btime)) << '\n';
+ std::cout << "Processes Created: " << stats.processes << '\n';
+ std::cout << "Processes Running: " << stats.procs_running << '\n';
+ std::cout << "Processes Blocked: " << stats.procs_blocked << '\n';
+#endif
+ std::cout << "Memory Usage: " << mem_percent << "%" << '\n';
+ std::cout << "Memory Available: " << mem_available << " MB" << '\n';
+ std::cout << "Memory Total: " << mem_total << " MB" << '\n';
+ std::cout << "Memory Used: " << mem_used << " MB" << '\n';
+ std::cout << "Network Sent: " << sent_rate_kbps << " KB/s" << std::endl;
+ std::cout << "Network Received: " << received_rate_kbps << " KB/s" << std::endl;
+ std::cout << "=========================================================== " << '\n';
+
+ std::cout << "========================System Mood======================== " << '\n';
+ if (cpu_percent > 80)
+ {
+ std::cout << "I am getting fried here helpppppp :o" << '\n';
+ }
+ else if (cpu_percent > 50)
+ {
+ std::cout << "Well I am working here, cool :)" << '\n';
}
- if (mem_percent > 80) {
- std::cout << "Whoa! My brain is almost full... I'm about to forget something! " << std::endl;
- } else if (mem_percent > 50) {
- std::cout << "Memory's getting a little crowded, but I can still juggle things! " << std::endl;
- } else {
- std::cout << "So much free memory! I could host a party in here! " << std::endl;
+ else
+ {
+ std::cout << "Yeah I am chilling here, toally chillll ;)" << '\n';
}
- std::cout << "=========================================================== " << std::endl;
-
-
+ if (mem_percent > 80)
+ {
+ std::cout << "Whoa! My brain is almost full... I'm about to forget something! " << '\n';
+ }
+ else if (mem_percent > 50)
+ {
+ std::cout << "Memory's getting a little crowded, but I can still juggle things! " << '\n';
+ }
+ else
+ {
+ std::cout << "So much free memory! I could host a party in here! " << '\n';
+ }
+
+ if (sum_rate_kbs <= 0.0)
+ {
+ std::cout << "Hello...? Anyone out there? I think I'm alone in the digital void..." << std::endl;
+ }
+ else if (sum_rate_kbs <= 10.0) // 1–10 KB/s:low
+ {
+ std::cout << "I can barely feel the connection... maybe send a ping to keep me alive?" << std::endl;
+ }
+ else if (sum_rate_kbs <= 100.0) // 11–100 KB/s:moderate
+ { // 11–100 KB/s:moderate
+ std::cout << "Hmm... data's trickling in. Not bad, but I'm starting to warm up!" << std::endl;
+ }
+ else if (sum_rate_kbs <= 1000.0) // 101–1000 KB/s:good
+ {
+ std::cout << "Nice flow! I can stream tunes, fetch memes, and still feel chill~" << std::endl;
+ }
+ else // > 1000 KB/s:fast
+ {
+ std::cout << "Wooosh! Data's flying-pages load before you blink. I'm unstoppable!!! " << std::endl;
+ }
+
+ std::cout << "=========================================================== " << '\n';
+
return 0;
}
\ No newline at end of file