Squashed commit of the following:

commit 285fb215d1
Author: aristocratos <gnmjpl@gmail.com>
Date:   Thu Dec 28 13:10:18 2023 +0100

    Proc::draw() -> Use std::erase_if() instead of for loops

commit 2fba934cde
Author: aristocratos <gnmjpl@gmail.com>
Date:   Wed Dec 27 00:54:28 2023 +0100

    Fixed leftover code in GPU init logging false errors

commit ad14554f32
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 26 19:32:43 2023 +0100

    Try alternative names for GPU libraries during GPU init

commit a8fda16bf6
Merge: e15e0b7 2796af3
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 26 19:19:14 2023 +0100

    Merge pull request #696 from aristocratos/map_safety

commit 2796af3f37
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 26 19:18:37 2023 +0100

    Document DEBUG flag for Makefile

commit f484326bf2
Merge: b4eb397 e15e0b7
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 26 19:11:26 2023 +0100

    Merge branch 'main' into map_safety

commit b4eb397fc6
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 10:52:52 2023 +0100

    Fix errors

commit 3c04a7a380
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 10:41:15 2023 +0100

    Added more checks and debug logging

commit 8b81c4a4ec
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 03:28:35 2023 +0100

    Return const refs

commit f836233b64
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 02:49:24 2023 +0100

    Remove robin_hood.h

commit 3a8ceacaf8
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 02:37:32 2023 +0100

    Fix call to compact and missing utility include

commit e15e0b7188
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 02:27:38 2023 +0100

    Revert "Replace robin_hood map and set with STD alternative and add safeVal() function for map/vector access with fallback"

    This reverts commit 6c87ab6196.

commit ced47a960f
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 02:26:13 2023 +0100

    Replace robin_hood map and set with STD alternative and add safeVal() function for map/vector access with fallback

commit 6c87ab6196
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Dec 25 02:16:15 2023 +0100

    Replace robin_hood map and set with STD alternative and add safeVal() function for map/vector access with fallback

commit a2325371d4
Merge: aab2e8c b598f02
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sun Dec 17 19:56:31 2023 +0100

    Merge pull request #690 from aristocratos/osx-fix

commit b598f02468
Merge: b1fe377 aab2e8c
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sun Dec 17 12:06:39 2023 +0100

    Merge branch 'main' into osx-fix

commit aab2e8cc55
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sun Dec 17 12:03:47 2023 +0100

    Fixed test-snap-can-build.yml

commit b1fe3779e1
Merge: 7805242 2d15c41
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sun Dec 17 11:56:14 2023 +0100

    Merge branch 'main' into osx-fix

commit 2d15c41555
Merge: fe699b4 2d3e453
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sun Dec 17 11:54:49 2023 +0100

    Merge pull request #684 from kz6fittycent/main

commit 2d3e453ed5
Merge: 0a38864 fe699b4
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Fri Dec 15 12:02:11 2023 -0600

    Merge branch 'main' into main

commit 0a388647cc
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Fri Dec 15 12:01:45 2023 -0600

    Update test-snap-can-build.yml

    whoops

commit 49f425f356
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Fri Dec 15 12:00:48 2023 -0600

    Update test-snap-can-build.yml

    https://github.com/aristocratos/btop/pull/684#issuecomment-1852801811

commit 780524267f
Author: Jos Dehaes <jos.dehaes@gmail.com>
Date:   Fri Dec 15 09:02:57 2023 +0100

    conditional compile on Big Sur and up

commit fe699b4333
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 12 23:20:09 2023 +0100

    Version bump to 1.3.0 in preparation for upcoming release

commit 2d2df23198
Merge: d7b581e b71538e
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 12 23:19:31 2023 +0100

    Merge branch 'main' of github.com:aristocratos/btop

commit d7b581eda4
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 12 23:17:36 2023 +0100

    Updated changes

commit b71538eabe
Merge: a017056 730af5d
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 23:07:39 2023 +0100

    Merge pull request #666 from muneebmahmed/macos-clang

commit 730af5d4e1
Merge: 0246b1b a017056
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 23:05:52 2023 +0100

    Merge branch 'main' into macos-clang

commit a017056ea0
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 12 23:05:07 2023 +0100

    Added swap to ignore for statvfs() since it will always fail

commit e770cccaf8
Author: aristocratos <gnmjpl@gmail.com>
Date:   Tue Dec 12 22:55:48 2023 +0100

    Added try->catch for get_zfs_stat_file() to avoid fs error

commit 0246b1b971
Author: Muneeb Ahmed <32603485+muneebmahmed@users.noreply.github.com>
Date:   Mon Nov 20 12:18:40 2023 -0800

    Enable macos clang

    Apple clang uses different versioning from LLVM, so 15.0.0 is compatible

commit 6282f36f8f
Merge: cfd20a3 be73160
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 22:06:02 2023 +0100

    Merge pull request #675 from imwints/cmake

commit be731600f1
Merge: f4b14ce cfd20a3
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 22:01:21 2023 +0100

    Merge branch 'main' into cmake

commit 450b59b657
Merge: 875f08b cfd20a3
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 21:55:27 2023 +0100

    Merge branch 'main' into main

commit cfd20a374b
Merge: 14e664e b6a8696
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 21:48:55 2023 +0100

    Merge pull request #677 from imwints/cpu-model

commit b6a86962e2
Merge: 8096433 14e664e
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 21:47:01 2023 +0100

    Merge branch 'main' into cpu-model

commit 14e664e756
Merge: 0d35746 5902484
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Dec 12 21:41:55 2023 +0100

    Merge pull request #679 from masiboss/main

commit 875f08ba5e
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Tue Dec 12 14:27:16 2023 -0600

    Update snapcraft.yaml - opengl

    - Testing opengl plug

commit 3ee4b18e57
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Tue Dec 12 14:14:59 2023 -0600

    Update bug_report.md

      - added snap info for bug reports to delineate

commit 2973a76f2b
Merge: fb782a2 0d35746
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Tue Dec 12 14:06:44 2023 -0600

    Merge branch 'aristocratos:main' into main

commit fb782a2ab3
Author: kz6fittycent <jimmy.tigert@gmail.com>
Date:   Tue Dec 12 14:02:27 2023 -0600

    Create test-snap-can-build.yml

commit 5902484f39
Author: masiboss <32394683+masiboss@users.noreply.github.com>
Date:   Thu Dec 7 21:42:11 2023 +0100

    simplify removal of "Apple"

commit 5beb9e12e5
Author: masiboss <32394683+masiboss@users.noreply.github.com>
Date:   Thu Dec 7 20:56:40 2023 +0100

    in case apple decides to add another suffix to the cpu name

commit 1b2f11b412
Author: masiboss <32394683+masiboss@users.noreply.github.com>
Date:   Thu Dec 7 20:49:34 2023 +0100

    cut less of cpu name if frequency is not shown

commit bcf4ad8ab6
Author: masiboss <32394683+masiboss@users.noreply.github.com>
Date:   Thu Dec 7 19:50:12 2023 +0100

    fix array out of bounds on regular m chip

commit aeefcacbc9
Author: masiboss <32394683+masiboss@users.noreply.github.com>
Date:   Thu Dec 7 19:34:11 2023 +0100

    fix cpu version not included

commit 23698940df
Author: masiboss <32394683+masiboss@users.noreply.github.com>
Date:   Thu Dec 7 19:23:58 2023 +0100

    strip "Apple" from name of Apple silicon chips

commit 8096433736
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Tue Dec 5 02:34:24 2023 +0100

    Fix printed model name for older Intel CPU

commit f4b14ce97e
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Tue Dec 5 01:00:14 2023 +0100

    Add CMake compile instructions for macOS

commit 97b35d9720
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Sat Dec 2 00:35:13 2023 +0100

    Add cmake workflow for all platforms

commit e35538fa29
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Sat Dec 2 00:34:32 2023 +0100

    Patch RPATH on FreeBSD, support OSX and format

commit 0d357468b5
Merge: ebc46ca 00f58b6
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Fri Dec 1 22:52:51 2023 +0100

    Merge pull request #674 from imwints/bsd-workflow

    Provide FreeBSD static release binaries

commit 00f58b6228
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Thu Nov 30 23:07:52 2023 +0100

    Provide FreeBSD static release binaries

    Bumps vmaction@freesdb-vm to version 1 which runs on Linux and doesn't
    hang all the time. Also uses clang for full static compilation

commit ebc46ca12c
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Mon Nov 27 18:21:42 2023 +0100

    Clean up compile instructions

commit d1384c9341
Merge: 2b0cc37 6f12e35
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Mon Nov 27 17:53:39 2023 +0100

    Merge pull request #671 from imwints/cmake-gpu

    Bring GPU support to CMake and improve how Make handles the ROCm library build

commit 6f12e3555d
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Mon Nov 27 00:33:11 2023 +0100

    Properly invoke CMake to build ROCm

    * Build an optimized library by default
    * Only build the library target
    * ROCm is build with debug symbols when `make DEBUG=true`
    * Enable LTO
    * Use the more generic CMake build command instead of calling make
      directly, this always uses all cores by default and makes it easier to
      switch to another generator e.g. Ninja
    * Use a variable to store the ROCm source directory. The directory can
      be changed with `make ROCM_DIR=<dir>`
    * The static library is now directly linked by CMake and not created off
      of the object files from a shared library build
    * The C++ compiler used to compile btop is now used to compile ROCm to
      avoid name mangling when `CXX` from the environment and `make CXX=`
      differ
    * CMake is invoked from btop's root directory

commit 0585bc9cfb
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Mon Nov 27 00:31:10 2023 +0100

    Suppress all output from ROCm build

    Similar to including external include files with `-isystem`, ignore
    output from ROCm build since these warnings aren't a concern here

commit 831be262b0
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Mon Nov 27 00:29:14 2023 +0100

    Remove ROCm object files with `make clean/distclean`

commit 2f59e61d87
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Sun Nov 26 22:56:58 2023 +0100

    Add GPU options for cmake based builds

commit 7588d96dd4
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Sun Nov 26 21:40:29 2023 +0100

    Add check for <ranges> header

commit ebbb769a6a
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Sun Nov 26 21:39:13 2023 +0100

    Move calls to find_package to where they're required

commit ed0fa34a9d
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Sun Nov 26 19:39:29 2023 +0100

    Bump required CMake version

commit 2b0cc37632
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Nov 25 23:11:54 2023 +0100

    Update compile instructions for Gpu support

commit 359c67136b
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Nov 25 22:49:26 2023 +0100

    Update changelog

commit 5b01235315
Merge: 0267eba 0bb8599
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Nov 25 21:57:32 2023 +0100

    Merge pull request #529 from romner-set/main

    Add GPU monitoring support

commit 0bb8599a96
Merge: 94d4502 0267eba
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Nov 25 21:51:09 2023 +0100

    Merge branch 'main' into main

commit 94d4502901
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Nov 25 21:48:50 2023 +0100

    Readme update and Makfile fixes.

commit 19bcff894b
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Nov 25 21:01:11 2023 +0100

    Squashed commit of the following:

    commit 0267eba2bb
    Merge: 50bbab0 e81cf2b
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Wed Nov 15 21:43:18 2023 +0100

        Merge pull request #659 from ivanp7/patch-1

        Add alternative key codes for Delete, Insert, Home, End

    commit 50bbab0512
    Merge: 9edbf27 5a14c7b
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Wed Nov 15 21:35:50 2023 +0100

        Merge pull request #660 from stradicat/feature/elementarish

        Elementarish theme: color update according to Elementary palette

    commit 5a14c7b6fa
    Merge: 979506f 71eb414
    Author: Dennis Mayr <dmayr.dev@gmail.com>
    Date:   Wed Nov 15 17:27:34 2023 -0300

        Merge branch 'main' of https://github.com/stradicat/btop

    commit 979506f18e
    Author: Dennis Mayr <dmayr.dev@gmail.com>
    Date:   Wed Nov 8 11:17:47 2023 -0300

        Elementarish theme: color update according to Elementary palette

    commit 71eb4142e8
    Author: Dennis Mayr <dmayr.dev@gmail.com>
    Date:   Wed Nov 8 11:17:47 2023 -0300

        Elementarish theme: color update according to Elementary palette

    commit e81cf2b7ff
    Author: vân <3432246+ivanp7@users.noreply.github.com>
    Date:   Tue Nov 7 15:12:27 2023 +0000

        Add alternative key codes for Insert, Home, End

    commit f9452ff6d5
    Author: vân <3432246+ivanp7@users.noreply.github.com>
    Date:   Mon Nov 6 13:31:53 2023 +0000

        Add alternative Delete key code

        Delete key not always produces ^[[3~, on some terminals (like st) it produces ^[[P.

    commit 9edbf27f1b
    Merge: 2a864f6 ff1f51c
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Oct 21 02:09:55 2023 +0200

        Merge pull request #649 from nobounce/workflow-timeout

        Set FreeBSD workflow timeout

    commit ff1f51ccbb
    Author: Steffen Winter <steffen.winter@proton.me>
    Date:   Wed Oct 18 22:26:36 2023 +0200

        Set FreeBSD workflow timeout

        Recently the FreeBSD workflow has started to hang in a boot loop when
        the VM starts up. The issue is being tracked upstream but there is not
        response at the moment.

        To work around this set a timeout to not waste CI minutes. Other
        workflows might also want this change since they don't take 20 minutes
        anyway.

    commit 2a864f6f2e
    Merge: 636eb25 b2bf8ef
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Oct 7 10:40:54 2023 +0200

        Merge pull request #643 from DecklynKern/main

        Fix scrollbar not clearing sometimes.

    commit b2bf8ef504
    Author: DecklynKern <DecklynKern@gmail.com>
    Date:   Fri Oct 6 17:33:38 2023 -0600

        Fix scrollbar not clearing sometimes.

    commit 636eb25f5e
    Merge: 260c0f6 b5ba2fc
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Sep 30 19:51:03 2023 +0200

        Merge pull request #623 from rahulaggarwal965/main

        Add keybind for toggling memory display mode in PROC box

    commit b5ba2fc963
    Author: Rahul Aggarwal <rahulaggarwal965@gmail.com>
    Date:   Wed Sep 20 22:55:56 2023 -0400

        Add keybind for toggling memory display mode in PROC box

    commit 260c0f6623
    Merge: 52bfff7 e6a06eb
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Sep 30 18:56:25 2023 +0200

        Merge pull request #635 from lvxnull/editorconfig

        Add hpp files to .editorconfig

    commit e6a06eb729
    Author: lvxnull <86745229+lvxnull@users.noreply.github.com>
    Date:   Thu Sep 28 19:44:47 2023 +0200

        Add hpp files to .editorconfig

    commit 52bfff7ceb
    Merge: 1f72e56 19dbbe1
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Sep 30 18:55:08 2023 +0200

        Merge pull request #636 from nobounce/performance-iili

        Minor string initialization improvement

    commit 19dbbe1a17
    Author: nobounce <steffen.winter@proton.me>
    Date:   Fri Sep 29 12:20:59 2023 +0200

        Minor string initialization improvement

    commit 1f72e56c7d
    Merge: 278a0e6 cdcf8bc
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Fri Sep 29 10:43:21 2023 +0200

        Merge pull request #633 from crestfallnatwork/main

        [fix] Made disks statvfs logic asynchronous.

    commit cdcf8bc929
    Author: crestfalln <guptahiman01@gmail.com>
    Date:   Fri Sep 29 09:07:27 2023 +0530

        fixed bug where updated disks stats overrided disk io data

    commit 9b4e85f08d
    Author: crestfalln <no-reply@crestfalln.com>
    Date:   Thu Sep 28 04:57:05 2023 +0530

        fixed bug where updated disks stats overrided disk io data

    commit 889623874e
    Author: crestfalln <no-reply@crestfalln.com>
    Date:   Wed Sep 27 23:57:06 2023 +0530

        made disks stat logic async

    commit 278a0e6b17
    Merge: d16adc9 e89519f
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Thu Sep 28 18:32:09 2023 +0200

        Merge pull request #630 from lvxnull/signal-list

        Fix signal list on non-linux/weird linux platforms

    commit e89519fbb2
    Author: lvxnull <86745229+lvxnull@users.noreply.github.com>
    Date:   Sun Sep 24 21:44:38 2023 +0200

        Fix signal list on non-linux/weird linux platforms

    commit d16adc9fd0
    Merge: 2c3ac48 f34b408
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Thu Sep 28 18:20:42 2023 +0200

        Merge pull request #618 from nobounce/aggregate-child-processes

        Add option to accumulate a child's resources in parent in tree-view

    commit f34b40892f
    Author: nobounce <steffen.winter@proton.me>
    Date:   Sun Sep 24 16:34:50 2023 +0200

        Make process thread count better readable when wider than 5 digits

    commit 6027cedd42
    Author: nobounce <steffen.winter@proton.me>
    Date:   Thu Sep 14 23:27:05 2023 +0200

        Add option to accumulate a child's resources in parent in tree-view

    commit 2c3ac4855d
    Merge: f90dc37 5c6a281
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Wed Sep 13 21:14:56 2023 +0200

        Merge pull request #589 from nobounce/cmake

        Add CMake support for Linux

    commit f90dc37c26
    Merge: 0cac861 68a49c1
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Wed Sep 13 20:27:05 2023 +0200

        Merge pull request #610 from SidVeld/feature/horizon-theme

        Horizon theme

    commit 5c6a281002
    Author: nobounce <steffen.winter@proton.me>
    Date:   Tue Aug 29 20:39:00 2023 +0200

        Add CMake support

        Linux is completly supported

        FreeBSD is not able to create a static executable for now. See
        https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273398

        MacOS was not tested

    commit 68a49c10a6
    Author: SidVeld <sidveld@gmail.com>
    Date:   Wed Sep 6 18:03:31 2023 +0300

        Add horizon theme

    commit 0cac861910
    Merge: 31be436 f798acd
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Tue Sep 5 19:27:38 2023 +0200

        Merge pull request #609 from scorpion-26/byteconv

        Fix short conversion of 1000-1023 *iB

    commit f798acdaf7
    Author: scorpion-26 <dev.scorpion26@gmail.com>
    Date:   Tue Sep 5 18:00:47 2023 +0200

        Fix short conversion of 1000-1023*iB

        floating_humanizer([1000-1024], true) with base 8 returns "2K", whereas it should return
        "1.0K" to align with other formats. The conversion is also broken for
        all other units(e.g. 1023M is also broken and returns "2G")

    commit 31be4362ce
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Sun Aug 27 02:00:07 2023 +0200

        FreeBSD Github action 13.1 -> 13.2 and static libgcc and libstdc++

    commit fc523fd1d0
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Sun Aug 27 01:36:26 2023 +0200

        Fix for FreeBSD github action not failing "correctly"...

commit b87772611c
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Nov 25 20:44:45 2023 +0100

    Added definition GPU_SUPPORT to toggle GPU related code

commit 0267eba2bb
Merge: 50bbab0 e81cf2b
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Wed Nov 15 21:43:18 2023 +0100

    Merge pull request #659 from ivanp7/patch-1

    Add alternative key codes for Delete, Insert, Home, End

commit 50bbab0512
Merge: 9edbf27 5a14c7b
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Wed Nov 15 21:35:50 2023 +0100

    Merge pull request #660 from stradicat/feature/elementarish

    Elementarish theme: color update according to Elementary palette

commit 5a14c7b6fa
Merge: 979506f 71eb414
Author: Dennis Mayr <dmayr.dev@gmail.com>
Date:   Wed Nov 15 17:27:34 2023 -0300

    Merge branch 'main' of https://github.com/stradicat/btop

commit 979506f18e
Author: Dennis Mayr <dmayr.dev@gmail.com>
Date:   Wed Nov 8 11:17:47 2023 -0300

    Elementarish theme: color update according to Elementary palette

commit 71eb4142e8
Author: Dennis Mayr <dmayr.dev@gmail.com>
Date:   Wed Nov 8 11:17:47 2023 -0300

    Elementarish theme: color update according to Elementary palette

commit e81cf2b7ff
Author: vân <3432246+ivanp7@users.noreply.github.com>
Date:   Tue Nov 7 15:12:27 2023 +0000

    Add alternative key codes for Insert, Home, End

commit f9452ff6d5
Author: vân <3432246+ivanp7@users.noreply.github.com>
Date:   Mon Nov 6 13:31:53 2023 +0000

    Add alternative Delete key code

    Delete key not always produces ^[[3~, on some terminals (like st) it produces ^[[P.

commit 9edbf27f1b
Merge: 2a864f6 ff1f51c
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Oct 21 02:09:55 2023 +0200

    Merge pull request #649 from nobounce/workflow-timeout

    Set FreeBSD workflow timeout

commit ff1f51ccbb
Author: Steffen Winter <steffen.winter@proton.me>
Date:   Wed Oct 18 22:26:36 2023 +0200

    Set FreeBSD workflow timeout

    Recently the FreeBSD workflow has started to hang in a boot loop when
    the VM starts up. The issue is being tracked upstream but there is not
    response at the moment.

    To work around this set a timeout to not waste CI minutes. Other
    workflows might also want this change since they don't take 20 minutes
    anyway.

commit 2a864f6f2e
Merge: 636eb25 b2bf8ef
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Oct 7 10:40:54 2023 +0200

    Merge pull request #643 from DecklynKern/main

    Fix scrollbar not clearing sometimes.

commit b2bf8ef504
Author: DecklynKern <DecklynKern@gmail.com>
Date:   Fri Oct 6 17:33:38 2023 -0600

    Fix scrollbar not clearing sometimes.

commit 636eb25f5e
Merge: 260c0f6 b5ba2fc
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Sep 30 19:51:03 2023 +0200

    Merge pull request #623 from rahulaggarwal965/main

    Add keybind for toggling memory display mode in PROC box

commit b5ba2fc963
Author: Rahul Aggarwal <rahulaggarwal965@gmail.com>
Date:   Wed Sep 20 22:55:56 2023 -0400

    Add keybind for toggling memory display mode in PROC box

commit 260c0f6623
Merge: 52bfff7 e6a06eb
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Sep 30 18:56:25 2023 +0200

    Merge pull request #635 from lvxnull/editorconfig

    Add hpp files to .editorconfig

commit e6a06eb729
Author: lvxnull <86745229+lvxnull@users.noreply.github.com>
Date:   Thu Sep 28 19:44:47 2023 +0200

    Add hpp files to .editorconfig

commit 52bfff7ceb
Merge: 1f72e56 19dbbe1
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Sat Sep 30 18:55:08 2023 +0200

    Merge pull request #636 from nobounce/performance-iili

    Minor string initialization improvement

commit 19dbbe1a17
Author: nobounce <steffen.winter@proton.me>
Date:   Fri Sep 29 12:20:59 2023 +0200

    Minor string initialization improvement

commit 1f72e56c7d
Merge: 278a0e6 cdcf8bc
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Fri Sep 29 10:43:21 2023 +0200

    Merge pull request #633 from crestfallnatwork/main

    [fix] Made disks statvfs logic asynchronous.

commit cdcf8bc929
Author: crestfalln <guptahiman01@gmail.com>
Date:   Fri Sep 29 09:07:27 2023 +0530

    fixed bug where updated disks stats overrided disk io data

commit 9b4e85f08d
Author: crestfalln <no-reply@crestfalln.com>
Date:   Thu Sep 28 04:57:05 2023 +0530

    fixed bug where updated disks stats overrided disk io data

commit 889623874e
Author: crestfalln <no-reply@crestfalln.com>
Date:   Wed Sep 27 23:57:06 2023 +0530

    made disks stat logic async

commit 278a0e6b17
Merge: d16adc9 e89519f
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Thu Sep 28 18:32:09 2023 +0200

    Merge pull request #630 from lvxnull/signal-list

    Fix signal list on non-linux/weird linux platforms

commit e89519fbb2
Author: lvxnull <86745229+lvxnull@users.noreply.github.com>
Date:   Sun Sep 24 21:44:38 2023 +0200

    Fix signal list on non-linux/weird linux platforms

commit d16adc9fd0
Merge: 2c3ac48 f34b408
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Thu Sep 28 18:20:42 2023 +0200

    Merge pull request #618 from nobounce/aggregate-child-processes

    Add option to accumulate a child's resources in parent in tree-view

commit f34b40892f
Author: nobounce <steffen.winter@proton.me>
Date:   Sun Sep 24 16:34:50 2023 +0200

    Make process thread count better readable when wider than 5 digits

commit 6027cedd42
Author: nobounce <steffen.winter@proton.me>
Date:   Thu Sep 14 23:27:05 2023 +0200

    Add option to accumulate a child's resources in parent in tree-view

commit 2c3ac4855d
Merge: f90dc37 5c6a281
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Wed Sep 13 21:14:56 2023 +0200

    Merge pull request #589 from nobounce/cmake

    Add CMake support for Linux

commit f90dc37c26
Merge: 0cac861 68a49c1
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Wed Sep 13 20:27:05 2023 +0200

    Merge pull request #610 from SidVeld/feature/horizon-theme

    Horizon theme

commit 5c6a281002
Author: nobounce <steffen.winter@proton.me>
Date:   Tue Aug 29 20:39:00 2023 +0200

    Add CMake support

    Linux is completly supported

    FreeBSD is not able to create a static executable for now. See
    https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=273398

    MacOS was not tested

commit 68a49c10a6
Author: SidVeld <sidveld@gmail.com>
Date:   Wed Sep 6 18:03:31 2023 +0300

    Add horizon theme

commit 0cac861910
Merge: 31be436 f798acd
Author: Jakob P. Liljenberg <admin@qvantnet.com>
Date:   Tue Sep 5 19:27:38 2023 +0200

    Merge pull request #609 from scorpion-26/byteconv

    Fix short conversion of 1000-1023 *iB

commit f798acdaf7
Author: scorpion-26 <dev.scorpion26@gmail.com>
Date:   Tue Sep 5 18:00:47 2023 +0200

    Fix short conversion of 1000-1023*iB

    floating_humanizer([1000-1024], true) with base 8 returns "2K", whereas it should return
    "1.0K" to align with other formats. The conversion is also broken for
    all other units(e.g. 1023M is also broken and returns "2G")

commit 975525d38f
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Aug 27 12:34:46 2023 +0200

    Fix: Cpu gpu stats always shown when show_gpu_info is On and sizing issues

commit 08abf0b930
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Aug 27 01:28:36 2023 +0200

    Quickfixes for MacOS and FreeBSD compilation.

commit 7290109f80
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Aug 27 00:58:30 2023 +0200

    Merge fix

commit 283d463242
Merge: efddad4 c296ac1
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Aug 27 00:56:22 2023 +0200

    Merge branch 'main' into pr/romner-set/529

commit efddad42dc
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Aug 27 00:39:57 2023 +0200

    Changed: cpu_graph_lower Auto defaults to cpu_graph_upper when show_gpu_info is Off

commit a9bc0874d4
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun Aug 27 00:31:07 2023 +0200

    Added show_gpu_info setting and Auto options for cpu graphs

commit b3970ee19c
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Aug 26 20:52:59 2023 +0200

    Fixed: Key 5-0 gpu box toggle

commit bd5d697830
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat Aug 26 20:29:43 2023 +0200

    Squashed commit of the following:

    commit c296ac13cd
    Merge: 9a1e760 091c30a
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Aug 26 19:29:57 2023 +0200

        Merge pull request #590 from nobounce/dangling-reference-config

        Convert parameters and config keys to std::string_view

    commit 9a1e760a66
    Merge: 9c8af4d 22e64ca
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Aug 26 19:20:18 2023 +0200

        Merge pull request #602 from jfouquart/main

        Fix getting zfs pool name with '.' char in freebsd

    commit 9c8af4df43
    Merge: 8a49d8c 2217cbe
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Aug 26 19:18:55 2023 +0200

        Merge pull request #601 from joske/cleanup

        [macos] don't check /sys on macos

    commit 8a49d8cf45
    Merge: 1556388 008fcd8
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Aug 26 19:18:07 2023 +0200

        Merge pull request #600 from joske/makefile

        [macos/freebsd] support gcc13

    commit 1556388c83
    Merge: 1b126f5 d17e1a2
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sat Aug 26 19:14:00 2023 +0200

        Merge pull request #599 from joske/main

        [macos] fix temp sensor on system with many cores

    commit d17e1a2dac
    Author: Jos Dehaes <jos.dehaes@gmail.com>
    Date:   Fri Aug 25 16:18:39 2023 +0200

        fix some warnings

    commit 4d8aa6b118
    Author: Jos Dehaes <jos.dehaes@gmail.com>
    Date:   Fri Aug 25 15:52:58 2023 +0200

        fix core check

    commit 22e64caaff
    Author: Jonathan Fouquart <jfouquart@hotmail.fr>
    Date:   Fri Aug 25 09:37:49 2023 +0200

        Fix getting zfs pool name with '.' char in freebsd

    commit 2217cbe143
    Author: Jos Dehaes <jos.dehaes@gmail.com>
    Date:   Wed Aug 23 16:01:04 2023 +0200

        [macos] don't check /sys on macos

    commit 008fcd889e
    Author: Jos Dehaes <jos.dehaes@gmail.com>
    Date:   Wed Aug 23 16:05:00 2023 +0200

        also add g++13

    commit 0fdca5eb03
    Author: Jos Dehaes <jos.dehaes@gmail.com>
    Date:   Wed Aug 23 15:54:07 2023 +0200

        support gcc13

    commit dcbdb7360d
    Author: Jos Dehaes <jos.dehaes@gmail.com>
    Date:   Wed Aug 23 15:46:47 2023 +0200

        [macos] fix temp sensor on system with many cores

    commit 1b126f55e3
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Fri Aug 4 01:08:27 2023 +0200

        Update Makefile for partial static compilation on freebsd

    commit c8ec6bbb00
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Thu Aug 3 23:08:33 2023 +0200

        Fix freebsd nullptr changes and makefile for gcc12 and newer

    commit 8a33aab588
    Merge: 94e5c02 e4abcef
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Sun Jul 30 13:21:48 2023 +0200

        Merge pull request #539 from nobounce/replace-NULL-nullptr

        Modernize using nullptr.

    commit 94e5c02d11
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Thu Jul 27 20:51:21 2023 +0200

        Better text editing

    commit 091c30ab2b
    Author: nobounce <steffen.winter@proton.me>
    Date:   Thu Jul 27 14:17:54 2023 +0200

        Convert parameters and config keys to std::string_view

        Using std::string_view instead of std::string& silences a new warning
        from GCC 13, -Wdangling-reference

        Also switch return type of `getI` from int& to int, trivial types are
        cheaper to copy by value

    commit e4abcefbf9
    Author: nobounce <steffen.winter@proton.me>
    Date:   Wed Jul 26 16:19:17 2023 +0200

        Use nullptr instead of NULL.

        See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
        TLDR: NULL is of type int and relies on proper implicit pointer
        conversion which may lead to issues when using overloaded functions

        It is also considered a 'best practise' for modern C++ and
        conveys the programmers intention more precisly.

    commit d53307f14c
    Author: nobounce <steffen.winter@proton.me>
    Date:   Sun Jul 23 19:53:36 2023 +0200

        Fix path to Linux CI file in itself

        The CI file has a list of dependent files including itself. The path was
        not updated when the CI was split into different files

    commit 594f42b9eb
    Merge: aca2e4b 53d6eba
    Author: Jakob P. Liljenberg <admin@qvantnet.com>
    Date:   Wed Jul 26 15:38:01 2023 +0200

        Merge pull request #584 from nobounce/nb/fix-ci-path

        Fix path to Linux CI file in itself

    commit aca2e4be75
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Wed Jul 26 14:38:48 2023 +0200

        Fix whitespace indent -> tab indent

    commit 33faa01910
    Author: aristocratos <gnmjpl@gmail.com>
    Date:   Wed Jul 26 14:34:15 2023 +0200

        Revert fmt submodule to static fmt folder in include

    commit 53d6ebabc0
    Author: nobounce <steffen.winter@proton.me>
    Date:   Sun Jul 23 19:53:36 2023 +0200

        Fix path to Linux CI file in itself

        The CI file has a list of dependent files including itself. The path was
        not updated when the CI was split into different files

commit 346c9e479b
Author: romner <roman@skotnica.com>
Date:   Wed Jul 19 16:53:58 2023 +0200

    Fix GPU text overflow in CPU panel, again

commit 3a5e5fd5d3
Author: romner <roman@skotnica.com>
Date:   Wed Jul 19 16:22:45 2023 +0200

    Improve 0-10 key input

commit 972b2b6a01
Author: romner <roman@skotnica.com>
Date:   Wed Jul 19 15:54:35 2023 +0200

    Fix available boxes in menu & config description

commit 1f73453aec
Author: romner <roman@skotnica.com>
Date:   Wed Jul 19 15:34:23 2023 +0200

    Fix crashes when trying to open nth GPU box with only n-1 GPUs in the system

commit 46c6be0a29
Author: romner <roman@skotnica.com>
Date:   Sun Jul 16 17:19:09 2023 +0200

    Fix GPU horizontal text overflow in CPU panel

commit 85fb28cee6
Author: romner <roman@skotnica.com>
Date:   Fri Jul 14 02:39:44 2023 +0200

    Fix RSMI_STATIC=true and add GPU section to README.md

commit 3fad8a6fde
Author: romner-set <roman@skotnica.com>
Date:   Mon Jun 26 13:10:31 2023 +0200

    Add GPU options

commit 746f716a02
Author: romner-set <roman@skotnica.com>
Date:   Fri Jun 16 11:11:57 2023 +0200

    Remove lib/rocm_smi_lib and add instructions for obtaining it to README

commit d8ebbe1181
Author: romner <roman@skotnica.com>
Date:   Thu Jun 8 20:24:01 2023 +0200

    Join NVML PCIe threads only if PCIe TX/RX is supported by GPU

commit be10989151
Author: romner <roman@skotnica.com>
Date:   Tue Jun 6 19:47:07 2023 +0200

    Parallelize NVML PCIe TX/RX data collection

commit 85892a9fe3
Author: aristocratos <gnmjpl@gmail.com>
Date:   Mon Jun 5 21:59:26 2023 +0200

    Fix type: ulong -> size_t and compare std::cmp_less

commit 85a10f0305
Author: romner <roman@skotnica.com>
Date:   Fri Jun 2 16:14:24 2023 +0200

    Fix ROCm SMI makefile flags

commit cd6979277d
Author: romner <roman@skotnica.com>
Date:   Fri Jun 2 15:44:44 2023 +0200

    Fix error when ROCm SMI static compilation fails

commit daaa45324f
Author: romner <roman@skotnica.com>
Date:   Fri Jun 2 15:34:12 2023 +0200

    Load ROCm SMI dynamically by default, optionally statically compile and link

commit 093edfe948
Author: aristocratos <gnmjpl@gmail.com>
Date:   Thu Jun 1 19:49:00 2023 +0200

    Minor changes in wording...

commit b9a4d31fa4
Author: aristocratos <gnmjpl@gmail.com>
Date:   Thu Jun 1 19:37:53 2023 +0200

    Fix Makefile dependency order and layout

commit a0163ce220
Author: romner <roman@skotnica.com>
Date:   Thu Jun 1 16:42:02 2023 +0200

    Statically link ROCm SMI

commit b2df0696fd
Author: romner-set <roman@skotnica.com>
Date:   Thu Jun 1 03:41:56 2023 +0200

    Dynamically load NVML

commit 547f17dda3
Author: romner-set <roman@skotnica.com>
Date:   Tue May 30 18:24:50 2023 +0200

    Add more GPU graph types to the CPU panel

commit 842c761a73
Author: romner-set <roman@skotnica.com>
Date:   Mon May 22 09:46:20 2023 +0200

    Fix crash when all GPU panels are open but the CPU panel is closed

commit 8c96bd51e9
Author: romner <roman@skotnica.com>
Date:   Sun May 21 20:34:47 2023 +0200

    Handle GPUs which cannot report certain stats in GPU panel

commit 414d7eb94c
Author: romner <roman@skotnica.com>
Date:   Sun May 21 18:02:50 2023 +0200

    Handle GPUs which cannot report certain stats in btop_collect.cpp and CPU panel

commit 005de97e6d
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun May 21 13:58:11 2023 +0200

    Add missing fmt prefixes

commit 1fee2bc08b
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sun May 21 13:52:19 2023 +0200

    Add DebugTimer class and change some Logger::error calls to Logger::debug

commit 2e68c0b916
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat May 20 17:27:20 2023 +0200

    Fixed key > gpu_names check

commit 04ed16a9f6
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat May 20 17:15:45 2023 +0200

    Merged changes from main

commit 8c710a2b68
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat May 20 01:41:04 2023 +0200

    Makefile auto detection and initial logic for excluding gpu code when libs are missing

commit 8bae1ec092
Author: aristocratos <gnmjpl@gmail.com>
Date:   Sat May 20 00:13:00 2023 +0200

    Fixed debug timer for gpu

commit 01acfd603e
Author: romner-set <roman@skotnica.com>
Date:   Fri May 19 16:42:32 2023 +0200

    Bind GPU panel to 5,6,7,8,9,0 and fully implement multi-GPU support

commit 22a463976d
Author: romner <roman@skotnica.com>
Date:   Thu May 18 16:07:05 2023 +0200

    Add GPU info to CPU panel

commit c352bf2613
Author: romner-set <roman@skotnica.com>
Date:   Mon May 15 19:42:55 2023 +0200

    Add ROCm SMI backend for AMD GPU support

commit 917d568a77
Author: romner-set <roman@skotnica.com>
Date:   Mon May 15 13:58:54 2023 +0200

    Add multi-GPU support for NVML data collection

commit 2d27f2ff61
Author: romner <roman@skotnica.com>
Date:   Sun May 14 17:40:50 2023 +0200

    Fix crash when no nvidia GPU is detected

commit 0e0025a2c3
Author: romner <roman@skotnica.com>
Date:   Sun May 14 17:31:39 2023 +0200

    Update makefile text, fix typo and adhere to contibuting guidelines

commit bcffcdf19f
Author: romner <roman@skotnica.com>
Date:   Sun May 14 16:53:06 2023 +0200

    Make GPU window's size dynamic and integrate it with the rest of btop

commit 95b3228308
Author: romner <roman@skotnica.com>
Date:   Sat May 13 19:41:51 2023 +0200

    Improve GPU side panel

commit adcdc583b0
Author: romner <roman@skotnica.com>
Date:   Sat May 13 00:27:23 2023 +0200

    Add GPU side panel

commit d522a91ef4
Author: romner <roman@skotnica.com>
Date:   Fri May 12 19:34:47 2023 +0200

    Add rudimentary, fullscreen single-GPU NVML utilization graph
This commit is contained in:
aristocratos 2024-01-02 15:29:53 +01:00
parent 33595a2c9e
commit 934a9e3cf2
39 changed files with 3217 additions and 2997 deletions

View file

@ -1,4 +1,4 @@
[*.{cpp,h,sh,md,cfg,sample}]
[*.{cpp,h,hpp,sh,md,cfg,sample}]
indent_style = tab
indent_size = 4

View file

@ -29,6 +29,7 @@ Any bug that can be solved by just reading the [prerequisites](https://github.co
**Info (please complete the following information):**
- btop++ version: `btop -v`
- If using snap: `snap info btop`
- Binary: [self compiled or static binary from release]
- (If compiled) Compiler and version:
- Architecture: [x86_64, aarch64, etc.] `uname -m`
@ -40,7 +41,9 @@ Any bug that can be solved by just reading the [prerequisites](https://github.co
**Additional context**
contents of `~/.config/btop/btop.log`
Contents of `~/.config/btop/btop.log`
Note: The snap uses: `~/snap/btop/current/.config/btop`
(try running btop with `--debug` flag if btop.log is empty)

40
.github/workflows/cmake-freebsd.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: FreeBSD CMake
on:
push:
branches: main
tags-ignore: '*.*'
paths:
- '.github/workflows/cmake-freebsd.yml'
- 'CMakeLists.txt'
- 'include/**'
- 'src/*pp'
- 'src/freebsd/*pp'
pull_request:
branches: main
paths:
- '.github/workflows/cmake-freebsd.yml'
- 'CMakeLists.txt'
- 'include/**'
- 'src/*pp'
- 'src/freebsd/*pp'
jobs:
cmake_build_on_freebsd:
runs-on: ubuntu-22.04
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- name: Compile
uses: vmactions/freebsd-vm@v1
with:
release: '14.0'
usesh: true
prepare: pkg install -y cmake ninja
run: |
CXX=clang++ cmake -B build -G Ninja -DBTOP_STATIC=ON
cmake --build build --verbose

40
.github/workflows/cmake-linux.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: Linux CMake
on:
push:
branches: main
tags-ignore: '*.*'
paths:
- '.github/workflows/cmake-linux.yml'
- 'CMakeLists.txt'
- 'include/**'
- 'src/*pp'
- 'src/linux/*pp'
pull_request:
branches: main
paths:
- '.github/workflows/cmake-linux.yml'
- 'CMakeLists.txt'
- 'include/**'
- 'src/*pp'
- 'src/linux/*pp'
jobs:
cmake_build_on_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 clang cmake lld ninja
- name: Configure
run: CXX=clang++ LDFLAGS=-fuse-ld=lld cmake -B build -G Ninja -DBTOP_STATIC=ON
- name: Compile
run: cmake --build build --verbose

47
.github/workflows/cmake-macos.yml vendored Normal file
View file

@ -0,0 +1,47 @@
name: macOS CMake
on:
push:
branches: main
tags-ignore: '*.*'
paths:
- '.github/workflows/cmake-macos.yml'
- 'CMakeLists.txt'
- 'include/**'
- 'src/*pp'
- 'src/osx/*pp'
pull_request:
branches: main
paths:
- '.github/workflows/cmake-macos.yml'
- 'CMakeLists.txt'
- 'include/**'
- 'src/*pp'
- 'src/osx/*pp'
jobs:
cmake_build_on_macos:
runs-on: macos-latest
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: |
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
brew update --quiet
brew install --force --overwrite cmake llvm@17 ninja
- name: Configure
run: |
export LLVM_PREFIX="$(brew --prefix llvm)"
export CXX="$LLVM_PREFIX/bin/clang++"
export CPPFLAGS="-I$LLVM_PREFIX/include"
export LDFLAGS="-L$LLVM_PREFIX/lib -L$LLVM_PREFIX/lib/c++ -Wl,-rpath,$LLVM_PREFIX/lib/c++ -fuse-ld=$LLVM_PREFIX/bin/ld64.lld"
cmake -B build -G Ninja
- name: Compile
run: cmake --build build --verbose

View file

@ -27,28 +27,34 @@ on:
jobs:
build-freebsd:
runs-on: macos-12
runs-on: ubuntu-22.04
timeout-minutes: 20
strategy:
matrix:
compiler: ["clang++", "g++"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Compile
uses: vmactions/freebsd-vm@v0
uses: vmactions/freebsd-vm@v1
with:
release: 13.2
release: '14.0'
usesh: true
prepare: |
pkg install -y gmake gcc11 coreutils git
git config --global --add safe.directory /Users/runner/work/btop/btop
pkg install -y gmake gcc coreutils git
git config --global --add safe.directory /home/runner/work/btop/btop
run: |
gmake STATIC=true STRIP=true
CXX=${{ matrix.compiler }} gmake STATIC=true STRIP=true
GIT_HASH=$(git rev-parse --short "$GITHUB_SHA")
mv bin/btop bin/btop-$GIT_HASH
COMPILER=$(echo ${{ matrix.compiler }} | sed 's/clang++/llvm/' | sed 's/g++/gcc/')
mv bin/btop bin/btop-"$COMPILER"-"$GIT_HASH"
ls -alh bin
- uses: actions/upload-artifact@v3
with:
name: btop-x86_64-FreeBSD-13.2
name: btop-x86_64-freebsd-14
path: 'bin/*'
if-no-files-found: error

View file

@ -0,0 +1,42 @@
name: 🧪 Test snap can be built on x86_64
on:
workflow_dispatch:
push:
branches: [ main ]
tags-ignore:
- '*.*'
paths:
- 'src/**'
- '!src/osx/**'
- '!src/freebsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/test-snap-can-build.yml'
pull_request:
branches: [ main ]
paths:
- 'src/**'
- '!src/osx/**'
- '!src/freebsd/**'
- 'include/**'
- 'Makefile'
- '.github/workflows/test-snap-can-build.yml'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
steps:
- uses: actions/checkout@v2
- uses: snapcore/action-build@v1
id: build
- uses: diddlesnaps/snapcraft-review-action@v1
with:
snap: ${{ steps.build.outputs.snap }}
isClassic: 'false'

22
.gitignore vendored
View file

@ -51,9 +51,11 @@ bin
btop
.*/
# 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
@ -64,3 +66,19 @@ btop
*.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-*

View file

@ -1,3 +1,49 @@
## v1.3.0
* Added Gpu Support | @romner-set | PR #529
* Enable macos clang | @muneebmahmed | PR #666
* Fix Apple Silicon CPUs misprinted | @masiboss | PR #679
* Cmake support for MacOS | @imwints | PR #675
* Elementarish theme: color update according to Elementary palette | @stradicat | PR #660
* Add alternative key codes for Delete, Insert, Home, End | @ivanp7 | PR #659
* Fix scrollbar not clearing sometimes. | @DecklynKern | PR #643
* Add keybind for toggling memory display mode in PROC box | @rahulaggarwal965 | PR #623
* Minor string initialization improvement | @imwints | PR #636
* Made disks statvfs logic asynchronous. | @crestfallnatwork | PR #633
* Fix signal list on non-linux/weird linux platforms | @lvxnull | PR #630
* Add option to accumulate a child's resources in parent in tree-view | @imwints | PR #618
* Add CMake support for Linux | @imwints | PR #589
* Horizon theme | @SidVeld | PR #610
* Fix short conversion of 1000-1023 *iB | @scorpion-26 | #609
* Fix integer overflows in btop_collect.cpp | @dorrellmw | #546
* Support compiling with LLVM | @imwints | #510
* Fix getting zfs pool name with '.' char in freebsd | @jfouquart | #602
* [macos/freebsd] support gcc13 | @joske | #600
* FreeBSD swap info | @rrveex | #560
* Create adwaita.theme | @flipflop133 | #485
+ Various fixes by @imwints, @simplepad, @joske, @gwena, @cpalv, @iambeingtracked, @mattico, @NexAdn
## v1.2.13
* Makefile: VERBOSE=true flag for Makefile to display all compiler commands and fixed so already set CXXFLAGS and LDFLAGS are displayed.

194
CMakeLists.txt Normal file
View file

@ -0,0 +1,194 @@
# SPDX-License-Identifier: Apache-2.0
#
# CMake configuration for btop
#
cmake_minimum_required(VERSION 3.24)
# 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
)
include(CheckCXXCompilerFlag)
include(CheckIncludeFileCXX)
include(CheckIPOSupported)
include(CMakeDependentOption)
# Make our Find<Package>.cmake files 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)
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)
option(BTOP_GPU "Enable GPU support" ON)
cmake_dependent_option(BTOP_RSMI_STATIC "Link statically to ROCm SMI" OFF "BTOP_GPU" OFF)
if(BTOP_STATIC AND NOT APPLE)
# Set this before calling find_package
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
endif()
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
)
if(APPLE)
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(LINUX)
target_sources(btop PRIVATE src/linux/btop_collect.cpp)
else()
message(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supported")
endif()
check_include_file_cxx(ranges CXX_HAVE_RANGES)
if(NOT CXX_HAVE_RANGES)
message(FATAL_ERROR "The compiler doesn't support <ranges>")
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()
target_compile_options(btop PRIVATE -Wall -Wextra -Wpedantic -ftree-vectorize)
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++
$<$<CXX_COMPILER_ID:Clang>:-Wheader-hygiene -Wgnu -Wthread-safety>
$<$<CXX_COMPILER_ID:GNU>:-Wduplicated-cond -Wduplicated-branches -Wlogical-op>
$<$<CXX_COMPILER_ID:GNU>:-Wnull-dereference -Wuseless-cast>
)
endif()
if(BTOP_WERROR)
target_compile_options(btop PRIVATE -Werror)
endif()
if(NOT APPLE)
target_compile_options(btop PRIVATE -fstack-clash-protection)
endif()
check_cxx_compiler_flag(-fstack-protector HAS_FSTACK_PROTECTOR)
if(HAS_FSTACK_PROTECTOR)
target_compile_options(btop PRIVATE -fstack-protector)
endif()
check_cxx_compiler_flag(-fcf-protection HAS_FCF_PROTECTION)
if(HAS_FCF_PROTECTION)
target_compile_options(btop PRIVATE -fcf-protection)
endif()
target_compile_definitions(btop PRIVATE
_FILE_OFFSET_BITS=64
$<$<CONFIG:Debug>:_GLIBCXX_ASSERTIONS _LIBCPP_ENABLE_ASSERTIONS=1>
# Only has an effect with optimizations enabled
$<$<NOT:$<CONFIG:Debug>>:_FORTIFY_SOURCE=2>
)
target_include_directories(btop SYSTEM PRIVATE include)
# Enable pthreads
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(btop Threads::Threads)
# Enable GPU support
if(LINUX AND BTOP_GPU)
target_compile_definitions(btop PRIVATE GPU_SUPPORT)
if(BTOP_RSMI_STATIC)
# ROCm doesn't properly add it's folders to the module path if `CMAKE_MODULE_PATH` is already
# set
# We could also manully append ROCm's path here
set(_CMAKE_MODULE_PATH CMAKE_MODULE_PATH)
unset(CMAKE_MODULE_PATH)
# NOTE: This might be problematic in the future if other sub projects depend on this or if
# btop starts producing libraries
# Build a static ROCm library
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
add_subdirectory(lib/rocm_smi_lib EXCLUDE_FROM_ALL)
add_library(ROCm INTERFACE)
# Export ROCm's properties to a target
target_compile_definitions(ROCm INTERFACE RSMI_STATIC)
target_include_directories(ROCm INTERFACE lib/rocm_smi_lib/include)
target_link_libraries(ROCm INTERFACE rocm_smi64)
set(CMAKE_MODULE_PATH _CMAKE_MODULE_PATH)
target_link_libraries(btop ROCm)
endif()
endif()
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()
# Other platform depdendent flags
if(APPLE)
target_link_libraries(btop
$<LINK_LIBRARY:FRAMEWORK,CoreFoundation> $<LINK_LIBRARY:FRAMEWORK,IOKit>
)
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
# Avoid version mismatch for libstdc++ when a specific version of GCC is installed and not the
# default one since all use the default ones RPATH
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
string(REGEX MATCH "^[0-9]+" GCC_VERSION_MAJOR "${CMAKE_CXX_COMPILER_VERSION}")
set_target_properties(btop PROPERTIES
INSTALL_RPATH "/usr/local/lib/gcc${GCC_VERSION_MAJOR}"
BUILD_WITH_INSTALL_RPATH TRUE
)
endif()
find_package(devstat REQUIRED)
target_link_libraries(btop devstat::devstat)
if(BTOP_STATIC)
find_package(elf REQUIRED)
find_package(kvm REQUIRED)
target_link_libraries(btop elf::elf kvm::kvm)
endif()
endif()
install(TARGETS btop RUNTIME)
install(FILES "btop.desktop" DESTINATION "share/applications")
install(FILES "Img/icon.png" DESTINATION "share/icons/hicolor/48x48/apps" RENAME "btop.png")
install(FILES "Img/icon.svg" DESTINATION "share/icons/hicolor/scalable/apps" RENAME "btop.svg")
install(DIRECTORY "themes" DESTINATION "share/btop")

101
Makefile
View file

@ -12,10 +12,7 @@ else
endif
ifneq ($(QUIET),true)
override PRE := info info-quiet
override QUIET := false
else
override PRE := info-quiet
endif
OLDCXX := $(CXXFLAGS)
@ -39,6 +36,20 @@ endif
override PLATFORM_LC := $(shell echo $(PLATFORM) | tr '[:upper:]' '[:lower:]')
#? GPU Support
ifeq ($(PLATFORM_LC)$(ARCH),linuxx86_64)
ifneq ($(STATIC),true)
GPU_SUPPORT := true
endif
endif
ifneq ($(GPU_SUPPORT),true)
GPU_SUPPORT := false
endif
ifeq ($(GPU_SUPPORT),true)
override ADDFLAGS += -DGPU_SUPPORT
endif
#? Compiler and Linker
ifeq ($(shell $(CXX) --version | grep clang >/dev/null 2>&1; echo $$?),0)
override CXX_IS_CLANG := true
@ -48,10 +59,18 @@ override CXX_VERSION_MAJOR := $(shell echo $(CXX_VERSION) | cut -d '.' -f 1)
CLANG_WORKS = false
GCC_WORKS = false
MIN_CLANG_VERSION = 16
ifeq ($(DEBUG),true)
override ADDFLAGS += -DBTOP_DEBUG
endif
#? Supported is Clang 16.0.0 and later
ifeq ($(CXX_IS_CLANG),true)
ifneq ($(shell test $(CXX_VERSION_MAJOR) -lt 16; echo $$?),0)
ifeq ($(shell $(CXX) --version | grep Apple >/dev/null 2>&1; echo $$?),0)
MIN_CLANG_VERSION := 15
endif
ifneq ($(shell test $(CXX_VERSION_MAJOR) -lt $(MIN_CLANG_VERSION); echo $$?),0)
CLANG_WORKS := true
endif
endif
@ -214,24 +233,38 @@ endif
P := %%
#? Default Make
all: $(PRE) directories btop
ifeq ($(VERBOSE),true)
# Doesn't work with `&>`
override SUPPRESS := > /dev/null 2> /dev/null
else
override SUPPRESS :=
endif
#? Default Make
.ONESHELL:
all: | info rocm_smi info-quiet directories btop
ifneq ($(QUIET),true)
info:
@printf " $(BANNER)\n"
@printf "\033[1;92mPLATFORM \033[1;93m?| \033[0m$(PLATFORM)\n"
@printf "\033[1;96mARCH \033[1;93m?| \033[0m$(ARCH)\n"
@printf "\033[1;93mCXX \033[1;93m?| \033[0m$(CXX) \033[1;93m(\033[97m$(CXX_VERSION)\033[93m)\n"
@printf "\033[1;94mTHREADS \033[1;94m:| \033[0m$(THREADS)\n"
@printf "\033[1;92mREQFLAGS \033[1;91m!| \033[0m$(REQFLAGS)\n"
@printf "\033[1;91mWARNFLAGS \033[1;94m:| \033[0m$(WARNFLAGS)\n"
@printf "\033[1;94mOPTFLAGS \033[1;94m:| \033[0m$(OPTFLAGS)\n"
@printf "\033[1;93mLDCXXFLAGS \033[1;94m:| \033[0m$(LDCXXFLAGS)\n"
@printf "\033[1;95mCXXFLAGS \033[1;92m+| \033[0;37m\$$(\033[92mREQFLAGS\033[37m) \$$(\033[93mLDCXXFLAGS\033[37m) \$$(\033[94mOPTFLAGS\033[37m) \$$(\033[91mWARNFLAGS\033[37m) $(OLDCXX)\n"
@printf "\033[1;95mLDFLAGS \033[1;92m+| \033[0;37m\$$(\033[93mLDCXXFLAGS\033[37m) \$$(\033[94mOPTFLAGS\033[37m) \$$(\033[91mWARNFLAGS\033[37m) $(OLDLD)\n"
@printf "\033[1;92mPLATFORM \033[1;93m?| \033[0m$(PLATFORM)\n"
@printf "\033[1;96mARCH \033[1;93m?| \033[0m$(ARCH)\n"
@printf "\033[1;95mGPU_SUPPORT \033[1;94m:| \033[0m$(GPU_SUPPORT)\n"
@printf "\033[1;93mCXX \033[1;93m?| \033[0m$(CXX) \033[1;93m(\033[97m$(CXX_VERSION)\033[93m)\n"
@printf "\033[1;94mTHREADS \033[1;94m:| \033[0m$(THREADS)\n"
@printf "\033[1;92mREQFLAGS \033[1;91m!| \033[0m$(REQFLAGS)\n"
@printf "\033[1;91mWARNFLAGS \033[1;94m:| \033[0m$(WARNFLAGS)\n"
@printf "\033[1;94mOPTFLAGS \033[1;94m:| \033[0m$(OPTFLAGS)\n"
@printf "\033[1;93mLDCXXFLAGS \033[1;94m:| \033[0m$(LDCXXFLAGS)\n"
@printf "\033[1;95mCXXFLAGS \033[1;92m+| \033[0;37m\$$(\033[92mREQFLAGS\033[37m) \$$(\033[93mLDCXXFLAGS\033[37m) \$$(\033[94mOPTFLAGS\033[37m) \$$(\033[91mWARNFLAGS\033[37m) $(OLDCXX)\n"
@printf "\033[1;95mLDFLAGS \033[1;92m+| \033[0;37m\$$(\033[93mLDCXXFLAGS\033[37m) \$$(\033[94mOPTFLAGS\033[37m) \$$(\033[91mWARNFLAGS\033[37m) $(OLDLD)\n"
else
info:
@true
endif
info-quiet:
@sleep 0.1 2>/dev/null || true
info-quiet: | info rocm_smi
@printf "\n\033[1;92mBuilding btop++ \033[91m(\033[97mv$(BTOP_VERSION)\033[91m) \033[93m$(PLATFORM) \033[96m$(ARCH)\033[0m\n"
help:
@ -258,11 +291,13 @@ directories:
clean:
@printf "\033[1;91mRemoving: \033[1;97mbuilt objects...\033[0m\n"
@rm -rf $(BUILDDIR)
@test -e lib/rocm_smi_lib/build && cmake --build lib/rocm_smi_lib/build --target clean &> /dev/null || true
#? Clean Objects and Binaries
distclean: clean
@printf "\033[1;91mRemoving: \033[1;97mbuilt binaries...\033[0m\n"
@rm -rf $(TARGETDIR)
@test -e lib/rocm_smi_lib/build && rm -rf lib/rocm_smi_lib/build || true
install:
@printf "\033[1;92mInstalling binary to: \033[1;97m$(DESTDIR)$(PREFIX)/bin/btop\n"
@ -308,9 +343,35 @@ uninstall:
#? Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
#? Compile rocm_smi
ifeq ($(GPU_SUPPORT)$(RSMI_STATIC),truetrue)
ROCM_DIR ?= lib/rocm_smi_lib
ROCM_BUILD_DIR := $(ROCM_DIR)/build
ifeq ($(DEBUG),true)
BUILD_TYPE := Debug
else
BUILD_TYPE := Release
endif
.ONESHELL:
rocm_smi:
@printf "\n\033[1;92mBuilding ROCm SMI static library\033[37m...\033[0m\n"
@TSTAMP=$$(date +%s 2>/dev/null || echo "0")
@$(QUIET) || printf "\033[1;97mRunning CMake...\033[0m\n"
CXX=$(CXX) cmake -S $(ROCM_DIR) -B $(ROCM_BUILD_DIR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DBUILD_SHARED_LIBS=OFF $(SUPPRESS) || { printf "\033[1;91mCMake failed, continuing build without statically linking ROCm SMI\033[37m...\033[0m\n"; exit 0; }
@$(QUIET) || printf "\n\033[1;97mBuilding and linking...\033[0m\n"
@cmake --build $(ROCM_BUILD_DIR) -j -t rocm_smi64 $(SUPPRESS) || { printf "\033[1;91mMake failed, continuing build without statically linking ROCm SMI\033[37m...\033[0m\n"; exit 0; }
@printf "\033[1;92m100$(P)\033[10D\033[5C-> \033[1;37m$(ROCM_BUILD_DIR)/rocm_smi/librocm_smi64.a \033[1;93m(\033[1;97m$$(du -ah $(ROCM_BUILD_DIR)/rocm_smi/librocm_smi64.a | cut -f1)iB\033[1;93m)\033[0m\n"
@printf "\033[1;92mROCm SMI build complete in \033[92m(\033[97m$$($(DATE_CMD) -d @$$(expr $$(date +%s 2>/dev/null || echo "0") - $(TIMESTAMP) 2>/dev/null) -u +%Mm:%Ss 2>/dev/null | sed 's/^00m://' || echo "unknown")\033[92m)\033[0m\n"
@$(eval override LDFLAGS += $(ROCM_BUILD_DIR)/rocm_smi/librocm_smi64.a -DRSMI_STATIC) # TODO: this seems to execute every time, no matter if the compilation failed or succeeded
@$(eval override CXXFLAGS += -DRSMI_STATIC)
else
rocm_smi:
@true
endif
#? Link
.ONESHELL:
btop: $(OBJECTS) | directories
btop: $(OBJECTS) | rocm_smi directories
@sleep 0.2 2>/dev/null || true
@TSTAMP=$$(date +%s 2>/dev/null || echo "0")
@$(QUIET) || printf "\n\033[1;92mLinking and optimizing binary\033[37m...\033[0m\n"
@ -321,7 +382,7 @@ btop: $(OBJECTS) | directories
#? Compile
.ONESHELL:
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) | directories
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT) | rocm_smi directories
@sleep 0.3 2>/dev/null || true
@TSTAMP=$$(date +%s 2>/dev/null || echo "0")
@$(QUIET) || printf "\033[1;97mCompiling $<\033[0m\n"

459
README.md
View file

@ -33,12 +33,33 @@
* [Compilation Linux](#compilation-linux)
* [Compilation macOS](#compilation-macos-osx)
* [Compilation FreeBSD](#compilation-freebsd)
* [GPU compatibility](#gpu-compatibility)
* [Installing the snap](#installing-the-snap)
* [Configurability](#configurability)
* [License](#license)
## News
##### 25 November 2023
GPU monitoring added for Linux!
Compile from git main to try it out.
Use keys `5`, `6`, `7` and `0` to show/hide the gpu monitoring boxes. `5` = Gpu 1, `6` = Gpu 2, etc.
Gpu stats/graphs can also be displayed in the "Cpu box" (not as verbose), see the cpu options menu for info and configuration.
Note that the binaries provided on the release page (when released) and the continuous builds will not have gpu support enabled.
Because the GPU support relies on loading of dynamic gpu libraries, gpu support will not work when also static linking.
See [Compilation Linux](#compilation-linux) for more info on how to compile with gpu monitoring support.
Many thanks to [@romner-set](https://github.com/romner-set) who wrote the vast majority of the implementation for GPU support.
Big update with version bump to 1.3 coming soon.
##### 28 August 2022
[![btop4win](https://github.com/aristocratos/btop4win/raw/master/Img/logo.png)](https://github.com/aristocratos/btop4win)
@ -305,16 +326,46 @@ Also needs a UTF8 locale and a font that covers:
## Compilation Linux
Needs GCC 10 or higher, (GCC 11 or above strongly recommended for better CPU efficiency in the compiled binary).
Requires at least GCC 10 or Clang 16.
The makefile also needs GNU coreutils and `sed` (should already be installed on any modern distribution).
For a `cmake` based build alternative see the [fork](https://github.com/jan-guenter/btop/tree/main) by @jan-guenter
### GPU compatibility
Btop++ supports NVIDIA and AMD GPUs out of the box on Linux x86_64, 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.
Gpu support will not work when static linking glibc (or musl, etc.)!
For x86_64 Linux the flag `GPU_SUPPORT` is automatically set to `true`, to manually disable gpu support set the flag to false, like:
`make GPU_SUPPORT=false` (or `cmake -DBTOP_GPU=false` with CMake)
* **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.
* **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.
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
git clone https://github.com/RadeonOpenCompute/rocm_smi_lib.git --depth 1 -b rocm-5.6.x lib/rocm_smi_lib
```
<details>
<summary>
### With Make
</summary>
1. **Install dependencies (example for Ubuntu 21.04 Hirsute)**
Use gcc-10 g++-10 if gcc-11 isn't available
```bash
sudo apt install coreutils sed git build-essential gcc-11 g++-11
```
@ -328,51 +379,51 @@ Also needs a UTF8 locale and a font that covers:
3. **Compile**
Append `VERBOSE=true` to display full compiler/linker commands.
Append `STATIC=true` for static compilation.
Notice! If using LDAP Authentication, usernames will show as UID number for LDAP users if compiling statically with glibc.
Append `QUIET=true` for less verbose output.
Append `STRIP=true` to force stripping of debug symbols (adds `-s` linker flag).
Append `ARCH=<architecture>` to manually set the target architecture.
If omitted the makefile uses the machine triple (output of `-dumpmachine` compiler parameter) to detect the target system.
Use `ADDFLAGS` variable for appending flags to both compiler and linker.
For example: `ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
If `g++` is linked to an older version of gcc on your system specify the correct version by appending `CXX=g++-10` or `CXX=g++-11`.
```bash
make
```
Options for make:
| Flag | Description |
|---------------------------------|-------------------------------------------------------------------------|
| `VERBOSE=true` | To display full compiler/linker commands |
| `STATIC=true` | For static compilation |
| `QUIET=true` | For less verbose output |
| `STRIP=true` | To force stripping of debug symbols (adds `-s` linker flag) |
| `DEBUG=true` | Sets OPTFLAGS to `-O0 -g` and enables more verbose debug logging |
| `ARCH=<architecture>` | To manually set the target architecture |
| `GPU_SUPPORT=<true\|false>` | Enable/disable GPU support (Enabled by default on X86_64 Linux) |
| `RSMI_STATIC=true` | To statically link the ROCm SMI library used for querying AMDGPU |
| `ADDFLAGS=<flags>` | For appending flags to both compiler and linker |
| `CXX=<compiler>` | Manualy set which compiler to use |
Example: `make ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
Notice! If using LDAP Authentication, usernames will show as UID number for LDAP users if compiling statically with glibc.
4. **Install**
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
```bash
sudo make install
```
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
5. **(Optional) Set suid bit to make btop always run as root (or other user)**
```bash
sudo make setuid
```
No need for `sudo` to enable signal sending to any process and to prevent /proc read permissions problems on some systems.
Run after make install and use same PREFIX if any was used at install.
Set `SU_USER` and `SU_GROUP` to select user and group, default is `root` and `root`
```bash
sudo make setuid
```
* **Uninstall**
```bash
@ -397,16 +448,94 @@ Also needs a UTF8 locale and a font that covers:
make help
```
</details>
<details>
<summary>
### With CMake (Community maintained)
</summary>
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=<ON\|OFF>` | Enables static linking (OFF by default) |
| `-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_GPU=<ON\|OFF>` | Enable GPU support (ON by default) |
| `-DBTOP_RSMI_STATIC=<ON\|OFF>` | Build and link the ROCm SMI library statically (OFF 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>
## Compilation macOS OSX
Needs GCC 10 or higher, (GCC 11 or above strongly recommended for better CPU efficiency in the compiled binary).
Requires at least GCC 10 or Clang 16.
GCC 12 needed for macOS Ventura. If you get linker errors on Ventura you'll need to upgrade your command line tools (Version 14.0) is bugged.
With GCC, version 12 (or better) is needed for macOS Ventura. If you get linker errors on Ventura you'll need to upgrade your command line tools (Version 14.0) is bugged.
The makefile also needs GNU coreutils and `sed`.
Install and use Homebrew or MacPorts package managers for easy dependency installation
<details>
<summary>
### With Make
</summary>
1. **Install dependencies (example for Homebrew)**
```bash
@ -419,50 +548,49 @@ Also needs a UTF8 locale and a font that covers:
git clone https://github.com/aristocratos/btop.git
cd btop
```
3. **Compile**
Append `VERBOSE=true` to display full compiler/linker commands.
Append `STATIC=true` for static compilation (only libgcc and libstdc++ will be static!).
Append `QUIET=true` for less verbose output.
Append `STRIP=true` to force stripping of debug symbols (adds `-s` linker flag).
Append `ARCH=<architecture>` to manually set the target architecture.
If omitted the makefile uses the machine triple (output of `-dumpmachine` compiler parameter) to detect the target system.
Use `ADDFLAGS` variable for appending flags to both compiler and linker.
For example: `ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
```bash
gmake
```
Options for make:
| Flag | Description |
|---------------------------------|-------------------------------------------------------------------------|
| `VERBOSE=true` | To display full compiler/linker commands |
| `STATIC=true` | For static compilation (only libgcc and libstdc++) |
| `QUIET=true` | For less verbose output |
| `STRIP=true` | To force stripping of debug symbols (adds `-s` linker flag) |
| `DEBUG=true` | Sets OPTFLAGS to `-O0 -g` and enables more verbose debug logging |
| `ARCH=<architecture>` | To manually set the target architecture |
| `ADDFLAGS=<flags>` | For appending flags to both compiler and linker |
| `CXX=<compiler>` | Manualy set which compiler to use |
Example: `gmake ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
4. **Install**
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
```bash
sudo gmake install
```
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
5. **(Recommended) Set suid bit to make btop always run as root (or other user)**
```bash
sudo gmake setuid
```
No need for `sudo` to see information for non user owned processes and to enable signal sending to any process.
Run after make install and use same PREFIX if any was used at install.
Set `SU_USER` and `SU_GROUP` to select user and group, default is `root` and `wheel`
```bash
sudo gmake setuid
```
* **Uninstall**
```bash
@ -487,12 +615,92 @@ Also needs a UTF8 locale and a font that covers:
gmake help
```
</details>
<details>
<summary>
### With CMake (Community maintained)
</summary>
1. **Install build dependencies**
Requires Clang, CMake, Ninja and Git
```bash
brew update --quiet
brew install cmake git llvm ninja
```
2. **Clone the repository**
```bash
git clone https://github.com/aristocratos/btop.git && cd btop
```
3. **Compile**
```bash
# Configure
export LLVM_PREFIX="$(brew --prefix llvm)"
export CXX="$LLVM_PREFIX/bin/clang++"
export CPPFLAGS="-I$LLVM_PREFIX/include"
export LDFLAGS="-L$LLVM_PREFIX/lib -L$LLVM_PREFIX/lib/c++ -Wl,-rpath,$LLVM_PREFIX/lib/c++ -fuse-ld=$LLVM_PREFIX/bin/ld64.lld"
cmake -B build -G Ninja
# Build
cmake --build build
```
_**Note:** btop uses lots of C++ 20 features, so it's necessary to be specific about the compiler and the standard library. If you get a compile with Apple-Clang or GCC, feel free to add the instructions here._
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) |
| `-DCMAKE_INSTALL_PREFIX=<path>` | The installation prefix ('/usr/local' by default) |
To force any specific 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>
## Compilation FreeBSD
Needs GCC 10 or higher, (GCC 11 or above strongly recommended for better CPU efficiency in the compiled binary).
Requires at least GCC 10 or Clang 16.
Note that GNU make (`gmake`) is required to compile on FreeBSD.
<details>
<summary>
### With gmake
</summary>
1. **Install dependencies**
```bash
@ -508,47 +716,47 @@ Also needs a UTF8 locale and a font that covers:
3. **Compile**
Append `VERBOSE=true` to display full compiler/linker commands.
Append `STATIC=true` for static compilation (only libgcc and libstdc++ will be static!).
Append `QUIET=true` for less verbose output.
Append `STRIP=true` to force stripping of debug symbols (adds `-s` linker flag).
Append `ARCH=<architecture>` to manually set the target architecture.
If omitted the makefile uses the machine triple (output of `-dumpmachine` compiler parameter) to detect the target system.
Use `ADDFLAGS` variable for appending flags to both compiler and linker.
For example: `ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
```bash
gmake
```
Options for make:
| Flag | Description |
|---------------------------------|-------------------------------------------------------------------------|
| `VERBOSE=true` | To display full compiler/linker commands |
| `STATIC=true` | For static compilation (only libgcc and libstdc++) |
| `QUIET=true` | For less verbose output |
| `STRIP=true` | To force stripping of debug symbols (adds `-s` linker flag) |
| `DEBUG=true` | Sets OPTFLAGS to `-O0 -g` and enables more verbose debug logging |
| `ARCH=<architecture>` | To manually set the target architecture |
| `ADDFLAGS=<flags>` | For appending flags to both compiler and linker |
| `CXX=<compiler>` | Manualy set which compiler to use |
Example: `gmake ADDFLAGS=-march=native` might give a performance boost if compiling only for your own system.
4. **Install**
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
```bash
sudo gmake install
```
Append `PREFIX=/target/dir` to set target, default: `/usr/local`
Notice! Only use "sudo" when installing to a NON user owned directory.
5. **(Recommended) Set suid bit to make btop always run as root (or other user)**
```bash
sudo gmake setuid
```
No need for `sudo` to see information for non user owned processes and to enable signal sending to any process.
Run after make install and use same PREFIX if any was used at install.
Set `SU_USER` and `SU_GROUP` to select user and group, default is `root` and `wheel`
```bash
sudo gmake setuid
```
* **Uninstall**
```bash
@ -573,6 +781,93 @@ Also needs a UTF8 locale and a font that covers:
gmake help
```
</details>
<details>
<summary>
### With CMake (Community maintained)
</summary>
1. **Install build dependencies**
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/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=<ON\|OFF>` | Enables static linking (OFF by default) |
| `-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) |
| `-DCMAKE_INSTALL_PREFIX=<path>` | The installation prefix ('/usr/local' by default) |
_**Note:** Static linking does not work with GCC._
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>
## Installing the snap
[![btop](https://snapcraft.io/btop/badge.svg)](https://snapcraft.io/btop)
@ -657,7 +952,7 @@ graph_symbol_net = "default"
# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty".
graph_symbol_proc = "default"
#* Manually set which boxes to show. Available values are "cpu mem net proc", separate values with whitespace.
#* Manually set which boxes to show. Available values are "cpu mem net proc" and "gpu0" through "gpu5", separate values with whitespace.
shown_boxes = "proc cpu mem net"
#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs.

View file

@ -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()

View file

@ -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()

View file

@ -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()

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,7 @@ apps:
- network-observe
- home
- removable-media
- opengl
parts:
btop:
@ -47,7 +48,6 @@ parts:
- PREFIX=/usr/local
- STATIC=true
- ADDFLAGS="-D SNAPPED"
build-packages:
- coreutils
- sed

View file

@ -32,6 +32,7 @@ tab-size = 4
#include <tuple>
#include <regex>
#include <chrono>
#include <utility>
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <mach-o/dyld.h>
@ -75,7 +76,7 @@ namespace Global {
{"#801414", "██████╔╝ ██║ ╚██████╔╝██║ ╚═╝ ╚═╝"},
{"#000000", "╚═════╝ ╚═╝ ╚═════╝ ╚═╝"},
};
const string Version = "1.2.13";
const string Version = "1.3.0";
int coreCount;
string overlay;
@ -183,8 +184,11 @@ void term_resize(bool force) {
if (force and refreshed) force = false;
}
else return;
static const array<string, 4> all_boxes = {"cpu", "mem", "net", "proc"};
#ifdef GPU_SUPPORT
static const array<string, 10> all_boxes = {"gpu5", "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4"};
#else
static const array<string, 5> all_boxes = {"", "cpu", "mem", "net", "proc"};
#endif
Global::resized = true;
if (Runner::active) Runner::stop();
Term::refresh();
@ -222,10 +226,18 @@ void term_resize(bool force) {
auto key = Input::get();
if (key == "q")
clean_quit(0);
else if (is_in(key, "1", "2", "3", "4")) {
Config::current_preset = -1;
Config::toggle_box(all_boxes.at(std::stoi(key) - 1));
boxes = Config::getS("shown_boxes");
else if (key.size() == 1 and isint(key)) {
auto intKey = stoi(key);
#ifdef GPU_SUPPORT
if ((intKey == 0 and Gpu::gpu_names.size() >= 5) or (intKey >= 5 and std::cmp_greater_equal(Gpu::gpu_names.size(), intKey - 4))) {
#else
if (intKey > 0 and intKey < 5) {
#endif
auto box = all_boxes.at(intKey);
Config::current_preset = -1;
Config::toggle_box(box);
boxes = Config::getS("shown_boxes");
}
}
}
min_size = Term::get_min_size(boxes);
@ -258,6 +270,11 @@ void clean_quit(int sig) {
#endif
}
#ifdef GPU_SUPPORT
Gpu::Nvml::shutdown();
Gpu::Rsmi::shutdown();
#endif
Config::write();
if (Term::initialized) {
@ -388,7 +405,9 @@ namespace Runner {
enum debug_actions {
collect_begin,
collect_done,
draw_begin,
draw_begin_only,
draw_done
};
@ -398,7 +417,7 @@ namespace Runner {
};
string debug_bg;
unordered_flat_map<string, array<uint64_t, 2>> debug_times;
std::unordered_map<string, array<uint64_t, 2>> debug_times;
class MyNumPunct : public std::numpunct<char>
{
@ -424,6 +443,13 @@ namespace Runner {
case collect_begin:
debug_times[name].at(collect) = time_micros();
return;
case collect_done:
debug_times[name].at(collect) = time_micros() - debug_times[name].at(collect);
debug_times["total"].at(collect) += debug_times[name].at(collect);
return;
case draw_begin_only:
debug_times[name].at(draw) = time_micros();
return;
case draw_begin:
debug_times[name].at(draw) = time_micros();
debug_times[name].at(collect) = debug_times[name].at(draw) - debug_times[name].at(collect);
@ -480,10 +506,14 @@ namespace Runner {
//! DEBUG stats
if (Global::debug) {
if (debug_bg.empty() or redraw)
Runner::debug_bg = Draw::createBox(2, 2, 33, 8, "", true, "μs");
if (debug_bg.empty() or redraw)
Runner::debug_bg = Draw::createBox(2, 2, 33,
#ifdef GPU_SUPPORT
9,
#else
8,
#endif
"", true, "μs");
debug_times.clear();
debug_times["total"] = {0, 0};
@ -493,6 +523,29 @@ namespace Runner {
//* Run collection and draw functions for all boxes
try {
#ifdef GPU_SUPPORT
//? GPU data collection
const bool gpu_in_cpu_panel = Gpu::gpu_names.size() > 0 and (
Config::getS("cpu_graph_lower").starts_with("gpu-") or Config::getS("cpu_graph_upper").starts_with("gpu-")
or (Gpu::shown == 0 and Config::getS("show_gpu_info") != "Off")
);
vector<unsigned int> gpu_panels = {};
for (auto& box : conf.boxes)
if (box.starts_with("gpu"))
gpu_panels.push_back(box.back()-'0');
vector<Gpu::gpu_info> gpus;
if (gpu_in_cpu_panel or not gpu_panels.empty()) {
if (Global::debug) debug_timer("gpu", collect_begin);
gpus = Gpu::collect(conf.no_update);
if (Global::debug) debug_timer("gpu", collect_done);
}
auto& gpus_ref = gpus;
#else
vector<Gpu::gpu_info> gpus_ref{};
#endif
//? CPU
if (v_contains(conf.boxes, "cpu")) {
try {
@ -512,7 +565,7 @@ namespace Runner {
if (Global::debug) debug_timer("cpu", draw_begin);
//? Draw box
if (not pause_output) output += Cpu::draw(cpu, conf.force_redraw, conf.no_update);
if (not pause_output) output += Cpu::draw(cpu, gpus_ref, conf.force_redraw, conf.no_update);
if (Global::debug) debug_timer("cpu", draw_done);
}
@ -520,7 +573,24 @@ namespace Runner {
throw std::runtime_error("Cpu:: -> " + string{e.what()});
}
}
#ifdef GPU_SUPPORT
//? GPU
if (not gpu_panels.empty() and not gpus_ref.empty()) {
try {
if (Global::debug) debug_timer("gpu", draw_begin_only);
//? Draw box
if (not pause_output)
for (unsigned long i = 0; i < gpu_panels.size(); ++i)
output += Gpu::draw(gpus_ref[gpu_panels[i]], i, conf.force_redraw, conf.no_update);
if (Global::debug) debug_timer("gpu", draw_done);
}
catch (const std::exception& e) {
throw std::runtime_error("Gpu:: -> " + string{e.what()});
}
}
#endif
//? MEM
if (v_contains(conf.boxes, "mem")) {
try {
@ -580,6 +650,7 @@ namespace Runner {
throw std::runtime_error("Proc:: -> " + string{e.what()});
}
}
}
catch (const std::exception& e) {
Global::exit_error_msg = "Exception in runner thread -> " + string{e.what()};
@ -610,8 +681,9 @@ namespace Runner {
"{mv3}{hiFg}2 {mainFg}| Show MEM box"
"{mv4}{hiFg}3 {mainFg}| Show NET box"
"{mv5}{hiFg}4 {mainFg}| Show PROC box"
"{mv6}{hiFg}esc {mainFg}| Show menu"
"{mv7}{hiFg}q {mainFg}| Quit",
"{mv6}{hiFg}5-0 {mainFg}| Show GPU boxes"
"{mv7}{hiFg}esc {mainFg}| Show menu"
"{mv8}{hiFg}q {mainFg}| Quit",
"banner"_a = Draw::banner_gen(y, 0, true),
"titleFg"_a = Theme::c("title"), "b"_a = Fx::b, "hiFg"_a = Theme::c("hi_fg"), "mainFg"_a = Theme::c("main_fg"),
"mv1"_a = Mv::to(y+6, x),
@ -620,7 +692,8 @@ namespace Runner {
"mv4"_a = Mv::to(y+10, x),
"mv5"_a = Mv::to(y+11, x),
"mv6"_a = Mv::to(y+12, x-2),
"mv7"_a = Mv::to(y+13, x)
"mv7"_a = Mv::to(y+13, x-2),
"mv8"_a = Mv::to(y+14, x)
);
}
output += empty_bg;
@ -634,7 +707,11 @@ namespace Runner {
"post"_a = Theme::c("main_fg") + Fx::ub
);
static auto loc = std::locale(std::locale::classic(), new MyNumPunct);
#ifdef GPU_SUPPORT
for (const string name : {"cpu", "mem", "net", "proc", "gpu", "total"}) {
#else
for (const string name : {"cpu", "mem", "net", "proc", "total"}) {
#endif
if (not debug_times.contains(name)) debug_times[name] = {0,0};
const auto& [time_collect, time_draw] = debug_times.at(name);
if (name == "total") output += Fx::b;

View file

@ -21,6 +21,7 @@ tab-size = 4
#include <fstream>
#include <ranges>
#include <string_view>
#include <utility>
#include <fmt/core.h>
@ -73,14 +74,16 @@ namespace Config {
"#* Note that \"tty\" only has half the horizontal resolution of the other two, so will show a shorter historical view."},
{"graph_symbol_cpu", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
#ifdef GPU_SUPPORT
{"graph_symbol_gpu", "# Graph symbol to use for graphs in gpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
#endif
{"graph_symbol_mem", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
{"graph_symbol_net", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
{"graph_symbol_proc", "# Graph symbol to use for graphs in cpu box, \"default\", \"braille\", \"block\" or \"tty\"."},
{"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\", separate values with whitespace."},
{"shown_boxes", "#* Manually set which boxes to show. Available values are \"cpu mem net proc\" and \"gpu0\" through \"gpu5\", separate values with whitespace."},
{"update_ms", "#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs."},
@ -107,12 +110,16 @@ 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."},
{"cpu_graph_lower", "#* Sets the CPU stat shown in lower half of the CPU graph, \"total\" is always available.\n"
"#* Select from a list of detected attributes from the options menu."},
#ifdef GPU_SUPPORT
{"show_gpu_info", "#* If gpu info should be shown in the cpu box. Available values = \"Auto\", \"On\" and \"Off\"."},
#endif
{"cpu_invert_lower", "#* Toggles if the lower CPU graph should be inverted."},
{"cpu_single_graph", "#* Set to True to completely disable the lower CPU graph."},
@ -192,21 +199,36 @@ namespace Config {
{"selected_battery", "#* Which battery to use if multiple are present. \"Auto\" for auto detection."},
{"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
{"nvml_measure_pcie_speeds",
"#* Measure PCIe throughput on NVIDIA cards, may impact performance on certain cards."},
{"gpu_mirror_graph", "#* Horizontally mirror the GPU graph."},
{"custom_gpu_name0", "#* Custom gpu0 model name, empty string to disable."},
{"custom_gpu_name1", "#* Custom gpu1 model name, empty string to disable."},
{"custom_gpu_name2", "#* Custom gpu2 model name, empty string to disable."},
{"custom_gpu_name3", "#* Custom gpu3 model name, empty string to disable."},
{"custom_gpu_name4", "#* Custom gpu4 model name, empty string to disable."},
{"custom_gpu_name5", "#* Custom gpu5 model name, empty string to disable."},
#endif
};
unordered_flat_map<std::string_view, string> strings = {
std::unordered_map<std::string_view, string> strings = {
{"color_theme", "Default"},
{"shown_boxes", "cpu mem net proc"},
{"graph_symbol", "braille"},
{"presets", "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty"},
{"graph_symbol_cpu", "default"},
{"graph_symbol_gpu", "default"},
{"graph_symbol_mem", "default"},
{"graph_symbol_net", "default"},
{"graph_symbol_proc", "default"},
{"proc_sorting", "cpu lazy"},
{"cpu_graph_upper", "total"},
{"cpu_graph_lower", "total"},
{"cpu_graph_upper", "Auto"},
{"cpu_graph_lower", "Auto"},
{"cpu_sensor", "Auto"},
{"selected_battery", "Auto"},
{"cpu_core_map", ""},
@ -220,10 +242,19 @@ namespace Config {
{"proc_filter", ""},
{"proc_command", ""},
{"selected_name", ""},
#ifdef GPU_SUPPORT
{"custom_gpu_name0", ""},
{"custom_gpu_name1", ""},
{"custom_gpu_name2", ""},
{"custom_gpu_name3", ""},
{"custom_gpu_name4", ""},
{"custom_gpu_name5", ""},
{"show_gpu_info", "Auto"}
#endif
};
unordered_flat_map<std::string_view, string> stringsTmp;
std::unordered_map<std::string_view, string> stringsTmp;
unordered_flat_map<std::string_view, bool> bools = {
std::unordered_map<std::string_view, bool> bools = {
{"theme_background", true},
{"truecolor", true},
{"rounded_corners", true},
@ -268,10 +299,15 @@ 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},
#endif
};
unordered_flat_map<std::string_view, bool> boolsTmp;
std::unordered_map<std::string_view, bool> boolsTmp;
unordered_flat_map<std::string_view, int> ints = {
std::unordered_map<std::string_view, int> ints = {
{"update_ms", 2000},
{"net_download", 100},
{"net_upload", 100},
@ -282,7 +318,7 @@ namespace Config {
{"proc_selected", 0},
{"proc_last_selected", 0},
};
unordered_flat_map<std::string_view, int> intsTmp;
std::unordered_map<std::string_view, int> intsTmp;
bool _locked(const std::string_view name) {
atomic_wait(writelock, true);
@ -318,7 +354,7 @@ namespace Config {
validError = "Malformatted preset in config value presets!";
return false;
}
if (not is_in(vals.at(0), "cpu", "mem", "net", "proc")) {
if (not is_in(vals.at(0), "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5")) {
validError = "Invalid box name in config value presets!";
return false;
}
@ -414,6 +450,11 @@ namespace Config {
else if (name == "shown_boxes" and not value.empty() and not check_boxes(value))
validError = "Invalid box name(s) in shown_boxes!";
#ifdef GPU_SUPPORT
else if (name == "show_gpu_info" and not v_contains(show_gpu_values, value))
validError = "Invalid value for show_gpu_info: " + value;
#endif
else if (name == "presets" and not presetsValid(value))
return false;
@ -516,6 +557,13 @@ namespace Config {
auto new_boxes = ssplit(boxes);
for (auto& box : new_boxes) {
if (not v_contains(valid_boxes, box)) return false;
#ifdef GPU_SUPPORT
if (box.starts_with("gpu")) {
size_t gpu_num = stoi(box.substr(3));
if (gpu_num == 0) gpu_num = 5;
if (std::cmp_greater(gpu_num, Gpu::gpu_names.size())) return false;
}
#endif
}
current_boxes = std::move(new_boxes);
return true;

View file

@ -22,11 +22,10 @@ tab-size = 4
#include <vector>
#include <filesystem>
#include <robin_hood.h>
#include <unordered_map>
using std::string;
using std::vector;
using robin_hood::unordered_flat_map;
//* Functions and variables for reading and writing the btop config file
namespace Config {
@ -34,18 +33,25 @@ namespace Config {
extern std::filesystem::path conf_dir;
extern std::filesystem::path conf_file;
extern unordered_flat_map<std::string_view, string> strings;
extern unordered_flat_map<std::string_view, string> stringsTmp;
extern unordered_flat_map<std::string_view, bool> bools;
extern unordered_flat_map<std::string_view, bool> boolsTmp;
extern unordered_flat_map<std::string_view, int> ints;
extern unordered_flat_map<std::string_view, int> intsTmp;
extern std::unordered_map<std::string_view, string> strings;
extern std::unordered_map<std::string_view, string> stringsTmp;
extern std::unordered_map<std::string_view, bool> bools;
extern std::unordered_map<std::string_view, bool> boolsTmp;
extern std::unordered_map<std::string_view, int> ints;
extern std::unordered_map<std::string_view, int> intsTmp;
const vector<string> valid_graph_symbols = { "braille", "block", "tty" };
const vector<string> valid_graph_symbols_def = { "default", "braille", "block", "tty" };
const vector<string> valid_boxes = { "cpu", "mem", "net", "proc" };
const vector<string> valid_boxes = {
"cpu", "mem", "net", "proc"
#ifdef GPU_SUPPORT
,"gpu0", "gpu1", "gpu2", "gpu3", "gpu4", "gpu5"
#endif
};
const vector<string> temp_scales = { "celsius", "fahrenheit", "kelvin", "rankine" };
#ifdef GPU_SUPPORT
const vector<string> show_gpu_values = { "Auto", "On", "Off" };
#endif
extern vector<string> current_boxes;
extern vector<string> preset_list;
extern vector<string> available_batteries;

File diff suppressed because it is too large Load diff

View file

@ -21,10 +21,9 @@ tab-size = 4
#include <string>
#include <vector>
#include <array>
#include <robin_hood.h>
#include <unordered_map>
#include <deque>
using robin_hood::unordered_flat_map;
using std::array;
using std::deque;
using std::string;
@ -108,7 +107,7 @@ namespace Draw {
long long offset;
long long last = 0, max_value = 0;
bool current = true, tty_mode = false;
unordered_flat_map<bool, vector<string>> graphs = { {true, {}}, {false, {}}};
std::unordered_map<bool, vector<string>> graphs = { {true, {}}, {false, {}}};
//* Create two representations of the graph to switch between to represent two values for each braille character
void _create(const deque<long long>& data, int data_offset);
@ -135,6 +134,6 @@ namespace Draw {
namespace Proc {
extern Draw::TextEdit filter;
extern unordered_flat_map<size_t, Draw::Graph> p_graphs;
extern unordered_flat_map<size_t, int> p_counters;
extern std::unordered_map<size_t, Draw::Graph> p_graphs;
extern std::unordered_map<size_t, int> p_counters;
}

View file

@ -22,6 +22,15 @@ tab-size = 4
#include <thread>
#include <mutex>
#include <signal.h>
#include <utility>
#include "btop_input.hpp"
#include "btop_tools.hpp"
#include "btop_config.hpp"
#include "btop_shared.hpp"
#include "btop_menu.hpp"
#include "btop_draw.hpp"
#include "btop_input.hpp"
#include "btop_tools.hpp"
@ -40,7 +49,7 @@ namespace rng = std::ranges;
namespace Input {
//* Map for translating key codes to readable values
const unordered_flat_map<string, string> Key_escapes = {
const std::unordered_map<string, string> Key_escapes = {
{"\033", "escape"},
{"\n", "enter"},
{" ", "space"},
@ -55,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"},
@ -79,7 +92,7 @@ namespace Input {
std::atomic<bool> interrupt (false);
std::atomic<bool> polling (false);
array<int, 2> mouse_pos;
unordered_flat_map<string, Mouse_loc> mouse_mappings;
std::unordered_map<string, Mouse_loc> mouse_mappings;
deque<string> history(50, "");
string old_filter;
@ -260,11 +273,21 @@ namespace Input {
Menu::show(Menu::Menus::Options);
return;
}
else if (is_in(key, "1", "2", "3", "4")) {
else if (key.size() == 1 and isint(key)) {
auto intKey = stoi(key);
#ifdef GPU_SUPPORT
static const array<string, 10> boxes = {"gpu5", "cpu", "mem", "net", "proc", "gpu0", "gpu1", "gpu2", "gpu3", "gpu4"};
if ((intKey == 0 and Gpu::gpu_names.size() < 5) or (intKey >= 5 and std::cmp_less(Gpu::gpu_names.size(), intKey - 4)))
return;
#else
static const array<string, 10> boxes = {"", "cpu", "mem", "net", "proc"};
if (intKey == 0 or intKey > 4)
return;
#endif
atomic_wait(Runner::active);
Config::current_preset = -1;
static const array<string, 4> boxes = {"cpu", "mem", "net", "proc"};
Config::toggle_box(boxes.at(std::stoi(key) - 1));
Config::toggle_box(boxes.at(intKey));
Draw::calcSizes();
Runner::run("all", false, true);
return;
@ -343,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);

View file

@ -21,10 +21,9 @@ tab-size = 4
#include <string>
#include <atomic>
#include <array>
#include <robin_hood.h>
#include <unordered_map>
#include <deque>
using robin_hood::unordered_flat_map;
using std::array;
using std::atomic;
using std::deque;
@ -44,7 +43,7 @@ namespace Input {
};
//? line, col, height, width
extern unordered_flat_map<string, Mouse_loc> mouse_mappings;
extern std::unordered_map<string, Mouse_loc> mouse_mappings;
extern atomic<bool> interrupt;
extern atomic<bool> polling;

View file

@ -17,7 +17,7 @@ tab-size = 4
*/
#include <deque>
#include <robin_hood.h>
#include <unordered_map>
#include <array>
#include <signal.h>
#include <errno.h>
@ -31,7 +31,6 @@ tab-size = 4
#include "btop_draw.hpp"
#include "btop_shared.hpp"
using robin_hood::unordered_flat_map;
using std::array;
using std::ceil;
using std::max;
@ -54,18 +53,76 @@ namespace Menu {
int signalKillRet{}; // defaults to 0
const array<string, 32> 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<string, Input::Mouse_loc> mouse_mappings;
std::unordered_map<string, Input::Mouse_loc> mouse_mappings;
const array<array<string, 3>, 3> menu_normal = {
array<string, 3>{
@ -115,6 +172,7 @@ namespace Menu {
{"2", "Toggle MEM box."},
{"3", "Toggle NET box."},
{"4", "Toggle PROC box."},
{"5", "Toggle GPU box."},
{"d", "Toggle disks view in MEM box."},
{"F2, o", "Shows options."},
{"F1, ?, h", "Shows this window."},
@ -137,6 +195,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."},
@ -212,6 +271,9 @@ namespace Menu {
"Manually set which boxes to show.",
"",
"Available values are \"cpu mem net proc\".",
#ifdef GPU_SUPPORT
"Or \"gpu0\" through \"gpu5\" for GPU boxes.",
#endif
"Separate values with whitespace.",
"",
"Toggle between presets with key \"p\"."},
@ -314,23 +376,49 @@ namespace Menu {
{"cpu_graph_upper",
"Cpu upper graph.",
"",
"Sets the CPU stat shown in upper half of",
"Sets the CPU/GPU stat shown in upper half of",
"the CPU graph.",
"",
"\"total\" = Total cpu usage.",
"CPU:",
"\"total\" = Total cpu usage. (Auto)",
"\"user\" = User mode cpu usage.",
"\"system\" = Kernel mode cpu usage.",
"+ more depending on kernel."},
"+ more depending on kernel.",
#ifdef GPU_SUPPORT
"",
"GPU:",
"\"gpu-totals\" = GPU usage split by device.",
"\"gpu-vram-totals\" = VRAM usage split by GPU.",
"\"gpu-pwr-totals\" = Power usage split by GPU.",
"\"gpu-average\" = Avg usage of all GPUs.",
"\"gpu-vram-total\" = VRAM usage of all GPUs.",
"\"gpu-pwr-total\" = Power usage of all GPUs.",
"Not all stats are supported on all devices."
#endif
},
{"cpu_graph_lower",
"Cpu lower graph.",
"",
"Sets the CPU stat shown in lower half of",
"Sets the CPU/GPU stat shown in lower half of",
"the CPU graph.",
"",
"CPU:",
"\"total\" = Total cpu usage.",
"\"user\" = User mode cpu usage.",
"\"system\" = Kernel mode cpu usage.",
"+ more depending on kernel."},
"+ more depending on kernel.",
#ifdef GPU_SUPPORT
"",
"GPU:",
"\"gpu-totals\" = GPU usage split/device. (Auto)",
"\"gpu-vram-totals\" = VRAM usage split by GPU.",
"\"gpu-pwr-totals\" = Power usage split by GPU.",
"\"gpu-average\" = Avg usage of all GPUs.",
"\"gpu-vram-total\" = VRAM usage of all GPUs.",
"\"gpu-pwr-total\" = Power usage of all GPUs.",
"Not all stats are supported on all devices."
#endif
},
{"cpu_invert_lower",
"Toggles orientation of the lower CPU graph.",
"",
@ -342,12 +430,24 @@ namespace Menu {
"to fit to box height.",
"",
"True or False."},
#ifdef GPU_SUPPORT
{"show_gpu_info",
"Show gpu info in cpu box.",
"",
"Toggles gpu stats in cpu box and the",
"gpu graph (if \"cpu_graph_lower\" is set to",
"\"Auto\").",
"",
"\"Auto\" to show when no gpu box is shown.",
"\"On\" to always show.",
"\"Off\" to never show."},
#endif
{"check_temp",
"Enable cpu temperature reporting.",
"",
"True or False."},
{"cpu_sensor",
"Cpu temperature sensor",
"Cpu temperature sensor.",
"",
"Select the sensor that corresponds to",
"your cpu temperature.",
@ -387,7 +487,7 @@ namespace Menu {
"Rankine, 0 = abosulte zero, 1 degree change",
"equals 1 degree change in Fahrenheit."},
{"show_cpu_freq",
"Show CPU frequency",
"Show CPU frequency.",
"",
"Can cause slowdowns on systems with many",
"cores and certain kernel versions."},
@ -403,6 +503,50 @@ namespace Menu {
"",
"True or False."},
},
#ifdef GPU_SUPPORT
{
{"nvml_measure_pcie_speeds",
"Measure PCIe throughput on NVIDIA cards.",
"",
"May impact performance on certain cards.",
"",
"True or False."},
{"graph_symbol_gpu",
"Graph symbol to use for graphs in gpu box.",
"",
"\"default\", \"braille\", \"block\" or \"tty\".",
"",
"\"default\" for the general default symbol.",},
{"gpu_mirror_graph",
"Horizontally mirror the GPU graph.",
"",
"True or False."},
{"custom_gpu_name0",
"Custom gpu0 model name in gpu stats box.",
"",
"Empty string to disable."},
{"custom_gpu_name1",
"Custom gpu1 model name in gpu stats box.",
"",
"Empty string to disable."},
{"custom_gpu_name2",
"Custom gpu2 model name in gpu stats box.",
"",
"Empty string to disable."},
{"custom_gpu_name3",
"Custom gpu3 model name in gpu stats box.",
"",
"Empty string to disable."},
{"custom_gpu_name4",
"Custom gpu4 model name in gpu stats box.",
"",
"Empty string to disable."},
{"custom_gpu_name5",
"Custom gpu5 model name in gpu stats box.",
"",
"Empty string to disable."},
},
#endif
{
{"mem_below_net",
"Mem box location.",
@ -589,6 +733,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.",
"",
@ -1015,7 +1164,7 @@ namespace Menu {
static Draw::TextEdit editor;
static string warnings;
static bitset<8> selPred;
static const unordered_flat_map<string, std::reference_wrapper<const vector<string>>> optionsList = {
static const std::unordered_map<string, std::reference_wrapper<const vector<string>>> optionsList = {
{"color_theme", std::cref(Theme::themes)},
{"log_level", std::cref(Logger::log_levels)},
{"temp_scale", std::cref(Config::temp_scales)},
@ -1029,6 +1178,10 @@ namespace Menu {
{"cpu_graph_lower", std::cref(Cpu::available_fields)},
{"cpu_sensor", std::cref(Cpu::available_sensors)},
{"selected_battery", std::cref(Config::available_batteries)},
#ifdef GPU_SUPPORT
{"show_gpu_info", std::cref(Config::show_gpu_values)},
{"graph_symbol_gpu", std::cref(Config::valid_graph_symbols_def)},
#endif
};
auto tty_mode = Config::getB("tty_mode");
auto vim_keys = Config::getB("vim_keys");
@ -1080,7 +1233,8 @@ namespace Menu {
const auto& option = categories[selected_cat][item_height * page + selected][0];
if (selPred.test(isString) and Config::stringValid(option, editor.text)) {
Config::set(option, editor.text);
if (option == "custom_cpu_name") screen_redraw = true;
if (option == "custom_cpu_name" or option.starts_with("custom_gpu_name"))
screen_redraw = true;
else if (is_in(option, "shown_boxes", "presets")) {
screen_redraw = true;
Config::current_preset = -1;
@ -1161,7 +1315,7 @@ namespace Menu {
if (--selected_cat < 0) selected_cat = (int)categories.size() - 1;
page = selected = 0;
}
else if (is_in(key, "1", "2", "3", "4", "5") or key.starts_with("select_cat_")) {
else if (is_in(key, "1", "2", "3", "4", "5", "6") or key.starts_with("select_cat_")) {
selected_cat = key.back() - '0' - 1;
page = selected = 0;
}
@ -1213,7 +1367,7 @@ namespace Menu {
Logger::set(optList.at(i));
Logger::info("Logger set to " + optList.at(i));
}
else if (is_in(option, "proc_sorting", "cpu_sensor") or option.starts_with("graph_symbol") or option.starts_with("cpu_graph_"))
else if (is_in(option, "proc_sorting", "cpu_sensor", "show_gpu_info") or option.starts_with("graph_symbol") or option.starts_with("cpu_graph_"))
screen_redraw = true;
}
else
@ -1259,11 +1413,19 @@ namespace Menu {
//? Category buttons
out += Mv::to(y+7, x+4);
#ifdef GPU_SUPPORT
for (int i = 0; const auto& m : {"general", "cpu", "gpu", "mem", "net", "proc"}) {
#else
for (int i = 0; const auto& m : {"general", "cpu", "mem", "net", "proc"}) {
#endif
out += Fx::b + (i == selected_cat
? Theme::c("hi_fg") + '[' + Theme::c("title") + m + Theme::c("hi_fg") + ']'
: Theme::c("hi_fg") + to_string(i + 1) + Theme::c("title") + m + ' ')
#ifdef GPU_SUPPORT
+ Mv::r(7);
#else
+ Mv::r(10);
#endif
if (string button_name = "select_cat_" + to_string(i + 1); not editing and not mouse_mappings.contains(button_name))
mouse_mappings[button_name] = {y+6, x+2 + 15*i, 3, 15};
i++;

View file

@ -38,7 +38,7 @@ namespace Menu {
extern bool redraw;
//? line, col, height, width
extern unordered_flat_map<string, Input::Mouse_loc> mouse_mappings;
extern std::unordered_map<string, Input::Mouse_loc> mouse_mappings;
//* Creates a message box centered on screen
//? Height of box is determined by size of content vector

View file

@ -18,12 +18,25 @@ tab-size = 4
#include <ranges>
#include "btop_config.hpp"
#include "btop_shared.hpp"
#include "btop_tools.hpp"
namespace rng = std::ranges;
using namespace Tools;
#ifdef GPU_SUPPORT
namespace Gpu {
vector<string> gpu_names;
vector<int> gpu_b_height_offsets;
std::unordered_map<string, deque<long long>> shared_gpu_percent = {
{"gpu-average", {}},
{"gpu-vram-total", {}},
{"gpu-pwr-total", {}},
};
long long gpu_pwr_total_max;
}
#endif
namespace Proc {
void proc_sorter(vector<proc_info>& proc_vec, const string& sorting, bool reverse, bool tree) {
@ -156,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;

View file

@ -26,10 +26,9 @@ tab-size = 4
#include <tuple>
#include <vector>
#include <ifaddrs.h>
#include <robin_hood.h>
#include <unordered_map>
#include <unistd.h>
using robin_hood::unordered_flat_map;
using std::array;
using std::atomic;
using std::deque;
@ -86,6 +85,91 @@ namespace Shared {
}
namespace Gpu {
#ifdef GPU_SUPPORT
extern vector<string> box;
extern int width, height, min_width, min_height;
extern vector<int> x_vec, y_vec;
extern vector<bool> redraw;
extern int shown;
extern vector<char> shown_panels;
extern vector<string> gpu_names;
extern vector<int> gpu_b_height_offsets;
extern long long gpu_pwr_total_max;
extern std::unordered_map<string, deque<long long>> shared_gpu_percent; // averages, power/vram total
const array mem_names { "used"s, "free"s };
//* Container for process information // TODO
/*struct proc_info {
unsigned int pid;
unsigned long long mem;
};*/
//* Container for supported Gpu::*::collect() functions
struct gpu_info_supported {
bool gpu_utilization = true,
mem_utilization = true,
gpu_clock = true,
mem_clock = true,
pwr_usage = true,
pwr_state = true,
temp_info = true,
mem_total = true,
mem_used = true,
pcie_txrx = true;
};
//* Per-device container for GPU info
struct gpu_info {
std::unordered_map<string, deque<long long>> gpu_percent = {
{"gpu-totals", {}},
{"gpu-vram-totals", {}},
{"gpu-pwr-totals", {}},
};
unsigned int gpu_clock_speed; // MHz
long long pwr_usage; // mW
long long pwr_max_usage = 255000;
long long pwr_state;
deque<long long> temp = {0};
long long temp_max = 110;
long long mem_total = 0;
long long mem_used = 0;
deque<long long> mem_utilization_percent = {0}; // TODO: properly handle GPUs that can't report some stats
long long mem_clock_speed = 0; // MHz
long long pcie_tx = 0; // KB/s
long long pcie_rx = 0;
gpu_info_supported supported_functions;
// vector<proc_info> graphics_processes = {}; // TODO
// vector<proc_info> compute_processes = {};
};
namespace Nvml {
extern bool shutdown();
}
namespace Rsmi {
extern bool shutdown();
}
//* Collect gpu stats and temperatures
auto collect(bool no_update = false) -> vector<gpu_info>&;
//* Draw contents of gpu box using <gpus> as source
string draw(const gpu_info& gpu, unsigned long index, bool force_redraw, bool data_same);
#else
struct gpu_info {
bool supported = false;
};
#endif
}
namespace Cpu {
extern string box;
extern int x, y, width, height, min_width, min_height;
@ -96,7 +180,7 @@ namespace Cpu {
extern tuple<int, long, string> current_bat;
struct cpu_info {
unordered_flat_map<string, deque<long long>> cpu_percent = {
std::unordered_map<string, deque<long long>> cpu_percent = {
{"total", {}},
{"user", {}},
{"nice", {}},
@ -119,11 +203,13 @@ namespace Cpu {
auto collect(bool no_update = false) -> cpu_info&;
//* Draw contents of cpu box using <cpu> as source
string draw(const cpu_info& cpu, bool force_redraw = false, bool data_same = false);
string draw(const cpu_info& cpu, const vector<Gpu::gpu_info>& gpu, bool force_redraw = false, bool data_same = false);
//* Parse /proc/cpu info for mapping of core ids
auto get_core_mapping() -> unordered_flat_map<int, int>;
extern unordered_flat_map<int, int> core_mapping;
auto get_core_mapping() -> std::unordered_map<int, int>;
extern std::unordered_map<int, int> core_mapping;
auto get_cpuHz() -> string;
//* Get battery info from /sys
auto get_battery() -> tuple<int, long, string>;
@ -155,13 +241,13 @@ namespace Mem {
};
struct mem_info {
unordered_flat_map<string, uint64_t> stats =
std::unordered_map<string, uint64_t> stats =
{{"used", 0}, {"available", 0}, {"cached", 0}, {"free", 0},
{"swap_total", 0}, {"swap_used", 0}, {"swap_free", 0}};
unordered_flat_map<string, deque<long long>> percent =
std::unordered_map<string, deque<long long>> percent =
{{"used", {}}, {"available", {}}, {"cached", {}}, {"free", {}},
{"swap_total", {}}, {"swap_used", {}}, {"swap_free", {}}};
unordered_flat_map<string, disk_info> disks;
std::unordered_map<string, disk_info> disks;
vector<string> disks_order;
};
@ -183,7 +269,7 @@ namespace Net {
extern string selected_iface;
extern vector<string> interfaces;
extern bool rescale;
extern unordered_flat_map<string, uint64_t> graph_max;
extern std::unordered_map<string, uint64_t> graph_max;
struct net_stat {
uint64_t speed{}; // defaults to 0
@ -195,14 +281,14 @@ namespace Net {
};
struct net_info {
unordered_flat_map<string, deque<long long>> bandwidth = { {"download", {}}, {"upload", {}} };
unordered_flat_map<string, net_stat> stat = { {"download", {}}, {"upload", {}} };
std::unordered_map<string, deque<long long>> bandwidth = { {"download", {}}, {"upload", {}} };
std::unordered_map<string, net_stat> stat = { {"download", {}}, {"upload", {}} };
string ipv4{}; // defaults to ""
string ipv6{}; // defaults to ""
bool connected{}; // defaults to false
};
extern unordered_flat_map<string, net_info> current_net;
extern std::unordered_map<string, net_info> current_net;
//* Collect net upload/download stats
auto collect(bool no_update=false) -> net_info&;
@ -235,7 +321,7 @@ namespace Proc {
};
//? Translation from process state char to explanative string
const unordered_flat_map<char, string> proc_states = {
const std::unordered_map<char, string> proc_states = {
{'R', "Running"},
{'S', "Sleeping"},
{'D', "Waiting"},

View file

@ -42,11 +42,11 @@ namespace Theme {
fs::path theme_dir;
fs::path user_theme_dir;
vector<string> themes;
unordered_flat_map<string, string> colors;
unordered_flat_map<string, array<int, 3>> rgbs;
unordered_flat_map<string, array<string, 101>> gradients;
std::unordered_map<string, string> colors;
std::unordered_map<string, array<int, 3>> rgbs;
std::unordered_map<string, array<string, 101>> gradients;
const unordered_flat_map<string, string> Default_theme = {
const std::unordered_map<string, string> Default_theme = {
{ "main_bg", "#00" },
{ "main_fg", "#cc" },
{ "title", "#ee" },
@ -91,7 +91,7 @@ namespace Theme {
{ "process_end", "#d45454" }
};
const unordered_flat_map<string, string> TTY_theme = {
const std::unordered_map<string, string> TTY_theme = {
{ "main_bg", "\x1b[0;40m" },
{ "main_fg", "\x1b[37m" },
{ "title", "\x1b[97m" },
@ -224,7 +224,7 @@ namespace Theme {
}
//* Generate colors and rgb decimal vectors for the theme
void generateColors(const unordered_flat_map<string, string>& source) {
void generateColors(const std::unordered_map<string, string>& source) {
vector<string> t_rgb;
string depth;
bool t_to_256 = Config::getB("lowcolor");
@ -372,7 +372,7 @@ namespace Theme {
//* Load a .theme file from disk
auto loadFile(const string& filename) {
unordered_flat_map<string, string> theme_out;
std::unordered_map<string, string> theme_out;
const fs::path filepath = filename;
if (not fs::exists(filepath))
return Default_theme;

View file

@ -22,12 +22,11 @@ tab-size = 4
#include <filesystem>
#include <string>
#include <vector>
#include <robin_hood.h>
#include <unordered_map>
using std::array;
using std::string;
using std::vector;
using robin_hood::unordered_flat_map;
namespace Theme {
extern std::filesystem::path theme_dir;
@ -54,9 +53,9 @@ namespace Theme {
//* Set current theme from current "color_theme" value in config
void setTheme();
extern unordered_flat_map<string, string> colors;
extern unordered_flat_map<string, array<int, 3>> rgbs;
extern unordered_flat_map<string, array<string, 101>> gradients;
extern std::unordered_map<string, string> colors;
extern std::unordered_map<string, array<int, 3>> rgbs;
extern std::unordered_map<string, array<string, 101>> gradients;
//* Return escape code for color <name>
inline const string& c(const string& name) { return colors.at(name); }

View file

@ -30,7 +30,7 @@ tab-size = 4
#include <termios.h>
#include <sys/ioctl.h>
#include "robin_hood.h"
#include "unordered_map"
#include "widechar_width.hpp"
#include "btop_shared.hpp"
#include "btop_tools.hpp"
@ -43,7 +43,6 @@ using std::flush;
using std::max;
using std::string_view;
using std::to_string;
using robin_hood::unordered_flat_map;
using namespace std::literals; // to use operator""s
@ -99,19 +98,31 @@ namespace Term {
}
auto get_min_size(const string& boxes) -> array<int, 2> {
bool cpu = boxes.find("cpu") != string::npos;
bool mem = boxes.find("mem") != string::npos;
bool net = boxes.find("net") != string::npos;
bool proc = boxes.find("proc") != string::npos;
int width = 0;
bool cpu = boxes.find("cpu") != string::npos;
bool mem = boxes.find("mem") != string::npos;
bool net = boxes.find("net") != string::npos;
bool proc = boxes.find("proc") != string::npos;
#ifdef GPU_SUPPORT
int gpu = 0;
if (not Gpu::gpu_names.empty())
for (char i = '0'; i <= '5'; ++i)
gpu += (boxes.find(std::string("gpu") + i) != string::npos);
#endif
int width = 0;
if (mem) width = Mem::min_width;
else if (net) width = Mem::min_width;
width += (proc ? Proc::min_width : 0);
if (cpu and width < Cpu::min_width) width = Cpu::min_width;
#ifdef GPU_SUPPORT
if (gpu != 0 and width < Gpu::min_width) width = Gpu::min_width;
#endif
int height = (cpu ? Cpu::min_height : 0);
if (proc) height += Proc::min_height;
else height += (mem ? Mem::min_height : 0) + (net ? Net::min_height : 0);
#ifdef GPU_SUPPORT
height += Gpu::min_height*gpu;
#endif
return { width, height };
}
@ -445,7 +456,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]);
@ -537,6 +548,74 @@ namespace Tools {
return (user != nullptr ? user : "");
}
DebugTimer::DebugTimer(const string name, bool start, bool delayed_report) : name(name), delayed_report(delayed_report) {
if (start)
this->start();
}
DebugTimer::~DebugTimer() {
if (running)
this->stop(true);
this->force_report();
}
void DebugTimer::start() {
if (running) return;
running = true;
start_time = time_micros();
}
void DebugTimer::stop(bool report) {
if (not running) return;
running = false;
elapsed_time = time_micros() - start_time;
if (report) this->report();
}
void DebugTimer::reset(bool restart) {
running = false;
start_time = 0;
elapsed_time = 0;
if (restart) this->start();
}
void DebugTimer::stop_rename_reset(const string &new_name, bool report, bool restart) {
this->stop(report);
name = new_name;
this->reset(restart);
}
void DebugTimer::report() {
string report_line;
if (start_time == 0 and elapsed_time == 0)
report_line = fmt::format("DebugTimer::report() warning -> Timer [{}] has not been started!", name);
else if (running)
report_line = fmt::format(custom_locale, "Timer [{}] (running) currently at {:L} μs", name, time_micros() - start_time);
else
report_line = fmt::format(custom_locale, "Timer [{}] took {:L} μs", name, elapsed_time);
if (delayed_report)
report_buffer.emplace_back(report_line);
else
Logger::log_write(log_level, report_line);
}
void DebugTimer::force_report() {
if (report_buffer.empty()) return;
for (const auto& line : report_buffer)
Logger::log_write(log_level, line);
report_buffer.clear();
}
uint64_t DebugTimer::elapsed() {
if (running)
return time_micros() - start_time;
return elapsed_time;
}
bool DebugTimer::is_running() {
return running;
}
}
namespace Logger {
@ -568,7 +647,7 @@ namespace Logger {
loglevel = v_index(log_levels, level);
}
void log_write(const size_t level, const string& msg) {
void log_write(const Level level, const string& msg) {
if (loglevel < level or logfile.empty()) return;
atomic_lock lck(busy, true);
lose_priv neutered{};

View file

@ -31,6 +31,10 @@ tab-size = 4
#include <vector>
#include <pthread.h>
#include <limits.h>
#include <unordered_map>
#ifdef BTOP_DEBUG
#include <source_location>
#endif
#ifndef HOST_NAME_MAX
#ifdef __APPLE__
#define HOST_NAME_MAX 255
@ -146,11 +150,46 @@ namespace Term {
void restore();
}
//* Simple logging implementation
namespace Logger {
const vector<string> log_levels = {
"DISABLED",
"ERROR",
"WARNING",
"INFO",
"DEBUG",
};
extern std::filesystem::path logfile;
enum Level : size_t {
DISABLED = 0,
ERROR = 1,
WARNING = 2,
INFO = 3,
DEBUG = 4,
};
//* Set log level, valid arguments: "DISABLED", "ERROR", "WARNING", "INFO" and "DEBUG"
void set(const string& level);
void log_write(const Level level, const string& msg);
inline void error(const string msg) { log_write(ERROR, msg); }
inline void warning(const string msg) { log_write(WARNING, msg); }
inline void info(const string msg) { log_write(INFO, msg); }
inline void debug(const string msg) { log_write(DEBUG, msg); }
}
//? --------------------------------------------------- FUNCTIONS -----------------------------------------------------
namespace Tools {
constexpr auto SSmax = std::numeric_limits<std::streamsize>::max();
class MyNumPunct : public std::numpunct<char> {
protected:
virtual char do_thousands_sep() const { return '\''; }
virtual std::string do_grouping() const { return "\03"; }
};
size_t wide_ulen(const string& str);
size_t wide_ulen(const std::wstring& w_str);
@ -298,6 +337,50 @@ namespace Tools {
//* Add std::string operator * : Repeat string <str> <n> number of times
std::string operator*(const string& str, int64_t n);
template <typename K, typename T>
#ifdef BTOP_DEBUG
const T& safeVal(const std::unordered_map<K, T>& map, const K& key, const T& fallback = T{}, std::source_location loc = std::source_location::current()) {
if (map.contains(key)) {
return map.at(key);
} else {
Logger::error(fmt::format("safeVal() called with invalid key: [{}] in file: {} on line: {}", key, loc.file_name(), loc.line()));
return fallback;
}
};
#else
const T& safeVal(const std::unordered_map<K, T>& map, const K& key, const T& fallback = T{}) {
if (map.contains(key)) {
return map.at(key);
} else {
Logger::error(fmt::format("safeVal() called with invalid key: [{}] (Compile btop with DEBUG=true for more extensive logging!)", key));
return fallback;
}
};
#endif
template <typename T>
#ifdef BTOP_DEBUG
const T& safeVal(const std::vector<T>& vec, const size_t& index, const T& fallback = T{}, std::source_location loc = std::source_location::current()) {
if (index < vec.size()) {
return vec.at(index);
} else {
Logger::error(fmt::format("safeVal() called with invalid index: [{}] in file: {} on line: {}", index, loc.file_name(), loc.line()));
return fallback;
}
};
#else
const T& safeVal(const std::vector<T>& vec, const size_t& index, const T& fallback = T{}) {
if (index < vec.size()) {
return vec.at(index);
} else {
Logger::error(fmt::format("safeVal() called with invalid index: [{}] (Compile btop with DEBUG=true for more extensive logging!)", index));
return fallback;
}
};
#endif
//* Return current time in <strf> format
string strf_time(const string& strf);
@ -334,27 +417,40 @@ namespace Tools {
//* Convert a celsius value to celsius, fahrenheit, kelvin or rankin and return tuple with new value and unit.
auto celsius_to(const long long& celsius, const string& scale) -> tuple<long long, string>;
}
//* Simple logging implementation
namespace Logger {
const vector<string> log_levels = {
"DISABLED",
"ERROR",
"WARNING",
"INFO",
"DEBUG",
namespace Tools {
//* Creates a named timer that is started on construct (by default) and reports elapsed time in microseconds to Logger::debug() on destruct if running
//* Unless delayed_report is set to false, all reporting is buffered and delayed until DebugTimer is destructed or .force_report() is called
//* Usage example: Tools::DebugTimer timer(name:"myTimer", [start:true], [delayed_report:true]) // Create timer and start
//* timer.stop(); // Stop timer and report elapsed time
//* timer.stop_rename_reset("myTimer2"); // Stop timer, report elapsed time, rename timer, reset and restart
class DebugTimer {
uint64_t start_time{};
uint64_t elapsed_time{};
bool running{};
std::locale custom_locale = std::locale(std::locale::classic(), new Tools::MyNumPunct);
vector<string> report_buffer{};
public:
string name{};
bool delayed_report{};
Logger::Level log_level = Logger::DEBUG;
DebugTimer() = default;
DebugTimer(const string name, bool start = true, bool delayed_report = true);
~DebugTimer();
void start();
void stop(bool report = true);
void reset(bool restart = true);
//* Stops and reports (default), renames timer then resets and restarts (default)
void stop_rename_reset(const string& new_name, bool report = true, bool restart = true);
void report();
void force_report();
uint64_t elapsed();
bool is_running();
};
extern std::filesystem::path logfile;
//* Set log level, valid arguments: "DISABLED", "ERROR", "WARNING", "INFO" and "DEBUG"
void set(const string& level);
void log_write(const size_t level, const string& msg);
inline void error(const string msg) { log_write(1, msg); }
inline void warning(const string msg) { log_write(2, msg); }
inline void info(const string msg) { log_write(3, msg); }
inline void debug(const string msg) { log_write(4, msg); }
}

View file

@ -58,6 +58,7 @@ tab-size = 4
#include <regex>
#include <string>
#include <memory>
#include <utility>
#include "../btop_config.hpp"
#include "../btop_shared.hpp"
@ -74,7 +75,7 @@ using namespace Tools;
namespace Cpu {
vector<long long> core_old_totals;
vector<long long> core_old_idles;
vector<string> available_fields = {"total"};
vector<string> available_fields = {"Auto", "total"};
vector<string> available_sensors = {"Auto"};
cpu_info current_cpu;
bool got_sensors = false, cpu_temp_only = false;
@ -98,7 +99,7 @@ namespace Cpu {
string cpu_sensor;
vector<string> core_sensors;
unordered_flat_map<int, int> core_mapping;
std::unordered_map<int, int> core_mapping;
} // namespace Cpu
namespace Mem {
@ -169,17 +170,23 @@ namespace Shared {
Cpu::current_cpu.temp.insert(Cpu::current_cpu.temp.begin(), Shared::coreCount + 1, {});
Cpu::core_old_totals.insert(Cpu::core_old_totals.begin(), Shared::coreCount, 0);
Cpu::core_old_idles.insert(Cpu::core_old_idles.begin(), Shared::coreCount, 0);
Logger::debug("Init -> Cpu::collect()");
Cpu::collect();
for (auto &[field, vec] : Cpu::current_cpu.cpu_percent) {
if (not vec.empty() and not v_contains(Cpu::available_fields, field)) Cpu::available_fields.push_back(field);
}
Logger::debug("Init -> Cpu::get_cpuName()");
Cpu::cpuName = Cpu::get_cpuName();
Logger::debug("Init -> Cpu::get_sensors()");
Cpu::got_sensors = Cpu::get_sensors();
Logger::debug("Init -> Cpu::get_core_mapping()");
Cpu::core_mapping = Cpu::get_core_mapping();
//? Init for namespace Mem
Mem::old_uptime = system_uptime();
Logger::debug("Init -> Mem::collect()");
Mem::collect();
Logger::debug("Init -> Mem::get_zpools()");
Mem::get_zpools();
}
@ -204,7 +211,7 @@ namespace Cpu {
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
unordered_flat_map<string, long long> cpu_old = {
std::unordered_map<string, long long> cpu_old = {
{"totals", 0},
{"idles", 0},
{"user", 0},
@ -323,8 +330,8 @@ namespace Cpu {
return std::to_string(freq / 1000.0 ).substr(0, 3); // seems to be in MHz
}
auto get_core_mapping() -> unordered_flat_map<int, int> {
unordered_flat_map<int, int> core_map;
auto get_core_mapping() -> std::unordered_map<int, int> {
std::unordered_map<int, int> core_map;
if (cpu_temp_only) return core_map;
for (long i = 0; i < Shared::coreCount; i++) {
@ -557,7 +564,7 @@ namespace Mem {
}
}
void collect_disk(unordered_flat_map<string, disk_info> &disks, unordered_flat_map<string, string> &mapping) {
void collect_disk(std::unordered_map<string, disk_info> &disks, std::unordered_map<string, string> &mapping) {
// this bit is for 'regular' mounts
static struct statinfo cur;
long double etime = 0;
@ -572,7 +579,7 @@ namespace Mem {
auto d = cur.dinfo->devices[i];
string devStatName = "/dev/" + string(d.device_name) + std::to_string(d.unit_number);
for (auto& [ignored, disk] : disks) { // find matching mountpoints - could be multiple as d.device_name is only ada (and d.unit_number is the device number), while the disk.dev is like /dev/ada0s1
if (disk.dev.string().rfind(devStatName, 0) == 0) {
if (disk.dev.string().rfind(devStatName, 0) == 0 and mapping.contains(disk.dev)) {
devstat_compute_statistics(&d, nullptr, etime, DSM_TOTAL_BYTES_READ, &total_bytes_read, DSM_TOTAL_BYTES_WRITE, &total_bytes_write, DSM_NONE);
assign_values(disk, total_bytes_read, total_bytes_write);
string mountpoint = mapping.at(disk.dev);
@ -581,7 +588,6 @@ namespace Mem {
}
}
Logger::debug("");
}
// this code is for ZFS mounts
@ -691,7 +697,7 @@ namespace Mem {
}
if (show_disks) {
unordered_flat_map<string, string> mapping; // keep mapping from device -> mountpoint, since IOKit doesn't give us the mountpoint
std::unordered_map<string, string> mapping; // keep mapping from device -> mountpoint, since IOKit doesn't give us the mountpoint
double uptime = system_uptime();
auto &disks_filter = Config::getS("disks_filter");
bool filter_exclude = false;
@ -807,13 +813,13 @@ namespace Mem {
} // namespace Mem
namespace Net {
unordered_flat_map<string, net_info> current_net;
std::unordered_map<string, net_info> current_net;
net_info empty_net = {};
vector<string> interfaces;
string selected_iface;
int errors = 0;
unordered_flat_map<string, uint64_t> graph_max = {{"download", {}}, {"upload", {}}};
unordered_flat_map<string, array<int, 2>> max_count = {{"download", {}}, {"upload", {}}};
std::unordered_map<string, uint64_t> graph_max = {{"download", {}}, {"upload", {}}};
std::unordered_map<string, array<int, 2>> max_count = {{"download", {}}, {"upload", {}}};
bool rescale = true;
uint64_t timestamp = 0;
@ -892,7 +898,7 @@ namespace Net {
} //else, ignoring family==AF_LINK (see man 3 getifaddrs)
}
unordered_flat_map<string, std::tuple<uint64_t, uint64_t>> ifstats;
std::unordered_map<string, std::tuple<uint64_t, uint64_t>> ifstats;
int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
size_t len;
if (sysctl(mib, 6, nullptr, &len, nullptr, 0) < 0) {
@ -966,7 +972,6 @@ namespace Net {
else
it++;
}
net.compact();
}
timestamp = new_timestamp;
@ -1037,7 +1042,7 @@ namespace Net {
namespace Proc {
vector<proc_info> current_procs;
unordered_flat_map<string, string> uid_user;
std::unordered_map<string, string> uid_user;
string current_sort;
string current_filter;
bool current_rev = false;

View file

@ -17,7 +17,8 @@ tab-size = 4
*/
#include <cstdlib>
#include <robin_hood.h>
#include <unordered_map>
#include <unordered_set>
#include <fstream>
#include <ranges>
#include <cmath>
@ -29,6 +30,14 @@ tab-size = 4
#include <net/if.h>
#include <arpa/inet.h> // for inet_ntop()
#include <filesystem>
#include <future>
#include <dlfcn.h>
#include <unordered_map>
#include <utility>
#if defined(RSMI_STATIC)
#include <rocm_smi/rocm_smi.h>
#endif
#if !(defined(STATIC_BUILD) && defined(__GLIBC__))
#include <pwd.h>
@ -48,18 +57,23 @@ 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 {
vector<long long> core_old_totals;
vector<long long> core_old_idles;
vector<string> available_fields;
vector<string> available_fields = {"Auto", "total"};
vector<string> available_sensors = {"Auto"};
cpu_info current_cpu;
fs::path freq_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq";
@ -83,10 +97,110 @@ namespace Cpu {
int64_t crit{}; // defaults to 0
};
unordered_flat_map<string, Sensor> found_sensors;
std::unordered_map<string, Sensor> found_sensors;
string cpu_sensor;
vector<string> core_sensors;
unordered_flat_map<int, int> core_mapping;
std::unordered_map<int, int> core_mapping;
}
namespace Gpu {
vector<gpu_info> gpus;
#ifdef GPU_SUPPORT
//? NVIDIA data collection
namespace Nvml {
//? NVML defines, structs & typedefs
#define NVML_DEVICE_NAME_BUFFER_SIZE 64
#define NVML_SUCCESS 0
#define NVML_TEMPERATURE_THRESHOLD_SHUTDOWN 0
#define NVML_CLOCK_GRAPHICS 0
#define NVML_CLOCK_MEM 2
#define NVML_TEMPERATURE_GPU 0
#define NVML_PCIE_UTIL_TX_BYTES 0
#define NVML_PCIE_UTIL_RX_BYTES 1
typedef void* nvmlDevice_t; // we won't be accessing any of the underlying struct's properties, so this is fine
typedef int nvmlReturn_t, // enums are basically ints
nvmlTemperatureThresholds_t,
nvmlClockType_t,
nvmlPstates_t,
nvmlTemperatureSensors_t,
nvmlPcieUtilCounter_t;
struct nvmlUtilization_t {unsigned int gpu, memory;};
struct nvmlMemory_t {unsigned long long total, free, used;};
//? Function pointers
const char* (*nvmlErrorString)(nvmlReturn_t);
nvmlReturn_t (*nvmlInit)();
nvmlReturn_t (*nvmlShutdown)();
nvmlReturn_t (*nvmlDeviceGetCount)(unsigned int*);
nvmlReturn_t (*nvmlDeviceGetHandleByIndex)(unsigned int, nvmlDevice_t*);
nvmlReturn_t (*nvmlDeviceGetName)(nvmlDevice_t, char*, unsigned int);
nvmlReturn_t (*nvmlDeviceGetPowerManagementLimit)(nvmlDevice_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetTemperatureThreshold)(nvmlDevice_t, nvmlTemperatureThresholds_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetUtilizationRates)(nvmlDevice_t, nvmlUtilization_t*);
nvmlReturn_t (*nvmlDeviceGetClockInfo)(nvmlDevice_t, nvmlClockType_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetPowerUsage)(nvmlDevice_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetPowerState)(nvmlDevice_t, nvmlPstates_t*);
nvmlReturn_t (*nvmlDeviceGetTemperature)(nvmlDevice_t, nvmlTemperatureSensors_t, unsigned int*);
nvmlReturn_t (*nvmlDeviceGetMemoryInfo)(nvmlDevice_t, nvmlMemory_t*);
nvmlReturn_t (*nvmlDeviceGetPcieThroughput)(nvmlDevice_t, nvmlPcieUtilCounter_t, unsigned int*);
//? Data
void* nvml_dl_handle;
bool initialized = false;
bool init();
bool shutdown();
template <bool is_init> bool collect(gpu_info* gpus_slice);
vector<nvmlDevice_t> devices;
unsigned int device_count = 0;
}
//? AMD data collection
namespace Rsmi {
#if !defined(RSMI_STATIC)
//? RSMI defines, structs & typedefs
#define RSMI_MAX_NUM_FREQUENCIES 32
#define RSMI_STATUS_SUCCESS 0
#define RSMI_MEM_TYPE_VRAM 0
#define RSMI_TEMP_CURRENT 0
#define RSMI_TEMP_TYPE_EDGE 0
#define RSMI_CLK_TYPE_MEM 4
#define RSMI_CLK_TYPE_SYS 0
#define RSMI_TEMP_MAX 1
typedef int rsmi_status_t,
rsmi_temperature_metric_t,
rsmi_clk_type_t,
rsmi_memory_type_t;
struct rsmi_frequencies_t {uint32_t num_supported, current, frequency[RSMI_MAX_NUM_FREQUENCIES];};
//? Function pointers
rsmi_status_t (*rsmi_init)(uint64_t);
rsmi_status_t (*rsmi_shut_down)();
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_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_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_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_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*);
//? Data
void* rsmi_dl_handle;
#endif
bool initialized = false;
bool init();
bool shutdown();
template <bool is_init> bool collect(gpu_info* gpus_slice);
uint32_t device_count = 0;
}
#endif
}
namespace Mem {
@ -139,7 +253,7 @@ namespace Shared {
Cpu::collect();
if (Runner::coreNum_reset) Runner::coreNum_reset = false;
for (auto& [field, vec] : Cpu::current_cpu.cpu_percent) {
if (not vec.empty()) Cpu::available_fields.push_back(field);
if (not vec.empty() and not v_contains(Cpu::available_fields, field)) Cpu::available_fields.push_back(field);
}
Cpu::cpuName = Cpu::get_cpuName();
Cpu::got_sensors = Cpu::get_sensors();
@ -148,12 +262,32 @@ namespace Shared {
}
Cpu::core_mapping = Cpu::get_core_mapping();
//? Init for namespace Gpu
#ifdef GPU_SUPPORT
Gpu::Nvml::init();
Gpu::Rsmi::init();
if (not Gpu::gpu_names.empty()) {
for (auto const& [key, _] : Gpu::gpus[0].gpu_percent)
Cpu::available_fields.push_back(key);
for (auto const& [key, _] : Gpu::shared_gpu_percent)
Cpu::available_fields.push_back(key);
using namespace Gpu;
gpu_b_height_offsets.resize(gpus.size());
for (size_t i = 0; i < gpu_b_height_offsets.size(); ++i)
gpu_b_height_offsets[i] = gpus[i].supported_functions.gpu_utilization
+ gpus[i].supported_functions.pwr_usage
+ (gpus[i].supported_functions.mem_total or gpus[i].supported_functions.mem_used)
* (1 + 2*(gpus[i].supported_functions.mem_total and gpus[i].supported_functions.mem_used) + 2*gpus[i].supported_functions.mem_utilization);
}
#endif
//? Init for namespace Mem
Mem::old_uptime = system_uptime();
Mem::collect();
Logger::debug("Shared::init() : Initialized.");
}
}
namespace Cpu {
@ -167,7 +301,7 @@ namespace Cpu {
"irq"s, "softirq"s, "steal"s, "guest"s, "guest_nice"s
};
unordered_flat_map<string, long long> cpu_old = {
std::unordered_map<string, long long> cpu_old = {
{"totals", 0},
{"idles", 0},
{"user", 0},
@ -208,7 +342,7 @@ namespace Cpu {
}
auto name_vec = ssplit(name);
auto name_vec = ssplit(name, ' ');
if ((s_contains(name, "Xeon"s) or v_contains(name_vec, "Duo"s)) and v_contains(name_vec, "CPU"s)) {
auto cpu_pos = v_index(name_vec, "CPU"s);
@ -224,7 +358,7 @@ namespace Cpu {
}
else if (s_contains(name, "Intel"s) and v_contains(name_vec, "CPU"s)) {
auto cpu_pos = v_index(name_vec, "CPU"s);
if (cpu_pos < name_vec.size() - 1 and not name_vec.at(cpu_pos + 1).ends_with(')') and name_vec.at(cpu_pos + 1) != "@")
if (cpu_pos < name_vec.size() - 1 and not name_vec.at(cpu_pos + 1).ends_with(')') and name_vec.at(cpu_pos + 1).size() != 1)
name = name_vec.at(cpu_pos + 1);
else
name.clear();
@ -464,8 +598,8 @@ namespace Cpu {
return cpuhz;
}
auto get_core_mapping() -> unordered_flat_map<int, int> {
unordered_flat_map<int, int> core_map;
auto get_core_mapping() -> std::unordered_map<int, int> {
std::unordered_map<int, int> core_map;
if (cpu_temp_only) return core_map;
//? Try to get core mapping from /proc/cpuinfo
@ -538,7 +672,7 @@ namespace Cpu {
auto get_battery() -> tuple<int, long, string> {
if (not has_battery) return {0, 0, ""};
static string auto_sel;
static unordered_flat_map<string, battery> batteries;
static std::unordered_map<string, battery> batteries;
//? Get paths to needed files and check for valid values on first run
if (batteries.empty() and has_battery) {
@ -807,6 +941,572 @@ namespace Cpu {
}
}
#ifdef GPU_SUPPORT
namespace Gpu {
//? NVIDIA
namespace Nvml {
bool init() {
if (initialized) return false;
//? Dynamic loading & linking
//? Try possible library names for libnvidia-ml.so
const array libNvAlts = {
"libnvidia-ml.so",
"libnvidia-ml.so.1",
};
for (const auto& l : libNvAlts) {
nvml_dl_handle = dlopen(l, RTLD_LAZY);
if (nvml_dl_handle != nullptr) {
break;
}
}
if (!nvml_dl_handle) {
Logger::info("Failed to load libnvidia-ml.so, NVIDIA GPUs will not be detected: "s + dlerror());
return false;
}
auto load_nvml_sym = [&](const char sym_name[]) {
auto sym = dlsym(nvml_dl_handle, sym_name);
auto err = dlerror();
if (err != nullptr) {
Logger::error(string("NVML: Couldn't find function ") + sym_name + ": " + err);
return (void*)nullptr;
} else return sym;
};
#define LOAD_SYM(NAME) if ((NAME = (decltype(NAME))load_nvml_sym(#NAME)) == nullptr) return false
LOAD_SYM(nvmlErrorString);
LOAD_SYM(nvmlInit);
LOAD_SYM(nvmlShutdown);
LOAD_SYM(nvmlDeviceGetCount);
LOAD_SYM(nvmlDeviceGetHandleByIndex);
LOAD_SYM(nvmlDeviceGetName);
LOAD_SYM(nvmlDeviceGetPowerManagementLimit);
LOAD_SYM(nvmlDeviceGetTemperatureThreshold);
LOAD_SYM(nvmlDeviceGetUtilizationRates);
LOAD_SYM(nvmlDeviceGetClockInfo);
LOAD_SYM(nvmlDeviceGetPowerUsage);
LOAD_SYM(nvmlDeviceGetPowerState);
LOAD_SYM(nvmlDeviceGetTemperature);
LOAD_SYM(nvmlDeviceGetMemoryInfo);
LOAD_SYM(nvmlDeviceGetPcieThroughput);
#undef LOAD_SYM
//? Function calls
nvmlReturn_t result = nvmlInit();
if (result != NVML_SUCCESS) {
Logger::debug(std::string("Failed to initialize NVML, NVIDIA GPUs will not be detected: ") + nvmlErrorString(result));
return false;
}
//? Device count
result = nvmlDeviceGetCount(&device_count);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get device count: ") + nvmlErrorString(result));
return false;
}
if (device_count > 0) {
devices.resize(device_count);
gpus.resize(device_count);
gpu_names.resize(device_count);
initialized = true;
//? Check supported functions & get maximums
Nvml::collect<1>(gpus.data());
return true;
} else {initialized = true; shutdown(); return false;}
}
bool shutdown() {
if (!initialized) return false;
nvmlReturn_t result = nvmlShutdown();
if (NVML_SUCCESS == result) {
initialized = false;
dlclose(nvml_dl_handle);
} else Logger::warning(std::string("Failed to shutdown NVML: ") + nvmlErrorString(result));
return !initialized;
}
template <bool is_init> // collect<1> is called in Nvml::init(), and populates gpus.supported_functions
bool collect(gpu_info* gpus_slice) { // raw pointer to vector data, size == device_count
if (!initialized) return false;
nvmlReturn_t result;
std::thread pcie_tx_thread, pcie_rx_thread;
// DebugTimer nvTotalTimer("Nvidia Total");
for (unsigned int i = 0; i < device_count; ++i) {
if constexpr(is_init) {
//? Device Handle
result = nvmlDeviceGetHandleByIndex(i, devices.data() + i);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get device handle: ") + nvmlErrorString(result));
gpus[i].supported_functions = {false, false, false, false, false, false, false, false};
continue;
}
//? Device name
char name[NVML_DEVICE_NAME_BUFFER_SIZE];
result = nvmlDeviceGetName(devices[i], name, NVML_DEVICE_NAME_BUFFER_SIZE);
if (result != NVML_SUCCESS)
Logger::warning(std::string("NVML: Failed to get device name: ") + nvmlErrorString(result));
else {
gpu_names[i] = string(name);
for (const auto& brand : {"NVIDIA", "Nvidia", "(R)", "(TM)"}) {
gpu_names[i] = s_replace(gpu_names[i], brand, "");
}
gpu_names[i] = trim(gpu_names[i]);
}
//? Power usage
unsigned int max_power;
result = nvmlDeviceGetPowerManagementLimit(devices[i], &max_power);
if (result != NVML_SUCCESS)
Logger::warning(std::string("NVML: Failed to get maximum GPU power draw, defaulting to 225W: ") + nvmlErrorString(result));
else {
gpus[i].pwr_max_usage = max_power; // RSMI reports power in microWatts
gpu_pwr_total_max += max_power;
}
//? Get temp_max
unsigned int temp_max;
result = nvmlDeviceGetTemperatureThreshold(devices[i], NVML_TEMPERATURE_THRESHOLD_SHUTDOWN, &temp_max);
if (result != NVML_SUCCESS)
Logger::warning(std::string("NVML: Failed to get maximum GPU temperature, defaulting to 110°C: ") + nvmlErrorString(result));
else gpus[i].temp_max = (long long)temp_max;
}
//? PCIe link speeds, the data collection takes >=20ms each call so they run on separate threads
if (gpus_slice[i].supported_functions.pcie_txrx and (Config::getB("nvml_measure_pcie_speeds") or is_init)) {
pcie_tx_thread = std::thread([gpus_slice, i]() {
unsigned int tx;
nvmlReturn_t result = nvmlDeviceGetPcieThroughput(devices[i], NVML_PCIE_UTIL_TX_BYTES, &tx);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get PCIe TX throughput: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.pcie_txrx = false;
} else gpus_slice[i].pcie_tx = (long long)tx;
});
pcie_rx_thread = std::thread([gpus_slice, i]() {
unsigned int rx;
nvmlReturn_t result = nvmlDeviceGetPcieThroughput(devices[i], NVML_PCIE_UTIL_RX_BYTES, &rx);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get PCIe RX throughput: ") + nvmlErrorString(result));
} else gpus_slice[i].pcie_rx = (long long)rx;
});
}
// DebugTimer nvTimer("Nv utilization");
//? GPU & memory utilization
if (gpus_slice[i].supported_functions.gpu_utilization) {
nvmlUtilization_t utilization;
result = nvmlDeviceGetUtilizationRates(devices[i], &utilization);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get GPU utilization: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.gpu_utilization = false;
if constexpr(is_init) gpus_slice[i].supported_functions.mem_utilization = false;
} else {
gpus_slice[i].gpu_percent.at("gpu-totals").push_back((long long)utilization.gpu);
gpus_slice[i].mem_utilization_percent.push_back((long long)utilization.memory);
}
}
// nvTimer.stop_rename_reset("Nv clock");
//? Clock speeds
if (gpus_slice[i].supported_functions.gpu_clock) {
unsigned int gpu_clock;
result = nvmlDeviceGetClockInfo(devices[i], NVML_CLOCK_GRAPHICS, &gpu_clock);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get GPU clock speed: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.gpu_clock = false;
} else gpus_slice[i].gpu_clock_speed = (long long)gpu_clock;
}
if (gpus_slice[i].supported_functions.mem_clock) {
unsigned int mem_clock;
result = nvmlDeviceGetClockInfo(devices[i], NVML_CLOCK_MEM, &mem_clock);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get VRAM clock speed: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.mem_clock = false;
} else gpus_slice[i].mem_clock_speed = (long long)mem_clock;
}
// nvTimer.stop_rename_reset("Nv power");
//? Power usage & state
if (gpus_slice[i].supported_functions.pwr_usage) {
unsigned int power;
result = nvmlDeviceGetPowerUsage(devices[i], &power);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get GPU power usage: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.pwr_usage = false;
} else {
gpus_slice[i].pwr_usage = (long long)power;
gpus_slice[i].gpu_percent.at("gpu-pwr-totals").push_back(clamp((long long)round((double)gpus_slice[i].pwr_usage * 100.0 / (double)gpus_slice[i].pwr_max_usage), 0ll, 100ll));
}
}
if (gpus_slice[i].supported_functions.pwr_state) {
nvmlPstates_t pState;
result = nvmlDeviceGetPowerState(devices[i], &pState);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get GPU power state: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.pwr_state = false;
} else gpus_slice[i].pwr_state = static_cast<int>(pState);
}
// nvTimer.stop_rename_reset("Nv temp");
//? GPU temperature
if (gpus_slice[i].supported_functions.temp_info) {
if (Config::getB("check_temp")) {
unsigned int temp;
nvmlReturn_t result = nvmlDeviceGetTemperature(devices[i], NVML_TEMPERATURE_GPU, &temp);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get GPU temperature: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.temp_info = false;
} else gpus_slice[i].temp.push_back((long long)temp);
}
}
// nvTimer.stop_rename_reset("Nv mem");
//? Memory info
if (gpus_slice[i].supported_functions.mem_total) {
nvmlMemory_t memory;
result = nvmlDeviceGetMemoryInfo(devices[i], &memory);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get VRAM info: ") + nvmlErrorString(result));
if constexpr(is_init) gpus_slice[i].supported_functions.mem_total = false;
if constexpr(is_init) gpus_slice[i].supported_functions.mem_used = false;
} else {
gpus_slice[i].mem_total = memory.total;
gpus_slice[i].mem_used = memory.used;
//gpu.mem_free = memory.free;
auto used_percent = (long long)round((double)memory.used * 100.0 / (double)memory.total);
gpus_slice[i].gpu_percent.at("gpu-vram-totals").push_back(used_percent);
}
}
//? TODO: Processes using GPU
/*unsigned int proc_info_len;
nvmlProcessInfo_t* proc_info = 0;
result = nvmlDeviceGetComputeRunningProcesses_v3(device, &proc_info_len, proc_info);
if (result != NVML_SUCCESS) {
Logger::warning(std::string("NVML: Failed to get compute processes: ") + nvmlErrorString(result));
} else {
for (unsigned int i = 0; i < proc_info_len; ++i)
gpus_slice[i].graphics_processes.push_back({proc_info[i].pid, proc_info[i].usedGpuMemory});
}*/
// nvTimer.stop_rename_reset("Nv pcie thread join");
//? Join PCIE TX/RX threads
if constexpr(is_init) { // there doesn't seem to be a better way to do this, but this should be fine considering it's just 2 lines
pcie_tx_thread.join();
pcie_rx_thread.join();
} else if (gpus_slice[i].supported_functions.pcie_txrx and Config::getB("nvml_measure_pcie_speeds")) {
pcie_tx_thread.join();
pcie_rx_thread.join();
}
}
return true;
}
}
//? AMD
namespace Rsmi {
bool init() {
if (initialized) return false;
//? Dynamic loading & linking
#if !defined(RSMI_STATIC)
//? Try possible library paths and names for librocm_smi64.so
const array libRocAlts = {
"/opt/rocm/lib/librocm_smi64.so",
"librocm_smi64.so",
"librocm_smi64.so.5", // fedora
"librocm_smi64.so.1.0", // debian
};
for (const auto& l : libRocAlts) {
rsmi_dl_handle = dlopen(l, RTLD_LAZY);
if (rsmi_dl_handle != nullptr) {
break;
}
}
if (!rsmi_dl_handle) {
Logger::info("Failed to load librocm_smi64.so, AMD GPUs will not be detected: "s + dlerror());
return false;
}
auto load_rsmi_sym = [&](const char sym_name[]) {
auto sym = dlsym(rsmi_dl_handle, sym_name);
auto err = dlerror();
if (err != nullptr) {
Logger::error(string("ROCm SMI: Couldn't find function ") + sym_name + ": " + err);
return (void*)nullptr;
} else return sym;
};
#define LOAD_SYM(NAME) if ((NAME = (decltype(NAME))load_rsmi_sym(#NAME)) == nullptr) return false
LOAD_SYM(rsmi_init);
LOAD_SYM(rsmi_shut_down);
LOAD_SYM(rsmi_num_monitor_devices);
LOAD_SYM(rsmi_dev_name_get);
LOAD_SYM(rsmi_dev_power_cap_get);
LOAD_SYM(rsmi_dev_temp_metric_get);
LOAD_SYM(rsmi_dev_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_memory_total_get);
LOAD_SYM(rsmi_dev_memory_usage_get);
LOAD_SYM(rsmi_dev_pci_throughput_get);
#undef LOAD_SYM
#endif
//? Function calls
rsmi_status_t result = rsmi_init(0);
if (result != RSMI_STATUS_SUCCESS) {
Logger::debug("Failed to initialize ROCm SMI, AMD GPUs will not be detected");
return false;
}
//? Device count
result = rsmi_num_monitor_devices(&device_count);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to fetch number of devices");
return false;
}
if (device_count > 0) {
gpus.resize(gpus.size() + device_count);
gpu_names.resize(gpus.size() + device_count);
initialized = true;
//? Check supported functions & get maximums
Rsmi::collect<1>(gpus.data() + Nvml::device_count);
return true;
} else {initialized = true; shutdown(); return false;}
}
bool shutdown() {
if (!initialized) return false;
if (rsmi_shut_down() == RSMI_STATUS_SUCCESS) {
initialized = false;
#if !defined(RSMI_STATIC)
dlclose(rsmi_dl_handle);
#endif
} else Logger::warning("Failed to shutdown ROCm SMI");
return true;
}
template <bool is_init>
bool collect(gpu_info* gpus_slice) { // raw pointer to vector data, size == device_count, offset by Nvml::device_count elements
if (!initialized) return false;
rsmi_status_t result;
for (uint32_t i = 0; i < device_count; ++i) {
if constexpr(is_init) {
//? Device name
char name[NVML_DEVICE_NAME_BUFFER_SIZE]; // ROCm SMI does not provide a constant for this as far as I can tell, this should be good enough
result = rsmi_dev_name_get(i, name, NVML_DEVICE_NAME_BUFFER_SIZE);
if (result != RSMI_STATUS_SUCCESS)
Logger::warning("ROCm SMI: Failed to get device name");
else gpu_names[Nvml::device_count + i] = string(name);
//? Power usage
uint64_t max_power;
result = rsmi_dev_power_cap_get(i, 0, &max_power);
if (result != RSMI_STATUS_SUCCESS)
Logger::warning("ROCm SMI: Failed to get maximum GPU power draw, defaulting to 225W");
else {
gpus_slice[i].pwr_max_usage = (long long)(max_power/1000); // RSMI reports power in microWatts
gpu_pwr_total_max += gpus_slice[i].pwr_max_usage;
}
//? Get temp_max
int64_t temp_max;
result = rsmi_dev_temp_metric_get(i, RSMI_TEMP_TYPE_EDGE, RSMI_TEMP_MAX, &temp_max);
if (result != RSMI_STATUS_SUCCESS)
Logger::warning("ROCm SMI: Failed to get maximum GPU temperature, defaulting to 110°C");
else gpus_slice[i].temp_max = (long long)temp_max;
}
//? GPU utilization
if (gpus_slice[i].supported_functions.gpu_utilization) {
uint32_t utilization;
result = rsmi_dev_busy_percent_get(i, &utilization);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get GPU utilization");
if constexpr(is_init) gpus_slice[i].supported_functions.gpu_utilization = false;
} else gpus_slice[i].gpu_percent.at("gpu-totals").push_back((long long)utilization);
}
//? Memory utilization
if (gpus_slice[i].supported_functions.mem_utilization) {
uint32_t utilization;
result = rsmi_dev_memory_busy_percent_get(i, &utilization);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get VRAM utilization");
if constexpr(is_init) gpus_slice[i].supported_functions.mem_utilization = false;
} else gpus_slice[i].mem_utilization_percent.push_back((long long)utilization);
}
//? Clock speeds
if (gpus_slice[i].supported_functions.gpu_clock) {
rsmi_frequencies_t frequencies;
result = rsmi_dev_gpu_clk_freq_get(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) {
rsmi_frequencies_t frequencies;
result = rsmi_dev_gpu_clk_freq_get(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
}
//? Power usage & state
if (gpus_slice[i].supported_functions.pwr_usage) {
uint64_t power;
result = rsmi_dev_power_ave_get(i, 0, &power);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get GPU power usage");
if constexpr(is_init) gpus_slice[i].supported_functions.pwr_usage = false;
} else gpus_slice[i].gpu_percent.at("gpu-pwr-totals").push_back(clamp((long long)round((double)gpus_slice[i].pwr_usage * 100.0 / (double)gpus_slice[i].pwr_max_usage), 0ll, 100ll));
if constexpr(is_init) gpus_slice[i].supported_functions.pwr_state = false;
}
//? GPU temperature
if (gpus_slice[i].supported_functions.temp_info) {
if (Config::getB("check_temp") or is_init) {
int64_t temp;
result = rsmi_dev_temp_metric_get(i, RSMI_TEMP_TYPE_EDGE, RSMI_TEMP_CURRENT, &temp);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get GPU temperature");
if constexpr(is_init) gpus_slice[i].supported_functions.temp_info = false;
} else gpus_slice[i].temp.push_back((long long)temp/1000);
}
}
//? Memory info
if (gpus_slice[i].supported_functions.mem_total) {
uint64_t total;
result = rsmi_dev_memory_total_get(i, RSMI_MEM_TYPE_VRAM, &total);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get total VRAM");
if constexpr(is_init) gpus_slice[i].supported_functions.mem_total = false;
} else gpus_slice[i].mem_total = total;
}
if (gpus_slice[i].supported_functions.mem_used) {
uint64_t used;
result = rsmi_dev_memory_usage_get(i, RSMI_MEM_TYPE_VRAM, &used);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get VRAM usage");
if constexpr(is_init) gpus_slice[i].supported_functions.mem_used = false;
} else {
gpus_slice[i].mem_used = used;
if (gpus_slice[i].supported_functions.mem_total)
gpus_slice[i].gpu_percent.at("gpu-vram-totals").push_back((long long)round((double)used * 100.0 / (double)gpus_slice[i].mem_total));
}
}
//? PCIe link speeds
if (gpus_slice[i].supported_functions.pcie_txrx) {
uint64_t tx, rx;
result = rsmi_dev_pci_throughput_get(i, &tx, &rx, 0);
if (result != RSMI_STATUS_SUCCESS) {
Logger::warning("ROCm SMI: Failed to get PCIe throughput");
if constexpr(is_init) gpus_slice[i].supported_functions.pcie_txrx = false;
} else {
gpus_slice[i].pcie_tx = (long long)tx;
gpus_slice[i].pcie_rx = (long long)rx;
}
}
}
return true;
}
}
// TODO: Intel
//? Collect data from GPU-specific libraries
auto collect(bool no_update) -> vector<gpu_info>& {
if (Runner::stopping or (no_update and not gpus.empty())) return gpus;
// DebugTimer gpu_timer("GPU Total");
//* Collect data
Nvml::collect<0>(gpus.data()); // raw pointer to vector data, size == Nvml::device_count
Rsmi::collect<0>(gpus.data() + Nvml::device_count); // size = Rsmi::device_count
//* Calculate average usage
long long avg = 0;
long long mem_usage_total = 0;
long long mem_total = 0;
long long pwr_total = 0;
for (auto& gpu : gpus) {
if (gpu.supported_functions.gpu_utilization)
avg += gpu.gpu_percent.at("gpu-totals").back();
if (gpu.supported_functions.mem_used)
mem_usage_total += gpu.mem_used;
if (gpu.supported_functions.mem_total)
mem_total += gpu.mem_total;
if (gpu.supported_functions.pwr_usage)
mem_total += gpu.pwr_usage;
//* Trim vectors if there are more values than needed for graphs
if (width != 0) {
//? GPU & memory utilization
while (cmp_greater(gpu.gpu_percent.at("gpu-totals").size(), width * 2)) gpu.gpu_percent.at("gpu-totals").pop_front();
while (cmp_greater(gpu.mem_utilization_percent.size(), width)) gpu.mem_utilization_percent.pop_front();
//? Power usage
while (cmp_greater(gpu.gpu_percent.at("gpu-pwr-totals").size(), width)) gpu.gpu_percent.at("gpu-pwr-totals").pop_front();
//? Temperature
while (cmp_greater(gpu.temp.size(), 18)) gpu.temp.pop_front();
//? Memory usage
while (cmp_greater(gpu.gpu_percent.at("gpu-vram-totals").size(), width/2)) gpu.gpu_percent.at("gpu-vram-totals").pop_front();
}
}
shared_gpu_percent.at("gpu-average").push_back(avg / gpus.size());
if (mem_total != 0)
shared_gpu_percent.at("gpu-vram-total").push_back(mem_usage_total / mem_total);
if (gpu_pwr_total_max != 0)
shared_gpu_percent.at("gpu-pwr-total").push_back(pwr_total / gpu_pwr_total_max);
if (width != 0) {
while (cmp_greater(shared_gpu_percent.at("gpu-average").size(), width * 2)) shared_gpu_percent.at("gpu-average").pop_front();
while (cmp_greater(shared_gpu_percent.at("gpu-pwr-total").size(), width * 2)) shared_gpu_percent.at("gpu-pwr-total").pop_front();
while (cmp_greater(shared_gpu_percent.at("gpu-vram-total").size(), width * 2)) shared_gpu_percent.at("gpu-vram-total").pop_front();
}
return gpus;
}
}
#endif
namespace Mem {
bool has_swap{}; // defaults to false
vector<string> fstab;
@ -939,6 +1639,7 @@ namespace Mem {
auto only_physical = Config::getB("only_physical");
auto zfs_hide_datasets = Config::getB("zfs_hide_datasets");
auto& disks = mem.disks;
static std::unordered_map<string, future<pair<disk_info, int>>> disks_stats_promises;
ifstream diskread;
vector<string> filter;
@ -1078,31 +1779,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) or disk.name == "swap") {
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<disk_info, int> {
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
@ -1245,29 +1962,32 @@ namespace Mem {
}
// looking through all files that start with 'objset' to find the one containing `device_name` object stats
for (const auto& file: fs::directory_iterator(zfs_pool_stat_path)) {
filename = file.path().filename();
if (filename.starts_with("objset")) {
filestream.open(file.path());
if (filestream.good()) {
// skip first two lines
for (int i = 0; i < 2; i++) filestream.ignore(numeric_limits<streamsize>::max(), '\n');
// skip characters until '7' is reached, indicating data type 7, next value will be object name
filestream.ignore(numeric_limits<streamsize>::max(), '7');
filestream >> name_compare;
if (name_compare == device_name) {
filestream.close();
if (access(file.path().c_str(), R_OK) == 0) {
return file.path();
} else {
Logger::debug("Can't access file: " + file.path().string());
return "";
try {
for (const auto& file: fs::directory_iterator(zfs_pool_stat_path)) {
filename = file.path().filename();
if (filename.starts_with("objset")) {
filestream.open(file.path());
if (filestream.good()) {
// skip first two lines
for (int i = 0; i < 2; i++) filestream.ignore(numeric_limits<streamsize>::max(), '\n');
// skip characters until '7' is reached, indicating data type 7, next value will be object name
filestream.ignore(numeric_limits<streamsize>::max(), '7');
filestream >> name_compare;
if (name_compare == device_name) {
filestream.close();
if (access(file.path().c_str(), R_OK) == 0) {
return file.path();
} else {
Logger::debug("Can't access file: " + file.path().string());
return "";
}
}
}
filestream.close();
}
filestream.close();
}
}
catch (fs::filesystem_error& e) {}
Logger::debug("Could not read directory: " + zfs_pool_stat_path.string());
return "";
@ -1354,13 +2074,13 @@ namespace Mem {
}
namespace Net {
unordered_flat_map<string, net_info> current_net;
std::unordered_map<string, net_info> current_net;
net_info empty_net = {};
vector<string> interfaces;
string selected_iface;
int errors{}; // defaults to 0
unordered_flat_map<string, uint64_t> graph_max = { {"download", {}}, {"upload", {}} };
unordered_flat_map<string, array<int, 2>> max_count = { {"download", {}}, {"upload", {}} };
std::unordered_map<string, uint64_t> graph_max = { {"download", {}}, {"upload", {}} };
std::unordered_map<string, array<int, 2>> max_count = { {"download", {}}, {"upload", {}} };
bool rescale{true};
uint64_t timestamp{}; // defaults to 0
@ -1499,7 +2219,6 @@ namespace Net {
else
it++;
}
net.compact();
}
timestamp = new_timestamp;
@ -1569,7 +2288,7 @@ namespace Net {
namespace Proc {
vector<proc_info> current_procs;
unordered_flat_map<string, string> uid_user;
std::unordered_map<string, string> uid_user;
string current_sort;
string current_filter;
bool current_rev{}; // defaults to false
@ -1584,7 +2303,7 @@ namespace Proc {
detail_container detailed;
constexpr size_t KTHREADD = 2;
static robin_hood::unordered_set<size_t> kernels_procs = {KTHREADD};
static std::unordered_set<size_t> kernels_procs = {KTHREADD};
//* Get detailed info for selected process
void _collect_details(const size_t pid, const uint64_t uptime, vector<proc_info>& procs) {
@ -2070,6 +2789,6 @@ namespace Tools {
catch (const std::invalid_argument&) {}
catch (const std::out_of_range&) {}
}
throw std::runtime_error("Failed get uptime from from " + string{Shared::procPath} + "/uptime");
throw std::runtime_error("Failed to get uptime from " + string{Shared::procPath} + "/uptime");
}
}

View file

@ -16,6 +16,7 @@ indent = tab
tab-size = 4
*/
#include <Availability.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <arpa/inet.h>
@ -44,6 +45,7 @@ tab-size = 4
#include <netinet/in.h> // for inet_ntop
#include <unistd.h>
#include <stdexcept>
#include <utility>
#include <cmath>
#include <fstream>
@ -56,7 +58,9 @@ tab-size = 4
#include "../btop_shared.hpp"
#include "../btop_tools.hpp"
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
#include "sensors.hpp"
#endif
#include "smc.hpp"
using std::clamp, std::string_literals::operator""s, std::cmp_equal, std::cmp_less, std::cmp_greater;
@ -70,7 +74,7 @@ using namespace Tools;
namespace Cpu {
vector<long long> core_old_totals;
vector<long long> core_old_idles;
vector<string> available_fields = {"total"};
vector<string> available_fields = {"Auto", "total"};
vector<string> available_sensors = {"Auto"};
cpu_info current_cpu;
bool got_sensors = false, cpu_temp_only = false;
@ -95,7 +99,7 @@ namespace Cpu {
string cpu_sensor;
vector<string> core_sensors;
unordered_flat_map<int, int> core_mapping;
std::unordered_map<int, int> core_mapping;
} // namespace Cpu
namespace Mem {
@ -191,7 +195,7 @@ namespace Cpu {
const array<string, 10> time_names = {"user", "nice", "system", "idle"};
unordered_flat_map<string, long long> cpu_old = {
std::unordered_map<string, long long> cpu_old = {
{"totals", 0},
{"idles", 0},
{"user", 0},
@ -236,7 +240,7 @@ namespace Cpu {
name += n + ' ';
}
name.pop_back();
for (const auto& replace : {"Processor", "CPU", "(R)", "(TM)", "Intel", "AMD", "Core"}) {
for (const auto& replace : {"Processor", "CPU", "(R)", "(TM)", "Intel", "AMD", "Apple", "Core"}) {
name = s_replace(name, replace, "");
name = s_replace(name, " ", " ");
}
@ -250,6 +254,7 @@ namespace Cpu {
Logger::debug("get_sensors(): show_coretemp=" + std::to_string(Config::getB("show_coretemp")) + " check_temp=" + std::to_string(Config::getB("check_temp")));
got_sensors = false;
if (Config::getB("show_coretemp") and Config::getB("check_temp")) {
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
ThermalSensors sensors;
if (sensors.getSensors() > 0) {
Logger::debug("M1 sensors found");
@ -257,6 +262,7 @@ namespace Cpu {
cpu_temp_only = true;
macM1 = true;
} else {
#endif
// try SMC (intel)
Logger::debug("checking intel");
SMCConnection smcCon;
@ -281,7 +287,9 @@ namespace Cpu {
// ignore, we don't have temp
got_sensors = false;
}
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
}
#endif
}
return got_sensors;
}
@ -290,11 +298,12 @@ namespace Cpu {
current_cpu.temp_max = 95; // we have no idea how to get the critical temp
try {
if (macM1) {
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
ThermalSensors sensors;
current_cpu.temp.at(0).push_back(sensors.getSensors());
if (current_cpu.temp.at(0).size() > 20)
current_cpu.temp.at(0).pop_front();
#endif
} else {
SMCConnection smcCon;
int threadsPerCore = Shared::coreCount / Shared::physicalCoreCount;
@ -329,8 +338,8 @@ namespace Cpu {
return std::to_string(freq / 1000.0 / 1000.0 / 1000.0).substr(0, 3);
}
auto get_core_mapping() -> unordered_flat_map<int, int> {
unordered_flat_map<int, int> core_map;
auto get_core_mapping() -> std::unordered_map<int, int> {
std::unordered_map<int, int> core_map;
if (cpu_temp_only) return core_map;
natural_t cpu_count;
@ -591,7 +600,7 @@ namespace Mem {
io_object_t &object;
};
void collect_disk(unordered_flat_map<string, disk_info> &disks, unordered_flat_map<string, string> &mapping) {
void collect_disk(std::unordered_map<string, disk_info> &disks, std::unordered_map<string, string> &mapping) {
io_registry_entry_t drive;
io_iterator_t drive_list;
@ -708,7 +717,7 @@ namespace Mem {
}
if (show_disks) {
unordered_flat_map<string, string> mapping; // keep mapping from device -> mountpoint, since IOKit doesn't give us the mountpoint
std::unordered_map<string, string> mapping; // keep mapping from device -> mountpoint, since IOKit doesn't give us the mountpoint
double uptime = system_uptime();
auto &disks_filter = Config::getS("disks_filter");
bool filter_exclude = false;
@ -821,13 +830,13 @@ namespace Mem {
} // namespace Mem
namespace Net {
unordered_flat_map<string, net_info> current_net;
std::unordered_map<string, net_info> current_net;
net_info empty_net = {};
vector<string> interfaces;
string selected_iface;
int errors = 0;
unordered_flat_map<string, uint64_t> graph_max = {{"download", {}}, {"upload", {}}};
unordered_flat_map<string, array<int, 2>> max_count = {{"download", {}}, {"upload", {}}};
std::unordered_map<string, uint64_t> graph_max = {{"download", {}}, {"upload", {}}};
std::unordered_map<string, array<int, 2>> max_count = {{"download", {}}, {"upload", {}}};
bool rescale = true;
uint64_t timestamp = 0;
@ -904,7 +913,7 @@ namespace Net {
} // else, ignoring family==AF_LINK (see man 3 getifaddrs)
}
unordered_flat_map<string, std::tuple<uint64_t, uint64_t>> ifstats;
std::unordered_map<string, std::tuple<uint64_t, uint64_t>> ifstats;
int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0};
size_t len;
if (sysctl(mib, 6, nullptr, &len, nullptr, 0) < 0) {
@ -978,7 +987,6 @@ namespace Net {
else
it++;
}
net.compact();
}
timestamp = new_timestamp;
@ -1049,7 +1057,7 @@ namespace Net {
namespace Proc {
vector<proc_info> current_procs;
unordered_flat_map<string, string> uid_user;
std::unordered_map<string, string> uid_user;
string current_sort;
string current_filter;
bool current_rev = false;

View file

@ -16,6 +16,8 @@ indent = tab
tab-size = 4
*/
#include <Availability.h>
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
#include "sensors.hpp"
#include <CoreFoundation/CoreFoundation.h>
@ -109,3 +111,4 @@ long long Cpu::ThermalSensors::getSensors() {
if (temps.empty()) return 0ll;
return round(std::accumulate(temps.begin(), temps.end(), 0ll) / temps.size());
}
#endif

View file

@ -16,9 +16,12 @@ indent = tab
tab-size = 4
*/
#include <Availability.h>
#if __MAC_OS_X_VERSION_MIN_REQUIRED > 101504
namespace Cpu {
class ThermalSensors {
public:
long long getSensors();
};
} // namespace Cpu
#endif

View file

@ -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"

86
themes/horizon.theme Normal file
View file

@ -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"