diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index e8f408a1ea..eabae9363a 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -91,10 +91,14 @@ bool send_ok[BUFSIZE]; #if ENABLED(BUFFER_MONITORING) uint32_t GCodeQueue::command_buffer_underruns = 0; bool GCodeQueue::command_buffer_empty = false; - millis_t GCodeQueue::max_command_buffer_empty_duration = 0; millis_t GCodeQueue::command_buffer_empty_at = 0; + uint32_t GCodeQueue::planner_buffer_underruns = 0; + bool GCodeQueue::planner_buffer_empty = false; + millis_t GCodeQueue::max_planner_buffer_empty_duration = 0; + millis_t GCodeQueue::planner_buffer_empty_at = 0; + uint8_t GCodeQueue::auto_buffer_report_interval; millis_t GCodeQueue::next_buffer_report_ms; #endif @@ -639,12 +643,14 @@ void GCodeQueue::advance() { } #if ENABLED(BUFFER_MONITORING) - static millis_t command_buffer_empty_duration; - command_buffer_empty_duration = millis() - command_buffer_empty_at; - if (command_buffer_empty_duration > max_command_buffer_empty_duration) { - max_command_buffer_empty_duration = command_buffer_empty_duration; + if (command_buffer_empty) { + static millis_t command_buffer_empty_duration; + command_buffer_empty_duration = millis() - command_buffer_empty_at; + if (command_buffer_empty_duration > max_command_buffer_empty_duration) { + max_command_buffer_empty_duration = command_buffer_empty_duration; + } + command_buffer_empty = false; } - command_buffer_empty = false; #endif @@ -697,15 +703,40 @@ void GCodeQueue::report_buffer_statistics() { SERIAL_ECHO("M576"); SERIAL_ECHOLNPAIR(SP_P_STR, int(planner.moves_free()), SP_B_STR, int(BUFSIZE - length), + " PU", queue.planner_buffer_underruns, + " PD", queue.max_planner_buffer_empty_duration, " BU", queue.command_buffer_underruns, " BD", queue.max_command_buffer_empty_duration, ); command_buffer_underruns = 0; max_command_buffer_empty_duration = 0; + + planner_buffer_underruns = 0; + max_planner_buffer_empty_duration = 0; } void GCodeQueue::auto_report_buffer_statistics() { + // Bit of a hack to try to catch planner buffer underruns without having logic + // running inside Stepper::block_phase_isr + if (planner.movesplanned() == 0) { + if (!planner_buffer_empty) { // if the planner buffer wasn't empty, but now it is + planner_buffer_empty = true; + planner_buffer_underruns++; + planner_buffer_empty_at = millis(); + } + } else if (planner_buffer_empty) { // if the planner buffer was empty, but now it ain't + static millis_t planner_buffer_empty_duration; + planner_buffer_empty_duration = millis() - planner_buffer_empty_at; + + // if it's longer than the currently tracked max duration, replace it + if (planner_buffer_empty_duration > max_planner_buffer_empty_duration) { + max_planner_buffer_empty_duration = planner_buffer_empty_duration; + } + + planner_buffer_empty = false; + } + if (queue.auto_buffer_report_interval && ELAPSED(millis(), queue.next_buffer_report_ms)) { queue.next_buffer_report_ms = millis() + 1000UL * queue.auto_buffer_report_interval; PORT_REDIRECT(SERIAL_BOTH); diff --git a/Marlin/src/gcode/queue.h b/Marlin/src/gcode/queue.h index aa7bc92c5e..a579ea7ef9 100644 --- a/Marlin/src/gcode/queue.h +++ b/Marlin/src/gcode/queue.h @@ -156,13 +156,21 @@ public: static millis_t max_command_buffer_empty_duration; static millis_t command_buffer_empty_at; + static uint32_t planner_buffer_underruns; + static bool planner_buffer_empty; + static millis_t max_planner_buffer_empty_duration; + static millis_t planner_buffer_empty_at; + /** * Report buffer statistics to the host to be able to detect buffer underruns * * Returns "M576 " followed by: - * P Planner space remaining - * B Command buffer space remaining - * U Number of command buffer underruns since last report + * P Planner space remaining + * B Command buffer space remaining + * PU Number of planner buffer underruns since last report + * PD Max time in ms the planner buffer was empty since last report + * BU Number of command buffer underruns since last report + * BD Max time in ms the command buffer was empty since last report */ static void report_buffer_statistics(); diff --git a/Marlin/src/gcode/stats/M576.cpp b/Marlin/src/gcode/stats/M576.cpp index ba7f89b3fc..dfa9a1cad0 100644 --- a/Marlin/src/gcode/stats/M576.cpp +++ b/Marlin/src/gcode/stats/M576.cpp @@ -30,7 +30,18 @@ #include "../queue.h" /** - * M576: Return buffer stats, and optionally set auto-report interval. M576 [S] + * M576: Return buffer stats, and optionally set auto-report interval. + * Usage: M576 [S] + * + * When called, printer emits the following output: + * "M576 P B PU PD BU BD" + * Where: + * P: Planner buffers available + * B: Command buffers available + * PU: Planner buffer underruns since last report + * PD: Maximum time in ms planner buffer was empty since last report + * BU: Command buffer underruns since last report + * BD: Maximum time in ms command buffer was empty since last report */ void GcodeSuite::M576() { if (parser.seenval('S')) {