tp: rate-limit Ruckig plan-failure logging to once per segment - #4420
Conversation
|
Two things on the logging itself. The
Neither changes my view that the rate limit is the right call. |
d7a62ba to
ed8c87a
Compare
|
Both points addressed and force-pushed (
Re-measured with the same fault injection (first-attempt position-plan failure forced, five-move program on |
A segment whose inputs Ruckig can never solve keeps ruckig_planned=0, so tpCalculateSCurveAccel re-enters its failure branch every servo cycle and logs at the full servo rate (e.g. 1kHz). Motion is unaffected (it falls back to trapezoidal), but over a long run this floods the kernel log / journald with GBs of identical records. Add per-segment "already logged" flags to TC_STRUCT (reset by tcInit on every new segment) and log each failure once, tagged with the segment id. Not re-armed on a later success within the same segment, so an oscillating fail/succeed segment also cannot flood. No change to motion behaviour. master's own tpCalculateSCurveAccel already carries a scurve_jerk_warned once-only guard for the adjacent warning. tpCalculateSCurveAccel has five distinct Ruckig failure sites, each retried every servo cycle: - pool acquire: ruckig_planner stays NULL and is re-acquired next cycle for as long as the preallocated pool is exhausted; - velocity control, replan failed: keeps the previous trajectory and falls straight back in on the next cycle; - velocity control, first attempt failed: returns TP_SCURVE_ACCEL_ERROR, which only makes the caller use trapezoidal for that one cycle before calling back in; - position control, replan failed / first attempt failed: the same two cases on the position-control path. Each site gets its own flag rather than one shared flag, so a segment that hits more than one failure mode (e.g. pool-acquire, then a plan failure once a planner frees up) still logs each mode once. A single shared flag would report only whichever fired first. The first-attempt position-control ERR dump also regains plan_result, which was previously only on the replan branch, so the give-up path again shows which limit Ruckig objected to. The velocity-control first-attempt warning carries it too, for symmetry.
Problem
When Ruckig cannot plan a segment,
tpCalculateSCurveAccel()logs the failureand falls back to trapezoidal motion for that cycle. The caller then calls
straight back in on the next servo cycle, and — because
ruckig_plannedonlyflips to 1 on success — the planning branch is re-entered and fails again. A
segment Ruckig can never solve therefore logs every servo cycle, i.e. at
1 kHz on a typical machine, for as long as that segment is being executed.
The fallback itself is graceful; the logging is not. On a long run this
produces a log measured in gigabytes and buries anything else in it.
Note that the S-curve path is the default (
mode = 1unless the move is anabort), so this is reachable on a stock machine with jerk limits configured.
Fix
Add per-segment "already logged" flags to
TC_STRUCT, cleared intcInit(),and guard each of the five failure sites in
tpCalculateSCurveAccel(): thepool-acquire failure, both velocity-control failures, and both position-control
failures. Each distinct segment still reports its first failure — and the
messages now carry
tc->id, so you can tell which segment — but a segmentthat keeps failing reports once instead of once per cycle.
One flag per site, not one shared flag: a segment that hits more than one
failure mode (say a pool-acquire failure, then a plan failure once a planner
frees up) still logs each mode once. A single shared flag would report only
whichever fired first.
The first-attempt position-control ERR dump also carries
plan_resultagain(it had been left only on the replan branch), so the give-up path shows which
limit Ruckig objected to; the velocity-control first-attempt warning carries
it too.
Nothing about the motion changes: the trapezoidal fallback, the return codes
and the retry behaviour are all untouched. This is a logging change only.
Precedent: master's own
tpCalculateSCurveAccel()already carries ascurve_jerk_warnedguard for the adjacent "max jerk < 1" warning, with thesame rationale in its comment ("warn ONCE instead of storming the log at servo
rate"). This applies that treatment to the Ruckig failure paths, per-segment
rather than per-process, so each new bad segment is still surfaced.
Testing
Build clean (RIP,
--with-realtime=uspace), no warnings.cppcheckclean onall three changed files.
tests/motion+tests/motion-logger+tests/interp: 91/91 pass, 1 skipped (tests/interp/compile, disabledupstream).
Measured with fault injection — forcing the first-attempt position-planning
failure (
plan_result = -1right afterruckig_plan_position()) and running afive-move G-code program on
configs/sim/axis/axis_mm_scurve.ini(which thearc blender expands to nine queued segments):
Ruckig planning failed (first attempt)linestp.c, same injectionThe nine remaining lines on the branch are one per queued segment that hits the
site (five moves plus four arc-blend segments, each its own
TC_STRUCT), eachtagged
reported onceand naming itstc->id. With the injection removed thebranch logs zero Ruckig-failure lines on the same program, so nothing that
should be reported is being suppressed.