Record what a command killed by the watchdog cost - #310
Merged
Conversation
A model whose command runs out of time reports nothing for the phase it was in,
so the time disappears from every phase column and only `exectime` still counts
it. In the master run of 2026-08-12 that is 15 models and 1.34 hours, including
three BuildingSystems models that spend the full 660 second budget in
translateModel and are recorded as having spent three seconds parsing and
nothing else.
The caller does try to account for it:
except TimeoutError as e:
execstat["frontend"]=monotonic()-start
but that handler never runs. `sendExpressionTimeout` kills the command and calls
`writeResultAndExit` itself, from inside, so the process is gone before the
exception is raised - the results written are whatever `execstat` held when the
command started.
Recording it where the results are written covers every way out instead of the
one path that remembered to. A phase now says when it started, `writeResult`
charges it if it never reported a time of its own, and a phase that ends
normally still reports exactly what it did before.
Which phase a killed command belongs to cannot be known - the timers of omc are
gone with it - so it is charged to what the command itself is: building an FMU
to the build, simulating to the simulation, translating to the front end, which
is also the phase such a model is reported as having failed in.
Verified on Modelica.Fluid.Examples.HeatExchanger.HeatExchangerSimulation with
ulimitOmc=1, which the watchdog kills:
before {'parsing': 1.73}
after {'parsing': 1.65, 'frontend': 3.01}
and on Modelica.Blocks.Examples.PID_Controller, which succeeds, where every
phase is unchanged.
Part of #308.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A model whose command runs out of time reports nothing for the phase it was in. The time only survives in
exectime, and no report showsexectimeper phase, so it vanishes.In the
masterrun of 2026-08-12 that is 15 models and 1.34 hours. Three of them areBuildingSystemsmodels that spend the full 660 secondulimitOmcbudget insidetranslateModeland are recorded like this:Eleven minutes, of which three seconds are accounted for.
Why
The caller does try to account for it:
That handler never runs.
sendExpressionTimeoutkills the command and callswriteResultAndExititself, from inside, before raising anything:So the process is gone before the exception reaches the caller, and the results written are whatever
execstatheld when the command started. The same applies to the path where omc dies mid-command.The change
Recording it where the results are written covers every way out, rather than the one path that remembered to. A phase says when it started,
writeResultcharges it if it never reported a time of its own, and a phase that ends normally still reports exactly what it did before:Which phase a killed command belongs to cannot be known — omc's timers die with it — so it is charged to what the command itself is: building an FMU to the build, simulating to the simulation, translating to the front end. That last one is also the phase such a model is reported as having failed in, so the row stays self-consistent.
Testing
Modelica.Fluid.Examples.HeatExchanger.HeatExchangerSimulationwithulimitOmc=1, which the watchdog kills (Thread is still alive. / Aborted the command.):Modelica.Blocks.Examples.PID_Controller, which succeeds, is unchanged:Both run against the real
testmodel.pyof this branch and oforigin/master, on the same configuration.Scope
This is the part of #308 that is a genuine defect. The rest of that issue's description was wrong and is corrected in a comment there: ordinary failures do record the phase they failed in — 851 of 867 front end failures and all 301 back end failures carry a time — and the remaining unattributed hours are about 0.7 s per model of process startup and teardown, which belongs to no phase because it is not one.
Part of #308.
Generated by Claude Code.