✨ D576 Buffer Monitoring (#19674)
This commit is contained in:
@ -67,6 +67,23 @@ GCodeQueue::RingBuffer GCodeQueue::ring_buffer = { 0 };
|
||||
static millis_t last_command_time = 0;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Track buffer underruns
|
||||
*/
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
uint32_t GCodeQueue::command_buffer_underruns = 0,
|
||||
GCodeQueue::planner_buffer_underruns = 0;
|
||||
bool GCodeQueue::command_buffer_empty = false,
|
||||
GCodeQueue::planner_buffer_empty = false;
|
||||
millis_t GCodeQueue::max_command_buffer_empty_duration = 0,
|
||||
GCodeQueue::max_planner_buffer_empty_duration = 0,
|
||||
GCodeQueue::command_buffer_empty_at = 0,
|
||||
GCodeQueue::planner_buffer_empty_at = 0;
|
||||
|
||||
uint8_t GCodeQueue::auto_buffer_report_interval;
|
||||
millis_t GCodeQueue::next_buffer_report_ms;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Serial command injection
|
||||
*/
|
||||
@ -82,7 +99,6 @@ PGM_P GCodeQueue::injected_commands_P; // = nullptr
|
||||
*/
|
||||
char GCodeQueue::injected_commands[64]; // = { 0 }
|
||||
|
||||
|
||||
void GCodeQueue::RingBuffer::commit_command(bool skip_ok
|
||||
OPTARG(HAS_MULTI_SERIAL, serial_index_t serial_ind/*=-1*/)
|
||||
) {
|
||||
@ -621,7 +637,24 @@ void GCodeQueue::advance() {
|
||||
if (process_injected_command_P() || process_injected_command()) return;
|
||||
|
||||
// Return if the G-code buffer is empty
|
||||
if (ring_buffer.empty()) return;
|
||||
if (ring_buffer.empty()) {
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
if (!command_buffer_empty) {
|
||||
command_buffer_empty = true;
|
||||
command_buffer_underruns++;
|
||||
command_buffer_empty_at = millis();
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
if (command_buffer_empty) {
|
||||
command_buffer_empty = false;
|
||||
const millis_t command_buffer_empty_duration = millis() - command_buffer_empty_at;
|
||||
NOLESS(max_command_buffer_empty_duration, command_buffer_empty_duration);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
@ -664,3 +697,41 @@ void GCodeQueue::advance() {
|
||||
// The queue may be reset by a command handler or by code invoked by idle() within a handler
|
||||
ring_buffer.advance_pos(ring_buffer.index_r, -1);
|
||||
}
|
||||
|
||||
#if ENABLED(BUFFER_MONITORING)
|
||||
|
||||
void GCodeQueue::report_buffer_statistics() {
|
||||
SERIAL_ECHOLNPAIR("D576"
|
||||
" P:", planner.moves_free(), " ", -queue.planner_buffer_underruns, " (", queue.max_planner_buffer_empty_duration, ")"
|
||||
" B:", BUFSIZE - ring_buffer.length, " ", -queue.command_buffer_underruns, " (", queue.max_command_buffer_empty_duration, ")"
|
||||
);
|
||||
command_buffer_underruns = planner_buffer_underruns = 0;
|
||||
max_command_buffer_empty_duration = 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
|
||||
const millis_t ms = millis();
|
||||
if (planner.movesplanned() == 0) {
|
||||
if (!planner_buffer_empty) { // the planner buffer wasn't empty, but now it is
|
||||
planner_buffer_empty = true;
|
||||
planner_buffer_underruns++;
|
||||
planner_buffer_empty_at = ms;
|
||||
}
|
||||
}
|
||||
else if (planner_buffer_empty) { // the planner buffer was empty, but now it's not
|
||||
planner_buffer_empty = false;
|
||||
const millis_t planner_buffer_empty_duration = ms - planner_buffer_empty_at;
|
||||
NOLESS(max_planner_buffer_empty_duration, planner_buffer_empty_duration); // if it's longer than the currently tracked max duration, replace it
|
||||
}
|
||||
|
||||
if (queue.auto_buffer_report_interval && ELAPSED(ms, queue.next_buffer_report_ms)) {
|
||||
queue.next_buffer_report_ms = ms + 1000UL * queue.auto_buffer_report_interval;
|
||||
PORT_REDIRECT(SERIAL_BOTH);
|
||||
report_buffer_statistics();
|
||||
PORT_RESTORE();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BUFFER_MONITORING
|
||||
|
Reference in New Issue
Block a user