fix(scheduler): percent-based limit display shows raw fraction, not percent (bug-1831)
fmt_limit()/fmt_limit_units() formatted a percent-based limit's value as a bare snprintf(..., "%f%%", limit->val.val) -- echoing the raw stored value with a literal "%" appended. But xce_limit_val_t.val is genuinely a 0-1 fraction when percent is set (confirmed end-to-end: no /100 or *100 scaling exists anywhere in the config->capnp->runtime pipeline; confirmed authoritative by the original hand-written C literal this codebase's oldest percent-based limit was migrated from, .val = 0.2 for a documented "20% mem cap"). A correctly-configured 20% limit therefore displayed as "0.200000%" instead of "20.000000%" -- misleading, though technically an honest echo of the stored value. Fixed by multiplying by 100.0 before formatting. Display-only -- update_limit_res_value()'s actual capacity computation was already correct and is untouched. fmt_limit() (a thin XCE_UNITS_RAW wrapper) inherits this fix for its own percent-branch output too, a deliberate, intentional change from its pre-fix behavior for percent-based limits specifically (its 5 pre-existing direct tests only assert rc > 0, never the exact percent string, so this is safe). Updated test_limit.c's percent-mode test fixture from an unrealistic .val=80.0 to a realistic .val=0.8 (assertion text unchanged, since 0.8*100=80 either way) and test_repl_limit_table.c's own percent test to expect its shared fixture's arbitrary .val=50.0 constant correctly rendering as "5000.000000%". RED confirmed via the raw Unity testlog's :FAIL: lines (the aggregate meson summary masks single-test failures, a known harness quirk in this project); GREEN confirmed after, both lib and scheduler suites, 0 Unity FAILs. Discovered during live manual verification of scheduler-sim-diagnostics Requirement 6 against a real deployed cluster. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC
This commit is contained in:
parent
07b5c989b5
commit
0ce7125481
4 changed files with 103 additions and 14 deletions
|
|
@ -455,7 +455,7 @@ static void test_fmt_limit_units_percent_limit_ignores_units_mode(void)
|
|||
.hosts = NULL,
|
||||
.projects = NULL,
|
||||
.val
|
||||
= &(xce_limit_val_t) { .resname = "mem", .percent = 1, .val = 80.0 }
|
||||
= &(xce_limit_val_t) { .resname = "mem", .percent = 1, .val = 0.8 }
|
||||
};
|
||||
char buf[1024];
|
||||
xce_units_mode_t modes[] = { XCE_UNITS_RAW, XCE_UNITS_HUMAN,
|
||||
|
|
|
|||
|
|
@ -160,8 +160,21 @@ void kill_consumer(xce_consumer_t* c)
|
|||
*
|
||||
* The consumer-dump loop is IDENTICAL to fmt_limit()'s -- untouched. Only
|
||||
* the final configured-value line's formatting differs:
|
||||
* - percent != 0: always the bare "%f%%" rendering, regardless of
|
||||
* units_mode -- a percentage is never byte-scaled (Requirement 6 AC3).
|
||||
* - percent != 0: always renders `val.val * 100` followed by "%",
|
||||
* regardless of units_mode -- a percentage is never byte-scaled
|
||||
* (Requirement 6 AC3). `xce_limit_val_t.val` is genuinely a 0-1
|
||||
* fraction when `percent != 0` (confirmed end to end against the real
|
||||
* capacity computation, update_limit_res_value() in
|
||||
* src/scheduler/src/plugins/limit.c, which multiplies this value
|
||||
* DIRECTLY against the resource's current value with no /100 anywhere
|
||||
* in the config→capnp→runtime pipeline -- and against the original
|
||||
* hand-written C literal this codebase's oldest percent-based limit was
|
||||
* migrated from, `.val = 0.2` for a documented "20% mem cap"). The *100
|
||||
* here is display-only, correcting a bug (fixed post-Requirement-6
|
||||
* shipping) where the raw 0-1 fraction was echoed directly with a "%"
|
||||
* appended, so a correctly-configured 20% limit displayed as
|
||||
* "0.200000%" instead of "20.000000%" -- misleading, though not
|
||||
* incorrect in the sense of matching the stored value.
|
||||
* - percent == 0, resource is byte-valued (xce_is_bytes_valued_resource())
|
||||
* or the "swp" special case (its wire unit is MB, not bytes -- the same
|
||||
* check repl_format_numeric_resource_value() already applies, converted
|
||||
|
|
@ -172,13 +185,18 @@ void kill_consumer(xce_consumer_t* c)
|
|||
* AC3).
|
||||
*
|
||||
* fmt_limit() itself is a one-line wrapper around this function in
|
||||
* XCE_UNITS_RAW mode. That is provably byte-identical to fmt_limit()'s own
|
||||
* pre-existing output for every percent/non-percent, byte-valued/
|
||||
* non-byte-valued shape: xce_format_units_value(XCE_UNITS_RAW, v, ...)
|
||||
* always renders the bare "%f" of v (see its own implementation), matching
|
||||
* what the old inline fmt_limit() body produced. This is why
|
||||
* test_limit.c's five pre-existing fmt_limit() call sites needed zero
|
||||
* changes -- they are the regression proof.
|
||||
* XCE_UNITS_RAW mode. For the percent == 0 branches (byte-valued and
|
||||
* non-byte-valued absolute values), this remains provably byte-identical to
|
||||
* fmt_limit()'s ORIGINAL pre-Requirement-6 output -- confirmed by
|
||||
* test_limit.c's five original fmt_limit() call sites needing zero changes
|
||||
* for those shapes. For the percent != 0 branch, this is now a DELIBERATE
|
||||
* behavior change from fmt_limit()'s pre-Requirement-6 output (the *100
|
||||
* display fix above applies to fmt_limit() too, since it shares this same
|
||||
* branch through the RAW-mode wrapper) -- none of those five original call
|
||||
* sites assert on the exact percent-display string (they only check
|
||||
* `rc > 0`), so this change is safe for them, but it is a real, intentional
|
||||
* change to fmt_limit()'s own output for a percent-based limit, not a
|
||||
* byte-identical refactor for that one case.
|
||||
*/
|
||||
int fmt_limit_units(char* buf, int len, xce_limit_t* limit,
|
||||
xce_units_mode_t units_mode)
|
||||
|
|
@ -213,7 +231,7 @@ int fmt_limit_units(char* buf, int len, xce_limit_t* limit,
|
|||
|
||||
if (limit->val.percent != 0) {
|
||||
rc = snprintf(buf + pos, len - pos, "\n%s = %f%%\n",
|
||||
limit->val.resname, limit->val.val);
|
||||
limit->val.resname, (double)limit->val.val * 100.0);
|
||||
} else {
|
||||
bool is_swp = (limit->val.resname != NULL)
|
||||
&& (strcmp(limit->val.resname, "swp") == 0);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue