Skip to content

Add configurable SI decimal vs IEC binary unit prefixes#1970

Open
tenox7 wants to merge 2 commits into
htop-dev:mainfrom
tenox7:units
Open

Add configurable SI decimal vs IEC binary unit prefixes#1970
tenox7 wants to merge 2 commits into
htop-dev:mainfrom
tenox7:units

Conversation

@tenox7

@tenox7 tenox7 commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

when displaying network or disk io meters allow to choose whether to use IEC or SI unit prefixes

@Explorer09

Explorer09 commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Why do we need this feature? Also I have concerns about how the feature is implemented:

  1. If we want to provide a configurable unit display (even for just the toggle between binary and deciml units), it should either affect globally, or allow a per-meter and per-table-column configuration. Limiting the setting to affect only DiskIO and NetworkIO meters doesn't make sense.
  2. For the fixed units like KiB/s, what to do if the number displayed is very large that it overflows the displayable space? No safeguards against that.
  3. What to do if the set of units is to be expanded? Say, TiB, PiB, EiB?

@fasterit

Copy link
Copy Markdown
Member

Nobody requested such a feature, what is the rationale @tenox7 ?

@tenox7 tenox7 force-pushed the units branch 3 times, most recently from 73563ea to 5698430 Compare April 23, 2026 04:13
@tenox7

tenox7 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

Why do we need this feature? Also I have concerns about how the feature is implemented:

I humbly believe that display of a transfer rate / bandwidth usage should be in SI decimal units (power of 10) and not IEC units (power of 2). In my personal use case output of htop network speed doesn't align with network equipment bandwidth usage measurement. Or for that matter with iostat for disk. Of course this is somewhat controversial. Rater than forcing some arbitrary standard users at least deserve choice. Hence configurable parameter.

  1. If we want to provide a configurable unit display (even for just the toggle between binary and deciml units), it should either affect globally, or allow a per-meter and per-table-column configuration. Limiting the setting to affect only DiskIO and NetworkIO meters doesn't make sense.

Absolutely agree, however I did not see any other place where transfer rate is being displayed. Saying that I found and updated per process table rate. So this should be global now?

  1. For the fixed units like KiB/s, what to do if the number displayed is very large that it overflows the displayable space? No safeguards against that.

Are you referring to visual misalignment? I think this is user choice. If someone wants to display something in small units, large numbers and misalignment are expected. Most people sticks with auto. Forcing specific unit like MB/s is rather rare and specific.

  1. What to do if the set of units is to be expanded? Say, TiB, PiB, EiB?

Good question! I don't think these are achievable on a single machine at this time outside of L1/L2 cache speed. I have added TB/s and TiB/s for future use.

@Explorer09

Explorer09 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Until there's a clarification on the requirements I don't think it worth it for you to revise the patches.

I humbly believe that display of a transfer rate / bandwidth usage should be in SI decimal units (power of 10) and not IEC units (power of 2). In my personal use case output of htop network speed doesn't align with network equipment bandwidth usage measurement. Of course this is somewhat controversial. Rater than forcing some arbitrary standard users at least deserve choice. Hence configurable parameter.

I have no personal objections on the SI vs. IEC unit switch. My concern is on the other part of the requirements that's either unclear or not worth it.

  1. If we want to provide a configurable unit display (even for just the toggle between binary and deciml units), it should either affect globally, or allow a per-meter and per-table-column configuration. Limiting the setting to affect only DiskIO and NetworkIO meters doesn't make sense.

Absolutely agree, however I did not see any other place where transfer rate is being displayed. Saying that I found and updated per process table rate. So this should be global now?

Grep the two keywords: Row_printRate and Row_printKBytes. The calls of these two utility functions are where the base-2 and base-10 unit switch are useful.

  1. For the fixed units like KiB/s, what to do if the number displayed is very large that it overflows the displayable space? No safeguards against that.

Are you referring to visual misalignment? I think this is user choice. If someone wants to display something in small units, large numbers and misalignment are expected. Most people sticks with auto. Forcing specific unit like MB/s is rather rare and specific.

Meter_humanUnit intentionally constrains the number of characters displayed to 5 (including the K, M, G or T prefix itself). If a decimal point is present, only a maximum of 3 digits can be printed. The reason was simply that extra digits of precision don't seem worth it.

I have added TB/s and TiB/s for future use.

My suggestion was to remove the fixed unit options altogether, and leave only the IEC and SI unit options. That would simplify the UI.

Because look at this:

5698430#diff-07aa5e06e3d4142e8e68a7c8ad5cc2da7a4843241640263649a7e24409d94792R317

   Panel_add(super, (Object*) NumberItem_newByRef("IO rate unit (0-auto IEC 1-auto SI 2-KiB/s 3-MiB/s 4-GiB/s 5-TiB/s 6-KB/s 7-MB/s 8-GB/s 9-TB/s)", &(settings->ioRateUnit), 0, 0, LAST_IO_UNIT - 1));

It can be expected in the future that there would be 10-PiB/s, 11-PB/s, etc. as a natural extensions of these. I would rather not have such a potential for scope creep. As you mentioned very few people would use these fixed units. Just ditch them. The original Meter_humanUnit code can work with units up to QiB (quebibytes) thanks to the unitPrefixes array and a loop that flexibly convert the numbers.

@fasterit

Copy link
Copy Markdown
Member

I think a IEC / SI switch could be acceptable, probably best to make an issue to discuss this first. I know this topic is a bit controversial among IT engineers.

I think the bulk of the PR does not stand a chance of getting merged.
It adds a lot of complexity for taking the auto-scaling feature (which is probably more useful the most of our users) away.

@fasterit

Copy link
Copy Markdown
Member

Prior art: #1187 and #224

@Explorer09

Copy link
Copy Markdown
Contributor

FYI, btop does have the SI / IEC unit switch.

@tenox7 tenox7 force-pushed the units branch 2 times, most recently from 5599d33 to 49acbd5 Compare April 23, 2026 13:18
@tenox7

tenox7 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

I have no personal objections on the SI vs. IEC unit switch. My concern is on the other part of the requirements that's either unclear or not worth it.

I have removed the non-auto sizing.

Grep the two keywords: Row_printRate and Row_printKBytes. The calls of these two utility functions are where the base-2 and base-10 unit switch are useful.

Okay I think this is addressed now.

My suggestion was to remove the fixed unit options altogether, and leave only the IEC and SI unit options. That would simplify the UI.

Done! I have no problem with that. My only requirement is to have SI / IEC unit choice in order to align with other tools.

@tenox7

tenox7 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor Author

I think a IEC / SI switch could be acceptable, probably best to make an issue to discuss this first.

Awesome. This is really all thats needed.

I know this topic is a bit controversial among IT engineers.

Actually I don't think it's controversial among IT engineers. Whats controversial is how this whole IEC units came to light and how it was adopted in software. Making it configurable addresses the issue.

I think the bulk of the PR does not stand a chance of getting merged. It adds a lot of complexity for taking the auto-scaling feature (which is probably more useful the most of our users) away.

Removed the non-auto scaled path.

@tenox7 tenox7 force-pushed the units branch 3 times, most recently from 39324dd to 82fb340 Compare April 23, 2026 14:07
@tenox7 tenox7 changed the title support for configurable units for network/disk io Add configurable SI decimal vs IEC binary unit prefixes Apr 23, 2026
Comment thread Row.h Outdated

/* Takes number in kibibytes (base 1024). Prints 6 columns. */
void Row_printKBytes(RichString* str, unsigned long long number, bool coloring);
/* Takes number in kibibytes (base 1024) or kilobytes (base 1000) per 'decimal'. Prints 6 columns. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I was thinking how the memory numbers are best represented when the SI base-10 units are enabled. In cases you didn't know, memory spaces of processes are allocated in pages, and a page is usually 4 KiB in size.

In other words, the smallest unit for memory allocation is always KiB, and forcing it to display as KB would distract users more than it helps. (Imagine, when a 64 KiB memory becomes 65 KB (65536 bytes) because of the base-10 conversion.)

My question is whether it's good to make a special case to display memory in KiB instead of KB, and only convert the unit to base-10 when the number is 100 MB or larger.

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.

That's how you end up with 3½" HD ("1.44 MB") floppy disks that were neither 1.44 MB nor 1.44 MiB, but 160 sectors on 18 tracks with 512 byte sectors, i.e. ~1.47 MB or 1.40 MiB if you do the math right …

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@BenBE My request was to keep the smallest unit for memory numbers to be KiB, even when the SI unit mode is set.
And no, I don't support the strange floppy-MB unit (1024000 bytes). What I mean is when the memory is converted from KiB to MB, it would be multiplied by 1024 / 1000000, that is, the real SI megabyte.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thought about it and I never really intended SI units for memory display — only rates, for data in flight. So memory now always stays IEC, and the SI toggle only applies to the I/O rates (disk/network meters + the per-process IO rate columns).

@BenBE

BenBE commented Apr 25, 2026

Copy link
Copy Markdown
Member

Just a note on organizing the enum: To be future-proof the most elegant solution would be to encode the LSb as IEC vs. SI, and use the other bits to denote the power to use, where 0 is "auto" and everything else is one step of the unit ladder.

But that aside, I see little benefit in this overall feature except to confuse people (for which it would work great). Historically we chose to use IEC throughout due to (visual) space constraints where we could not reliably tell the unit to the user otherwise. And given htop is resource monitor for telling you about memory consumption it makes most sense to use the IEC units as a basis.. This even holds when talking about transfer rates from and to disks, as the OS operates on sectors (IEC-based) and cache pages (also IEC-based). The only place where this historically broke down somewhat is with network related metrics as these use SI units mostly.

@Explorer09

Copy link
Copy Markdown
Contributor

Historically we chose to use IEC throughout due to (visual) space constraints where we could not reliably tell the unit to the user otherwise. And given htop is resource monitor for telling you about memory consumption it makes most sense to use the IEC units as a basis.. This even holds when talking about transfer rates from and to disks, as the OS operates on sectors (IEC-based) and cache pages (also IEC-based). The only place where this historically broke down somewhat is with network related metrics as these use SI units mostly.

I agree that the IEC units should remain the default as the main thing htop users would want to monitor is the memory usage.

For hard disks and SSDs, despite the fact that sector sizes are usually engineered to be a power of two, disk sizes are instead marketed in base-10 units. (A 1 TB SSD is 1000 GB of space, not 1024 GiB.) Fortunately monitoring hard disks is not the primary use case of htop, thus the unit problem affects only a niche group of people. Just for your information.

@tenox7

tenox7 commented Apr 28, 2026

Copy link
Copy Markdown
Contributor Author

It is a niche group of people, but the problem is that having only IEC units is sometimes incompatible with other monitoring tools, for example iostat even on latest Ubuntu or FreeBSD, or network monitoring software.

I would like to have option to switch to SI units to compare or correlate results from htop with network monitoring software which as @BenBE mentioned uses SI units, or iostat and related.

Perhaps instead of menu configurable option we can add flag --units or something like that?

@tenox7

tenox7 commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

So what would take to merge this PR? Does anything need to be changed?

@Explorer09

Copy link
Copy Markdown
Contributor

For me, the only question remains is whether we need to special case the memory KiB units (this comment). I have no other objections.

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 49d5abd8-cad9-493b-b7ab-e4955a12d663

📥 Commits

Reviewing files that changed from the base of the PR and between 822ffa2 and 5da7a07.

📒 Files selected for processing (12)
  • DiskIOMeter.c
  • DisplayOptionsPanel.c
  • Meter.c
  • Meter.h
  • NetworkIOMeter.c
  • Row.c
  • Row.h
  • Settings.c
  • Settings.h
  • linux/LinuxProcess.c
  • pcp/PCPDynamicColumn.c
  • pcp/PCPProcess.c

📝 Walkthrough

Overview

Adds a global, persistent setting to display I/O throughput using SI decimal units (base‑1000: KB/s, MB/s, etc.) instead of the existing IEC binary units (base‑1024: KiB/s, MiB/s). The option is exposed in Display Options and applied consistently to per-process I/O columns, disk meters, network meters, and PCP dynamic/process columns.

What changed

  • Settings: added bool Settings_.decimalUnits (default false) with read/write support in Settings.c/h.
  • UI: checkbox wired to settings->decimalUnits in DisplayOptionsPanel.
  • Formatting helper: new Meter_ioRateUnit(char* buffer, size_t, double bytesPerSec, bool decimal) in Meter.c/h to produce scaled numeric text and a unit suffix ("B/s" vs "iB/s").
  • Row formatting: Row_printRate signature gains a bool decimal; logic replaced with a looped scaler that selects base‑1000 or base‑1024 prefixes and chooses precision/colors accordingly.
  • Meters: DiskIOMeter.c and NetworkIOMeter.c use Meter_ioRateUnit and a cached unit suffix instead of hardcoded "iB/s".
  • Call sites: LinuxProcess.c, PCPProcess.c, PCPDynamicColumn.c updated to pass host->settings->decimalUnits into Row_printRate.

Quality of implementation

  • Clean, focused changes: configuration, UI, helper, and call-site edits are separated and consistent across files; no unrelated churn in the diffs.
  • Commit/patch scope appears logical and in‑scope: adding a setting, a helper, and propagating it is the expected split of responsibilities.
  • Impact: the Row_printRate API change is a breaking signature change across many callers but all affected call sites were updated in this PR.

Notable design trade-offs and risks

  • Asymmetric formatting: IEC path reuses existing Meter_humanUnit (with existing field‑width tuning) while the SI path uses new scaling/precision logic. That produces different rounding/precision and alignment behavior between modes and may affect visual alignment of meters.
  • Display constraints: meters rely on compact width (5‑char prefix fields); the SI logic may cause overflow/precision edge cases for very large values or tight layouts.
  • Scope choices: fixed-unit and non-auto sizing options were removed (intentionally avoiding scope creep). The change is focused on the IEC vs SI toggle only.

Recommendation / follow-up

Consider unifying the formatting paths (IEC and SI) into a single helper to ensure identical field‑width/precision behavior between modes, or add tests/visual samples for boundary cases to validate alignment across common terminal widths.

Walkthrough

Adds a boolean Settings.decimalUnits (default false) with config read/write and a DisplayOptionsPanel checkbox. Introduces Meter_ioRateUnit(...) which formats bytes/sec and returns the unit suffix for SI ("B/s") or IEC ("iB/s"). Row_printRate gains a decimal flag and is refactored to scale using base-1000 or base-1024. DiskIOMeter and NetworkIOMeter call Meter_ioRateUnit, cache the returned suffix, and append it to text and RichString outputs. Linux and PCP process writers and dynamic columns pass settings->decimalUnits when printing rates.

Poem

Decimal or binary, the counters align,
Settings choose how numbers chime,
Meters whisper units precise,
Rows print rates, scaled and concise,
Read and write in chosen time.


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

@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: Pro Plus

Run ID: 5a9972ce-0472-4b07-81a8-cedfe13dc8a5

📥 Commits

Reviewing files that changed from the base of the PR and between 1579d02 and f9d0cdc.

📒 Files selected for processing (12)
  • DiskIOMeter.c
  • DisplayOptionsPanel.c
  • Meter.c
  • Meter.h
  • NetworkIOMeter.c
  • Row.c
  • Row.h
  • Settings.c
  • Settings.h
  • linux/LinuxProcess.c
  • pcp/PCPDynamicColumn.c
  • pcp/PCPProcess.c

Comment thread Meter.c
Comment thread Row.c Outdated
Comment thread Row.c Outdated
Comment on lines +480 to +496
static const char prefixes[] = { 'B', 'K', 'M', 'G', 'T', 'P' };
const int colors[ARRAYSIZE(prefixes)] = {
baseColor, baseColor, megabytesColor,
largeNumberColor, largeNumberColor, largeNumberColor
};

const double base = decimal ? ONE_DECIMAL_K : ONE_K;
size_t i = 0;
double scaled = rate;
while (scaled >= base && i + 1 < ARRAYSIZE(prefixes)) {
scaled /= base;
i++;
}

int color = (rate < 0.005) ? shadowColor : colors[i];
int len = xSnprintf(buffer, sizeof(buffer), "%7.2f %c/s ", scaled, prefixes[i]);
RichString_appendnAscii(str, color, buffer, len);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would appreciate if you make this part of the change a separate commit. In particular the reduction of code size by changing the series of if-conditionals into a loop (without the base-10 or base-2 switch).

Also, Since you've transformed this into a loop, it's helpful to use unitPrefixes array in XUtils.h. That way you can get sizes up to quettabytes and quebibytes with little cost.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done — pulled the loop refactor out into its own commit (no unit switch), and it now uses the unitPrefixes table so it scales up to Q. The SI/IEC feature sits on top.

tenox7 added 2 commits May 25, 2026 03:25
Replace the if-else unit ladder with a loop over the shared unitPrefixes table (XUtils.h). This extends the range up to quetta and drops the duplicated snprintf calls. Displayed output is unchanged for realistic rates.
Adds a Display Options toggle (and decimal_units config key) to show I/O rates in SI decimal units (KB/s, MB/s) instead of IEC binary (KiB/s, MiB/s). Affects the disk/network I/O meters and the per-process IO rate columns; memory stays IEC.
@tenox7

tenox7 commented May 30, 2026

Copy link
Copy Markdown
Contributor Author

Is there anything outstanding on this PR? Can I get an approval? Thanks!

@BenBE

BenBE commented May 31, 2026

Copy link
Copy Markdown
Member

@tenox7 This PR has not been forgotten. Just had little time the past days and also there's internally still an open question. Of the two commits I'm inclined to merge at least the first one (might even happen out-of-line); the second one still is under consideration.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants