Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package btop for openSUSE:Factory checked in at 2025-09-22 19:29:16 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/btop (Old) and /work/SRC/openSUSE:Factory/.btop.new.27445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "btop" Mon Sep 22 19:29:16 2025 rev:39 rq:1306565 version:1.4.4+git20250910.bdddfc4 Changes: -------- --- /work/SRC/openSUSE:Factory/btop/btop.changes 2025-07-31 17:50:15.866285513 +0200 +++ /work/SRC/openSUSE:Factory/.btop.new.27445/btop.changes 2025-09-22 19:29:18.705928456 +0200 @@ -1,0 +2,38 @@ +Mon Sep 15 13:55:27 UTC 2025 - Scott Bradnick <[email protected]> + +- Commenting out code for RSMI_STATIC + * Removing rocm_smi_lib-rocm-6.4.3.tar.gz + * Adding 'Recommends: rocm-smi' +- Update to version 1.4.4+git20250910.bdddfc4: + * Enable vim movement in help menu (#1242) + * Remove reduntant symbols in tree view (#948) + * Use /sys/dev/block/MAJOR:MINOR instead of /sys/block/NAME for disk I/O + * Don't terminate on GPU access failure + * fix: setcap cap_dac_read_search was overriding cap_perfmon + * Fix musl builds missing artifacts + * chore(deps): update actions/checkout action to v5 + * chore(deps): update actions/checkout action to v5 + * Update README.md + * feat: display CPU power draw & fix GPU+load avg overwriting core info + * refactor: remove reduntant casts and avoid conversions + * Revert unnecessary locale changes and remove debug line. + +------------------------------------------------------------------- +Thu Aug 07 15:08:30 UTC 2025 - Scott Bradnick <[email protected]> + +- Updating ROCm to v6.4.3 +- Update to version 1.4.4+git20250805.a05192f: + * fix: disable locale when writing config file + * Update CODE_OF_CONDUCT.md + * match formatting for units + * fix layout issue when enc/dec meters are unavailable + * disable encode/decode monitoring on AMD and Intel GPUs + * impl encode/decode monitoring for Nvidia + * Add utilisation meters for GPU hardware video encoder and decoder + * linux-batt: Battery Time-to-full + * Convert ascii escape codes in mountpoint names before reading statvfs. + * Fix presets erroring with gpu* usage. + * Clarify where btop loads themes from + * Update "cpu responsive" to "cpu direct" in README.md (#1199) + +------------------------------------------------------------------- Old: ---- btop-1.4.4+git20250718.86ec5fd.tar.gz rocm_smi_lib-rocm-6.4.2.tar.gz New: ---- btop-1.4.4+git20250910.bdddfc4.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ btop.spec ++++++ --- /var/tmp/diff_new_pack.K2fSxJ/_old 2025-09-22 19:29:19.713970908 +0200 +++ /var/tmp/diff_new_pack.K2fSxJ/_new 2025-09-22 19:29:19.713970908 +0200 @@ -15,21 +15,27 @@ # Please submit bugfixes or comments via https://bugs.opensuse.org/ # -%define ROCm_version 6.4.2 +### 20250915: TO_BE_REMOVED +#%%define ROCm_version 6.4.3 +##### Name: btop -Version: 1.4.4+git20250718.86ec5fd +Version: 1.4.4+git20250910.bdddfc4 Release: 0 Summary: Usage and stats for processor, memory, disks, network and processes License: Apache-2.0 Group: System/Monitoring URL: https://github.com/aristocratos/btop Source0: %{name}-%{version}.tar.gz -Source1: https://github.com/ROCm/rocm_smi_lib/archive/refs/tags/rocm-%{ROCm_version}.tar.gz#/rocm_smi_lib-rocm-%{ROCm_version}.tar.gz +### 20250915: TO_BE_REMOVED +#Source1: https://github.com/ROCm/rocm_smi_lib/archive/refs/tags/rocm-%%{ROCm_version}.tar.gz#/rocm_smi_lib-rocm-%%{ROCm_version}.tar.gz +##### Source99: btop-rpmlintrc Patch0: Makefile.diff BuildRequires: coreutils BuildRequires: cmake BuildRequires: pkgconfig(libdrm) +#BuildRequires: rocm-smi +#BuildRequires: rocm-smi-devel BuildRequires: sed %if 0%{?suse_version} < 1550 BuildRequires: gcc13-c++ @@ -48,6 +54,7 @@ %define cxxopt %{nil} %define lddopt %{nil} %endif +Recommends: rocm-smi %description Resource monitor that shows usage and stats for processor, memory, disks, @@ -55,15 +62,20 @@ %prep %autosetup -p0 -cd %{_builddir}/%{name}-%{version} -mkdir -vp %{_builddir}/%{name}-%{version}/lib/rocm_smi_lib -tar zxf %{SOURCE1} -C %{_builddir}/%{name}-%{version}/lib/rocm_smi_lib --strip-components=1 +### 20250915: TO_BE_REMOVED +#cd %%{_builddir}/%%{name}-%%{version} +#mkdir -vp %%{_builddir}/%%{name}-%%{version}/lib/rocm_smi_lib +#tar zxf %%{SOURCE1} -C %%{_builddir}/%%{name}-%%{version}/lib/rocm_smi_lib --strip-components=1 +##### %build ### ### RSMI_STATIC will break with gcc-14, as of <= v6.1.2 (20240606) ### -%make_build %{cxxflags} %{cxxopt} %{lddopt} RSMI_STATIC=true +%make_build %{cxxflags} %{cxxopt} %{lddopt} +### 20250915: TO_BE_REMOVED +#RSMI_STATIC=true +##### %install %make_install %{cxxopt} %{lddopt} PREFIX=%{_prefix} ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.K2fSxJ/_old 2025-09-22 19:29:19.757972761 +0200 +++ /var/tmp/diff_new_pack.K2fSxJ/_new 2025-09-22 19:29:19.761972929 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/aristocratos/btop</param> - <param name="changesrevision">86ec5fd06282a96ae46542e653490b7144e801f9</param></service></servicedata> + <param name="changesrevision">bdddfc46a2bbfe4ba70c7fba4fbb30978d61dab9</param></service></servicedata> (No newline at EOF) ++++++ btop-1.4.4+git20250718.86ec5fd.tar.gz -> btop-1.4.4+git20250910.bdddfc4.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-freebsd.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-freebsd.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-freebsd.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-freebsd.yml 2025-09-10 17:49:55.000000000 +0200 @@ -33,7 +33,7 @@ arch: ['aarch64', 'x86_64'] version: ['14.3', '15.0'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Compile uses: vmactions/freebsd-vm@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-linux.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-linux.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-linux.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-linux.yml 2025-09-10 17:49:55.000000000 +0200 @@ -44,7 +44,7 @@ - compiler: gcc version: 14 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install clang ${{ matrix.version }} if: ${{ matrix.compiler == 'clang' }} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-macos.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-macos.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-macos.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-macos.yml 2025-09-10 17:49:55.000000000 +0200 @@ -28,7 +28,7 @@ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install build tools run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-netbsd.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-netbsd.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/cmake-netbsd.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/cmake-netbsd.yml 2025-09-10 17:49:55.000000000 +0200 @@ -33,7 +33,7 @@ arch: ['aarch64', 'amd64'] version: ['10.1'] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Compile uses: vmactions/netbsd-vm@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-freebsd.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-freebsd.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-freebsd.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-freebsd.yml 2025-09-10 17:49:55.000000000 +0200 @@ -37,7 +37,7 @@ matrix: compiler: ["clang++", "g++"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Compile uses: vmactions/freebsd-vm@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-gpu.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-gpu.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-gpu.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-gpu.yml 2025-09-10 17:49:55.000000000 +0200 @@ -37,7 +37,7 @@ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install build tools run: apk add --no-cache --update gcc g++ make linux-headers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-linux.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-linux.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-linux.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-linux.yml 2025-09-10 17:49:55.000000000 +0200 @@ -90,14 +90,17 @@ container: muslcc/x86_64:${{ matrix.toolchain }} steps: + - name: Update alpine repositories + run: sed -i 's/3\.14/3\.22/' /etc/apk/repositories + - name: Install build tools - run: apk add --no-cache coreutils git make tar zstd + run: apk add --no-cache --upgrade coreutils git make tar zstd - name: Fix - Unsafe repository stop run: git config --global --add safe.directory /__w/btop/btop - name: Checkout source - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: recursive @@ -126,4 +129,5 @@ uses: actions/upload-artifact@v4 with: name: btop-${{ matrix.toolchain }} - path: '.artifacts/**' + path: '${{ github.workspace }}/.artifacts/*' + include-hidden-files: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-macos.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-macos.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-macos.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-macos.yml 2025-09-10 17:49:55.000000000 +0200 @@ -43,7 +43,7 @@ with: xcode-version: latest-stable - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install build tools run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-netbsd.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-netbsd.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-netbsd.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-netbsd.yml 2025-09-10 17:49:55.000000000 +0200 @@ -34,7 +34,7 @@ runs-on: ubuntu-24.04 timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Compile uses: vmactions/netbsd-vm@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-openbsd.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-openbsd.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/continuous-build-openbsd.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/continuous-build-openbsd.yml 2025-09-10 17:49:55.000000000 +0200 @@ -34,7 +34,7 @@ runs-on: ubuntu-24.04 timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Compile uses: vmactions/openbsd-vm@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/test-snap-can-build.yml new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/test-snap-can-build.yml --- old/btop-1.4.4+git20250718.86ec5fd/.github/workflows/test-snap-can-build.yml 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/.github/workflows/test-snap-can-build.yml 2025-09-10 17:49:55.000000000 +0200 @@ -34,7 +34,7 @@ node-version: [20.x] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: snapcore/action-build@v1 id: build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/CODE_OF_CONDUCT.md new/btop-1.4.4+git20250910.bdddfc4/CODE_OF_CONDUCT.md --- old/btop-1.4.4+git20250718.86ec5fd/CODE_OF_CONDUCT.md 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/CODE_OF_CONDUCT.md 2025-09-10 17:49:55.000000000 +0200 @@ -1,76 +1,93 @@ -# Contributor Covenant Code of Conduct + +# Contributor Covenant 3.0 ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +We pledge to make our community welcoming, safe, and equitable for all. + +We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant. + + +## Encouraged Behaviors + +While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language. + +With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including: + +1. Respecting the **purpose of our community**, our activities, and our ways of gathering. +2. Engaging **kindly and honestly** with others. +3. Respecting **different viewpoints** and experiences. +4. **Taking responsibility** for our actions and contributions. +5. Gracefully giving and accepting **constructive feedback**. +6. Committing to **repairing harm** when it occurs. +7. Behaving in other ways that promote and sustain the **well-being of our community**. + + +## Restricted Behaviors + +We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct. + +1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop. +2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people. +3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits. +4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community. +5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission. +6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group. +7. Behaving in other ways that **threaten the well-being** of our community. + +### Other Restrictions + +1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions. +2. **Failing to credit sources.** Not properly crediting the sources of content you contribute. +3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community. +4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors. + + +## Reporting an Issue + +Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm. + +When an incident does occur, it is important to report it promptly. To report a possible violation, **[NOTE: describe your means of reporting here.]** + +Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution. + + +## Addressing and Repairing Harm + +**[NOTE: The remedies and repairs outlined below are suggestions based on best practices in code of conduct enforcement. If your community has its own established enforcement process, be sure to edit this section to describe your own policies.]** + +If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped. + +1) Warning + 1) Event: A violation involving a single incident or series of incidents. + 2) Consequence: A private, written warning from the Community Moderators. + 3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations. +2) Temporarily Limited Activities + 1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation. + 2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members. + 3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over. +3) Temporary Suspension + 1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation. + 2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions. + 3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted. +4) Permanent Ban + 1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member. + 2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior. + 3) Repair: There is no possible repair in cases of this severity. + +This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community. + ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [email protected]. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html +This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/). + +Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/) -[homepage]: https://www.contributor-covenant.org +For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion). -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/Makefile new/btop-1.4.4+git20250910.bdddfc4/Makefile --- old/btop-1.4.4+git20250718.86ec5fd/Makefile 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/Makefile 2025-09-10 17:49:55.000000000 +0200 @@ -333,7 +333,7 @@ setcap: @printf "\033[1;97mFile: $(DESTDIR)$(PREFIX)/bin/btop\n" @printf "\033[1;92mSetting capabilities...\033[0m\n" - @setcap cap_perfmon=+ep $(DESTDIR)$(PREFIX)/bin/btop + @setcap "cap_perfmon=+ep cap_dac_read_search=+ep" $(DESTDIR)$(PREFIX)/bin/btop # With 'rm -v' user will see what files (if any) got removed uninstall: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/README.md new/btop-1.4.4+git20250910.bdddfc4/README.md --- old/btop-1.4.4+git20250718.86ec5fd/README.md 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/README.md 2025-09-10 17:49:55.000000000 +0200 @@ -203,12 +203,26 @@ ## Themes -Btop++ uses the same theme files as bpytop and bashtop (some color values missing in bashtop themes) . +Btop++ uses the same theme files as bpytop and bashtop (some color values missing in bashtop themes). See [themes](https://github.com/aristocratos/btop/tree/main/themes) folder for available themes. +Btop searches the following directories for system themes: + +* `../share/btop/themes` (this path is relative to the btop executable) +* `/usr/local/share/btop/themes` +* `/usr/share/btop/themes` + +The first directory that exists and isn't empty is used as the system themes directory. + +The user themes directory depends on which environment variables are set: + +* If `$XDG_CONFIG_HOME` is set, the user themes directory is `$XDG_CONFIG_HOME/btop/themes` +* Otherwise, if `$HOME` is set, the user themes directory is `$HOME/.config/btop/themes` +* Otherwise, the user themes directory is `~/.config/btop/themes` + The `make install` command places the default themes in `[$PREFIX or /usr/local]/share/btop/themes`. -User created themes should be placed in `$XDG_CONFIG_HOME/btop/themes` or `$HOME/.config/btop/themes`. +User created themes should be placed in the user themes directory. Let me know if you want to contribute with new themes. @@ -317,11 +331,11 @@ sudo make install ``` -3. **(Optional/Required for Intel GPU) Set extended capabilities or suid bit to btop** +3. **(Optional/Required for Intel GPU and CPU wattage) Set extended capabilities or suid bit to btop** Enables signal sending to any process without starting with `sudo` and can prevent /proc read permissions problems on some systems. - Is required for Intel GPU support. + Is required for Intel GPU support and CPU wattage monitoring. * **Run:** @@ -471,11 +485,11 @@ Notice! Only use "sudo" when installing to a NON user owned directory. -5. **(Optional/Required for Intel GPU support) Set extended capabilities or suid bit to btop** +5. **(Optional/Required for Intel GPU support and CPU wattage) Set extended capabilities or suid bit to btop** No need for `sudo` to enable signal sending to any process and to prevent /proc read permissions problems on some systems. - Also required for Intel GPU monitoring. + Also required for Intel GPU monitoring and CPU wattage monitoring. Run after make install and use same PREFIX if any was used at install. @@ -1340,8 +1354,8 @@ #* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. update_ms = 1500 -#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu responsive", -#* "cpu lazy" sorts top process over time (easier to follow), "cpu responsive" updates top process directly. +#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", +#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. proc_sorting = "cpu lazy" #* Reverse sorting order, True or False. @@ -1388,6 +1402,9 @@ #* Shows the system uptime in the CPU box. show_uptime = True +#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo. +show_cpu_watts = True + #* Show cpu temperature. check_temp = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/btop.cpp new/btop-1.4.4+git20250910.bdddfc4/src/btop.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/btop.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/btop.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -898,7 +898,6 @@ //? Try to find and set a UTF-8 locale if (std::setlocale(LC_ALL, "") != nullptr and not s_contains((string)std::setlocale(LC_ALL, ""), ";") and str_to_upper(s_replace((string)std::setlocale(LC_ALL, ""), "-", "")).ends_with("UTF8")) { - std::locale::global(std::locale(std::setlocale(LC_ALL, ""))); Logger::debug("Using locale " + std::locale().name()); } else { @@ -921,7 +920,6 @@ if (str_to_upper(s_replace(l, "-", "")).ends_with("UTF8")) { found = l.substr(l.find('=') + 1); if (std::setlocale(LC_ALL, found.c_str()) != nullptr) { - std::locale::global(std::locale(found)); break; } } @@ -943,11 +941,9 @@ Logger::warning("No UTF-8 locale detected! Some symbols might not display correctly."); } else if (std::setlocale(LC_ALL, string(cur_locale + ".UTF-8").c_str()) != nullptr) { - std::locale::global(std::locale(cur_locale + ".UTF-8")); Logger::debug("Setting LC_ALL=" + cur_locale + ".UTF-8"); } else if(std::setlocale(LC_ALL, "en_US.UTF-8") != nullptr) { - std::locale::global(std::locale("en_US.UTF-8")); Logger::debug("Setting LC_ALL=en_US.UTF-8"); } else { @@ -977,8 +973,6 @@ Logger::info("Running on " + Term::current_tty); } - Logger::debug(to_string(1.0).substr(1,1)); - configure_tty_mode(cli.force_tty); //? Check for valid terminal dimensions diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/btop_config.cpp new/btop-1.4.4+git20250910.bdddfc4/src/btop_config.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/btop_config.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/btop_config.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -20,6 +20,7 @@ #include <atomic> #include <filesystem> #include <fstream> +#include <locale> #include <optional> #include <ranges> #include <string_view> @@ -131,6 +132,8 @@ {"show_uptime", "#* Shows the system uptime in the CPU box."}, + {"show_cpu_watts", "#* Shows the CPU package current power consumption in watts. Requires running `make setcap` or `make setuid` or running with sudo."}, + {"check_temp", "#* Show cpu temperature."}, {"cpu_sensor", "#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors."}, @@ -280,6 +283,7 @@ {"cpu_single_graph", false}, {"cpu_bottom", false}, {"show_uptime", true}, + {"show_cpu_watts", true}, {"check_temp", true}, {"show_coretemp", true}, {"show_cpu_freq", true}, @@ -467,7 +471,11 @@ } else if (vals.at(0) == "proc") { set("proc_left", (vals.at(1) != "0")); } - set("graph_symbol_" + vals.at(0), vals.at(2)); + if (vals.at(0).starts_with("gpu")) { + set("graph_symbol_gpu", vals.at(2)); + } else { + set("graph_symbol_" + vals.at(0), vals.at(2)); + } } if (set_boxes(boxes)) { @@ -760,6 +768,7 @@ Logger::debug("Writing new config file"); if (geteuid() != Global::real_uid and seteuid(Global::real_uid) != 0) return; std::ofstream cwrite(conf_file, std::ios::trunc); + cwrite.imbue(std::locale::classic()); if (cwrite.good()) { cwrite << "#? Config file for btop v. " << Global::Version << "\n"; for (const auto& [name, description] : descriptions) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/btop_draw.cpp new/btop-1.4.4+git20250910.bdddfc4/src/btop_draw.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/btop_draw.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/btop_draw.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -519,7 +519,8 @@ int x = 1, y = 1, width = 20, height; int b_columns, b_column_size; int b_x, b_y, b_width, b_height; - long unsigned int lavg_str_len = 0; + float max_observed_pwr = 1.0f; + int graph_up_height, graph_low_height; int graph_up_width, graph_low_width; int gpu_meter_width; @@ -538,6 +539,7 @@ if (Runner::stopping) return ""; if (force_redraw) redraw = true; bool show_temps = (Config::getB("check_temp") and got_sensors); + bool show_watts = (Config::getB("show_cpu_watts") and supports_watts); auto single_graph = Config::getB("cpu_single_graph"); bool hide_cores = show_temps and (cpu_temp_only or not Config::getB("show_coretemp")); const int extra_width = (hide_cores ? max(6, 6 * b_column_size) : 0); @@ -584,7 +586,6 @@ graph_up_height = (single_graph ? height - 2 : ceil((double)(height - 2) / 2) - (mid_line and height % 2 != 0)); graph_low_height = height - 2 - graph_up_height - mid_line; const int button_y = cpu_bottom ? y + height - 1 : y; - lavg_str_len = 0; out += box; //? Buttons on title @@ -681,7 +682,12 @@ } #endif - cpu_meter = Draw::Meter{b_width - (show_temps ? 23 - (b_column_size <= 1 and b_columns == 1 ? 6 : 0) : 11), "cpu"}; + int cpu_meter_width = b_width - (show_temps ? 23 - (b_column_size <= 1 and b_columns == 1 ? 6 : 0) : 11); + if (show_watts) { + cpu_meter_width -= 6; + } + + cpu_meter = Draw::Meter{cpu_meter_width, "cpu"}; if (mid_line) { out += Mv::to(y + graph_up_height + 1, x) + Fx::ub + Theme::c("cpu_box") + Symbols::div_left + Theme::c("div_line") @@ -752,58 +758,64 @@ } try { - //? Cpu/Gpu graphs - out += Fx::ub + Mv::to(y + 1, x + 1); - auto draw_graphs = [&](vector<Draw::Graph>& graphs, const int graph_height, const int graph_width, const string& graph_field) { - #ifdef GPU_SUPPORT - if (graph_field.starts_with("gpu")) - if (graph_field.ends_with("totals")) { - int gpu_drawn = 0; - for (size_t i = 0; i < gpus.size(); i++) { - if (gpu_auto and v_contains(Gpu::shown_panels, i)) - continue; - out += graphs[i](safeVal(gpus[i].gpu_percent, graph_field), (data_same or redraw)); - if (Gpu::count - (gpu_auto ? Gpu::shown : 0) > 1) { - auto i_str = to_string(i); - out += Mv::l(graph_width-1) + Mv::u(graph_height/2) + (graph_width > 5 ? "GPU" : "") + i_str - + Mv::d(graph_height/2) + Mv::r(graph_width - 1 - (graph_width > 5)*3 - i_str.size()); - } + //? Cpu/Gpu graphs + out += Fx::ub + Mv::to(y + 1, x + 1); + auto draw_graphs = [&](vector<Draw::Graph>& graphs, const int graph_height, const int graph_width, const string& graph_field) { + #ifdef GPU_SUPPORT + if (graph_field.starts_with("gpu")) + if (graph_field.ends_with("totals")) { + int gpu_drawn = 0; + for (size_t i = 0; i < gpus.size(); i++) { + if (gpu_auto and v_contains(Gpu::shown_panels, i)) { + continue; + } + try { + const auto& gpu_percent = gpus[i].gpu_percent; + out += graphs[i](safeVal(gpu_percent, graph_field), (data_same or redraw)); + } catch (std::out_of_range& /* unused */) { + continue; + } + if (Gpu::count - (gpu_auto ? Gpu::shown : 0) > 1) { + auto i_str = to_string(i); + out += Mv::l(graph_width-1) + Mv::u(graph_height/2) + (graph_width > 5 ? "GPU" : "") + i_str + + Mv::d(graph_height/2) + Mv::r(graph_width - 1 - (graph_width > 5)*3 - i_str.size()); + } - if (++gpu_drawn < Gpu::count - (gpu_auto ? Gpu::shown : 0)) - out += Theme::c("div_line") + (Symbols::v_line + Mv::l(1) + Mv::u(1))*graph_height + Mv::r(1) + Mv::d(1); + if (++gpu_drawn < Gpu::count - (gpu_auto ? Gpu::shown : 0)) + out += Theme::c("div_line") + (Symbols::v_line + Mv::l(1) + Mv::u(1))*graph_height + Mv::r(1) + Mv::d(1); + } } - } + else + out += graphs[0](safeVal(Gpu::shared_gpu_percent, graph_field), (data_same or redraw)); else - out += graphs[0](safeVal(Gpu::shared_gpu_percent, graph_field), (data_same or redraw)); - else - #else - (void)graph_height; - (void)graph_width; - #endif - out += graphs[0](safeVal(cpu.cpu_percent, graph_field), (data_same or redraw)); - }; + #else + (void)graph_height; + (void)graph_width; + #endif + out += graphs[0](safeVal(cpu.cpu_percent, graph_field), (data_same or redraw)); + }; - draw_graphs(graphs_upper, graph_up_height, graph_up_width, graph_up_field); - if (not single_graph) { - out += Mv::to(y + graph_up_height + 1 + mid_line, x + 1); - draw_graphs(graphs_lower, graph_low_height, graph_low_width, graph_lo_field); - } - - //? Uptime - if (Config::getB("show_uptime")) { - string upstr = sec_to_dhms(system_uptime()); - if (upstr.size() > 8) { - upstr.resize(upstr.size() - 3); - upstr = trans(upstr); - } - out += Mv::to(y + (single_graph or not Config::getB("cpu_invert_lower") ? 1 : height - 2), x + 2) - + Theme::c("graph_text") + "up" + Mv::r(1) + upstr; - } - - //? Cpu clock and cpu meter - if (Config::getB("show_cpu_freq") and not cpuHz.empty()) - out += Mv::to(b_y, b_x + b_width - 10) + Fx::ub + Theme::c("div_line") + Symbols::h_line * (7 - cpuHz.size()) - + Symbols::title_left + Fx::b + Theme::c("title") + cpuHz + Fx::ub + Theme::c("div_line") + Symbols::title_right; + draw_graphs(graphs_upper, graph_up_height, graph_up_width, graph_up_field); + if (not single_graph) { + out += Mv::to(y + graph_up_height + 1 + mid_line, x + 1); + draw_graphs(graphs_lower, graph_low_height, graph_low_width, graph_lo_field); + } + + //? Uptime + if (Config::getB("show_uptime")) { + string upstr = sec_to_dhms(system_uptime()); + if (upstr.size() > 8) { + upstr.resize(upstr.size() - 3); + upstr = trans(upstr); + } + out += Mv::to(y + (single_graph or not Config::getB("cpu_invert_lower") ? 1 : height - 2), x + 2) + + Theme::c("graph_text") + "up" + Mv::r(1) + upstr; + } + + //? Cpu clock and cpu meter + if (Config::getB("show_cpu_freq") and not cpuHz.empty()) + out += Mv::to(b_y, b_x + b_width - 10) + Fx::ub + Theme::c("div_line") + Symbols::h_line * (7 - cpuHz.size()) + + Symbols::title_left + Fx::b + Theme::c("title") + cpuHz + Fx::ub + Theme::c("div_line") + Symbols::title_right; out += Mv::to(b_y + 1, b_x + 1) + Theme::c("main_fg") + Fx::b + "CPU " + cpu_meter(safeVal(cpu.cpu_percent, "total"s).back()) + Theme::g("cpu").at(clamp(safeVal(cpu.cpu_percent, "total"s).back(), 0ll, 100ll)) + rjust(to_string(safeVal(cpu.cpu_percent, "total"s).back()), 4) + Theme::c("main_fg") + '%'; @@ -815,9 +827,26 @@ + temp_graphs.at(0)(safeVal(cpu.temp, 0), data_same or redraw); out += rjust(to_string(temp), 4) + Theme::c("main_fg") + unit; } - out += Theme::c("div_line") + Symbols::v_line; - } catch (const std::exception& e) { throw std::runtime_error("graphs, clock, meter : " + string{e.what()}); } + if (show_watts) { + string cwatts = fmt::format(" {:>4.{}f}", cpu.usage_watts, cpu.usage_watts < 10.0f ? 2 : cpu.usage_watts < 100.0f ? 1 : 0); + string cwatts_post = "W"; + + max_observed_pwr = max(max_observed_pwr, cpu.usage_watts); + out += Theme::g("cached").at(clamp(cpu.usage_watts / max_observed_pwr * 100.0f, 0.0f, 100.0f)) + cwatts + Theme::c("main_fg") + cwatts_post; + } + + out += Theme::c("div_line") + Symbols::v_line; + } catch (const std::exception& e) { + throw std::runtime_error("graphs, clock, meter : " + string{e.what()}); + } + + int max_row = b_height - 3; // Subtracting one extra row for the load average (and power if enabled) + int n_gpus_to_show = 0; + #ifdef GPU_SUPPORT + n_gpus_to_show = show_gpu ? (gpus.size() - (gpu_always ? 0 : Gpu::shown)) : 0; + #endif + max_row -= n_gpus_to_show; //? Core text and graphs int cx = 0, cy = 1, cc = 0, core_width = (b_column_size == 0 ? 2 : 3); @@ -843,7 +872,7 @@ out += Theme::c("div_line") + Symbols::v_line; - if ((++cy > ceil((double)Shared::coreCount / b_columns) or cy == b_height - 2) and n != Shared::coreCount - 1) { + if ((++cy > ceil((double)Shared::coreCount / b_columns) or cy == max_row) and n != Shared::coreCount - 1) { if (++cc >= b_columns) break; cy = 1; cx = (b_width / b_columns) * cc; } @@ -851,28 +880,17 @@ //? Load average if (cy < b_height - 1 and cc <= b_columns) { - string lavg_pre; - int sep = 1; - if (b_column_size == 2 and show_temps) { lavg_pre = "Load AVG: "; sep = 3; } - else if (b_column_size == 2 or (b_column_size == 1 and show_temps)) { lavg_pre = "LAV:"; } - else if (b_column_size == 1 or (b_column_size == 0 and show_temps)) { lavg_pre = "L "; } - string lavg; + cy = b_height - 2 - n_gpus_to_show; + + string load_avg_pre = "Load avg:"; + string load_avg; + for (const auto& val : cpu.load_avg) { - lavg += string(sep, ' ') + (lavg_pre.size() < 3 ? fmt::format("{:.0f}", val) : fmt::format("{:.2f}", val)); + load_avg += fmt::format(" {:.2f}", val); } - string lavg_str = lavg_pre + lavg; - if (lavg_str_len > lavg_str.length()) { - lavg_str += string(lavg_str_len - lavg_str.length(), ' '); - } else { - lavg_str_len = lavg_str.length(); - } - #ifdef GPU_SUPPORT - cy = b_height - 2 - (show_gpu ? (gpus.size() - (gpu_always ? 0 : Gpu::shown)) : 0); - #else - cy = b_height - 2; - #endif - out += Mv::to(b_y + cy, b_x + cx + 1) + Theme::c("main_fg") + lavg_str; + int len = load_avg_pre.size() + load_avg.size(); + out += Mv::to(b_y + cy, b_x + 1) + string(max(b_width - len - 2, 0), ' ') + Theme::c("main_fg") + Fx::b + load_avg_pre + Fx::ub + load_avg; } #ifdef GPU_SUPPORT @@ -947,6 +965,7 @@ vector<Draw::Graph> mem_used_graph_vec = {}, mem_util_graph_vec = {}; vector<Draw::Meter> gpu_meter_vec = {}; vector<Draw::Meter> pwr_meter_vec = {}; + vector<Draw::Meter> enc_meter_vec = {}; vector<string> box = {}; string draw(const gpu_info& gpu, unsigned long index, bool force_redraw, bool data_same) { @@ -964,6 +983,7 @@ auto& mem_util_graph = mem_util_graph_vec[index]; auto& gpu_meter = gpu_meter_vec[index]; auto& pwr_meter = pwr_meter_vec[index]; + auto& enc_meter = enc_meter_vec[index]; if (force_redraw) redraw[index] = true; bool show_temps = gpu.supported_functions.temp_info and (Config::getB("check_temp")); @@ -1002,6 +1022,8 @@ mem_util_graph = Draw::Graph{b_width/2 - 1, 2, "free", gpu.mem_utilization_percent, graph_symbol, 0, 0, 100, 4}; // offset so the graph isn't empty at 0-5% utilization if (gpu.supported_functions.mem_used and gpu.supported_functions.mem_total) mem_used_graph = Draw::Graph{b_width/2 - 2, 2 + 2*(gpu.supported_functions.mem_utilization), "used", safeVal(gpu.gpu_percent, "gpu-vram-totals"s), graph_symbol}; + if (gpu.supported_functions.encoder_utilization) + enc_meter = Draw::Meter{b_width/2 - 10, "cpu"}; } @@ -1041,8 +1063,17 @@ out += std::string(" P-state: ") + (gpu.pwr_state > 9 ? "" : " ") + 'P' + Theme::g("cached").at(clamp(gpu.pwr_state, 0ll, 100ll)) + to_string(gpu.pwr_state); } + //? Encode and Decode meters + bool drawnEncDec = gpu.supported_functions.encoder_utilization and gpu.supported_functions.decoder_utilization; + if (drawnEncDec) { + out += Mv::to(b_y + 3, b_x +1) + Theme::c("main_fg") + Fx::b + "ENC " + enc_meter(gpu.encoder_utilization) + + Theme::g("cpu").at(clamp(gpu.encoder_utilization, 0ll, 100ll)) + rjust(to_string(gpu.encoder_utilization), 4) + Theme::c("main_fg") + '%' + + Theme::c("div_line") + Symbols::v_line + Theme::c("main_fg") + Fx::b + "DEC " + enc_meter(gpu.decoder_utilization) + + Theme::g("cpu").at(clamp(gpu.decoder_utilization, 0ll, 100ll)) + rjust(to_string(gpu.decoder_utilization), 4) + Theme::c("main_fg") + '%'; + } + if (gpu.supported_functions.mem_total or gpu.supported_functions.mem_used) { - out += Mv::to(b_y + 3, b_x); + out += Mv::to(b_y + (drawnEncDec ? 4 : 3), b_x); if (gpu.supported_functions.mem_total and gpu.supported_functions.mem_used) { string used_memory_string = floating_humanizer(gpu.mem_used); @@ -1067,7 +1098,7 @@ //? Memory clock speed if (gpu.supported_functions.mem_clock) { string clock_speed_string = to_string(gpu.mem_clock_speed); - out += Mv::to(b_y + 3, b_x + b_width/2 - 11) + Theme::c("div_line") + Symbols::h_line*(5-clock_speed_string.size()) + out += Mv::to(b_y + (drawnEncDec ? 4 : 3), b_x + b_width/2 - 11) + Theme::c("div_line") + Symbols::h_line*(5-clock_speed_string.size()) + Symbols::title_left + Fx::b + Theme::c("title") + clock_speed_string + " MHz" + Fx::ub + Theme::c("div_line") + Symbols::title_right; } } else { @@ -2100,6 +2131,7 @@ mem_used_graph_vec.resize(shown); mem_util_graph_vec.resize(shown); gpu_meter_vec.resize(shown); pwr_meter_vec.resize(shown); + enc_meter_vec.resize(shown); redraw.resize(shown); for (auto i = 0; i < shown; ++i) { redraw[i] = true; @@ -2120,7 +2152,7 @@ box[i] = createBox(x_vec[i], y_vec[i], width, height, Theme::c("cpu_box"), true, std::string("gpu") + (char)(shown_panels[i]+'0'), "", (shown_panels[i]+5)%10); // TODO gpu_box b_height_vec[i] = 2 + gpu_b_height_offsets[shown_panels[i]]; - b_width = clamp(width/2, min_width, 64); + b_width = clamp(width/2, min_width, 65); //? Main statistics box b_x_vec[i] = x_vec[i] + width - b_width - 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/btop_menu.cpp new/btop-1.4.4+git20250910.bdddfc4/src/btop_menu.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/btop_menu.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/btop_menu.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -510,6 +510,13 @@ "\"/uptime\" in the formatting.", "", "True or False."}, + {"show_cpu_watts", + "Shows the CPU power consumption in watts.", + "", + "Requires running `make setcap` or", + "`make setuid` or running with sudo.", + "", + "True or False."}, }, #ifdef GPU_SUPPORT { @@ -1557,10 +1564,10 @@ else if (is_in(key, "escape", "q", "h", "backspace", "space", "enter", "mouse_click")) { return Closed; } - else if (pages > 1 and is_in(key, "down", "page_down", "tab", "mouse_scroll_down")) { + else if (pages > 1 and is_in(key, "down", "j", "page_down", "tab", "mouse_scroll_down")) { if (++page >= pages) page = 0; } - else if (pages > 1 and is_in(key, "up", "page_up", "shift_tab", "mouse_scroll_up")) { + else if (pages > 1 and is_in(key, "up", "k", "page_up", "shift_tab", "mouse_scroll_up")) { if (--page < 0) page = pages - 1; } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/btop_shared.cpp new/btop-1.4.4+git20250910.bdddfc4/src/btop_shared.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/btop_shared.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/btop_shared.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -181,7 +181,6 @@ void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs, int cur_depth, bool collapsed, const string& filter, bool found, bool no_update, bool should_filter) { - auto cur_pos = out_procs.size(); bool filtering = false; //? If filtering, include children of matching processes @@ -241,17 +240,18 @@ cur_proc.threads += p.threads; } } - if (collapsed or filtering) { - return; - } - - //? Add tree terminator symbol if it's the last child in a sub-tree - if (out_procs.back().children.size() > 0 and out_procs.back().children.back().entry.get().prefix.size() >= 8 and not out_procs.back().children.back().entry.get().prefix.ends_with("]─")) - out_procs.back().children.back().entry.get().prefix.replace(out_procs.back().children.back().entry.get().prefix.size() - 8, 8, " └─ "); - - //? Add collapse/expand symbols if process have any children - out_procs.at(cur_pos).entry.get().prefix = " │ "s * cur_depth + (out_procs.at(cur_pos).children.size() > 0 ? (cur_proc.collapsed ? "[+]─" : "[-]─") : " ├─ "); - } + void _collect_prefixes(tree_proc &t, const bool is_last, const string &header) { + const bool is_filtered = t.entry.get().filtered; + if (is_filtered) t.entry.get().depth = 0; + + if (!t.children.empty()) t.entry.get().prefix = header + (t.entry.get().collapsed ? "[+]─": "[-]─"); + else t.entry.get().prefix = header + (is_last ? " └─": " ├─"); + + for (auto child = t.children.begin(); child != t.children.end(); ++child) { + _collect_prefixes(*child, child == (t.children.end() - 1), + is_filtered ? "": header + (is_last ? " ": " │ ")); + } + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/btop_shared.hpp new/btop-1.4.4+git20250910.bdddfc4/src/btop_shared.hpp --- old/btop-1.4.4+git20250718.86ec5fd/src/btop_shared.hpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/btop_shared.hpp 2025-09-10 17:49:55.000000000 +0200 @@ -139,7 +139,9 @@ temp_info = true, mem_total = true, mem_used = true, - pcie_txrx = true; + pcie_txrx = true, + encoder_utilization = true, + decoder_utilization = true; }; //* Per-device container for GPU info @@ -166,6 +168,9 @@ long long pcie_tx = 0; // KB/s long long pcie_rx = 0; + long long encoder_utilization = 0; + long long decoder_utilization = 0; + gpu_info_supported supported_functions; // vector<proc_info> graphics_processes = {}; // TODO @@ -194,7 +199,7 @@ namespace Cpu { extern string box; extern int x, y, width, height, min_width, min_height; - extern bool shown, redraw, got_sensors, cpu_temp_only, has_battery; + extern bool shown, redraw, got_sensors, cpu_temp_only, has_battery, supports_watts; extern string cpuName, cpuHz; extern vector<string> available_fields; extern vector<string> available_sensors; @@ -218,6 +223,7 @@ vector<deque<long long>> temp; long long temp_max = 0; array<double, 3> load_avg; + float usage_watts = 0; }; //* Collect cpu stats and temperatures @@ -438,4 +444,7 @@ void _tree_gen(proc_info& cur_proc, vector<proc_info>& in_procs, vector<tree_proc>& out_procs, int cur_depth, bool collapsed, const string& filter, bool found = false, bool no_update = false, bool should_filter = false); + + //* Build prefixes for tree view + void _collect_prefixes(tree_proc& t, bool is_last, const string &header = ""); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/freebsd/btop_collect.cpp new/btop-1.4.4+git20250910.bdddfc4/src/freebsd/btop_collect.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/freebsd/btop_collect.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/freebsd/btop_collect.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -78,7 +78,7 @@ vector<string> available_fields = {"Auto", "total"}; vector<string> available_sensors = {"Auto"}; cpu_info current_cpu; - bool got_sensors = false, cpu_temp_only = false; + bool got_sensors = false, cpu_temp_only = false, supports_watts = false; //* Populate found_sensors map bool get_sensors(); @@ -1266,13 +1266,10 @@ int index = 0; tree_sort(tree_procs, sorting, reverse, index, current_procs.size()); - //? Add tree begin symbol to first item if childless - if (tree_procs.front().children.empty()) - tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ "); - - //? Add tree terminator symbol to last item if childless - if (tree_procs.back().children.empty()) - tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ "); + //? Recursive construction of ASCII tree prefixes. + for (auto t = tree_procs.begin(); t != tree_procs.end(); ++t) { + _collect_prefixes(*t, t == tree_procs.end() - 1); + } //? Final sort based on tree index rng::sort(current_procs, rng::less{}, & proc_info::tree_index); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/linux/btop_collect.cpp new/btop-1.4.4+git20250910.bdddfc4/src/linux/btop_collect.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/linux/btop_collect.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/linux/btop_collect.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -54,6 +54,7 @@ #undef class #endif +using std::abs; using std::clamp; using std::cmp_greater; using std::cmp_less; @@ -77,6 +78,18 @@ using namespace std::chrono_literals; //? --------------------------------------------------- FUNCTIONS ----------------------------------------------------- +namespace +{ + +long long get_monotonicTimeUSec() +{ + struct timespec time; + clock_gettime(CLOCK_MONOTONIC, &time); + return time.tv_sec * 1000000 + time.tv_nsec / 1000; +} + +} + namespace Cpu { vector<long long> core_old_totals; vector<long long> core_old_idles; @@ -86,6 +99,7 @@ fs::path freq_path = "/sys/devices/system/cpu/cpufreq/policy0/scaling_cur_freq"; bool got_sensors{}; bool cpu_temp_only{}; + bool supports_watts = true; //* Populate found_sensors map bool get_sensors(); @@ -150,6 +164,8 @@ 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*); + nvmlReturn_t (*nvmlDeviceGetEncoderUtilization)(nvmlDevice_t, unsigned int*, unsigned int*); + nvmlReturn_t (*nvmlDeviceGetDecoderUtilization)(nvmlDevice_t, unsigned int*, unsigned int*); //? Data void* nvml_dl_handle; @@ -307,6 +323,7 @@ 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.encoder_utilization or gpus[i].supported_functions.decoder_utilization) + (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); } @@ -765,21 +782,21 @@ //? Try to get battery percentage if (percent < 0) { try { - percent = stoll(readfile(b.base_dir / "capacity", "-1")); + percent = stoi(readfile(b.base_dir / "capacity", "-1")); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } if (b.use_energy_or_charge and percent < 0) { try { - percent = round(100.0 * stoll(readfile(b.energy_now, "-1")) / stoll(readfile(b.energy_full, "1"))); + percent = round(100.0 * stod(readfile(b.energy_now, "-1")) / stod(readfile(b.energy_full, "1"))); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } if (b.use_energy_or_charge and percent < 0) { try { - percent = round(100.0 * stoll(readfile(b.charge_now, "-1")) / stoll(readfile(b.charge_full, "1"))); + percent = round(100.0 * stod(readfile(b.charge_now, "-1")) / stod(readfile(b.charge_full, "1"))); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } @@ -803,14 +820,14 @@ if (b.use_energy_or_charge ) { if (not b.power_now.empty()) { try { - seconds = round((double)stoll(readfile(b.energy_now, "0")) / stoll(readfile(b.power_now, "1")) * 3600); + seconds = abs(round(stod(readfile(b.energy_now, "0")) / stod(readfile(b.power_now, "1")) * 3600)); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } else if (not b.current_now.empty()) { try { - seconds = round((double)stoll(readfile(b.charge_now, "0")) / (double)stoll(readfile(b.current_now, "1")) * 3600); + seconds = abs(round(stod(readfile(b.charge_now, "0")) / stod(readfile(b.current_now, "1")) * 3600)); } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } @@ -824,20 +841,41 @@ catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } - } + } + //? Or get seconds to full + else if(is_in(status, "charging")) { + if (b.use_energy_or_charge ) { + if (not b.power_now.empty()) { + try { + seconds = (round(stod(readfile(b.energy_full , "0")) - round(stod(readfile(b.energy_now, "0")))) + / abs(stod(readfile(b.power_now, "1"))) * 3600); + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } + } + else if (not b.current_now.empty()) { + try { + seconds = (round(stod(readfile(b.charge_full , "0")) - stod(readfile(b.charge_now, "0"))) + / std::abs(stod(readfile(b.current_now, "1"))) * 3600); + } + catch (const std::invalid_argument&) { } + catch (const std::out_of_range&) { } + } + } + } //? Get power draw if (b.use_power) { if (not b.power_now.empty()) { try { - watts = (float)stoll(readfile(b.power_now, "-1")) / 1000000.0; + watts = stof(readfile(b.power_now, "-1")) / 1000000.0F; } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } } else if (not b.voltage_now.empty() and not b.current_now.empty()) { try { - watts = (float)stoll(readfile(b.current_now, "-1")) / 1000000.0 * stoll(readfile(b.voltage_now, "1")) / 1000000.0; + watts = stof(readfile(b.current_now, "-1")) / 1000000.0F * stof(readfile(b.voltage_now, "1")) / 1000000.0F; } catch (const std::invalid_argument&) { } catch (const std::out_of_range&) { } @@ -848,6 +886,47 @@ return {percent, watts, seconds, status}; } + long long get_cpuConsumptionUJoules() + { + long long consumption = -1; + const auto rapl_power_usage_path = "/sys/class/powercap/intel-rapl:0/energy_uj"; + std::ifstream file(rapl_power_usage_path); + if(file.good()) + { + file >> consumption; + } + return consumption; + } + + float get_cpuConsumptionWatts() + { + static long long previous_usage = 0; + static long long previous_timestamp = 0; + + if (previous_usage == 0) + { + previous_usage = get_cpuConsumptionUJoules(); + previous_timestamp = get_monotonicTimeUSec(); + supports_watts = (previous_usage > 0); + return 0; + } + + if (!supports_watts) + { + return -1; + } + + auto current_timestamp = get_monotonicTimeUSec(); + auto current_usage = get_cpuConsumptionUJoules(); + + auto watts = (float)(current_usage - previous_usage) / (float)(current_timestamp - previous_timestamp); + + previous_timestamp = current_timestamp; + previous_usage = current_usage; + + return watts; + } + auto collect(bool no_update) -> cpu_info& { if (Runner::stopping or (no_update and not current_cpu.cpu_percent.at("total").empty())) return current_cpu; auto& cpu = current_cpu; @@ -985,6 +1064,9 @@ if (Config::getB("show_battery") and has_battery) current_bat = get_battery(); + if (Config::getB("show_cpu_watts") and supports_watts) + current_cpu.usage_watts = get_cpuConsumptionWatts(); + return cpu; } } @@ -1040,6 +1122,8 @@ LOAD_SYM(nvmlDeviceGetTemperature); LOAD_SYM(nvmlDeviceGetMemoryInfo); LOAD_SYM(nvmlDeviceGetPcieThroughput); + LOAD_SYM(nvmlDeviceGetEncoderUtilization); + LOAD_SYM(nvmlDeviceGetDecoderUtilization); #undef LOAD_SYM @@ -1095,7 +1179,7 @@ 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}; + gpus[i].supported_functions = {false, false, false, false, false, false, false, false, false, false}; continue; } @@ -1242,6 +1326,30 @@ } } + // nvTimer.stop_rename_reset("Nv enc"); + //? Encoder info + if (gpus_slice[i].supported_functions.encoder_utilization) { + unsigned int utilization; + unsigned int samplingPeriodUs; + result = nvmlDeviceGetEncoderUtilization(devices[i], &utilization, &samplingPeriodUs); + if (result != NVML_SUCCESS) { + Logger::warning(std::string("NVML: Failed to get encoder utilization: ") + nvmlErrorString(result)); + if constexpr(is_init) gpus_slice[i].supported_functions.encoder_utilization = false; + } else gpus_slice[i].encoder_utilization = (long long)utilization; + } + + // nvTimer.stop_rename_reset("Nv dec"); + //? Decoder info + if (gpus_slice[i].supported_functions.decoder_utilization) { + unsigned int utilization; + unsigned int samplingPeriodUs; + result = nvmlDeviceGetDecoderUtilization(devices[i], &utilization, &samplingPeriodUs); + if (result != NVML_SUCCESS) { + Logger::warning(std::string("NVML: Failed to get decoder utilization: ") + nvmlErrorString(result)); + if constexpr(is_init) gpus_slice[i].supported_functions.decoder_utilization = false; + } else gpus_slice[i].decoder_utilization = (long long)utilization; + } + //? TODO: Processes using GPU /*unsigned int proc_info_len; nvmlProcessInfo_t* proc_info = 0; @@ -1415,6 +1523,10 @@ 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; + + //? Disable encoder and decoder utilisation on AMD + gpus_slice[i].supported_functions.encoder_utilization = false; + gpus_slice[i].supported_functions.decoder_utilization = false; } //? GPU utilization @@ -1646,7 +1758,9 @@ .temp_info = false, .mem_total = false, .mem_used = false, - .pcie_txrx = false + .pcie_txrx = false, + .encoder_utilization = false, + .decoder_utilization = false }; gpus_slice->pwr_max_usage = 10'000; //? 10W @@ -1738,6 +1852,36 @@ } #endif +/// Convert ascii escapes like \040 into chars. +static auto convert_ascii_escapes(const std::string& input) -> std::string { + std::string out; + out.reserve(input.size()); + + for (std::size_t i = 0; i < input.size(); ++i) { + if (input[i] == '\\' && + // Peek the next three characters. + i + 3 < input.size() && + std::isdigit(input[i + 1]) && + std::isdigit(input[i + 2]) && + std::isdigit(input[i + 3])) { + + // Convert octal chars to decimal int. + // '0' - '0' -> 0, '4' - '0' -> 4, '0' - '0' -> 0. + // 0 * 64 (0) + // + 4 * 8 (32) + // + 0 + // = 32 (ascii space) + int value = ((input[i + 1] - '0') * 64) + ((input[i + 2] - '0') * 8) + (input[i + 3] - '0'); + out.push_back(static_cast<char>(value)); + // Consume the three digits. + i += 3; + } else { + out.push_back(input[i]); + } + } + return out; +} + namespace Mem { bool has_swap{}; vector<string> fstab; @@ -1923,17 +2067,22 @@ diskread.close(); } - //? Get mounts from /etc/mtab or /proc/self/mounts - diskread.open((fs::exists("/etc/mtab") ? fs::path("/etc/mtab") : Shared::procPath / "self/mounts")); + //? Get mounts from /proc/self/mountinfo + diskread.open((Shared::procPath / "self/mountinfo")); if (diskread.good()) { vector<string> found; found.reserve(last_found.size()); - string dev, mountpoint, fstype; + string dev, major_minor, mountpoint, fstype, _; while (not diskread.eof()) { + // See proc_pid_mountinfo(5) for the file format + // We specifically want the major/minor device numbers std::error_code ec; - diskread >> dev >> mountpoint >> fstype; + diskread >> _ >> _ >> major_minor >> _ >> mountpoint >> _ >> _ >> _ >> fstype >> dev >> _; diskread.ignore(SSmax, '\n'); + // A mountpoint can ascii escape codes, which will not work with `statvfs`. + mountpoint = convert_ascii_escapes(mountpoint); + if (v_contains(ignore_list, mountpoint) or v_contains(found, mountpoint)) continue; //? Match filter if not empty @@ -1961,25 +2110,17 @@ if (mountpoint == "/mnt") disks.at(mountpoint).name = "root"; #endif if (disks.at(mountpoint).name.empty()) disks.at(mountpoint).name = (mountpoint == "/" ? "root" : mountpoint); - string devname = disks.at(mountpoint).dev.filename(); - int c = 0; - while (devname.size() >= 2) { - if (fs::exists("/sys/block/" + devname + "/stat", ec) and access(string("/sys/block/" + devname + "/stat").c_str(), R_OK) == 0) { - if (c > 0 and fs::exists("/sys/block/" + devname + '/' + disks.at(mountpoint).dev.filename().string() + "/stat", ec)) - disks.at(mountpoint).stat = "/sys/block/" + devname + '/' + disks.at(mountpoint).dev.filename().string() + "/stat"; - else - disks.at(mountpoint).stat = "/sys/block/" + devname + "/stat"; - break; + + // Use the major:minor device numbers to get device stats; see sysfs(5) + auto stat_path = "/sys/dev/block/" + major_minor + "/stat"; + if (fs::exists(stat_path, ec) and access(stat_path.c_str(), R_OK) == 0) { + disks.at(mountpoint).stat = stat_path; + } else if (fstype == "zfs") { //? Set ZFS stat filepath - } else if (fstype == "zfs") { - disks.at(mountpoint).stat = get_zfs_stat_file(dev, zfs_dataset_name_start, zfs_hide_datasets); - if (disks.at(mountpoint).stat.empty()) { - Logger::debug("Failed to get ZFS stat file for device " + dev); - } - break; + disks.at(mountpoint).stat = get_zfs_stat_file(dev, zfs_dataset_name_start, zfs_hide_datasets); + if (disks.at(mountpoint).stat.empty()) { + Logger::debug("Failed to get ZFS stat file for device " + dev); } - devname.resize(devname.size() - 1); - c++; } } @@ -2006,7 +2147,7 @@ last_found = std::move(found); } else - throw std::runtime_error("Failed to get mounts from /etc/mtab and /proc/self/mounts"); + throw std::runtime_error("Failed to get mounts from /proc/self/mountinfo"); diskread.close(); //? Get disk/partition stats @@ -2399,7 +2540,7 @@ auto& bandwidth = netif.bandwidth.at(dir); uint64_t val{}; - try { val = (uint64_t)stoull(readfile(sys_file, "0")); } + try { val = stoull(readfile(sys_file, "0")); } catch (const std::invalid_argument&) {} catch (const std::out_of_range&) {} @@ -2974,13 +3115,10 @@ int index = 0; tree_sort(tree_procs, sorting, reverse, index, current_procs.size()); - //? Add tree begin symbol to first item if childless - if (tree_procs.size() > 0 and tree_procs.front().children.empty() and tree_procs.front().entry.get().prefix.size() >= 8) - tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ "); - - //? Add tree terminator symbol to last item if childless - if (tree_procs.size() > 0 and tree_procs.back().children.empty() and tree_procs.back().entry.get().prefix.size() >= 8) - tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ "); + //? Recursive construction of ASCII tree prefixes. + for (auto t = tree_procs.begin(); t != tree_procs.end(); ++t) { + _collect_prefixes(*t, t == tree_procs.end() - 1); + } //? Final sort based on tree index rng::sort(current_procs, rng::less{}, & proc_info::tree_index); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/netbsd/btop_collect.cpp new/btop-1.4.4+git20250910.bdddfc4/src/netbsd/btop_collect.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/netbsd/btop_collect.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/netbsd/btop_collect.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -84,7 +84,7 @@ vector<string> available_fields = {"total"}; vector<string> available_sensors = {"Auto"}; cpu_info current_cpu; - bool got_sensors = false, cpu_temp_only = false; + bool got_sensors = false, cpu_temp_only = false, supports_watts = false; //* Populate found_sensors map bool get_sensors(); @@ -1346,13 +1346,10 @@ int index = 0; tree_sort(tree_procs, sorting, reverse, index, current_procs.size()); - //? Add tree begin symbol to first item if childless - if (tree_procs.front().children.empty()) - tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ "); - - //? Add tree terminator symbol to last item if childless - if (tree_procs.back().children.empty()) - tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ "); + //? Recursive construction of ASCII tree prefixes. + for (auto t = tree_procs.begin(); t != tree_procs.end(); ++t) { + _collect_prefixes(*t, t == tree_procs.end() - 1); + } //? Final sort based on tree index rng::sort(current_procs, rng::less{}, & proc_info::tree_index); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/openbsd/btop_collect.cpp new/btop-1.4.4+git20250910.bdddfc4/src/openbsd/btop_collect.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/openbsd/btop_collect.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/openbsd/btop_collect.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -83,7 +83,7 @@ vector<string> available_fields = {"total"}; vector<string> available_sensors = {"Auto"}; cpu_info current_cpu; - bool got_sensors = false, cpu_temp_only = false; + bool got_sensors = false, cpu_temp_only = false, supports_watts = false; //* Populate found_sensors map bool get_sensors(); @@ -1198,13 +1198,10 @@ int index = 0; tree_sort(tree_procs, sorting, reverse, index, current_procs.size()); - //? Add tree begin symbol to first item if childless - if (tree_procs.front().children.empty()) - tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ "); - - //? Add tree terminator symbol to last item if childless - if (tree_procs.back().children.empty()) - tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ "); + //? Recursive construction of ASCII tree prefixes. + for (auto t = tree_procs.begin(); t != tree_procs.end(); ++t) { + _collect_prefixes(*t, t == tree_procs.end() - 1); + } //? Final sort based on tree index rng::sort(current_procs, rng::less{}, & proc_info::tree_index); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/btop-1.4.4+git20250718.86ec5fd/src/osx/btop_collect.cpp new/btop-1.4.4+git20250910.bdddfc4/src/osx/btop_collect.cpp --- old/btop-1.4.4+git20250718.86ec5fd/src/osx/btop_collect.cpp 2025-07-18 00:20:18.000000000 +0200 +++ new/btop-1.4.4+git20250910.bdddfc4/src/osx/btop_collect.cpp 2025-09-10 17:49:55.000000000 +0200 @@ -77,7 +77,7 @@ vector<string> available_fields = {"Auto", "total"}; vector<string> available_sensors = {"Auto"}; cpu_info current_cpu; - bool got_sensors = false, cpu_temp_only = false; + bool got_sensors = false, cpu_temp_only = false, supports_watts = false; int core_offset = 0; //* Populate found_sensors map @@ -1337,13 +1337,10 @@ int index = 0; tree_sort(tree_procs, sorting, reverse, index, current_procs.size()); - //? Add tree begin symbol to first item if childless - if (tree_procs.front().children.empty()) - tree_procs.front().entry.get().prefix.replace(tree_procs.front().entry.get().prefix.size() - 8, 8, " ┌─ "); - - //? Add tree terminator symbol to last item if childless - if (tree_procs.back().children.empty()) - tree_procs.back().entry.get().prefix.replace(tree_procs.back().entry.get().prefix.size() - 8, 8, " └─ "); + //? Recursive construction of ASCII tree prefixes. + for (auto t = tree_procs.begin(); t != tree_procs.end(); ++t) { + _collect_prefixes(*t, t == tree_procs.end() - 1); + } //? Final sort based on tree index rng::sort(current_procs, rng::less{}, & proc_info::tree_index); ++++++ btop.obsinfo ++++++ --- /var/tmp/diff_new_pack.K2fSxJ/_old 2025-09-22 19:29:19.925979836 +0200 +++ /var/tmp/diff_new_pack.K2fSxJ/_new 2025-09-22 19:29:19.929980004 +0200 @@ -1,5 +1,5 @@ name: btop -version: 1.4.4+git20250718.86ec5fd -mtime: 1752790818 -commit: 86ec5fd06282a96ae46542e653490b7144e801f9 +version: 1.4.4+git20250910.bdddfc4 +mtime: 1757519395 +commit: bdddfc46a2bbfe4ba70c7fba4fbb30978d61dab9
