Skip to content

FreeBSD: add an I/O screen with per-process I/O rates - #2129

Open
samm-git wants to merge 2 commits into
htop-dev:mainfrom
samm-git:freebsd-io-screen
Open

samm-git wants to merge 2 commits into
htop-dev:mainfrom
samm-git:freebsd-io-screen

Conversation

@samm-git

@samm-git samm-git commented Oct 7, 2026

Copy link
Copy Markdown

What

Adds a second default screen, I/O, on FreeBSD with three new process columns:

  • IO_RATE (IO R/W)
  • IO_READ_RATE (IO READ)
  • IO_WRITE_RATE (IO WRITE)

Linux and PCP already ship such a screen; FreeBSD only had Main.

How

The rates are computed from the per-process rusage block-operation counters
(ki_rusage.ru_inblock / ru_oublock) that are already returned by the existing
kvm_getprocs() call, i.e. the same data source the base system top(1) uses for
its -m io mode. No new syscalls and no privileges required.

Because these counters count block operations rather than bytes, the columns
report operations per second, unlike their Linux counterparts (FreeBSD exposes
no unprivileged per-process byte counters). The manual page notes this difference.

Counters are refreshed on every scan, so switching to the I/O screen shows valid
rates immediately rather than a lifetime-sized first sample.

Testing

  • ./configure --enable-unicode --enable-werror && make on FreeBSD 14.5 (clang) - clean.
  • Ran the binary: the I/O tab appears and shows live rates.
  • Fresh configs generate both screens; existing configs keep their own screens
    (default screens are only created when no screens section is present).

Notes

  • IO_PRIORITY, PERCENT_IO_DELAY and PERCENT_SWAP_DELAY are intentionally not
    added: FreeBSD has no equivalent per-process I/O priority or delay accounting.

Assisted-by: DeepSeek V4.1 Flash

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 281d001c-b4c1-4d28-b5c2-d0ef1044d7d7
📥 Commits

Reviewing files that changed from the base of the PR and between 629a82b and d1474e7.

📒 Files selected for processing (8)
  • Row.c
  • Row.h
  • freebsd/FreeBSDProcess.c
  • freebsd/FreeBSDProcess.h
  • freebsd/FreeBSDProcessTable.c
  • freebsd/Platform.c
  • freebsd/ProcessField.h
  • htop.1.in

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

FreeBSD now calculates per-process block read and write operation rates from sampled counters. It provides read, write, and combined rate fields with display and sorting support. The default screens include an I/O screen, and the manual documents the FreeBSD rate units.

Suggested reviewers: benbe

Priority: ⬇️ Low

Change: Feature

Merge Risk: ⚪ Minimal · up to d1474

The previously identified PID-reuse and column-alignment issues appear corrected. No actionable merge-blocking risk remains after normal checks.

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Counters mark the passing time
Read and write rates take their place
A total joins the measured flow
Columns sort and values show
FreeBSD’s I/O screen comes to life

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 0c40b2e7-0c6e-4b05-8a82-628e7878f360
📥 Commits

Reviewing files that changed from the base of the PR and between 44a59cf and 62eb8b0.

📒 Files selected for processing (6)
  • freebsd/FreeBSDProcess.c
  • freebsd/FreeBSDProcess.h
  • freebsd/FreeBSDProcessTable.c
  • freebsd/Platform.c
  • freebsd/ProcessField.h
  • htop.1.in

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

Comment thread freebsd/FreeBSDProcess.c Outdated
Comment thread freebsd/FreeBSDProcessTable.c Outdated
@fasterit fasterit added FreeBSD 👹 FreeBSD related issues enhancement Extension or improvement to existing feature labels Oct 7, 2026

@BenBE BenBE left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the normal IO rate values (B/s) available too or could that be added?

Comment thread freebsd/FreeBSDProcess.c Outdated
Comment thread freebsd/FreeBSDProcess.c Outdated
Linux and PCP provide a second default screen ("I/O") with per-process
I/O rate columns, but FreeBSD only ever shipped the "Main" screen.

Add an "I/O" screen with IO_OPS, IO_READ_OPS and IO_WRITE_OPS, plus the
same three columns to the available fields.  The rates are derived from
the rusage block-operation counters (ki_rusage.ru_inblock and
ki_rusage.ru_oublock) already returned by the kvm_getprocs() call used
to enumerate processes, the same source the base system top(1) uses for
its "-m io" mode.  As these counters report block operations rather than
bytes, the columns are named after the operation count, leaving the
"rate" suffix to the byte-rate columns.

Reuse across platforms is enabled by adding the generic
Row_printCountRate() helper to Row.c.

The default screen is only created when the configuration has no
screens section; existing configurations keep their own set of screens.

Assisted-by: DeepSeek V4.1 Flash
Signed-off-by: Alex Samorukov <samm@os2.kiev.ua>
Add manual entries for IO_READ_OPS, IO_WRITE_OPS and IO_OPS, the
FreeBSD columns reporting block operations per second.

Assisted-by: DeepSeek V4.1 Flash
Signed-off-by: Alex Samorukov <samm@os2.kiev.ua>
@samm-git
samm-git force-pushed the freebsd-io-screen branch 2 times, most recently from 629a82b to d1474e7 Compare October 7, 2026 19:14
@samm-git

samm-git commented Oct 7, 2026

Copy link
Copy Markdown
Author

Are the normal IO rate values (B/s) available too or could that be added?

Not really

@samm-git
samm-git requested a review from BenBE October 7, 2026 19:18
@BenBE

BenBE commented Oct 7, 2026

Copy link
Copy Markdown
Member

@samm-git Full review of the PR will take some time. I noted the things that I noticed while skimming over in my initial review.

AFAICT, FreeBSD's RACCT framework potentiall exposes readbps/writebps in addition to readiops/writeiops. Using rctl_get_racct(2) could be used to return byte-based I/O rates when those counters are available at runtime, as that is usually more informative than raw operation counts alone. Given this has to be done per process, an extra column flag for readbps/writebps would be needed. If you decide to add this (a separate PR is entirely okay for this), please do this as a separate commit.

@samm-git

samm-git commented Oct 8, 2026 •

Copy link
Copy Markdown
Author

@samm-git Full review of the PR will take some time. I noted the things that I noticed while skimming over in my initial review.

AFAICT, FreeBSD's RACCT framework potentiall exposes readbps/writebps in addition to readiops/writeiops. Using rctl_get_racct(2) could be used to return byte-based I/O rates when those counters are available at runtime, as that is usually more informative than raw operation counts alone. Given this has to be done per process, an extra column flag for readbps/writebps would be needed. If you decide to add this (a separate PR is entirely okay for this), please do this as a separate commit.

Thank you for your reply. Somehow I was wrongly assuming that RACCT would not work for ZFS.

However, the real problem is that rctl_get_racct is a root-only call, even for own processes. E.g., nobody gets EPERM for both process:<own> and user:<own>. So this could be a root-only feature, but I'm not sure it's a good idea. This is likely why top -mio also uses ops/s on BSD (I used it as inspiration).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Extension or improvement to existing feature FreeBSD 👹 FreeBSD related issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants