mirror of
https://github.com/aristocratos/btop.git
synced 2024-05-18 19:33:03 +12:00
Merge branch 'main' into build-info
This commit is contained in:
commit
967ea1ab6f
45
.github/workflows/continuous-build-gpu.yml
vendored
Normal file
45
.github/workflows/continuous-build-gpu.yml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
name: Continuous Build Gpu
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
tags-ignore:
|
||||||
|
- '*.*'
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- '!src/osx/**'
|
||||||
|
- '!src/freebsd/**'
|
||||||
|
- '!src/openbsd/**'
|
||||||
|
- 'include/**'
|
||||||
|
- 'Makefile'
|
||||||
|
- '.github/workflows/continuous-build-gpu.yml'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- 'src/**'
|
||||||
|
- '!src/osx/**'
|
||||||
|
- '!src/freebsd/**'
|
||||||
|
- '!src/openbsd/**'
|
||||||
|
- 'include/**'
|
||||||
|
- 'Makefile'
|
||||||
|
- '.github/workflows/continuous-build-gpu.yml'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
gpu_build_linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: alpine:edge
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install build tools
|
||||||
|
run: apk add --no-cache --update gcc g++ make
|
||||||
|
|
||||||
|
- name: Compile
|
||||||
|
run: make CXX=g++ GPU_SUPPORT=true
|
||||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,3 +1,25 @@
|
||||||
|
## v1.3.2
|
||||||
|
|
||||||
|
Description | Author(s) | References
|
||||||
|
--- | --- | ---
|
||||||
|
fix: Can't detect librocm 6.0.x | @imwints, @aristocratos | #761
|
||||||
|
|
||||||
|
## v1.3.1
|
||||||
|
|
||||||
|
Description | Author(s) | References
|
||||||
|
--- | --- | ---
|
||||||
|
GPU: Added support for dynamic loading of ROCm v6 libraries | @aristocratos, @fxzjshm | 5511131, #737
|
||||||
|
Increase max network interface name to 15 | @tessus | #714
|
||||||
|
Fix OpenBSD UTF-8 locale detection | @lcheylus, @imwints | #753, #717
|
||||||
|
Add hot-reloading of config file with CTRL+R or SIGUSR2 signal | @MartinPit | #722
|
||||||
|
Add battery power draw for linux and freebsd | @vsey | #689
|
||||||
|
Fix crash caused by string exception when cpu clock is exactly between 999.5 and 999.9 Mhz | @rkmcode | #735
|
||||||
|
Write newline at end of config file | @planet36 | #743
|
||||||
|
Add theme based on Everforest Dark Medium palette | @M-Sviridov | #746
|
||||||
|
fix: don't mangle memory for zombie processes | @joske | #747
|
||||||
|
Share common code from collect | @imwints | #756
|
||||||
|
Fixed incorrect used and available memory for OSX | | 4461a43
|
||||||
|
|
||||||
## v1.3.0
|
## v1.3.0
|
||||||
|
|
||||||
* Added Gpu Support Linux | @romner-set | PR #529
|
* Added Gpu Support Linux | @romner-set | PR #529
|
||||||
|
|
|
@ -11,7 +11,6 @@ if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project("btop"
|
project("btop"
|
||||||
VERSION 1.3.0
|
|
||||||
DESCRIPTION "A monitor of resources"
|
DESCRIPTION "A monitor of resources"
|
||||||
HOMEPAGE_URL "https://github.com/aristocratos/btop"
|
HOMEPAGE_URL "https://github.com/aristocratos/btop"
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
|
@ -65,6 +64,8 @@ if(APPLE)
|
||||||
target_sources(btop PRIVATE src/osx/btop_collect.cpp src/osx/sensors.cpp src/osx/smc.cpp)
|
target_sources(btop PRIVATE src/osx/btop_collect.cpp src/osx/sensors.cpp src/osx/smc.cpp)
|
||||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
target_sources(btop PRIVATE src/freebsd/btop_collect.cpp)
|
target_sources(btop PRIVATE src/freebsd/btop_collect.cpp)
|
||||||
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||||
|
target_sources(btop PRIVATE src/openbsd/btop_collect.cpp src/openbsd/sysctlbyname.cpp)
|
||||||
elseif(LINUX)
|
elseif(LINUX)
|
||||||
target_sources(btop PRIVATE src/linux/btop_collect.cpp)
|
target_sources(btop PRIVATE src/linux/btop_collect.cpp)
|
||||||
else()
|
else()
|
||||||
|
@ -125,6 +126,7 @@ if(HAS_FCF_PROTECTION)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(btop PRIVATE
|
target_compile_definitions(btop PRIVATE
|
||||||
|
FMT_HEADER_ONLY
|
||||||
_FILE_OFFSET_BITS=64
|
_FILE_OFFSET_BITS=64
|
||||||
$<$<CONFIG:Debug>:_GLIBCXX_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS=1>
|
$<$<CONFIG:Debug>:_GLIBCXX_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS=1>
|
||||||
# Only has an effect with optimizations enabled
|
# Only has an effect with optimizations enabled
|
||||||
|
@ -194,12 +196,18 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(devstat REQUIRED)
|
find_package(devstat REQUIRED)
|
||||||
target_link_libraries(btop devstat::devstat)
|
find_package(kvm REQUIRED)
|
||||||
|
target_link_libraries(btop devstat::devstat kvm::kvm)
|
||||||
if(BTOP_STATIC)
|
if(BTOP_STATIC)
|
||||||
find_package(elf REQUIRED)
|
find_package(elf REQUIRED)
|
||||||
find_package(kvm REQUIRED)
|
target_link_libraries(btop elf::elf)
|
||||||
target_link_libraries(btop elf::elf kvm::kvm)
|
|
||||||
endif()
|
endif()
|
||||||
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
|
||||||
|
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
|
target_compile_options(btop PRIVATE -static-libstdc++)
|
||||||
|
endif()
|
||||||
|
find_package(kvm REQUIRED)
|
||||||
|
target_link_libraries(btop kvm::kvm)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(TARGETS btop RUNTIME)
|
install(TARGETS btop RUNTIME)
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -143,7 +143,7 @@ else ifeq ($(PLATFORM_LC),macos)
|
||||||
else ifeq ($(PLATFORM_LC),openbsd)
|
else ifeq ($(PLATFORM_LC),openbsd)
|
||||||
PLATFORM_DIR := openbsd
|
PLATFORM_DIR := openbsd
|
||||||
THREADS := $(shell sysctl -n hw.ncpu || echo 1)
|
THREADS := $(shell sysctl -n hw.ncpu || echo 1)
|
||||||
override ADDFLAGS += -lkvm
|
override ADDFLAGS += -lkvm -static-libstdc++
|
||||||
export MAKE = gmake
|
export MAKE = gmake
|
||||||
SU_GROUP := wheel
|
SU_GROUP := wheel
|
||||||
else
|
else
|
||||||
|
@ -185,7 +185,7 @@ override GOODFLAGS := $(foreach flag,$(TESTFLAGS),$(strip $(shell echo "int main
|
||||||
override REQFLAGS := -std=c++20
|
override REQFLAGS := -std=c++20
|
||||||
WARNFLAGS := -Wall -Wextra -pedantic
|
WARNFLAGS := -Wall -Wextra -pedantic
|
||||||
OPTFLAGS := -O2 -ftree-vectorize -flto=$(LTO)
|
OPTFLAGS := -O2 -ftree-vectorize -flto=$(LTO)
|
||||||
LDCXXFLAGS := -pthread -D_GLIBCXX_ASSERTIONS -D_FILE_OFFSET_BITS=64 $(GOODFLAGS) $(ADDFLAGS)
|
LDCXXFLAGS := -pthread -DFMT_HEADER_ONLY -D_GLIBCXX_ASSERTIONS -D_FILE_OFFSET_BITS=64 $(GOODFLAGS) $(ADDFLAGS)
|
||||||
override CXXFLAGS += $(REQFLAGS) $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS)
|
override CXXFLAGS += $(REQFLAGS) $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS)
|
||||||
override LDFLAGS += $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS)
|
override LDFLAGS += $(LDCXXFLAGS) $(OPTFLAGS) $(WARNFLAGS)
|
||||||
INC := $(foreach incdir,$(INCDIRS),-isystem $(incdir)) -I$(SRCDIR) -I$(BUILDDIR)
|
INC := $(foreach incdir,$(INCDIRS),-isystem $(incdir)) -I$(SRCDIR) -I$(BUILDDIR)
|
||||||
|
|
72
README.md
72
README.md
|
@ -378,12 +378,12 @@ If you have an AMD GPU `rocm_smi_lib` is required, which may or may not be packa
|
||||||
|
|
||||||
* **AMD**
|
* **AMD**
|
||||||
|
|
||||||
AMDGPU data is queried using the [ROCm SMI](https://github.com/RadeonOpenCompute/rocm_smi_lib) library, which may or may not be packaged for your distribution. If your distribution doesn't provide a package, btop++ is statically linked to ROCm SMI with the `RSMI_STATIC=true` make flag.
|
AMDGPU data is queried using the [ROCm SMI](https://github.com/rocm/rocm_smi_lib) library, which may or may not be packaged for your distribution. If your distribution doesn't provide a package, btop++ is statically linked to ROCm SMI with the `RSMI_STATIC=true` make flag.
|
||||||
|
|
||||||
This flag expects the ROCm SMI source code in `lib/rocm_smi_lib`, and compilation will fail if it's not there. The latest tested version is 5.6.x, which can be obtained with the following command:
|
This flag expects the ROCm SMI source code in `lib/rocm_smi_lib`, and compilation will fail if it's not there. The latest tested version is 5.6.x, which can be obtained with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/RadeonOpenCompute/rocm_smi_lib.git --depth 1 -b rocm-5.6.x lib/rocm_smi_lib
|
git clone https://github.com/rocm/rocm_smi_lib.git --depth 1 -b rocm-5.6.x lib/rocm_smi_lib
|
||||||
```
|
```
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
@ -995,6 +995,74 @@ If you have an AMD GPU `rocm_smi_lib` is required, which may or may not be packa
|
||||||
gmake help
|
gmake help
|
||||||
```
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
|
||||||
|
### With CMake (Community maintained)
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
1. **Install build dependencies**
|
||||||
|
|
||||||
|
Requires GCC, CMake, Ninja and Git
|
||||||
|
|
||||||
|
_**Note:** LLVM's libc++ shipped with OpenBSD 7.4 is too old and cannot compile btop._
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pkg_add cmake g++%11 git ninja
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Clone the repository**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/aristocratos/btop.git && cd btop
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Compile**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Configure
|
||||||
|
CXX=eg++ cmake -B build -G Ninja
|
||||||
|
# Build
|
||||||
|
cmake --build build
|
||||||
|
```
|
||||||
|
|
||||||
|
This will automatically build a release version of btop.
|
||||||
|
|
||||||
|
Some useful options to pass to the configure step:
|
||||||
|
|
||||||
|
| Configure flag | Description |
|
||||||
|
|---------------------------------|-------------------------------------------------------------------------|
|
||||||
|
| `-DBTOP_LTO=<ON\|OFF>` | Enables link time optimization (ON by default) |
|
||||||
|
| `-DBTOP_USE_MOLD=<ON\|OFF>` | Use mold to link btop (OFF by default) |
|
||||||
|
| `-DBTOP_PEDANTIC=<ON\|OFF>` | Compile with additional warnings (OFF by default) |
|
||||||
|
| `-DBTOP_WERROR=<ON\|OFF>` | Compile with warnings as errors (OFF by default) |
|
||||||
|
| `-DBTOP_FORTIFY=<ON\|OFF>` | Detect buffer overflows with `_FORTIFY_SOURCE=3` (ON by default) |
|
||||||
|
| `-DCMAKE_INSTALL_PREFIX=<path>` | The installation prefix ('/usr/local' by default) |
|
||||||
|
|
||||||
|
To force any other compiler, run `CXX=<compiler> cmake -B build -G Ninja`
|
||||||
|
|
||||||
|
4. **Install**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --install build
|
||||||
|
```
|
||||||
|
|
||||||
|
May require root privileges
|
||||||
|
|
||||||
|
5. **Uninstall**
|
||||||
|
|
||||||
|
CMake doesn't generate an uninstall target by default. To remove installed files, run
|
||||||
|
```
|
||||||
|
cat build/install_manifest.txt | xargs rm -irv
|
||||||
|
```
|
||||||
|
|
||||||
|
6. **Cleanup build directory**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake --build build -t clean
|
||||||
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
## Installing the snap
|
## Installing the snap
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# Find libkvm, the Kernel Data Access Library
|
# Find libkvm, the Kernel Data Access Library
|
||||||
#
|
#
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
if(BSD)
|
||||||
find_path(kvm_INCLUDE_DIR NAMES kvm.h)
|
find_path(kvm_INCLUDE_DIR NAMES kvm.h)
|
||||||
find_library(kvm_LIBRARY NAMES kvm)
|
find_library(kvm_LIBRARY NAMES kvm)
|
||||||
|
|
||||||
|
|
81
src/btop.cpp
81
src/btop.cpp
|
@ -54,6 +54,7 @@ tab-size = 4
|
||||||
#include "btop_menu.hpp"
|
#include "btop_menu.hpp"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
#include "fmt/ostream.h"
|
||||||
|
|
||||||
using std::atomic;
|
using std::atomic;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
@ -79,7 +80,7 @@ namespace Global {
|
||||||
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
|
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
|
||||||
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
|
||||||
};
|
};
|
||||||
const string Version = "1.3.0";
|
const string Version = "1.3.2";
|
||||||
|
|
||||||
int coreCount;
|
int coreCount;
|
||||||
string overlay;
|
string overlay;
|
||||||
|
@ -109,6 +110,7 @@ namespace Global {
|
||||||
atomic<bool> should_sleep (false);
|
atomic<bool> should_sleep (false);
|
||||||
atomic<bool> _runner_started (false);
|
atomic<bool> _runner_started (false);
|
||||||
atomic<bool> init_conf (false);
|
atomic<bool> init_conf (false);
|
||||||
|
atomic<bool> reload_conf (false);
|
||||||
|
|
||||||
bool arg_tty{};
|
bool arg_tty{};
|
||||||
bool arg_low_color{};
|
bool arg_low_color{};
|
||||||
|
@ -382,9 +384,38 @@ void _signal_handler(const int sig) {
|
||||||
case SIGUSR1:
|
case SIGUSR1:
|
||||||
// Input::poll interrupt
|
// Input::poll interrupt
|
||||||
break;
|
break;
|
||||||
|
case SIGUSR2:
|
||||||
|
Global::reload_conf = true;
|
||||||
|
Input::interrupt();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//* Config init
|
||||||
|
void init_config(){
|
||||||
|
atomic_lock lck(Global::init_conf);
|
||||||
|
vector<string> load_warnings;
|
||||||
|
Config::load(Config::conf_file, load_warnings);
|
||||||
|
Config::set("lowcolor", (Global::arg_low_color ? true : not Config::getB("truecolor")));
|
||||||
|
|
||||||
|
static bool first_init = true;
|
||||||
|
|
||||||
|
if (Global::debug and first_init) {
|
||||||
|
Logger::set("DEBUG");
|
||||||
|
Logger::debug("Running in DEBUG mode!");
|
||||||
|
}
|
||||||
|
else Logger::set(Config::getS("log_level"));
|
||||||
|
|
||||||
|
static string log_level;
|
||||||
|
if (const string current_level = Config::getS("log_level"); log_level != current_level) {
|
||||||
|
log_level = current_level;
|
||||||
|
Logger::info("Logger set to " + (Global::debug ? "DEBUG" : log_level));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& err_str : load_warnings) Logger::warning(err_str);
|
||||||
|
first_init = false;
|
||||||
|
}
|
||||||
|
|
||||||
//* Manages secondary thread for collection and drawing of boxes
|
//* Manages secondary thread for collection and drawing of boxes
|
||||||
namespace Runner {
|
namespace Runner {
|
||||||
atomic<bool> active (false);
|
atomic<bool> active (false);
|
||||||
|
@ -913,22 +944,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//? Config init
|
//? Config init
|
||||||
{
|
init_config();
|
||||||
atomic_lock lck(Global::init_conf);
|
|
||||||
vector<string> load_warnings;
|
|
||||||
Config::load(Config::conf_file, load_warnings);
|
|
||||||
Config::set("lowcolor", (Global::arg_low_color ? true : not Config::getB("truecolor")));
|
|
||||||
|
|
||||||
if (Global::debug) {
|
|
||||||
Logger::set("DEBUG");
|
|
||||||
Logger::debug("Starting in DEBUG mode!");
|
|
||||||
}
|
|
||||||
else Logger::set(Config::getS("log_level"));
|
|
||||||
|
|
||||||
Logger::info("Logger set to " + (Global::debug ? "DEBUG" : Config::getS("log_level")));
|
|
||||||
|
|
||||||
for (const auto& err_str : load_warnings) Logger::warning(err_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
//? Try to find and set a UTF-8 locale
|
//? Try to find and set a UTF-8 locale
|
||||||
if (std::setlocale(LC_ALL, "") != nullptr and not s_contains((string)std::setlocale(LC_ALL, ""), ";")
|
if (std::setlocale(LC_ALL, "") != nullptr and not s_contains((string)std::setlocale(LC_ALL, ""), ";")
|
||||||
|
@ -938,7 +954,7 @@ int main(int argc, char **argv) {
|
||||||
else {
|
else {
|
||||||
string found;
|
string found;
|
||||||
bool set_failure{};
|
bool set_failure{};
|
||||||
for (const auto loc_env : array{"LANG", "LC_ALL"}) {
|
for (const auto loc_env : array{"LANG", "LC_ALL", "LC_CTYPE"}) {
|
||||||
if (std::getenv(loc_env) != nullptr and str_to_upper(s_replace((string)std::getenv(loc_env), "-", "")).ends_with("UTF8")) {
|
if (std::getenv(loc_env) != nullptr and str_to_upper(s_replace((string)std::getenv(loc_env), "-", "")).ends_with("UTF8")) {
|
||||||
found = std::getenv(loc_env);
|
found = std::getenv(loc_env);
|
||||||
if (std::setlocale(LC_ALL, found.c_str()) == nullptr) {
|
if (std::setlocale(LC_ALL, found.c_str()) == nullptr) {
|
||||||
|
@ -1053,6 +1069,7 @@ int main(int argc, char **argv) {
|
||||||
std::signal(SIGCONT, _signal_handler);
|
std::signal(SIGCONT, _signal_handler);
|
||||||
std::signal(SIGWINCH, _signal_handler);
|
std::signal(SIGWINCH, _signal_handler);
|
||||||
std::signal(SIGUSR1, _signal_handler);
|
std::signal(SIGUSR1, _signal_handler);
|
||||||
|
std::signal(SIGUSR2, _signal_handler);
|
||||||
|
|
||||||
sigset_t mask;
|
sigset_t mask;
|
||||||
sigemptyset(&mask);
|
sigemptyset(&mask);
|
||||||
|
@ -1104,9 +1121,27 @@ int main(int argc, char **argv) {
|
||||||
try {
|
try {
|
||||||
while (not true not_eq not false) {
|
while (not true not_eq not false) {
|
||||||
//? Check for exceptions in secondary thread and exit with fail signal if true
|
//? Check for exceptions in secondary thread and exit with fail signal if true
|
||||||
if (Global::thread_exception) clean_quit(1);
|
if (Global::thread_exception) {
|
||||||
else if (Global::should_quit) clean_quit(0);
|
clean_quit(1);
|
||||||
else if (Global::should_sleep) { Global::should_sleep = false; _sleep(); }
|
}
|
||||||
|
else if (Global::should_quit) {
|
||||||
|
clean_quit(0);
|
||||||
|
}
|
||||||
|
else if (Global::should_sleep) {
|
||||||
|
Global::should_sleep = false;
|
||||||
|
_sleep();
|
||||||
|
}
|
||||||
|
//? Hot reload config from CTRL + R or SIGUSR2
|
||||||
|
else if (Global::reload_conf) {
|
||||||
|
Global::reload_conf = false;
|
||||||
|
if (Runner::active) Runner::stop();
|
||||||
|
Config::unlock();
|
||||||
|
init_config();
|
||||||
|
Theme::updateThemes();
|
||||||
|
Theme::setTheme();
|
||||||
|
Draw::banner_gen(0, 0, false, true);
|
||||||
|
Global::resized = true;
|
||||||
|
}
|
||||||
|
|
||||||
//? Make sure terminal size hasn't changed (in case of SIGWINCH not working properly)
|
//? Make sure terminal size hasn't changed (in case of SIGWINCH not working properly)
|
||||||
term_resize(Global::resized);
|
term_resize(Global::resized);
|
||||||
|
@ -1141,9 +1176,9 @@ int main(int argc, char **argv) {
|
||||||
update_ms = Config::getI("update_ms");
|
update_ms = Config::getI("update_ms");
|
||||||
future_time = time_ms() + update_ms;
|
future_time = time_ms() + update_ms;
|
||||||
}
|
}
|
||||||
else if (future_time - current_time > update_ms)
|
else if (future_time - current_time > update_ms) {
|
||||||
future_time = current_time;
|
future_time = current_time;
|
||||||
|
}
|
||||||
//? Poll for input and process any input detected
|
//? Poll for input and process any input detected
|
||||||
else if (Input::poll(min((uint64_t)1000, future_time - current_time))) {
|
else if (Input::poll(min((uint64_t)1000, future_time - current_time))) {
|
||||||
if (not Runner::active) Config::unlock();
|
if (not Runner::active) Config::unlock();
|
||||||
|
|
|
@ -199,6 +199,8 @@ namespace Config {
|
||||||
|
|
||||||
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
|
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
|
||||||
|
|
||||||
|
{"show_battery_watts", "#* Show power stats of battery next to charge indicator."},
|
||||||
|
|
||||||
{"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
|
{"log_level", "#* Set loglevel for \"~/.config/btop/btop.log\" levels are: \"ERROR\" \"WARNING\" \"INFO\" \"DEBUG\".\n"
|
||||||
"#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."},
|
"#* The level set includes all lower levels, i.e. \"DEBUG\" will show all logging info."},
|
||||||
#ifdef GPU_SUPPORT
|
#ifdef GPU_SUPPORT
|
||||||
|
@ -293,6 +295,7 @@ namespace Config {
|
||||||
{"net_auto", true},
|
{"net_auto", true},
|
||||||
{"net_sync", true},
|
{"net_sync", true},
|
||||||
{"show_battery", true},
|
{"show_battery", true},
|
||||||
|
{"show_battery_watts", true},
|
||||||
{"vim_keys", false},
|
{"vim_keys", false},
|
||||||
{"tty_mode", false},
|
{"tty_mode", false},
|
||||||
{"disk_free_priv", false},
|
{"disk_free_priv", false},
|
||||||
|
@ -729,9 +732,9 @@ namespace Config {
|
||||||
if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return;
|
if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return;
|
||||||
std::ofstream cwrite(conf_file, std::ios::trunc);
|
std::ofstream cwrite(conf_file, std::ios::trunc);
|
||||||
if (cwrite.good()) {
|
if (cwrite.good()) {
|
||||||
cwrite << "#? Config file for btop v. " << Global::Version;
|
cwrite << "#? Config file for btop v. " << Global::Version << "\n";
|
||||||
for (auto [name, description] : descriptions) {
|
for (auto [name, description] : descriptions) {
|
||||||
cwrite << "\n\n" << (description.empty() ? "" : description + "\n")
|
cwrite << "\n" << (description.empty() ? "" : description + "\n")
|
||||||
<< name << " = ";
|
<< name << " = ";
|
||||||
if (strings.contains(name))
|
if (strings.contains(name))
|
||||||
cwrite << "\"" << strings.at(name) << "\"";
|
cwrite << "\"" << strings.at(name) << "\"";
|
||||||
|
@ -739,6 +742,7 @@ namespace Config {
|
||||||
cwrite << ints.at(name);
|
cwrite << ints.at(name);
|
||||||
else if (bools.contains(name))
|
else if (bools.contains(name))
|
||||||
cwrite << (bools.at(name) ? "True" : "False");
|
cwrite << (bools.at(name) ? "True" : "False");
|
||||||
|
cwrite << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -706,6 +706,7 @@ namespace Cpu {
|
||||||
if (Config::getB("show_battery") and has_battery) {
|
if (Config::getB("show_battery") and has_battery) {
|
||||||
static int old_percent{}; // defaults to = 0
|
static int old_percent{}; // defaults to = 0
|
||||||
static long old_seconds{}; // defaults to = 0
|
static long old_seconds{}; // defaults to = 0
|
||||||
|
static float old_watts{}; // defaults to = 0
|
||||||
static string old_status;
|
static string old_status;
|
||||||
static Draw::Meter bat_meter {10, "cpu", true};
|
static Draw::Meter bat_meter {10, "cpu", true};
|
||||||
static const std::unordered_map<string, string> bat_symbols = {
|
static const std::unordered_map<string, string> bat_symbols = {
|
||||||
|
@ -715,16 +716,18 @@ namespace Cpu {
|
||||||
{"unknown", "○"}
|
{"unknown", "○"}
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto& [percent, seconds, status] = current_bat;
|
const auto& [percent, watts, seconds, status] = current_bat;
|
||||||
|
|
||||||
if (redraw or percent != old_percent or seconds != old_seconds or status != old_status) {
|
if (redraw or percent != old_percent or (watts != old_watts and Config::getB("show_battery_watts")) or seconds != old_seconds or status != old_status) {
|
||||||
old_percent = percent;
|
old_percent = percent;
|
||||||
|
old_watts = watts;
|
||||||
old_seconds = seconds;
|
old_seconds = seconds;
|
||||||
old_status = status;
|
old_status = status;
|
||||||
const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : "");
|
const string str_time = (seconds > 0 ? sec_to_dhms(seconds, true, true) : "");
|
||||||
const string str_percent = to_string(percent) + '%';
|
const string str_percent = to_string(percent) + '%';
|
||||||
|
const string str_watts = (watts != -1 and Config::getB("show_battery_watts") ? fmt::format("{:.2f}", watts) + 'W' : "");
|
||||||
const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown"));
|
const auto& bat_symbol = bat_symbols.at((bat_symbols.contains(status) ? status : "unknown"));
|
||||||
const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + to_string(Config::getI("update_ms")).size();
|
const int current_len = (Term::width >= 100 ? 11 : 0) + str_time.size() + str_percent.size() + str_watts.size() + to_string(Config::getI("update_ms")).size();
|
||||||
const int current_pos = Term::width - current_len - 17;
|
const int current_pos = Term::width - current_len - 17;
|
||||||
|
|
||||||
if ((bat_pos != current_pos or bat_len != current_len) and bat_pos > 0 and not redraw)
|
if ((bat_pos != current_pos or bat_len != current_len) and bat_pos > 0 and not redraw)
|
||||||
|
@ -734,7 +737,7 @@ namespace Cpu {
|
||||||
|
|
||||||
out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent
|
out += Mv::to(y, bat_pos) + title_left + Theme::c("title") + Fx::b + "BAT" + bat_symbol + ' ' + str_percent
|
||||||
+ (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "")
|
+ (Term::width >= 100 ? Fx::ub + ' ' + bat_meter(percent) + Fx::b : "")
|
||||||
+ (not str_time.empty() ? ' ' + Theme::c("title") + str_time : " ") + Fx::ub + title_right;
|
+ (not str_time.empty() ? ' ' + Theme::c("title") + str_time : "") + (not str_watts.empty() ? " " + Theme::c("title") + Fx::b + str_watts : "") + Fx::ub + title_right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (bat_pos > 0) {
|
else if (bat_pos > 0) {
|
||||||
|
@ -1361,6 +1364,7 @@ namespace Net {
|
||||||
int x = 1, y, width = 20, height;
|
int x = 1, y, width = 20, height;
|
||||||
int b_x, b_y, b_width, b_height, d_graph_height, u_graph_height;
|
int b_x, b_y, b_width, b_height, d_graph_height, u_graph_height;
|
||||||
bool shown = true, redraw = true;
|
bool shown = true, redraw = true;
|
||||||
|
const int MAX_IFNAMSIZ = 15;
|
||||||
string old_ip;
|
string old_ip;
|
||||||
std::unordered_map<string, Draw::Graph> graphs;
|
std::unordered_map<string, Draw::Graph> graphs;
|
||||||
string box;
|
string box;
|
||||||
|
@ -1381,7 +1385,7 @@ namespace Net {
|
||||||
out.reserve(width * height);
|
out.reserve(width * height);
|
||||||
const string title_left = Theme::c("net_box") + Fx::ub + Symbols::title_left;
|
const string title_left = Theme::c("net_box") + Fx::ub + Symbols::title_left;
|
||||||
const string title_right = Theme::c("net_box") + Fx::ub + Symbols::title_right;
|
const string title_right = Theme::c("net_box") + Fx::ub + Symbols::title_right;
|
||||||
const int i_size = min((int)selected_iface.size(), 10);
|
const int i_size = min((int)selected_iface.size(), MAX_IFNAMSIZ);
|
||||||
const long long down_max = (net_auto ? safeVal(graph_max, "download"s) : ((long long)(Config::getI("net_download")) << 20) / 8);
|
const long long down_max = (net_auto ? safeVal(graph_max, "download"s) : ((long long)(Config::getI("net_download")) << 20) / 8);
|
||||||
const long long up_max = (net_auto ? safeVal(graph_max, "upload"s) : ((long long)(Config::getI("net_upload")) << 20) / 8);
|
const long long up_max = (net_auto ? safeVal(graph_max, "upload"s) : ((long long)(Config::getI("net_upload")) << 20) / 8);
|
||||||
|
|
||||||
|
@ -1403,7 +1407,7 @@ namespace Net {
|
||||||
//? Interface selector and buttons
|
//? Interface selector and buttons
|
||||||
|
|
||||||
out += Mv::to(y, x+width - i_size - 9) + title_left + Fx::b + Theme::c("hi_fg") + "<b " + Theme::c("title")
|
out += Mv::to(y, x+width - i_size - 9) + title_left + Fx::b + Theme::c("hi_fg") + "<b " + Theme::c("title")
|
||||||
+ uresize(selected_iface, 10) + Theme::c("hi_fg") + " n>" + title_right
|
+ uresize(selected_iface, MAX_IFNAMSIZ) + Theme::c("hi_fg") + " n>" + title_right
|
||||||
+ Mv::to(y, x+width - i_size - 15) + title_left + Theme::c("hi_fg") + (safeVal(net.stat, "download"s).offset + safeVal(net.stat, "upload"s).offset > 0 ? Fx::b : "") + 'z'
|
+ Mv::to(y, x+width - i_size - 15) + title_left + Theme::c("hi_fg") + (safeVal(net.stat, "download"s).offset + safeVal(net.stat, "upload"s).offset > 0 ? Fx::b : "") + 'z'
|
||||||
+ Theme::c("title") + "ero" + title_right;
|
+ Theme::c("title") + "ero" + title_right;
|
||||||
Input::mouse_mappings["b"] = {y, x+width - i_size - 8, 1, 3};
|
Input::mouse_mappings["b"] = {y, x+width - i_size - 8, 1, 3};
|
||||||
|
@ -2238,3 +2242,4 @@ namespace Draw {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ namespace Input {
|
||||||
//* Map for translating key codes to readable values
|
//* Map for translating key codes to readable values
|
||||||
const std::unordered_map<string, string> Key_escapes = {
|
const std::unordered_map<string, string> Key_escapes = {
|
||||||
{"\033", "escape"},
|
{"\033", "escape"},
|
||||||
|
{"\x12", "ctrl_r"},
|
||||||
{"\n", "enter"},
|
{"\n", "enter"},
|
||||||
{" ", "space"},
|
{" ", "space"},
|
||||||
{"\x7f", "backspace"},
|
{"\x7f", "backspace"},
|
||||||
|
@ -258,8 +259,10 @@ namespace Input {
|
||||||
Draw::calcSizes();
|
Draw::calcSizes();
|
||||||
Runner::run("all", false, true);
|
Runner::run("all", false, true);
|
||||||
return;
|
return;
|
||||||
}
|
} else if (is_in(key, "ctrl_r")) {
|
||||||
else
|
kill(getpid(), SIGUSR2);
|
||||||
|
return;
|
||||||
|
} else
|
||||||
keep_going = true;
|
keep_going = true;
|
||||||
|
|
||||||
if (not keep_going) return;
|
if (not keep_going) return;
|
||||||
|
|
|
@ -177,6 +177,7 @@ namespace Menu {
|
||||||
{"F2, o", "Shows options."},
|
{"F2, o", "Shows options."},
|
||||||
{"F1, ?, h", "Shows this window."},
|
{"F1, ?, h", "Shows this window."},
|
||||||
{"ctrl + z", "Sleep program and put in background."},
|
{"ctrl + z", "Sleep program and put in background."},
|
||||||
|
{"ctrl + r", "Reloads config file from disk."},
|
||||||
{"q, ctrl + c", "Quits program."},
|
{"q, ctrl + c", "Quits program."},
|
||||||
{"+, -", "Add/Subtract 100ms to/from update timer."},
|
{"+, -", "Add/Subtract 100ms to/from update timer."},
|
||||||
{"Up, Down", "Select in process list."},
|
{"Up, Down", "Select in process list."},
|
||||||
|
@ -353,6 +354,11 @@ namespace Menu {
|
||||||
"Can be both batteries and UPS.",
|
"Can be both batteries and UPS.",
|
||||||
"",
|
"",
|
||||||
"\"Auto\" for auto detection."},
|
"\"Auto\" for auto detection."},
|
||||||
|
{"show_battery_watts",
|
||||||
|
"Show battery power.",
|
||||||
|
"",
|
||||||
|
"Show discharge power when discharging.",
|
||||||
|
"Show charging power when charging."},
|
||||||
{"log_level",
|
{"log_level",
|
||||||
"Set loglevel for error.log",
|
"Set loglevel for error.log",
|
||||||
"",
|
"",
|
||||||
|
|
|
@ -25,10 +25,19 @@ tab-size = 4
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ifaddrs.h>
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// From `man 3 getifaddrs`: <net/if.h> must be included before <ifaddrs.h>
|
||||||
|
// clang-format off
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
# include <kvm.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using std::array;
|
using std::array;
|
||||||
using std::atomic;
|
using std::atomic;
|
||||||
using std::deque;
|
using std::deque;
|
||||||
|
@ -83,6 +92,15 @@ namespace Shared {
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
extern long coreCount, page_size, clk_tck;
|
extern long coreCount, page_size, clk_tck;
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
struct KvmDeleter {
|
||||||
|
void operator()(kvm_t* handle) {
|
||||||
|
kvm_close(handle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using KvmPtr = std::unique_ptr<kvm_t, KvmDeleter>;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -178,7 +196,7 @@ namespace Cpu {
|
||||||
extern string cpuName, cpuHz;
|
extern string cpuName, cpuHz;
|
||||||
extern vector<string> available_fields;
|
extern vector<string> available_fields;
|
||||||
extern vector<string> available_sensors;
|
extern vector<string> available_sensors;
|
||||||
extern tuple<int, long, string> current_bat;
|
extern tuple<int, float, long, string> current_bat;
|
||||||
|
|
||||||
struct cpu_info {
|
struct cpu_info {
|
||||||
std::unordered_map<string, deque<long long>> cpu_percent = {
|
std::unordered_map<string, deque<long long>> cpu_percent = {
|
||||||
|
@ -213,7 +231,7 @@ namespace Cpu {
|
||||||
auto get_cpuHz() -> string;
|
auto get_cpuHz() -> string;
|
||||||
|
|
||||||
//* Get battery info from /sys
|
//* Get battery info from /sys
|
||||||
auto get_battery() -> tuple<int, long, string>;
|
auto get_battery() -> tuple<int, float, long, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Mem {
|
namespace Mem {
|
||||||
|
@ -289,6 +307,17 @@ namespace Net {
|
||||||
bool connected{};
|
bool connected{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IfAddrsPtr {
|
||||||
|
struct ifaddrs* ifaddr;
|
||||||
|
int status;
|
||||||
|
public:
|
||||||
|
IfAddrsPtr() { status = getifaddrs(&ifaddr); }
|
||||||
|
~IfAddrsPtr() { freeifaddrs(ifaddr); }
|
||||||
|
[[nodiscard]] constexpr auto operator()() -> struct ifaddrs* { return ifaddr; }
|
||||||
|
[[nodiscard]] constexpr auto get() -> struct ifaddrs* { return ifaddr; }
|
||||||
|
[[nodiscard]] constexpr auto get_status() const noexcept -> int { return status; };
|
||||||
|
};
|
||||||
|
|
||||||
extern std::unordered_map<string, net_info> current_net;
|
extern std::unordered_map<string, net_info> current_net;
|
||||||
|
|
||||||
//* Collect net upload/download stats
|
//* Collect net upload/download stats
|
||||||
|
|
|
@ -18,6 +18,10 @@ tab-size = 4
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(NDEBUG)
|
||||||
|
# define BTOP_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <algorithm> // for std::ranges::count_if
|
#include <algorithm> // for std::ranges::count_if
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
@ -42,11 +46,9 @@ tab-size = 4
|
||||||
#define HOST_NAME_MAX 64
|
#define HOST_NAME_MAX 64
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#define FMT_HEADER_ONLY
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/ostream.h"
|
|
||||||
#include "fmt/ranges.h"
|
|
||||||
|
|
||||||
using std::array;
|
using std::array;
|
||||||
using std::atomic;
|
using std::atomic;
|
||||||
|
|
|
@ -189,25 +189,13 @@ namespace Shared {
|
||||||
Logger::debug("Init -> Mem::get_zpools()");
|
Logger::debug("Init -> Mem::get_zpools()");
|
||||||
Mem::get_zpools();
|
Mem::get_zpools();
|
||||||
}
|
}
|
||||||
|
|
||||||
//* RAII wrapper for kvm_openfiles
|
|
||||||
class kvm_openfiles_wrapper {
|
|
||||||
kvm_t* kd = nullptr;
|
|
||||||
public:
|
|
||||||
kvm_openfiles_wrapper(const char* execf, const char* coref, const char* swapf, int flags, char* err) {
|
|
||||||
this->kd = kvm_openfiles(execf, coref, swapf, flags, err);
|
|
||||||
}
|
|
||||||
~kvm_openfiles_wrapper() { kvm_close(kd); }
|
|
||||||
auto operator()() -> kvm_t* { return kd; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Shared
|
} // namespace Shared
|
||||||
|
|
||||||
namespace Cpu {
|
namespace Cpu {
|
||||||
string cpuName;
|
string cpuName;
|
||||||
string cpuHz;
|
string cpuHz;
|
||||||
bool has_battery = true;
|
bool has_battery = true;
|
||||||
tuple<int, long, string> current_bat;
|
tuple<int, float, long, string> current_bat;
|
||||||
|
|
||||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||||
|
|
||||||
|
@ -373,10 +361,11 @@ namespace Cpu {
|
||||||
return core_map;
|
return core_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto get_battery() -> tuple<int, long, string> {
|
auto get_battery() -> tuple<int, float, long, string> {
|
||||||
if (not has_battery) return {0, 0, ""};
|
if (not has_battery) return {0, 0, 0, ""};
|
||||||
|
|
||||||
long seconds = -1;
|
long seconds = -1;
|
||||||
|
float watts = -1;
|
||||||
uint32_t percent = -1;
|
uint32_t percent = -1;
|
||||||
size_t size = sizeof(percent);
|
size_t size = sizeof(percent);
|
||||||
string status = "discharging";
|
string status = "discharging";
|
||||||
|
@ -388,6 +377,10 @@ namespace Cpu {
|
||||||
if (sysctlbyname("hw.acpi.battery.time", &seconds, &size, nullptr, 0) < 0) {
|
if (sysctlbyname("hw.acpi.battery.time", &seconds, &size, nullptr, 0) < 0) {
|
||||||
seconds = 0;
|
seconds = 0;
|
||||||
}
|
}
|
||||||
|
size = sizeof(watts);
|
||||||
|
if (sysctlbyname("hw.acpi.battery.rate", &watts, &size, nullptr, 0) < 0) {
|
||||||
|
watts = -1;
|
||||||
|
}
|
||||||
int state;
|
int state;
|
||||||
size = sizeof(state);
|
size = sizeof(state);
|
||||||
if (sysctlbyname("hw.acpi.battery.state", &state, &size, nullptr, 0) < 0) {
|
if (sysctlbyname("hw.acpi.battery.state", &state, &size, nullptr, 0) < 0) {
|
||||||
|
@ -402,7 +395,7 @@ namespace Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {percent, seconds, status};
|
return {percent, watts, seconds, status};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collect(bool no_update) -> cpu_info & {
|
auto collect(bool no_update) -> cpu_info & {
|
||||||
|
@ -668,9 +661,9 @@ namespace Mem {
|
||||||
|
|
||||||
if (show_swap) {
|
if (show_swap) {
|
||||||
char buf[_POSIX2_LINE_MAX];
|
char buf[_POSIX2_LINE_MAX];
|
||||||
Shared::kvm_openfiles_wrapper kd(nullptr, _PATH_DEVNULL, nullptr, O_RDONLY, buf);
|
Shared::KvmPtr kd {kvm_openfiles(nullptr, _PATH_DEVNULL, nullptr, O_RDONLY, buf)};
|
||||||
struct kvm_swap swap[16];
|
struct kvm_swap swap[16];
|
||||||
int nswap = kvm_getswapinfo(kd(), swap, 16, 0);
|
int nswap = kvm_getswapinfo(kd.get(), swap, 16, 0);
|
||||||
int totalSwap = 0, usedSwap = 0;
|
int totalSwap = 0, usedSwap = 0;
|
||||||
for (int i = 0; i < nswap; i++) {
|
for (int i = 0; i < nswap; i++) {
|
||||||
totalSwap += swap[i].ksw_total;
|
totalSwap += swap[i].ksw_total;
|
||||||
|
@ -823,17 +816,6 @@ namespace Net {
|
||||||
bool rescale = true;
|
bool rescale = true;
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
|
|
||||||
//* RAII wrapper for getifaddrs
|
|
||||||
class getifaddr_wrapper {
|
|
||||||
struct ifaddrs *ifaddr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
int status;
|
|
||||||
getifaddr_wrapper() { status = getifaddrs(&ifaddr); }
|
|
||||||
~getifaddr_wrapper() { freeifaddrs(ifaddr); }
|
|
||||||
auto operator()() -> struct ifaddrs * { return ifaddr; }
|
|
||||||
};
|
|
||||||
|
|
||||||
auto collect(bool no_update) -> net_info & {
|
auto collect(bool no_update) -> net_info & {
|
||||||
auto &net = current_net;
|
auto &net = current_net;
|
||||||
auto &config_iface = Config::getS("net_iface");
|
auto &config_iface = Config::getS("net_iface");
|
||||||
|
@ -843,10 +825,10 @@ namespace Net {
|
||||||
|
|
||||||
if (not no_update and errors < 3) {
|
if (not no_update and errors < 3) {
|
||||||
//? Get interface list using getifaddrs() wrapper
|
//? Get interface list using getifaddrs() wrapper
|
||||||
getifaddr_wrapper if_wrap{};
|
IfAddrsPtr if_addrs {};
|
||||||
if (if_wrap.status != 0) {
|
if (if_addrs.get_status() != 0) {
|
||||||
errors++;
|
errors++;
|
||||||
Logger::error("Net::collect() -> getifaddrs() failed with id " + to_string(if_wrap.status));
|
Logger::error("Net::collect() -> getifaddrs() failed with id " + to_string(if_addrs.get_status()));
|
||||||
redraw = true;
|
redraw = true;
|
||||||
return empty_net;
|
return empty_net;
|
||||||
}
|
}
|
||||||
|
@ -858,7 +840,7 @@ namespace Net {
|
||||||
string ipv4, ipv6;
|
string ipv4, ipv6;
|
||||||
|
|
||||||
//? Iteration over all items in getifaddrs() list
|
//? Iteration over all items in getifaddrs() list
|
||||||
for (auto *ifa = if_wrap(); ifa != nullptr; ifa = ifa->ifa_next) {
|
for (auto *ifa = if_addrs.get(); ifa != nullptr; ifa = ifa->ifa_next) {
|
||||||
if (ifa->ifa_addr == nullptr) continue;
|
if (ifa->ifa_addr == nullptr) continue;
|
||||||
family = ifa->ifa_addr->sa_family;
|
family = ifa->ifa_addr->sa_family;
|
||||||
const auto &iface = ifa->ifa_name;
|
const auto &iface = ifa->ifa_name;
|
||||||
|
@ -1164,8 +1146,8 @@ namespace Proc {
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
char buf[_POSIX2_LINE_MAX];
|
char buf[_POSIX2_LINE_MAX];
|
||||||
Shared::kvm_openfiles_wrapper kd(nullptr, _PATH_DEVNULL, nullptr, O_RDONLY, buf);
|
Shared::KvmPtr kd {kvm_openfiles(nullptr, _PATH_DEVNULL, nullptr, O_RDONLY, buf)};
|
||||||
const struct kinfo_proc* kprocs = kvm_getprocs(kd(), KERN_PROC_PROC, 0, &count);
|
const struct kinfo_proc* kprocs = kvm_getprocs(kd.get(), KERN_PROC_PROC, 0, &count);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
const struct kinfo_proc* kproc = &kprocs[i];
|
const struct kinfo_proc* kproc = &kprocs[i];
|
||||||
|
@ -1192,7 +1174,7 @@ namespace Proc {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new_proc.name = kproc->ki_comm;
|
new_proc.name = kproc->ki_comm;
|
||||||
char** argv = kvm_getargv(kd(), kproc, 0);
|
char** argv = kvm_getargv(kd.get(), kproc, 0);
|
||||||
if (argv) {
|
if (argv) {
|
||||||
for (int i = 0; argv[i] and cmp_less(new_proc.cmd.size(), 1000); i++) {
|
for (int i = 0; argv[i] and cmp_less(new_proc.cmd.size(), 1000); i++) {
|
||||||
new_proc.cmd += argv[i] + " "s;
|
new_proc.cmd += argv[i] + " "s;
|
||||||
|
|
|
@ -160,37 +160,44 @@ namespace Gpu {
|
||||||
namespace Rsmi {
|
namespace Rsmi {
|
||||||
#if !defined(RSMI_STATIC)
|
#if !defined(RSMI_STATIC)
|
||||||
//? RSMI defines, structs & typedefs
|
//? RSMI defines, structs & typedefs
|
||||||
#define RSMI_MAX_NUM_FREQUENCIES 32
|
#define RSMI_MAX_NUM_FREQUENCIES_V5 32
|
||||||
#define RSMI_STATUS_SUCCESS 0
|
#define RSMI_MAX_NUM_FREQUENCIES_V6 33
|
||||||
#define RSMI_MEM_TYPE_VRAM 0
|
#define RSMI_STATUS_SUCCESS 0
|
||||||
#define RSMI_TEMP_CURRENT 0
|
#define RSMI_MEM_TYPE_VRAM 0
|
||||||
#define RSMI_TEMP_TYPE_EDGE 0
|
#define RSMI_TEMP_CURRENT 0
|
||||||
#define RSMI_CLK_TYPE_MEM 4
|
#define RSMI_TEMP_TYPE_EDGE 0
|
||||||
#define RSMI_CLK_TYPE_SYS 0
|
#define RSMI_CLK_TYPE_MEM 4
|
||||||
#define RSMI_TEMP_MAX 1
|
#define RSMI_CLK_TYPE_SYS 0
|
||||||
|
#define RSMI_TEMP_MAX 1
|
||||||
|
|
||||||
typedef int rsmi_status_t,
|
typedef int rsmi_status_t,
|
||||||
rsmi_temperature_metric_t,
|
rsmi_temperature_metric_t,
|
||||||
rsmi_clk_type_t,
|
rsmi_clk_type_t,
|
||||||
rsmi_memory_type_t;
|
rsmi_memory_type_t;
|
||||||
|
|
||||||
struct rsmi_frequencies_t {uint32_t num_supported, current, frequency[RSMI_MAX_NUM_FREQUENCIES];};
|
struct rsmi_version_t {uint32_t major, minor, patch; const char* build;};
|
||||||
|
struct rsmi_frequencies_t_v5 {uint32_t num_supported, current; uint64_t frequency[RSMI_MAX_NUM_FREQUENCIES_V5];};
|
||||||
|
struct rsmi_frequencies_t_v6 {bool has_deep_sleep; uint32_t num_supported, current; uint64_t frequency[RSMI_MAX_NUM_FREQUENCIES_V6];};
|
||||||
|
|
||||||
//? Function pointers
|
//? Function pointers
|
||||||
rsmi_status_t (*rsmi_init)(uint64_t);
|
rsmi_status_t (*rsmi_init)(uint64_t);
|
||||||
rsmi_status_t (*rsmi_shut_down)();
|
rsmi_status_t (*rsmi_shut_down)();
|
||||||
|
rsmi_status_t (*rsmi_version_get)(rsmi_version_t*);
|
||||||
rsmi_status_t (*rsmi_num_monitor_devices)(uint32_t*);
|
rsmi_status_t (*rsmi_num_monitor_devices)(uint32_t*);
|
||||||
rsmi_status_t (*rsmi_dev_name_get)(uint32_t, char*, size_t);
|
rsmi_status_t (*rsmi_dev_name_get)(uint32_t, char*, size_t);
|
||||||
rsmi_status_t (*rsmi_dev_power_cap_get)(uint32_t, uint32_t, uint64_t*);
|
rsmi_status_t (*rsmi_dev_power_cap_get)(uint32_t, uint32_t, uint64_t*);
|
||||||
rsmi_status_t (*rsmi_dev_temp_metric_get)(uint32_t, uint32_t, rsmi_temperature_metric_t, int64_t*);
|
rsmi_status_t (*rsmi_dev_temp_metric_get)(uint32_t, uint32_t, rsmi_temperature_metric_t, int64_t*);
|
||||||
rsmi_status_t (*rsmi_dev_busy_percent_get)(uint32_t, uint32_t*);
|
rsmi_status_t (*rsmi_dev_busy_percent_get)(uint32_t, uint32_t*);
|
||||||
rsmi_status_t (*rsmi_dev_memory_busy_percent_get)(uint32_t, uint32_t*);
|
rsmi_status_t (*rsmi_dev_memory_busy_percent_get)(uint32_t, uint32_t*);
|
||||||
rsmi_status_t (*rsmi_dev_gpu_clk_freq_get)(uint32_t, rsmi_clk_type_t, rsmi_frequencies_t*);
|
rsmi_status_t (*rsmi_dev_gpu_clk_freq_get_v5)(uint32_t, rsmi_clk_type_t, rsmi_frequencies_t_v5*);
|
||||||
|
rsmi_status_t (*rsmi_dev_gpu_clk_freq_get_v6)(uint32_t, rsmi_clk_type_t, rsmi_frequencies_t_v6*);
|
||||||
rsmi_status_t (*rsmi_dev_power_ave_get)(uint32_t, uint32_t, uint64_t*);
|
rsmi_status_t (*rsmi_dev_power_ave_get)(uint32_t, uint32_t, uint64_t*);
|
||||||
rsmi_status_t (*rsmi_dev_memory_total_get)(uint32_t, rsmi_memory_type_t, uint64_t*);
|
rsmi_status_t (*rsmi_dev_memory_total_get)(uint32_t, rsmi_memory_type_t, uint64_t*);
|
||||||
rsmi_status_t (*rsmi_dev_memory_usage_get)(uint32_t, rsmi_memory_type_t, uint64_t*);
|
rsmi_status_t (*rsmi_dev_memory_usage_get)(uint32_t, rsmi_memory_type_t, uint64_t*);
|
||||||
rsmi_status_t (*rsmi_dev_pci_throughput_get)(uint32_t, uint64_t*, uint64_t*, uint64_t*);
|
rsmi_status_t (*rsmi_dev_pci_throughput_get)(uint32_t, uint64_t*, uint64_t*, uint64_t*);
|
||||||
|
|
||||||
|
uint32_t version_major = 0;
|
||||||
|
|
||||||
//? Data
|
//? Data
|
||||||
void* rsmi_dl_handle;
|
void* rsmi_dl_handle;
|
||||||
#endif
|
#endif
|
||||||
|
@ -294,7 +301,7 @@ namespace Cpu {
|
||||||
string cpuName;
|
string cpuName;
|
||||||
string cpuHz;
|
string cpuHz;
|
||||||
bool has_battery = true;
|
bool has_battery = true;
|
||||||
tuple<int, long, string> current_bat;
|
tuple<int, float, long, string> current_bat;
|
||||||
|
|
||||||
const array time_names {
|
const array time_names {
|
||||||
"user"s, "nice"s, "system"s, "idle"s, "iowait"s,
|
"user"s, "nice"s, "system"s, "idle"s, "iowait"s,
|
||||||
|
@ -583,7 +590,7 @@ namespace Cpu {
|
||||||
cpuhz += " GHz";
|
cpuhz += " GHz";
|
||||||
}
|
}
|
||||||
else if (hz > 0)
|
else if (hz > 0)
|
||||||
cpuhz = to_string((int)round(hz)) + " MHz";
|
cpuhz = to_string((int)hz) + " MHz";
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
|
@ -664,13 +671,14 @@ namespace Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct battery {
|
struct battery {
|
||||||
fs::path base_dir, energy_now, energy_full, power_now, status, online;
|
fs::path base_dir, energy_now, charge_now, energy_full, charge_full, power_now, current_now, voltage_now, status, online;
|
||||||
string device_type;
|
string device_type;
|
||||||
bool use_energy = true;
|
bool use_energy_or_charge = true;
|
||||||
|
bool use_power = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto get_battery() -> tuple<int, long, string> {
|
auto get_battery() -> tuple<int, float, long, string> {
|
||||||
if (not has_battery) return {0, 0, ""};
|
if (not has_battery) return {0, 0, 0, ""};
|
||||||
static string auto_sel;
|
static string auto_sel;
|
||||||
static std::unordered_map<string, battery> batteries;
|
static std::unordered_map<string, battery> batteries;
|
||||||
|
|
||||||
|
@ -702,19 +710,27 @@ namespace Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs::exists(bat_dir / "energy_now")) new_bat.energy_now = bat_dir / "energy_now";
|
if (fs::exists(bat_dir / "energy_now")) new_bat.energy_now = bat_dir / "energy_now";
|
||||||
else if (fs::exists(bat_dir / "charge_now")) new_bat.energy_now = bat_dir / "charge_now";
|
else if (fs::exists(bat_dir / "charge_now")) new_bat.charge_now = bat_dir / "charge_now";
|
||||||
else new_bat.use_energy = false;
|
else new_bat.use_energy_or_charge = false;
|
||||||
|
|
||||||
if (fs::exists(bat_dir / "energy_full")) new_bat.energy_full = bat_dir / "energy_full";
|
if (fs::exists(bat_dir / "energy_full")) new_bat.energy_full = bat_dir / "energy_full";
|
||||||
else if (fs::exists(bat_dir / "charge_full")) new_bat.energy_full = bat_dir / "charge_full";
|
else if (fs::exists(bat_dir / "charge_full")) new_bat.charge_full = bat_dir / "charge_full";
|
||||||
else new_bat.use_energy = false;
|
else new_bat.use_energy_or_charge = false;
|
||||||
|
|
||||||
if (not new_bat.use_energy and not fs::exists(bat_dir / "capacity")) {
|
if (not new_bat.use_energy_or_charge and not fs::exists(bat_dir / "capacity")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fs::exists(bat_dir / "power_now")) new_bat.power_now = bat_dir / "power_now";
|
if (fs::exists(bat_dir / "power_now")) {
|
||||||
else if (fs::exists(bat_dir / "current_now")) new_bat.power_now = bat_dir / "current_now";
|
new_bat.power_now = bat_dir / "power_now";
|
||||||
|
}
|
||||||
|
else if ((fs::exists(bat_dir / "current_now")) and (fs::exists(bat_dir / "current_now"))) {
|
||||||
|
new_bat.current_now = bat_dir / "current_now";
|
||||||
|
new_bat.voltage_now = bat_dir / "voltage_now";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_bat.use_power = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (fs::exists(bat_dir / "AC0/online")) new_bat.online = bat_dir / "AC0/online";
|
if (fs::exists(bat_dir / "AC0/online")) new_bat.online = bat_dir / "AC0/online";
|
||||||
else if (fs::exists(bat_dir / "AC/online")) new_bat.online = bat_dir / "AC/online";
|
else if (fs::exists(bat_dir / "AC/online")) new_bat.online = bat_dir / "AC/online";
|
||||||
|
@ -729,7 +745,7 @@ namespace Cpu {
|
||||||
}
|
}
|
||||||
if (batteries.empty()) {
|
if (batteries.empty()) {
|
||||||
has_battery = false;
|
has_battery = false;
|
||||||
return {0, 0, ""};
|
return {0, 0, 0, ""};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -749,15 +765,9 @@ namespace Cpu {
|
||||||
|
|
||||||
int percent = -1;
|
int percent = -1;
|
||||||
long seconds = -1;
|
long seconds = -1;
|
||||||
|
float watts = -1;
|
||||||
|
|
||||||
//? Try to get battery percentage
|
//? Try to get battery percentage
|
||||||
if (b.use_energy) {
|
|
||||||
try {
|
|
||||||
percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
|
|
||||||
}
|
|
||||||
catch (const std::invalid_argument&) { }
|
|
||||||
catch (const std::out_of_range&) { }
|
|
||||||
}
|
|
||||||
if (percent < 0) {
|
if (percent < 0) {
|
||||||
try {
|
try {
|
||||||
percent = stoll(readfile(b.base_dir / "capacity", "-1"));
|
percent = stoll(readfile(b.base_dir / "capacity", "-1"));
|
||||||
|
@ -765,9 +775,23 @@ namespace Cpu {
|
||||||
catch (const std::invalid_argument&) { }
|
catch (const std::invalid_argument&) { }
|
||||||
catch (const std::out_of_range&) { }
|
catch (const std::out_of_range&) { }
|
||||||
}
|
}
|
||||||
|
if (b.use_energy_or_charge and percent < 0) {
|
||||||
|
try {
|
||||||
|
percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1")));
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&) { }
|
||||||
|
catch (const std::out_of_range&) { }
|
||||||
|
}
|
||||||
|
if (b.use_energy_or_charge and percent < 0) {
|
||||||
|
try {
|
||||||
|
percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1")));
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&) { }
|
||||||
|
catch (const std::out_of_range&) { }
|
||||||
|
}
|
||||||
if (percent < 0) {
|
if (percent < 0) {
|
||||||
has_battery = false;
|
has_battery = false;
|
||||||
return {0, 0, ""};
|
return {0, 0, 0, ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
//? Get charging/discharging status
|
//? Get charging/discharging status
|
||||||
|
@ -781,13 +805,23 @@ namespace Cpu {
|
||||||
|
|
||||||
//? Get seconds to empty
|
//? Get seconds to empty
|
||||||
if (not is_in(status, "charging", "full")) {
|
if (not is_in(status, "charging", "full")) {
|
||||||
if (b.use_energy and not b.power_now.empty()) {
|
if (b.use_energy_or_charge ) {
|
||||||
try {
|
if (not b.power_now.empty()) {
|
||||||
seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600);
|
try {
|
||||||
|
seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600);
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&) { }
|
||||||
|
catch (const std::out_of_range&) { }
|
||||||
|
}
|
||||||
|
else if (not b.current_now.empty()) {
|
||||||
|
try {
|
||||||
|
seconds = round((double)stoll(readfile(b.charge_now, "0")) / (double)stoll(readfile(b.current_now, "1")) * 3600);
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&) { }
|
||||||
|
catch (const std::out_of_range&) { }
|
||||||
}
|
}
|
||||||
catch (const std::invalid_argument&) { }
|
|
||||||
catch (const std::out_of_range&) { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) {
|
if (seconds < 0 and fs::exists(b.base_dir / "time_to_empty")) {
|
||||||
try {
|
try {
|
||||||
seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60;
|
seconds = stoll(readfile(b.base_dir / "time_to_empty", "0")) * 60;
|
||||||
|
@ -797,7 +831,26 @@ namespace Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {percent, seconds, status};
|
//? Get power draw
|
||||||
|
if (b.use_power) {
|
||||||
|
if (not b.power_now.empty()) {
|
||||||
|
try {
|
||||||
|
watts = (float)stoll(readfile(b.power_now, "-1")) / 1000000.0;
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&) { }
|
||||||
|
catch (const std::out_of_range&) { }
|
||||||
|
}
|
||||||
|
else if (not b.voltage_now.empty() and not b.current_now.empty()) {
|
||||||
|
try {
|
||||||
|
watts = (float)stoll(readfile(b.current_now, "-1")) / 1000000.0 * stoll(readfile(b.voltage_now, "1")) / 1000000.0;
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument&) { }
|
||||||
|
catch (const std::out_of_range&) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return {percent, watts, seconds, status};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collect(bool no_update) -> cpu_info& {
|
auto collect(bool no_update) -> cpu_info& {
|
||||||
|
@ -1232,6 +1285,7 @@ namespace Gpu {
|
||||||
"librocm_smi64.so",
|
"librocm_smi64.so",
|
||||||
"librocm_smi64.so.5", // fedora
|
"librocm_smi64.so.5", // fedora
|
||||||
"librocm_smi64.so.1.0", // debian
|
"librocm_smi64.so.1.0", // debian
|
||||||
|
"librocm_smi64.so.6"
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& l : libRocAlts) {
|
for (const auto& l : libRocAlts) {
|
||||||
|
@ -1259,13 +1313,13 @@ namespace Gpu {
|
||||||
|
|
||||||
LOAD_SYM(rsmi_init);
|
LOAD_SYM(rsmi_init);
|
||||||
LOAD_SYM(rsmi_shut_down);
|
LOAD_SYM(rsmi_shut_down);
|
||||||
|
LOAD_SYM(rsmi_version_get);
|
||||||
LOAD_SYM(rsmi_num_monitor_devices);
|
LOAD_SYM(rsmi_num_monitor_devices);
|
||||||
LOAD_SYM(rsmi_dev_name_get);
|
LOAD_SYM(rsmi_dev_name_get);
|
||||||
LOAD_SYM(rsmi_dev_power_cap_get);
|
LOAD_SYM(rsmi_dev_power_cap_get);
|
||||||
LOAD_SYM(rsmi_dev_temp_metric_get);
|
LOAD_SYM(rsmi_dev_temp_metric_get);
|
||||||
LOAD_SYM(rsmi_dev_busy_percent_get);
|
LOAD_SYM(rsmi_dev_busy_percent_get);
|
||||||
LOAD_SYM(rsmi_dev_memory_busy_percent_get);
|
LOAD_SYM(rsmi_dev_memory_busy_percent_get);
|
||||||
LOAD_SYM(rsmi_dev_gpu_clk_freq_get);
|
|
||||||
LOAD_SYM(rsmi_dev_power_ave_get);
|
LOAD_SYM(rsmi_dev_power_ave_get);
|
||||||
LOAD_SYM(rsmi_dev_memory_total_get);
|
LOAD_SYM(rsmi_dev_memory_total_get);
|
||||||
LOAD_SYM(rsmi_dev_memory_usage_get);
|
LOAD_SYM(rsmi_dev_memory_usage_get);
|
||||||
|
@ -1281,6 +1335,27 @@ namespace Gpu {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(RSMI_STATIC)
|
||||||
|
//? Check version
|
||||||
|
rsmi_version_t version;
|
||||||
|
result = rsmi_version_get(&version);
|
||||||
|
if (result != RSMI_STATUS_SUCCESS) {
|
||||||
|
Logger::warning("ROCm SMI: Failed to get version");
|
||||||
|
return false;
|
||||||
|
} else if (version.major == 5) {
|
||||||
|
if ((rsmi_dev_gpu_clk_freq_get_v5 = (decltype(rsmi_dev_gpu_clk_freq_get_v5))load_rsmi_sym("rsmi_dev_gpu_clk_freq_get")) == nullptr)
|
||||||
|
return false;
|
||||||
|
// In the release tarballs of rocm 6.0.0 and 6.0.2 the version queried with rsmi_version_get is 7.0.0.0
|
||||||
|
} else if (version.major == 6 || version.major == 7) {
|
||||||
|
if ((rsmi_dev_gpu_clk_freq_get_v6 = (decltype(rsmi_dev_gpu_clk_freq_get_v6))load_rsmi_sym("rsmi_dev_gpu_clk_freq_get")) == nullptr)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
Logger::warning("ROCm SMI: Dynamic loading only supported for version 5 and 6");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
version_major = version.major;
|
||||||
|
#endif
|
||||||
|
|
||||||
//? Device count
|
//? Device count
|
||||||
result = rsmi_num_monitor_devices(&device_count);
|
result = rsmi_num_monitor_devices(&device_count);
|
||||||
if (result != RSMI_STATUS_SUCCESS) {
|
if (result != RSMI_STATUS_SUCCESS) {
|
||||||
|
@ -1364,7 +1439,46 @@ namespace Gpu {
|
||||||
if constexpr(is_init) gpus_slice[i].supported_functions.mem_utilization = false;
|
if constexpr(is_init) gpus_slice[i].supported_functions.mem_utilization = false;
|
||||||
} else gpus_slice[i].mem_utilization_percent.push_back((long long)utilization);
|
} else gpus_slice[i].mem_utilization_percent.push_back((long long)utilization);
|
||||||
}
|
}
|
||||||
|
#if !defined(RSMI_STATIC)
|
||||||
|
//? Clock speeds
|
||||||
|
if (gpus_slice[i].supported_functions.gpu_clock) {
|
||||||
|
if (version_major == 5) {
|
||||||
|
rsmi_frequencies_t_v5 frequencies;
|
||||||
|
result = rsmi_dev_gpu_clk_freq_get_v5(i, RSMI_CLK_TYPE_SYS, &frequencies);
|
||||||
|
if (result != RSMI_STATUS_SUCCESS) {
|
||||||
|
Logger::warning("ROCm SMI: Failed to get GPU clock speed: ");
|
||||||
|
if constexpr(is_init) gpus_slice[i].supported_functions.gpu_clock = false;
|
||||||
|
} else gpus_slice[i].gpu_clock_speed = (long long)frequencies.frequency[frequencies.current]/1000000; // Hz to MHz
|
||||||
|
}
|
||||||
|
else if (version_major == 6 || version_major == 7) {
|
||||||
|
rsmi_frequencies_t_v6 frequencies;
|
||||||
|
result = rsmi_dev_gpu_clk_freq_get_v6(i, RSMI_CLK_TYPE_SYS, &frequencies);
|
||||||
|
if (result != RSMI_STATUS_SUCCESS) {
|
||||||
|
Logger::warning("ROCm SMI: Failed to get GPU clock speed: ");
|
||||||
|
if constexpr(is_init) gpus_slice[i].supported_functions.gpu_clock = false;
|
||||||
|
} else gpus_slice[i].gpu_clock_speed = (long long)frequencies.frequency[frequencies.current]/1000000; // Hz to MHz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpus_slice[i].supported_functions.mem_clock) {
|
||||||
|
if (version_major == 5) {
|
||||||
|
rsmi_frequencies_t_v5 frequencies;
|
||||||
|
result = rsmi_dev_gpu_clk_freq_get_v5(i, RSMI_CLK_TYPE_MEM, &frequencies);
|
||||||
|
if (result != RSMI_STATUS_SUCCESS) {
|
||||||
|
Logger::warning("ROCm SMI: Failed to get VRAM clock speed: ");
|
||||||
|
if constexpr(is_init) gpus_slice[i].supported_functions.mem_clock = false;
|
||||||
|
} else gpus_slice[i].mem_clock_speed = (long long)frequencies.frequency[frequencies.current]/1000000; // Hz to MHz
|
||||||
|
}
|
||||||
|
else if (version_major == 6 || version_major == 7) {
|
||||||
|
rsmi_frequencies_t_v6 frequencies;
|
||||||
|
result = rsmi_dev_gpu_clk_freq_get_v6(i, RSMI_CLK_TYPE_MEM, &frequencies);
|
||||||
|
if (result != RSMI_STATUS_SUCCESS) {
|
||||||
|
Logger::warning("ROCm SMI: Failed to get VRAM clock speed: ");
|
||||||
|
if constexpr(is_init) gpus_slice[i].supported_functions.mem_clock = false;
|
||||||
|
} else gpus_slice[i].mem_clock_speed = (long long)frequencies.frequency[frequencies.current]/1000000; // Hz to MHz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
//? Clock speeds
|
//? Clock speeds
|
||||||
if (gpus_slice[i].supported_functions.gpu_clock) {
|
if (gpus_slice[i].supported_functions.gpu_clock) {
|
||||||
rsmi_frequencies_t frequencies;
|
rsmi_frequencies_t frequencies;
|
||||||
|
@ -1383,6 +1497,7 @@ namespace Gpu {
|
||||||
if constexpr(is_init) gpus_slice[i].supported_functions.mem_clock = false;
|
if constexpr(is_init) gpus_slice[i].supported_functions.mem_clock = false;
|
||||||
} else gpus_slice[i].mem_clock_speed = (long long)frequencies.frequency[frequencies.current]/1000000; // Hz to MHz
|
} else gpus_slice[i].mem_clock_speed = (long long)frequencies.frequency[frequencies.current]/1000000; // Hz to MHz
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//? Power usage & state
|
//? Power usage & state
|
||||||
if (gpus_slice[i].supported_functions.pwr_usage) {
|
if (gpus_slice[i].supported_functions.pwr_usage) {
|
||||||
|
@ -2084,16 +2199,6 @@ namespace Net {
|
||||||
bool rescale{true};
|
bool rescale{true};
|
||||||
uint64_t timestamp{};
|
uint64_t timestamp{};
|
||||||
|
|
||||||
//* RAII wrapper for getifaddrs
|
|
||||||
class getifaddr_wrapper {
|
|
||||||
struct ifaddrs* ifaddr;
|
|
||||||
public:
|
|
||||||
int status;
|
|
||||||
getifaddr_wrapper() { status = getifaddrs(&ifaddr); }
|
|
||||||
~getifaddr_wrapper() { freeifaddrs(ifaddr); }
|
|
||||||
auto operator()() -> struct ifaddrs* { return ifaddr; }
|
|
||||||
};
|
|
||||||
|
|
||||||
auto collect(bool no_update) -> net_info& {
|
auto collect(bool no_update) -> net_info& {
|
||||||
if (Runner::stopping) return empty_net;
|
if (Runner::stopping) return empty_net;
|
||||||
auto& net = current_net;
|
auto& net = current_net;
|
||||||
|
@ -2104,10 +2209,10 @@ namespace Net {
|
||||||
|
|
||||||
if (not no_update and errors < 3) {
|
if (not no_update and errors < 3) {
|
||||||
//? Get interface list using getifaddrs() wrapper
|
//? Get interface list using getifaddrs() wrapper
|
||||||
getifaddr_wrapper if_wrap {};
|
IfAddrsPtr if_addrs {};
|
||||||
if (if_wrap.status != 0) {
|
if (if_addrs.get_status() != 0) {
|
||||||
errors++;
|
errors++;
|
||||||
Logger::error("Net::collect() -> getifaddrs() failed with id " + to_string(if_wrap.status));
|
Logger::error("Net::collect() -> getifaddrs() failed with id " + to_string(if_addrs.get_status()));
|
||||||
redraw = true;
|
redraw = true;
|
||||||
return empty_net;
|
return empty_net;
|
||||||
}
|
}
|
||||||
|
@ -2119,7 +2224,7 @@ namespace Net {
|
||||||
string ipv4, ipv6;
|
string ipv4, ipv6;
|
||||||
|
|
||||||
//? Iteration over all items in getifaddrs() list
|
//? Iteration over all items in getifaddrs() list
|
||||||
for (auto* ifa = if_wrap(); ifa != nullptr; ifa = ifa->ifa_next) {
|
for (auto* ifa = if_addrs.get(); ifa != nullptr; ifa = ifa->ifa_next) {
|
||||||
if (ifa->ifa_addr == nullptr) continue;
|
if (ifa->ifa_addr == nullptr) continue;
|
||||||
family = ifa->ifa_addr->sa_family;
|
family = ifa->ifa_addr->sa_family;
|
||||||
const auto& iface = ifa->ifa_name;
|
const auto& iface = ifa->ifa_name;
|
||||||
|
|
|
@ -184,25 +184,13 @@ namespace Shared {
|
||||||
Mem::old_uptime = system_uptime();
|
Mem::old_uptime = system_uptime();
|
||||||
Mem::collect();
|
Mem::collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
//* RAII wrapper for kvm_openfiles
|
|
||||||
class kvm_openfiles_wrapper {
|
|
||||||
kvm_t* kd = nullptr;
|
|
||||||
public:
|
|
||||||
kvm_openfiles_wrapper(const char* execf, const char* coref, const char* swapf, int flags, char* err) {
|
|
||||||
this->kd = kvm_openfiles(execf, coref, swapf, flags, err);
|
|
||||||
}
|
|
||||||
~kvm_openfiles_wrapper() { kvm_close(kd); }
|
|
||||||
auto operator()() -> kvm_t* { return kd; }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Shared
|
} // namespace Shared
|
||||||
|
|
||||||
namespace Cpu {
|
namespace Cpu {
|
||||||
string cpuName;
|
string cpuName;
|
||||||
string cpuHz;
|
string cpuHz;
|
||||||
bool has_battery = true;
|
bool has_battery = true;
|
||||||
tuple<int, long, string> current_bat;
|
tuple<int, float, long, string> current_bat;
|
||||||
|
|
||||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||||
|
|
||||||
|
@ -385,8 +373,8 @@ namespace Cpu {
|
||||||
return core_map;
|
return core_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto get_battery() -> tuple<int, long, string> {
|
auto get_battery() -> tuple<int, float, long, string> {
|
||||||
if (not has_battery) return {0, 0, ""};
|
if (not has_battery) return {0, 0, 0, ""};
|
||||||
|
|
||||||
long seconds = -1;
|
long seconds = -1;
|
||||||
uint32_t percent = -1;
|
uint32_t percent = -1;
|
||||||
|
@ -417,7 +405,7 @@ namespace Cpu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {percent, seconds, status};
|
return {percent, -1, seconds, status};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collect(bool no_update) -> cpu_info & {
|
auto collect(bool no_update) -> cpu_info & {
|
||||||
|
@ -780,17 +768,6 @@ namespace Net {
|
||||||
bool rescale = true;
|
bool rescale = true;
|
||||||
uint64_t timestamp = 0;
|
uint64_t timestamp = 0;
|
||||||
|
|
||||||
//* RAII wrapper for getifaddrs
|
|
||||||
class getifaddr_wrapper {
|
|
||||||
struct ifaddrs *ifaddr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
int status;
|
|
||||||
getifaddr_wrapper() { status = getifaddrs(&ifaddr); }
|
|
||||||
~getifaddr_wrapper() { freeifaddrs(ifaddr); }
|
|
||||||
auto operator()() -> struct ifaddrs * { return ifaddr; }
|
|
||||||
};
|
|
||||||
|
|
||||||
auto collect(bool no_update) -> net_info & {
|
auto collect(bool no_update) -> net_info & {
|
||||||
auto &net = current_net;
|
auto &net = current_net;
|
||||||
auto &config_iface = Config::getS("net_iface");
|
auto &config_iface = Config::getS("net_iface");
|
||||||
|
@ -800,10 +777,10 @@ namespace Net {
|
||||||
|
|
||||||
if (not no_update and errors < 3) {
|
if (not no_update and errors < 3) {
|
||||||
//? Get interface list using getifaddrs() wrapper
|
//? Get interface list using getifaddrs() wrapper
|
||||||
getifaddr_wrapper if_wrap{};
|
IfAddrsPtr if_addrs {};
|
||||||
if (if_wrap.status != 0) {
|
if (if_addrs.get_status() != 0) {
|
||||||
errors++;
|
errors++;
|
||||||
Logger::error("Net::collect() -> getifaddrs() failed with id " + to_string(if_wrap.status));
|
Logger::error("Net::collect() -> getifaddrs() failed with id " + to_string(if_addrs.get_status()));
|
||||||
redraw = true;
|
redraw = true;
|
||||||
return empty_net;
|
return empty_net;
|
||||||
}
|
}
|
||||||
|
@ -815,7 +792,7 @@ namespace Net {
|
||||||
string ipv4, ipv6;
|
string ipv4, ipv6;
|
||||||
|
|
||||||
//? Iteration over all items in getifaddrs() list
|
//? Iteration over all items in getifaddrs() list
|
||||||
for (auto *ifa = if_wrap(); ifa != nullptr; ifa = ifa->ifa_next) {
|
for (auto *ifa = if_addrs.get(); ifa != nullptr; ifa = ifa->ifa_next) {
|
||||||
if (ifa->ifa_addr == nullptr) continue;
|
if (ifa->ifa_addr == nullptr) continue;
|
||||||
family = ifa->ifa_addr->sa_family;
|
family = ifa->ifa_addr->sa_family;
|
||||||
const auto &iface = ifa->ifa_name;
|
const auto &iface = ifa->ifa_name;
|
||||||
|
@ -1102,8 +1079,8 @@ namespace Proc {
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
char buf[_POSIX2_LINE_MAX];
|
char buf[_POSIX2_LINE_MAX];
|
||||||
Shared::kvm_openfiles_wrapper kd(nullptr, nullptr, nullptr, KVM_NO_FILES, buf);
|
Shared::KvmPtr kd {kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, buf)};
|
||||||
const struct kinfo_proc* kprocs = kvm_getprocs(kd(), KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &count);
|
const struct kinfo_proc* kprocs = kvm_getprocs(kd.get() , KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &count);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
const struct kinfo_proc* kproc = &kprocs[i];
|
const struct kinfo_proc* kproc = &kprocs[i];
|
||||||
|
@ -1130,7 +1107,7 @@ namespace Proc {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
new_proc.name = kproc->p_comm;
|
new_proc.name = kproc->p_comm;
|
||||||
char** argv = kvm_getargv(kd(), kproc, 0);
|
char** argv = kvm_getargv(kd.get(), kproc, 0);
|
||||||
if (argv) {
|
if (argv) {
|
||||||
for (int i = 0; argv[i] and cmp_less(new_proc.cmd.size(), 1000); i++) {
|
for (int i = 0; argv[i] and cmp_less(new_proc.cmd.size(), 1000); i++) {
|
||||||
new_proc.cmd += argv[i] + " "s;
|
new_proc.cmd += argv[i] + " "s;
|
||||||
|
|
|
@ -191,7 +191,7 @@ namespace Cpu {
|
||||||
string cpuHz;
|
string cpuHz;
|
||||||
bool has_battery = true;
|
bool has_battery = true;
|
||||||
bool macM1 = false;
|
bool macM1 = false;
|
||||||
tuple<int, long, string> current_bat;
|
tuple<int, float, long, string> current_bat;
|
||||||
|
|
||||||
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
|
||||||
|
|
||||||
|
@ -407,8 +407,8 @@ namespace Cpu {
|
||||||
~IOPSList_Wrap() { CFRelease(data); }
|
~IOPSList_Wrap() { CFRelease(data); }
|
||||||
};
|
};
|
||||||
|
|
||||||
auto get_battery() -> tuple<int, long, string> {
|
auto get_battery() -> tuple<int, float, long, string> {
|
||||||
if (not has_battery) return {0, 0, ""};
|
if (not has_battery) return {0, 0, 0, ""};
|
||||||
|
|
||||||
uint32_t percent = -1;
|
uint32_t percent = -1;
|
||||||
long seconds = -1;
|
long seconds = -1;
|
||||||
|
@ -447,7 +447,7 @@ namespace Cpu {
|
||||||
has_battery = false;
|
has_battery = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {percent, seconds, status};
|
return {percent, -1, seconds, status};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto collect(bool no_update) -> cpu_info & {
|
auto collect(bool no_update) -> cpu_info & {
|
||||||
|
@ -686,7 +686,7 @@ namespace Mem {
|
||||||
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&p, &info_size) == 0) {
|
if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&p, &info_size) == 0) {
|
||||||
mem.stats.at("free") = p.free_count * Shared::pageSize;
|
mem.stats.at("free") = p.free_count * Shared::pageSize;
|
||||||
mem.stats.at("cached") = p.external_page_count * Shared::pageSize;
|
mem.stats.at("cached") = p.external_page_count * Shared::pageSize;
|
||||||
mem.stats.at("used") = (p.active_count + p.inactive_count + p.wire_count) * Shared::pageSize;
|
mem.stats.at("used") = (p.active_count + p.wire_count) * Shared::pageSize;
|
||||||
mem.stats.at("available") = Shared::totalMem - mem.stats.at("used");
|
mem.stats.at("available") = Shared::totalMem - mem.stats.at("used");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1212,10 +1212,14 @@ namespace Proc {
|
||||||
//? Get program name, command, username, parent pid, nice and status
|
//? Get program name, command, username, parent pid, nice and status
|
||||||
if (no_cache) {
|
if (no_cache) {
|
||||||
char fullname[PROC_PIDPATHINFO_MAXSIZE];
|
char fullname[PROC_PIDPATHINFO_MAXSIZE];
|
||||||
proc_pidpath(pid, fullname, sizeof(fullname));
|
int rc = proc_pidpath(pid, fullname, sizeof(fullname));
|
||||||
const string f_name = std::string(fullname);
|
string f_name = "<defunct>";
|
||||||
size_t lastSlash = f_name.find_last_of('/');
|
if (rc != 0) {
|
||||||
new_proc.name = f_name.substr(lastSlash + 1);
|
f_name = std::string(fullname);
|
||||||
|
size_t lastSlash = f_name.find_last_of('/');
|
||||||
|
f_name = f_name.substr(lastSlash + 1);
|
||||||
|
}
|
||||||
|
new_proc.name = f_name;
|
||||||
//? Get process arguments if possible, fallback to process path in case of failure
|
//? Get process arguments if possible, fallback to process path in case of failure
|
||||||
if (Shared::arg_max > 0) {
|
if (Shared::arg_max > 0) {
|
||||||
std::unique_ptr<char[]> proc_chars(new char[Shared::arg_max]);
|
std::unique_ptr<char[]> proc_chars(new char[Shared::arg_max]);
|
||||||
|
|
92
themes/everforest-dark-medium.theme
Normal file
92
themes/everforest-dark-medium.theme
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
# All graphs and meters can be gradients
|
||||||
|
# For single color graphs leave "mid" and "end" variable empty.
|
||||||
|
# Use "start" and "end" variables for two color gradient
|
||||||
|
# Use "start", "mid" and "end" for three color gradient
|
||||||
|
|
||||||
|
# Main background, empty for terminal default, need to be empty if you want transparent background
|
||||||
|
theme[main_bg]="#2d353b"
|
||||||
|
|
||||||
|
# Main text color
|
||||||
|
theme[main_fg]="#d3c6aa"
|
||||||
|
|
||||||
|
# Title color for boxes
|
||||||
|
theme[title]="#d3c6aa"
|
||||||
|
|
||||||
|
# Highlight color for keyboard shortcuts
|
||||||
|
theme[hi_fg]="#e67e80"
|
||||||
|
|
||||||
|
# Background color of selected items
|
||||||
|
theme[selected_bg]="#3d484d"
|
||||||
|
|
||||||
|
# Foreground color of selected items
|
||||||
|
theme[selected_fg]="#dbbc7f"
|
||||||
|
|
||||||
|
# Color of inactive/disabled text
|
||||||
|
theme[inactive_fg]="#2d353b"
|
||||||
|
|
||||||
|
# Color of text appearing on top of graphs, i.e uptime and current network graph scaling
|
||||||
|
theme[graph_text]="#d3c6aa"
|
||||||
|
|
||||||
|
# Misc colors for processes box including mini cpu graphs, details memory graph and details status text
|
||||||
|
theme[proc_misc]="#a7c080"
|
||||||
|
|
||||||
|
# Cpu box outline color
|
||||||
|
theme[cpu_box]="#3d484d"
|
||||||
|
|
||||||
|
# Memory/disks box outline color
|
||||||
|
theme[mem_box]="#3d484d"
|
||||||
|
|
||||||
|
# Net up/down box outline color
|
||||||
|
theme[net_box]="#3d484d"
|
||||||
|
|
||||||
|
# Processes box outline color
|
||||||
|
theme[proc_box]="#3d484d"
|
||||||
|
|
||||||
|
# Box divider line and small boxes line color
|
||||||
|
theme[div_line]="#3d484d"
|
||||||
|
|
||||||
|
# Temperature graph colors
|
||||||
|
theme[temp_start]="#a7c080"
|
||||||
|
theme[temp_mid]="#dbbc7f"
|
||||||
|
theme[temp_end]="#f85552"
|
||||||
|
|
||||||
|
# CPU graph colors
|
||||||
|
theme[cpu_start]="#a7c080"
|
||||||
|
theme[cpu_mid]="#dbbc7f"
|
||||||
|
theme[cpu_end]="#f85552"
|
||||||
|
|
||||||
|
# Mem/Disk free meter
|
||||||
|
theme[free_start]="#f85552"
|
||||||
|
theme[free_mid]="#dbbc7f"
|
||||||
|
theme[free_end]="#a7c080"
|
||||||
|
|
||||||
|
# Mem/Disk cached meter
|
||||||
|
theme[cached_start]="#7fbbb3"
|
||||||
|
theme[cached_mid]="#83c092"
|
||||||
|
theme[cached_end]="#a7c080"
|
||||||
|
|
||||||
|
# Mem/Disk available meter
|
||||||
|
theme[available_start]="#f85552"
|
||||||
|
theme[available_mid]="#dbbc7f"
|
||||||
|
theme[available_end]="#a7c080"
|
||||||
|
|
||||||
|
# Mem/Disk used meter
|
||||||
|
theme[used_start]="#a7c080"
|
||||||
|
theme[used_mid]="#dbbc7f"
|
||||||
|
theme[used_end]="#f85552"
|
||||||
|
|
||||||
|
# Download graph colors
|
||||||
|
theme[download_start]="#a7c080"
|
||||||
|
theme[download_mid]="#83c092"
|
||||||
|
theme[download_end]="#7fbbb3"
|
||||||
|
|
||||||
|
# Upload graph colors
|
||||||
|
theme[upload_start]="#dbbc7f"
|
||||||
|
theme[upload_mid]="#e69875"
|
||||||
|
theme[upload_end]="#e67e80"
|
||||||
|
|
||||||
|
# Process box color gradient for threads, mem and cpu usage
|
||||||
|
theme[process_start]="#a7c080"
|
||||||
|
theme[process_mid]="#e67e80"
|
||||||
|
theme[process_end]="#f85552"
|
||||||
|
|
Loading…
Reference in a new issue