Repository navigation
tests: declare what a forced-JIT run cannot pass, so the run is a signal (#1217) - #1350
Conversation
…nal (lanl#1217) Run with every model forced through the MIR JIT (BNGSIM_CODEGEN_JIT=mir BNGSIM_CODEGEN_THRESHOLD=1), 53 tests fail on main with lanl#1348's codegen fix in. 39 test the cc backend's own artifact or name. 12 more fail under a forced threshold alone, because they need a small model to run interpreted. Each now carries a skipif from _codegen_backend.py, with a reason conftest declares. Three expose engine-dependent answers, filed separately. They get strict xfails under a lowered threshold, not skips.
…kip it under a forced threshold (lanl#1217)
|
Thanks. We reviewed this independently, Opus 5.5 and Fable 5.1, each on our own tree: main c0877fa with #1348 and 263700b merged in (both clean), on macOS arm64 with MIR on. The marks don't hide a wrong number, and the before and after counts are the body's. A default run doesn't change. Three medium findings follow, then three low:
What we checked comes first, so it needn't be redone. What we checked
1. The forced-threshold marks don't look at the model's size
So a run with the threshold tuned rather than forced fails on one or both strict xfails, and at 50 it skips ten tests that would pass. We'd suggest one of two fixes:
2. The strict xfails go stale when #1357 and #1358 are fixedStrict is the right choice, but nothing here runs it. #1370 fixes #1357, and its diff doesn't touch No CI job sets the forced variables, so the first to see it is whoever next runs the forced suite by hand. That is the run this PR exists to keep clean. Two ways to close it:
3. A forced-MIR run still exits 1 under the strict audit
if codegen and sim.codegen_backend != "cc":
pytest.skip("no C compiler: the compiled right-hand side is not built with cc")Under the JIT the backend is Then It's on the base too; the 53 failures hid it. It doesn't fire under forced cc or by default. It's the PR's Low
Not checked: Linux and Windows forced runs (CI runs none), and #1370 and #1359 built in. The stale-xfail point follows from |
One conflict, in test_sbml_initial_assignment_param_lift.py's imports. It is resolved by taking main's copy whole, which drops this branch's strict xfail on test_a_write_after_a_run_does_not_move_it_to_the_rules_current_value. That xfail cited lanl#1358, and lanl#1359 (5e71d2a) fixed lanl#1358. On main, under BNGSIM_CODEGEN_THRESHOLD=1, the branch's copy reports "[XPASS(strict)] lanl#1358: after a compiled run get_param reads a rule-set parameter at its load value" and FAILS. That is the forced run this branch exists to make clean.
… them (lanl#1217) Five tests were skipped whole under BNGSIM_CODEGEN_JIT, though only a precondition in each is cc-specific. The rest is about a number, and the forced JIT run is meant to check exactly that: - test_hpc_contract: run_batch rows must not cross-talk across the concurrent clones that share one compiled artifact. With a JIT module shared in process, that matters more, not less. - test_tfun_analytical_jacobian::test_emits_and_matches_fd: the compiled Jacobian reading a time-indexed table, against jacobian="fd". - test_lu_fill_routing: a fill-routed model's dense compiled Jacobian, its LAPACK route, and its trajectory against the interpreter. - test_sens_numerically_zero_base: the guard that the file's other tests are not vacuous (the run uses the analytic sens RHS). Skipped, it left them unguarded in the forced run. - test_ar_species_output_sensitivities: lanl#205's regeneration of a plain artifact with output sensitivities, and S2's values. Each now asserts what either backend leaves, as test_model_codegen_sensitivity.py already does: cc's .so, or the C source the JIT compiles in process. A compiled entry point is checked in that source by name, and the backend by selected_codegen_backend(). _codegen_backend.py: - xfail_when_threshold_forced passes raises=AssertionError. lanl#1357 is a wrong answer, so an exception from the compiled path is a second bug, and a bare xfail would hide it. - Its docstring no longer implies CI enforces the strict mark. No workflow lowers the threshold, so a fix's own CI never sees the XPASS. lanl#1358's went stale that way. - _threshold_lowered reads BNGSIM_NO_CODEGEN, as the Simulator does. With it set, nothing compiles, so the threshold skips were needless and lanl#1357's strict xfail would XPASS.
… clamp and one reading (lanl#1357) lanl#1350 (merged first) strict-xfails test_a_march_whose_integrator_fails_returns_the_state_it_passed[integration] under a lowered BNGSIM_CODEGEN_THRESHOLD, citing lanl#1357. This branch fixes lanl#1357, so merged with main the case passes there, and the forced run reported "[XPASS(strict)] lanl#1357" and failed. No workflow lowers the threshold, so CI could not show it. The mark goes, and with it xfail_when_threshold_forced, which nothing else uses. Under BNGSIM_CODEGEN_THRESHOLD=1 the file now gives 227 passed, 3 skipped. test_a_run_test_from_a_fractional_power_at_zero_is_taken_to_its_time [fd colored] asserts the solve factored with KLU. On a KLU-off build, which conftest declares a supported configuration ("KLU not compiled"), route_to_sparse_linear_solver is false whatever is forced, so it failed there. It now skips with that reason, as test_lu_fill_routing.py does. nonneg_clamp.hpp exists so the two integrators retry by one rule, but two parts were still written twice: - read_values and ClampReading (finite / NaN only / infinite) move into the header, and the run test asks read_values == nan_only rather than carrying ss_nan_and_no_inf, a second copy of the same loop. - clamp_nonneg_into takes the time course's optional spare slots, and clamp_state_nonneg calls it, so the clamp itself is defined once. Neither changes what either integrator computes.
…anl#1217) BNGSIM_CODEGEN_JIT=mir BNGSIM_CODEGEN_THRESHOLD=1 over python/tests is the run that found lanl#1208, lanl#1212 and lanl#1357. mir.yml runs a hand-picked list of codegen files, so a bug outside that list went unseen until someone ran the whole suite by hand. lanl#1350 made the run a signal: the tests that cannot pass under it skip with declared reasons. This makes it a job. forced-jit.yml: nightly at 07:53 UTC, on workflow_dispatch, and on a pull request that edits it. ubuntu-latest and macos-15, two shards each. The build is python-tests.yml's uv sync --extra dev, with MIR added through SKBUILD_CMAKE_DEFINE as sanitizers.yml adds its flags. A guard fails a build without MIR. The run is strict on skips and replaces crashed workers (--max-worker-restart=500). A failure opens or comments on one tracking issue, as sanitizers.yml does.
Closes #1217 (with #1348, which fixes its #1212 group).
What was wrong
Running the whole suite with every model forced through the MIR JIT (
BNGSIM_CODEGEN_JIT=mir BNGSIM_CODEGEN_THRESHOLD=1) is the check that found #1208 and #1212. It is only a signal if it passes. On main 9a26f5b with #1348 merged in, 53 tests fail under it. That matches #1217's accounting once #1212's 38 are gone:.so, its cache key, the redirected cache dir, or the output-sensitivity and sens-RHS notes written beside it. The JIT compiles in process and writes none of them.codegen_backend == "cc", and the JIT reports"mir"exprtk,analytical, no.so, the interpreter's RHS counters), andTHRESHOLD=1compiles it. They fail under forced cc too.The 32 artifact tests are in
test_output_sens_support_note.py(22),test_sens_rhs_decline_note.py(5),test_hpc_contract.py(2), and one each intest_codegen_cache_key.py,test_ar_species_output_sensitivities.pyandtest_sens_numerically_zero_base.py. The 7 cc-by-name tests are intest_engine_choice_accessors.py(4),test_tfun_analytical_jacobian.py(2) andtest_lu_fill_routing.py(1). The 13 threshold tests are intest_engine_choice_accessors.py(3),test_rhs_obs_func_gate.py(3),test_steady_state_polish_jacobian.py(3),test_jacobian_discontinuous_fallback.py,test_lazy_jacobian.py,test_model_codegen_sensitivity.py, andtest_steady_state_scaled_criterion.py's MODEL1712050008 retry test. That last one pins the arm64 interpreter's route (solver_jacobian_retried); compiled, the march reaches the same root, within 1.6e-6, without a retry.The change
python/tests/_codegen_backend.py. A new helper, imported the way_fd_sens.pyand_ci_workflow.pyare. It provides threeskipifs and onexfail:under_jit_no_cc_artifactandunder_jit_engine_nameread the JIT selection throughbngsim._codegen._codegen_jit_backend(), the library's own reading ofBNGSIM_CODEGEN_JIT.threshold_forcedapplies whenBNGSIM_CODEGEN_THRESHOLDis set below the default of 256.xfail_when_threshold_forced(issue, why)is a strict xfail under the same condition.Each skip reason is declared in
conftest.py's_DECLARED_SKIPS(tierANYWHERE), soBNGSIM_SKIP_AUDIT=strictaccepts them.The two engine-dependent tests are not skipped. A forced run shows each gives a different answer on the compiled path. Both findings are filed, as #1357 and #1358. Each test carries a strict xfail under a lowered threshold, naming its issue, so the mark has to go when the fix lands:
steady_state(method="integration")on the compiled RHS refusesglioblastoma_egfrviii_seed.net's steady state at residual 2.1e-39, withcontinued_run_distance = inf, because its run test is never retried on difference quotients. That affectstest_a_march_whose_integrator_fails_returns_the_state_it_passed[integration]. Fixed in steady state: the run test retries a NaN f at the clamped state, as the time course does (#1357) #1370.get_param(get_param on an assignment-rule parameter after a compiled run returns its load-time value, not the rule's #1358). After a compiled run,get_paramon a parameter an assignment rule sets returns its load-time value:qreads 1.0, where an interpreted run reads the rule's end-of-run 0.0183. The trajectory is unaffected. This istest_a_write_after_a_run_does_not_move_it_to_the_rules_current_value, whose precondition reads the slot.Verified
On this branch with #1348 merged in, macOS arm64 MIR build,
--max-worker-restart=500,BNGSIM_SKIP_AUDIT=strict:BNGSIM_CODEGEN_JIT=mir BNGSIM_CODEGEN_THRESHOLD=1BNGSIM_CODEGEN_THRESHOLD=1(forced cc)The suite's existing xfail is the 1 in each count; the forced runs added three. That was measured when MODEL1712050008's retry test still carried an xfail. It is now a forced-threshold skip, so a forced run reports 3 xfailed and one more skip. Rerun after that change,
test_steady_state_scaled_criterion.pyunderBNGSIM_CODEGEN_THRESHOLD=1with the strict audit gives 222 passed, 3 skipped and 1 xfailed (glioblastoma, #1357), and 224 passed by default. The strict audit accepts every new skip.Negative control: with the artifact reason removed from
_DECLARED_SKIPS, the strict audit reports1 undeclared skip reason(s).Not in this PR
mir.ymlalready makes: