Skip to content

--budget panics on an empty value, and treats NaN and infinity as no budget at all #33

Description

@vyncint

It panics

$ launchbound tune reduce-flip --backend model --cc 8.6 --budget ""
thread 'main' panicked at core/src/str/mod.rs:845:21:
end byte index 18446744073709551615 is out of bounds for string of length 0
$ echo $?
101

--budget " " does the same. crates/launchbound-cli/src/main.rs:

fn parse_budget(text: &str) -> anyhow::Result<f64> {
    let text = text.trim();
    let (digits, unit) = text.split_at(text.len() - 1);   // 0usize - 1

"".len() - 1 is usize::MAX. A trimmed-empty argument is the whole of it.

It accepts NaN and infinity, and they mean the opposite of a budget

$ launchbound tune ... --budget NaNs      # exit 0
$ launchbound tune ... --budget 1e400s    # exit 0

"NaN".parse::<f64>() succeeds; so does 1e400 (as inf). The value reaches
the guard in launchbound-bench/src/run.rs and launchbound-metal/src/lib.rs:

if let Some(budget) = options.budget_secs
    && sweep_started.elapsed().as_secs_f64() >= budget

x >= NaN is false for every x, and elapsed >= inf never becomes true.
So the branch never fires and the sweep runs to completion — unbounded.

That is not a cosmetic accept. --budget is how a measured run is bounded on
real silicon; a user who typed something that parsed to NaN gets an unbounded
--backend cuda sweep, believing it is capped. The one failure mode a budget
exists to prevent is the one it silently produces.

--budget 0 is the mirror image and is fine — the guard fires immediately and
the run reports budget exhausted after 0.0s: 0 of 11 candidates measured.

The errors are the float parser's, not the tool's

input message
abc error: invalid float literal
30min error: invalid float literal
1hr error: invalid float literal
s error: cannot parse float from empty string

None names --budget, and none says what is accepted. 30min and 1hr are
what a person types; only 30m and 1h work, and nothing says so. Compare
--cc, which 2.0.0 taught to answer `abc` is not a compute capability — expected MAJOR.MINOR, e.g. `8.6`.

Fix

Parse it properly rather than by split_at(len - 1):

  • an empty or whitespace argument is an error, not an index
  • reject a value that is not finite and positive — is_finite() and > 0.0
    together close NaN, inf and negatives
  • name the flag and the accepted forms in the message, and accept min/hr
    alongside m/h or say plainly that they are not accepted
  • a unit-less number is currently taken as seconds; keep that, and say so

Worth a table test over "", " ", abc, 30min, 1hr, s, NaNs,
1e400s, 0, -5s, 30m, 90s, 1h, 45.

Done when

No input to --budget panics, nothing that parses to NaN or infinity is
accepted, and a rejected value is told what would have been accepted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions