diff --git a/.editorconfig b/.editorconfig index 63202f0..b27d25a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -[*.{cpp,h,sh,md,cfg,sample}] +[*.{cpp,h,hpp,sh,md,cfg,sample}] indent_style = tab indent_size = 4 diff --git a/.github/workflows/continuous-build-freebsd.yml b/.github/workflows/continuous-build-freebsd.yml index b341211..4cdc550 100644 --- a/.github/workflows/continuous-build-freebsd.yml +++ b/.github/workflows/continuous-build-freebsd.yml @@ -28,6 +28,7 @@ on: jobs: build-freebsd: runs-on: macos-12 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 with: @@ -36,18 +37,19 @@ jobs: - name: Compile uses: vmactions/freebsd-vm@v0 with: - release: 13.1 + release: 13.2 usesh: true prepare: | pkg install -y gmake gcc11 coreutils git git config --global --add safe.directory /Users/runner/work/btop/btop run: | - gmake + gmake STATIC=true STRIP=true GIT_HASH=$(git rev-parse --short "$GITHUB_SHA") mv bin/btop bin/btop-$GIT_HASH ls -alh bin - uses: actions/upload-artifact@v3 with: - name: btop-x86_64-FreeBSD-13.1 + name: btop-x86_64-FreeBSD-13.2 path: 'bin/*' + if-no-files-found: error diff --git a/.gitignore b/.gitignore index 8e986b0..35382d0 100644 --- a/.gitignore +++ b/.gitignore @@ -54,9 +54,11 @@ btop # Optional libraries lib/rocm_smi_lib +# Optional libraries +lib/rocm_smi_lib -#do not ignore .github directory -!.github +# Don't ignore .github directory +!.github/ # Ignore files created by Qt Creator *.config @@ -67,3 +69,19 @@ lib/rocm_smi_lib *.cxxflags *.files *.includes + +# CMake +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +# CLion +cmake-build-* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d11a250 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,167 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# CMake configuration for btop +# + +cmake_minimum_required(VERSION 3.12) + +# Disable in-source builds since they would override the Makefile +if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") + message(FATAL_ERROR "In-source builds are not allowed") +endif() + +project("btop" + VERSION 1.2.13 + DESCRIPTION "A monitor of resources" + HOMEPAGE_URL "https://github.com/aristocratos/btop" + LANGUAGES CXX +) + +# Make custom modules available +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/") + +# When the build type is not set we can't fortify +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_COLOR_DIAGNOSTICS ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Options +option(BTOP_STATIC "Link btop statically" OFF) +option(BTOP_LTO "Enable LTO" ON) +option(BTOP_USE_MOLD "Use mold to link btop" OFF) +option(BTOP_PEDANTIC "Enable a bunch of additional warnings" OFF) +option(BTOP_WERROR "Compile with warnings as errors" OFF) + +if(BTOP_STATIC) + # Set this before calling find_package + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") +endif() + +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + find_package(devstat REQUIRED) + find_package(kvm REQUIRED) + if(BTOP_STATIC) + find_package(elf REQUIRED) + endif() +endif() + +include(CheckCXXCompilerFlag) +include(CheckIPOSupported) + +add_executable(btop + src/btop.cpp + src/btop_config.cpp + src/btop_draw.cpp + src/btop_input.cpp + src/btop_menu.cpp + src/btop_shared.cpp + src/btop_theme.cpp + src/btop_tools.cpp +) + +# NOTE: Checks can be simplified with CMake 3.25 +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_sources(btop PRIVATE + src/osx/btop_collect.cpp + src/osx/sensors.cpp + src/osx/smc.cpp + ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + target_sources(btop PRIVATE src/freebsd/btop_collect.cpp) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + target_sources(btop PRIVATE src/linux/btop_collect.cpp) +else() + message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supported") +endif() + +# Check for and enable LTO +check_ipo_supported(RESULT ipo_supported) +if(ipo_supported AND BTOP_LTO) + set_target_properties(btop PROPERTIES INTERPROCEDURAL_OPTIMIZATION ON) +endif() + +# TODO: enable more warnings in coordination with upstream +target_compile_options(btop PRIVATE + -Wall -Wextra -Wpedantic + -ftree-vectorize -fstack-clash-protection +) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(btop PRIVATE + -Wheader-hygiene -Wgnu -Wthread-safety + ) +endif() + +if(BTOP_PEDANTIC) + target_compile_options(btop PRIVATE + -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused + -Woverloaded-virtual -Wconversion -Wsign-conversion -Wdouble-promotion + -Wformat=2 -Wimplicit-fallthrough -Weffc++ + ) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(btop PRIVATE + -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wnull-dereference + -Wuseless-cast + ) + endif() +endif() + +if(BTOP_WERROR) + target_compile_options(btop PRIVATE -Werror) +endif() + +check_cxx_compiler_flag(-fstack-protector CXX_HAS_FSTACK_PROTECTOR) +if(CXX_HAS_FSTACK_PROTECTOR) + target_compile_options(btop PRIVATE -fstack-protector) +endif() + +check_cxx_compiler_flag(-fcf-protection CXX_HAS_FCF_PROTECTION) +if(CXX_HAS_FCF_PROTECTION) + target_compile_options(btop PRIVATE -fcf-protection) +endif() + +target_compile_definitions(btop PRIVATE + _FILE_OFFSET_BITS=64 + _GLIBCXX_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS=1 + # Only has an effect with optimizations enabled + $<$>:_FORTIFY_SOURCE=2> +) + +target_include_directories(btop SYSTEM PRIVATE include) + +# mold +if(BTOP_USE_MOLD) + target_link_options(btop PRIVATE -fuse-ld=mold) +endif() + +if(BTOP_STATIC) + target_compile_definitions(btop PRIVATE STATIC_BUILD) + target_link_options(btop PRIVATE -static LINKER:--fatal-warnings) +endif() + +# Add libraries +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +target_link_libraries(btop PRIVATE Threads::Threads) + +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_link_libraries(btop PRIVATE $ + + + +### With Make + + 1. **Install dependencies (example for Ubuntu 21.04 Hirsute)** @@ -401,6 +429,79 @@ Also needs a UTF8 locale and a font that covers: make help ``` + + +
+ + + +### With CMake (Community maintained) + + + +1. **Install build dependencies** + + Requires Clang / GCC, CMake, Ninja and Git + + For example, with Debian Bookworm: + + ```bash + sudo apt install cmake git g++ ninja-build + ``` + +2. **Clone the repository** + + ```bash + git clone https://github.com/aristocratos/btop.git && cd btop + `````` + +3. **Compile** + + ```bash + # Configure + 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_STATIC=` | Enables static linking (OFF by default) | + | `-DBTOP_LTO=` | Enables link time optimization (ON by default) | + | `-DBTOP_USE_MOLD=` | Use mold to link btop (OFF by default) | + | `-DBTOP_PEDANTIC=` | Compile with additional warnings (OFF by default) | + | `-DBTOP_WERROR=` | Compile with warnings as errors (OFF by default) | + | `-DCMAKE_INSTALL_PREFIX=` | The installation prefix ('/usr/local' by default) | + + To force a compiler, run `CXX= 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 + ``` + +
+ ## Compilation macOS OSX Needs GCC 10 or higher, (GCC 11 or above strongly recommended for better CPU efficiency in the compiled binary). @@ -497,6 +598,14 @@ Also needs a UTF8 locale and a font that covers: Note that GNU make (`gmake`) is required to compile on FreeBSD. +
+ + + +### With gmake + + + 1. **Install dependencies** ```bash @@ -577,28 +686,98 @@ Also needs a UTF8 locale and a font that covers: gmake help ``` -## GPU compatibility - Btop++ supports NVIDIA and AMD GPUs out of the box on Linux, provided you have the correct drivers and libraries. - Compatibility with Intel GPUs using generic DRM calls is planned, as is compatibility for FreeBSD and macOS. +
- * **NVIDIA** +
- You must use an official NVIDIA driver, both the closed-source and [open-source](https://github.com/NVIDIA/open-gpu-kernel-modules) ones have been verified to work. + - In addition to that you must also have the `nvidia-ml` dynamic library installed, which should be included with the driver package of your distribution. +### With CMake (Community maintained) - * **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. +1. **Install build dependencies** - 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: + Requires Clang / GCC, CMake, Ninja and Git + + _**Note:** LLVM's libc++ shipped with FreeBSD 13 is too old and cannot compile btop._ + + FreeBSD 14 and later: + ```bash + pkg install cmake ninja + ``` + + FreeBSD 13: + ```bash + pkg install cmake gcc13 ninja + ``` + +2. **Clone the repository** ```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/aristocratos/btop.git && cd btop + `````` + +3. **Compile** + + FreeBSD 14 and later: + ```bash + # Configure + cmake -B build -G Ninja + # Build + cmake --build build ``` + FreeBSD 13: + ```bash + # Configure + CXX=g++13 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_STATIC=` | Enables static linking (OFF by default) | + | `-DBTOP_LTO=` | Enables link time optimization (ON by default) | + | `-DBTOP_USE_MOLD=` | Use mold to link btop (OFF by default) | + | `-DBTOP_PEDANTIC=` | Compile with additional warnings (OFF by default) | + | `-DBTOP_WERROR=` | Compile with warnings as errors (OFF by default) | + | `-DCMAKE_INSTALL_PREFIX=` | The installation prefix ('/usr/local' by default) | + + _**Note:** Static linking does not work with GCC._ + + To force a compiler, run `CXX= 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 + ``` + +
+ ## Installing the snap [![btop](https://snapcraft.io/btop/badge.svg)](https://snapcraft.io/btop) diff --git a/cmake/Modules/Finddevstat.cmake b/cmake/Modules/Finddevstat.cmake new file mode 100644 index 0000000..694e613 --- /dev/null +++ b/cmake/Modules/Finddevstat.cmake @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Find devstat, the Device Statistics Library +# + +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + find_path(devstat_INCLUDE_DIR NAMES devstat.h) + find_library(devstat_LIBRARY NAMES devstat) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(devstat REQUIRED_VARS devstat_LIBRARY devstat_INCLUDE_DIR) + + if(devstat_FOUND AND NOT TARGET devstat::devstat) + add_library(devstat::devstat UNKNOWN IMPORTED) + set_target_properties(devstat::devstat PROPERTIES + IMPORTED_LOCATION "${devstat_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${devstat_INCLUDE_DIR}" + ) + endif() + + mark_as_advanced(devstat_INCLUDE_DIR devstat_LIBRARY) +endif() + diff --git a/cmake/Modules/Findelf.cmake b/cmake/Modules/Findelf.cmake new file mode 100644 index 0000000..91e0beb --- /dev/null +++ b/cmake/Modules/Findelf.cmake @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Find libelf, the ELF Access Library +# + +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + find_path(elf_INCLUDE_DIR NAMES libelf.h) + find_library(elf_LIBRARY NAMES elf) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(elf REQUIRED_VARS elf_LIBRARY elf_INCLUDE_DIR) + + if(elf_FOUND AND NOT TARGET elf::elf) + add_library(elf::elf UNKNOWN IMPORTED) + set_target_properties(elf::elf PROPERTIES + IMPORTED_LOCATION "${elf_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${elf_INCLUDE_DIR}" + ) + endif() + + mark_as_advanced(elf_INCLUDE_DIR elf_LIBRARY) +endif() + diff --git a/cmake/Modules/Findkvm.cmake b/cmake/Modules/Findkvm.cmake new file mode 100644 index 0000000..a0847de --- /dev/null +++ b/cmake/Modules/Findkvm.cmake @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Find libkvm, the Kernel Data Access Library +# + +if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + find_path(kvm_INCLUDE_DIR NAMES kvm.h) + find_library(kvm_LIBRARY NAMES kvm) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(kvm REQUIRED_VARS kvm_LIBRARY kvm_INCLUDE_DIR) + + if(kvm_FOUND AND NOT TARGET kvm::kvm) + add_library(kvm::kvm UNKNOWN IMPORTED) + set_target_properties(kvm::kvm PROPERTIES + IMPORTED_LOCATION "${kvm_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${kvm_INCLUDE_DIR}" + ) + endif() + + mark_as_advanced(kvm_INCLUDE_DIR kvm_LIBRARY) +endif() + diff --git a/src/btop_config.cpp b/src/btop_config.cpp index 4189c64..0f723b7 100644 --- a/src/btop_config.cpp +++ b/src/btop_config.cpp @@ -109,6 +109,8 @@ namespace Config { {"proc_filter_kernel", "#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop)."}, + {"proc_aggregate", "#* In tree-view, always accumulate child process resources in the parent process."}, + {"cpu_graph_upper", "#* Sets the CPU stat shown in upper half of the CPU graph, \"total\" is always available.\n" "#* Select from a list of detected attributes from the options menu."}, @@ -296,6 +298,7 @@ namespace Config { {"lowcolor", false}, {"show_detailed", false}, {"proc_filtering", false}, + {"proc_aggregate", false}, #ifdef GPU_SUPPORT {"nvml_measure_pcie_speeds", true}, {"gpu_mirror_graph", true}, diff --git a/src/btop_draw.cpp b/src/btop_draw.cpp index 1327562..edb1eec 100644 --- a/src/btop_draw.cpp +++ b/src/btop_draw.cpp @@ -1876,7 +1876,17 @@ namespace Proc { else mem_str.resize((mem_p < 10 or mem_p >= 100 ? 3 : 4)); mem_str += '%'; } - out += (thread_size > 0 ? t_color + rjust(to_string(min(p.threads, (size_t)9999)), thread_size) + ' ' + end : "" ) + + // Shorten process thread representation when larger than 5 digits: 10000 -> 10K ... + const std::string proc_threads_string = [&] { + if (p.threads > 9999) { + return std::to_string(p.threads / 1000) + 'K'; + } else { + return std::to_string(p.threads); + } + }(); + + out += (thread_size > 0 ? t_color + rjust(proc_threads_string, thread_size) + ' ' + end : "" ) + g_color + ljust((cmp_greater(p.user.size(), user_size) ? p.user.substr(0, user_size - 1) + '+' : p.user), user_size) + ' ' + m_color + rjust(mem_str, 5) + end + ' ' + (is_selected ? "" : Theme::c("inactive_fg")) + (show_graphs ? graph_bg * 5: "") @@ -1892,8 +1902,11 @@ namespace Proc { if (numpids > select_max) { const int scroll_pos = clamp((int)round((double)start * select_max / (numpids - select_max)), 0, height - 5); out += Mv::to(y + 1, x + width - 2) + Fx::b + Theme::c("main_fg") + Symbols::up - + Mv::to(y + height - 2, x + width - 2) + Symbols::down - + Mv::to(y + 2 + scroll_pos, x + width - 2) + "█"; + + Mv::to(y + height - 2, x + width - 2) + Symbols::down; + + for (int i = y + 2; i < y + height - 2; i++) { + out += Mv::to(i, x + width - 2) + ((i == y + 2 + scroll_pos) ? "█" : " "); + } } //? Current selection and number of processes diff --git a/src/btop_input.cpp b/src/btop_input.cpp index ce3ac48..88f307b 100644 --- a/src/btop_input.cpp +++ b/src/btop_input.cpp @@ -64,9 +64,13 @@ namespace Input { {"[C", "right"}, {"OC", "right"}, {"[2~", "insert"}, + {"[4h", "insert"}, {"[3~", "delete"}, + {"[P", "delete"}, {"[H", "home"}, + {"[1~", "home"}, {"[F", "end"}, + {"[4~", "end"}, {"[5~", "page_up"}, {"[6~", "page_down"}, {"\t", "tab"}, @@ -362,6 +366,9 @@ namespace Input { else if (key == "c") Config::flip("proc_per_core"); + else if (key == "%") + Config::flip("proc_mem_bytes"); + else if (key == "delete" and not Config::getS("proc_filter").empty()) Config::set("proc_filter", ""s); diff --git a/src/btop_menu.cpp b/src/btop_menu.cpp index 9b11f21..206052f 100644 --- a/src/btop_menu.cpp +++ b/src/btop_menu.cpp @@ -54,15 +54,73 @@ namespace Menu { int signalKillRet{}; // defaults to 0 const array P_Signals = { - "0", + "0", +#ifdef __linux__ +#if defined(__hppa__) + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGSTKFLT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGXCPU", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGUSR1", + "SIGUSR2", "SIGCHLD", "SIGPWR", "SIGVTALRM", + "SIGPROF", "SIGIO", "SIGWINCH", "SIGSTOP", + "SIGTSTP", "SIGCONT", "SIGTTIN", "SIGTTOU", + "SIGURG", "SIGXFSZ", "SIGSYS" +#elif defined(__mips__) + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGUSR1", + "SIGUSR2", "SIGCHLD", "SIGPWR", "SIGWINCH", + "SIGURG", "SIGIO", "SIGSTOP", "SIGTSTP", + "SIGCONT", "SIGTTIN", "SIGTTOU", "SIGVTALRM", + "SIGPROF", "SIGXCPU", "SIGXFSZ" +#elif defined(__alpha__) + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGPWR", "SIGUSR1", "SIGUSR2" +#elif defined (__sparc__) + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2" +#else "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGTRAP", "SIGABRT", "SIGBUS", "SIGFPE", "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", - "SIGPIPE", "SIGALRM", "SIGTERM", "16", "SIGCHLD", - "SIGCONT", "SIGSTOP", "SIGTSTP", "SIGTTIN", - "SIGTTOU", "SIGURG", "SIGXCPU", "SIGXFSZ", - "SIGVTALRM", "SIGPROF", "SIGWINCH", "SIGIO", - "SIGPWR", "SIGSYS" + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGSYS" +#endif +#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__APPLE__) + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2" +#else + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "7", "SIGFPE", + "SIGKILL", "10", "SIGSEGV", "12", + "SIGPIPE", "SIGALRM", "SIGTERM", "16", + "17", "18", "19", "20", + "21", "22", "23", "24", + "25", "26", "27", "28", + "29", "30", "31" +#endif }; unordered_flat_map mouse_mappings; @@ -138,6 +196,7 @@ namespace Menu { {"c", "Toggle per-core cpu usage of processes."}, {"r", "Reverse sorting order in processes box."}, {"e", "Toggle processes tree view."}, + {"%", "Toggles memory display mode in processes box."}, {"Selected +, -", "Expand/collapse the selected process in tree view."}, {"Selected t", "Terminate selected process with SIGTERM - 15."}, {"Selected k", "Kill selected process with SIGKILL - 9."}, @@ -675,6 +734,11 @@ namespace Menu { "Set true to show processes grouped by", "parents with lines drawn between parent", "and child process."}, + {"proc_aggregate", + "Aggregate child's resources in parent.", + "", + "In tree-view, include all child resources", + "with the parent even while expanded."}, {"proc_colors", "Enable colors in process view.", "", diff --git a/src/btop_shared.cpp b/src/btop_shared.cpp index b2f70a8..fe0f334 100644 --- a/src/btop_shared.cpp +++ b/src/btop_shared.cpp @@ -18,6 +18,7 @@ tab-size = 4 #include +#include "btop_config.hpp" #include "btop_shared.hpp" #include "btop_tools.hpp" @@ -168,6 +169,12 @@ namespace Proc { filter_found++; p.filtered = true; } + else if (Config::getB("proc_aggregate")) { + cur_proc.cpu_p += p.cpu_p; + cur_proc.cpu_c += p.cpu_c; + cur_proc.mem += p.mem; + cur_proc.threads += p.threads; + } } if (collapsed or filtering) { return; diff --git a/src/btop_tools.cpp b/src/btop_tools.cpp index 75adae9..88bf711 100644 --- a/src/btop_tools.cpp +++ b/src/btop_tools.cpp @@ -455,7 +455,7 @@ namespace Tools { out = to_string((int)round(stod(out))); } if (out.size() > 3) { - out = to_string((int)(out[0] - '0') + 1); + out = to_string((int)(out[0] - '0')) + ".0"; start++; } out.push_back(units[start][0]); diff --git a/src/linux/btop_collect.cpp b/src/linux/btop_collect.cpp index 9899224..4bb5e71 100644 --- a/src/linux/btop_collect.cpp +++ b/src/linux/btop_collect.cpp @@ -29,6 +29,7 @@ tab-size = 4 #include #include // for inet_ntop() #include +#include #include #if defined(RSMI_STATIC) @@ -53,12 +54,17 @@ using std::numeric_limits; using std::round; using std::streamsize; using std::vector; +using std::future; +using std::async; +using std::pair; + namespace fs = std::filesystem; namespace rng = std::ranges; using namespace Tools; using namespace std::literals; // for operator""s +using namespace std::chrono_literals; //? --------------------------------------------------- FUNCTIONS ----------------------------------------------------- namespace Cpu { @@ -1607,6 +1613,7 @@ namespace Mem { auto only_physical = Config::getB("only_physical"); auto zfs_hide_datasets = Config::getB("zfs_hide_datasets"); auto& disks = mem.disks; + static unordered_flat_map>> disks_stats_promises; ifstream diskread; vector filter; @@ -1746,31 +1753,47 @@ namespace Mem { diskread.close(); //? Get disk/partition stats - bool new_ignored = false; - for (auto& [mountpoint, disk] : disks) { - if (std::error_code ec; not fs::exists(mountpoint, ec) or v_contains(ignore_list, mountpoint)) continue; - struct statvfs vfs; - if (statvfs(mountpoint.c_str(), &vfs) < 0) { - Logger::warning("Failed to get disk/partition stats for mount \""+ mountpoint + "\" with statvfs error code: " + to_string(errno) + ". Ignoring..."); - ignore_list.push_back(mountpoint); - new_ignored = true; + for (auto it = disks.begin(); it != disks.end(); ) { + auto &[mountpoint, disk] = *it; + if (v_contains(ignore_list, mountpoint)) { + it = disks.erase(it); continue; } - disk.total = vfs.f_blocks * vfs.f_frsize; - disk.free = (free_priv ? vfs.f_bfree : vfs.f_bavail) * vfs.f_frsize; - disk.used = disk.total - disk.free; - disk.used_percent = round((double)disk.used * 100 / disk.total); - disk.free_percent = 100 - disk.used_percent; - } - - //? Remove any problematic disks added to the ignore_list - if (new_ignored) { - for (auto it = disks.begin(); it != disks.end();) { - if (v_contains(ignore_list, it->first)) + if(auto promises_it = disks_stats_promises.find(mountpoint); promises_it != disks_stats_promises.end()){ + auto& promise = promises_it->second; + if(promise.valid() && + promise.wait_for(0s) == std::future_status::timeout) { + ++it; + continue; + } + auto promise_res = promises_it->second.get(); + if(promise_res.second != -1){ + ignore_list.push_back(mountpoint); + Logger::warning("Failed to get disk/partition stats for mount \""+ mountpoint + "\" with statvfs error code: " + to_string(promise_res.second) + ". Ignoring..."); it = disks.erase(it); - else - it++; + continue; + } + auto &updated_stats = promise_res.first; + disk.total = updated_stats.total; + disk.free = updated_stats.free; + disk.used = updated_stats.used; + disk.used_percent = updated_stats.used_percent; + disk.free_percent = updated_stats.free_percent; } + disks_stats_promises[mountpoint] = async(std::launch::async, [mountpoint, &free_priv]() -> pair { + struct statvfs vfs; + disk_info disk; + if (statvfs(mountpoint.c_str(), &vfs) < 0) { + return pair{disk, errno}; + } + disk.total = vfs.f_blocks * vfs.f_frsize; + disk.free = (free_priv ? vfs.f_bfree : vfs.f_bavail) * vfs.f_frsize; + disk.used = disk.total - disk.free; + disk.used_percent = round((double)disk.used * 100 / disk.total); + disk.free_percent = 100 - disk.used_percent; + return pair{disk, -1}; + }); + ++it; } //? Setup disks order in UI and add swap if enabled diff --git a/themes/elementarish.theme b/themes/elementarish.theme index 8d5b9d1..0fe5398 100644 --- a/themes/elementarish.theme +++ b/themes/elementarish.theme @@ -3,7 +3,7 @@ # By: Dennis Mayr # Main bg -theme[main_bg]="#2b2b2b" +theme[main_bg]="#333333" # Main text color theme[main_fg]="#eee8d5" @@ -12,71 +12,71 @@ theme[main_fg]="#eee8d5" theme[title]="#eee8d5" # Higlight color for keyboard shortcuts -theme[hi_fg]="#dc322f" +theme[hi_fg]="#d1302c" # Background color of selected item in processes box -theme[selected_bg]="#268bd2" +theme[selected_bg]="#268ad0" # Foreground color of selected item in processes box theme[selected_fg]="#eee8d5" # Color of inactive/disabled text -theme[inactive_fg]="#586e75" +theme[inactive_fg]="#657b83" # Misc colors for processes box including mini cpu graphs, details memory graph and details status text -theme[proc_misc]="#268bd2" +theme[proc_misc]="#268ad0" # Cpu box outline color -theme[cpu_box]="#586e75" +theme[cpu_box]="#657b83" # Memory/disks box outline color -theme[mem_box]="#586e75" +theme[mem_box]="#657b83" # Net up/down box outline color -theme[net_box]="#586e75" +theme[net_box]="#657b83" # Processes box outline color -theme[proc_box]="#586e75" +theme[proc_box]="#657b83" # Box divider line and small boxes line color -theme[div_line]="#586e75" +theme[div_line]="#657b83" # Temperature graph colors theme[temp_start]="#859900" -theme[temp_mid]="#b58901" -theme[temp_end]="#dc322f" +theme[temp_mid]="#b28602" +theme[temp_end]="#d1302c" # CPU graph colors theme[cpu_start]="#859900" -theme[cpu_mid]="#b58901" -theme[cpu_end]="#dc322f" +theme[cpu_mid]="#b28602" +theme[cpu_end]="#d1302c" # Mem/Disk free meter -theme[free_start]="#268bd2" +theme[free_start]="#268ad0" theme[free_mid]="#6c71c4" theme[free_end]="#2a9d95" # Mem/Disk cached meter -theme[cached_start]="#268bd2" +theme[cached_start]="#268ad0" theme[cached_mid]="#6c71c4" -theme[cached_end]="#dc322f" +theme[cached_end]="#d1302c" # Mem/Disk available meter -theme[available_start]="#268bd2" +theme[available_start]="#268ad0" theme[available_mid]="#6c71c4" -theme[available_end]="#dc322f" +theme[available_end]="#d1302c" # Mem/Disk used meter theme[used_start]="#859900" -theme[used_mid]="#b58901" -theme[used_end]="#dc322f" +theme[used_mid]="#b28602" +theme[used_end]="#d1302c" # Download graph colors -theme[download_start]="#268bd2" +theme[download_start]="#268ad0" theme[download_mid]="#6c71c4" -theme[download_end]="#dc322f" +theme[download_end]="#d1302c" # Upload graph colors -theme[upload_start]="#268bd2" +theme[upload_start]="#268ad0" theme[upload_mid]="#6c71c4" -theme[upload_end]="#dc322f" +theme[upload_end]="#d1302c" diff --git a/themes/horizon.theme b/themes/horizon.theme new file mode 100644 index 0000000..15c2d0e --- /dev/null +++ b/themes/horizon.theme @@ -0,0 +1,86 @@ +# 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]="#1C1E26" + +# Main text color +theme[main_fg]="#f8f8f2" + +# Title color for boxes +theme[title]="#f8f8f2" + +# Highlight color for keyboard shortcuts +theme[hi_fg]="#B877DB" + +# Background color of selected items +theme[selected_bg]="#282b37" + +# Foreground color of selected items +theme[selected_fg]="#f8f8f2" + +# Color of inactive/disabled text +theme[inactive_fg]="#272e33" + +# Color of text appearing on top of graphs, i.e uptime and current network graph scaling +theme[graph_text]="#f8f8f2" + +# Misc colors for processes box including mini cpu graphs, details memory graph and details status text +theme[proc_misc]="#27D796" + +# Cpu box outline color +theme[cpu_box]="#B877DB" + +# Memory/disks box outline color +theme[mem_box]="#27D796" + +# Net up/down box outline color +theme[net_box]="#E95678" + +# Processes box outline color +theme[proc_box]="#25B2BC" + +# Box divider line and small boxes line color +theme[div_line]="#272e33" + +# Temperature graph colors +theme[temp_start]="#27D796" +theme[temp_mid]="#FAC29A" +theme[temp_end]="#E95678" + +# CPU graph colors +theme[cpu_start]="#27D796" +theme[cpu_mid]="#FAC29A" +theme[cpu_end]="#E95678" + +# Mem/Disk free meter +theme[free_start]="#E95678" +theme[free_mid]="#FAC29A" +theme[free_end]="#27D796" + +# Mem/Disk cached meter +theme[cached_start]="#27D796" +theme[cached_mid]="#FAC29A" +theme[cached_end]="#E95678" + +# Mem/Disk available meter +theme[available_start]="#27D796" +theme[available_mid]="#FAC29A" +theme[available_end]="#E95678" + +# Mem/Disk used meter +theme[used_start]="#27D796" +theme[used_mid]="#FAC29A" +theme[used_end]="#E95678" + +# Download graph colors +theme[download_start]="#27D796" +theme[download_mid]="#FAC29A" +theme[download_end]="#E95678" + +# Upload graph colors +theme[upload_start]="#27D796" +theme[upload_mid]="#FAC29A" +theme[upload_end]="#E95678"