From d15e36cf24505754915b209813f23628d1585f3a Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 20 Aug 2025 14:54:18 +0200 Subject: [PATCH] chpstat: Add options to select IEC units for scaling Add options to select power-of-two based IEC units such as KiB/s (1024 B/s) for scaling throughput values in human readable reports. Option Scaling factor ================================ --scale ki 1024 --scale mi 1048576 --scale gi 1073741824 --scale auto-iec IEC units Reviewed-by: Jimmy Brisson Reviewed-by: Vineeth Vijayan Signed-off-by: Peter Oberparleiter Signed-off-by: Steffen Eiden --- zconf/chp/chpstat/chpstat.8 | 22 +++++++++++++++++++ zconf/chp/chpstat/chpstat.c | 42 +++++++++++++++++++++++++------------ zconf/chp/chpstat/column.c | 4 +++- zconf/chp/chpstat/column.h | 2 +- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/zconf/chp/chpstat/chpstat.8 b/zconf/chp/chpstat/chpstat.8 index 3c505290..b83308f0 100644 --- a/zconf/chp/chpstat/chpstat.8 +++ b/zconf/chp/chpstat/chpstat.8 @@ -294,6 +294,12 @@ Scale automatically to fit value into each column. To indicate the current scali an SI-suffix is added to each scaled number (e.g. K for 1000). This is the default. .PP .IP \(bu 3 +.B auto-iec: +Same as +.B auto +but using power-of-two based IEC-suffixes (e.g. Ki for 1024). +.PP +.IP \(bu 3 .IR number : Scale by .I number @@ -314,6 +320,22 @@ Scale by 1,000,000,000 (GB) .B T: Scale by 1,000,000,000,000 (TB) .PP +.IP \(bu 3 +.B Ki: +Scale by 1024 (KiB) +.PP +.IP \(bu 3 +.B Mi: +Scale by 1,048,576 (MiB) +.PP +.IP \(bu 3 +.B Gi: +Scale by 1,073,741,824 (GiB) +.PP +.IP \(bu 3 +.B Ti: +Scale by 1,099,511,627,776 (TiB) +.PP .RE .BR \-\-cmg diff --git a/zconf/chp/chpstat/chpstat.c b/zconf/chp/chpstat/chpstat.c index a4abc7a7..699aa132 100644 --- a/zconf/chp/chpstat/chpstat.c +++ b/zconf/chp/chpstat/chpstat.c @@ -265,6 +265,7 @@ static struct { unsigned long unit; char unit_suffix; bool unit_specified; + bool unit_iec; } opts; /* Per CHPID run-time data. */ @@ -336,6 +337,7 @@ static void init_opts(void) opts.unit = UNIT_AUTO; opts.unit_suffix = 0; opts.unit_specified = false; + opts.unit_iec = false; } /* @@ -459,23 +461,30 @@ static void parse_cmgs(char *arg) } } -static bool suffix_to_unit(char *arg, unsigned long *unit_ptr, char *suffix_ptr) +static bool suffix_to_unit(char *arg, unsigned long *unit_ptr, char *suffix_ptr, + bool *iec_ptr) { const char *suffixes = "KMGT"; unsigned long unit, base; size_t len = strlen(arg); char suffix; + bool iec; int i; - if (len != 1) + if (len == 1) + iec = false; + else if (len == 2 && toupper(arg[1]) == 'I') + iec = true; + else return false; suffix = (char)toupper(*arg); - base = UNIT_DEC; + base = iec ? UNIT_BIN : UNIT_DEC; unit = base; for (i = 0; suffixes[i]; i++) { if (suffix == suffixes[i]) { *unit_ptr = unit; *suffix_ptr = suffix; + *iec_ptr = iec; return true; } unit *= base; @@ -491,8 +500,12 @@ static unsigned long parse_unit(char *arg) unsigned long unit; char *endptr; - if (suffix_to_unit(arg, &unit, &opts.unit_suffix)) + if (suffix_to_unit(arg, &unit, &opts.unit_suffix, &opts.unit_iec)) return unit; + if (strcmp(arg, "auto-iec") == 0) { + opts.unit_iec = true; + return UNIT_AUTO; + } if (strcmp(arg, "auto") == 0) return UNIT_AUTO; /* Parse as number. */ @@ -1353,7 +1366,7 @@ static void scale_fixed(struct cmg_pair_t *p, unsigned long unit) static void add_pair_value(struct util_rec *table, struct column_t *col, struct cmg_pair_t *pair) { - char suffix = 0, str[16]; + char suffix = 0, suffix2 = opts.unit_iec ? 'i' : 0, str[16]; int p; if (!pair->valid) { @@ -1365,23 +1378,25 @@ static void add_pair_value(struct util_rec *table, struct column_t *col, suffix = scale_auto(pair, UNIT_DEC); } else if (pair->unit == CMG_BPS) { if (opts.unit == UNIT_AUTO) - suffix = scale_auto(pair, UNIT_DEC); + suffix = scale_auto(pair, opts.unit_iec ? UNIT_BIN : UNIT_DEC); else scale_fixed(pair, opts.unit); } switch (pair->type) { case CMG_U32: - snprintf(str, sizeof(str), "%u%c", pair->value_u32, suffix); + snprintf(str, sizeof(str), "%u%c%c", pair->value_u32, suffix, + suffix2); break; case CMG_U64: - snprintf(str, sizeof(str), "%llu%c", pair->value_u64, suffix); + snprintf(str, sizeof(str), "%llu%c%c", pair->value_u64, suffix, + suffix2); break; case CMG_FLOAT: /* Find highest precision that fits into @width characters. */ for (p = 2; p >= 0; p--) { - snprintf(str, sizeof(str), "%.*f%c", p, - pair->value_double, suffix); + snprintf(str, sizeof(str), "%.*f%c%c", p, + pair->value_double, suffix, suffix2); if (strlen(str) <= col->width) break; } @@ -1681,8 +1696,8 @@ static void calc_column_widths(void) width = 4; /* "999K" */ } else { v = MAX_BPS / (double)opts.unit; - snprintf(str, sizeof(str) - 1, "%.0f%c", v, - opts.unit_suffix); + snprintf(str, sizeof(str) - 1, "%.0f%c%c", v, + opts.unit_suffix, opts.unit_iec ? 'i' : 0); width = strlen_u(str); } break; @@ -1707,7 +1722,8 @@ static void cmd_table(void) apply_column_selection(); calc_column_widths(); - column_update_bps_suffix(opts.unit == UNIT_AUTO, opts.unit_suffix); + column_update_bps_suffix(opts.unit == UNIT_AUTO, opts.unit_iec, + opts.unit_suffix); printf("Collecting initial utilization data\n"); update_util_all(true); diff --git a/zconf/chp/chpstat/column.c b/zconf/chp/chpstat/column.c index 621d4d18..1b83d7a9 100644 --- a/zconf/chp/chpstat/column.c +++ b/zconf/chp/chpstat/column.c @@ -478,13 +478,15 @@ void column_select_all(void) column_select(col); } -void column_update_bps_suffix(bool auto_scale, char suffix_char) +void column_update_bps_suffix(bool auto_scale, bool iec, char suffix_char) { struct column_t *col; char *str; if (auto_scale) util_asprintf(&str, "(B/s)"); + else if (suffix_char && iec) + util_asprintf(&str, "(%ciB/s)", suffix_char); else if (suffix_char) util_asprintf(&str, "(%cB/s)", suffix_char); else diff --git a/zconf/chp/chpstat/column.h b/zconf/chp/chpstat/column.h index 44f8e406..32775fa9 100644 --- a/zconf/chp/chpstat/column.h +++ b/zconf/chp/chpstat/column.h @@ -84,7 +84,7 @@ void column_select_id_list(const int *ids); void column_select_default(void); void column_select_all(void); -void column_update_bps_suffix(bool auto_scale, char suffix_char); +void column_update_bps_suffix(bool auto_scale, bool iec, char suffix_char); void column_exit(void); #endif /* COLUMN_H */