perf(GCodeProcessor): stop recompiling std::regex on every g-code line (up to 2.9x faster slicing) (#14166)

perf(GCodeProcessor): stop recompiling std::regex on every g-code line

process_SET_VELOCITY_LIMIT() constructed three std::regex objects from
scratch on every call, and Klipper-flavor g-code contains
SET_VELOCITY_LIMIT on a large share of lines (8,834 of 103,549 lines for
a single 3DBenchy sliced for a Creality K2). perf attributes 6.4% of the
whole slicing run to this one function, almost all of it regex
compilation and the allocator traffic it generates.
process_SET_PRESSURE_ADVANCE() and the External_Purge_Tag handler had
the same per-call construction.

Hoist all five patterns to function-local static const std::regex so
they compile once. Generated g-code is byte-identical (modulo the
timestamp header); slicing a 16x Benchy plate for a K2 drops from
78.5s to 27.3s wall (2.9x) on a 16-core Linux box, single Benchy from
8.9s to 5.6s.

Co-authored-by: grant0013 <grant@harktech.co.uk>
This commit is contained in:
Grant Harkness
2026-06-16 16:51:27 +01:00
committed by GitHub
parent 454335dba6
commit 5ed8f5ef25

View File

@@ -3120,7 +3120,7 @@ void GCodeProcessor::process_tags(const std::string_view comment, bool producers
// Orca: Integrate filament consumption for purging performed to an external device and controlled via macros
// (eg. Happy Hare) in the filament consumption stats.
if (boost::starts_with(comment, GCodeProcessor::External_Purge_Tag)) {
std::regex numberRegex(R"(\d+\.\d+)");
static const std::regex numberRegex(R"(\d+\.\d+)");
std::smatch match;
std::string line(comment);
if (std::regex_search(line, match, numberRegex)) {
@@ -4976,7 +4976,7 @@ void GCodeProcessor::process_M572(const GCodeReader::GCodeLine &line)
void GCodeProcessor::process_SET_PRESSURE_ADVANCE(const GCodeReader::GCodeLine& line)
{
std::regex regex(R"(SET_PRESSURE_ADVANCE\s+(?:.*\s+)?ADVANCE\s*=\s*([\d.]+))");
static const std::regex regex(R"(SET_PRESSURE_ADVANCE\s+(?:.*\s+)?ADVANCE\s*=\s*([\d.]+))");
std::smatch matches;
if (std::regex_search(line.raw(), matches, regex) && matches.size() > 1) {
@@ -5198,9 +5198,9 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
void GCodeProcessor::process_SET_VELOCITY_LIMIT(const GCodeReader::GCodeLine& line)
{
// handle SQUARE_CORNER_VELOCITY
std::regex pattern("\\sSQUARE_CORNER_VELOCITY\\s*=\\s*([0-9]*\\.*[0-9]*)");
static const std::regex square_corner_velocity_pattern("\\sSQUARE_CORNER_VELOCITY\\s*=\\s*([0-9]*\\.*[0-9]*)");
std::smatch matches;
if (std::regex_search(line.raw(), matches, pattern) && matches.size() == 2) {
if (std::regex_search(line.raw(), matches, square_corner_velocity_pattern) && matches.size() == 2) {
float _jerk = 0;
try
{
@@ -5213,8 +5213,8 @@ void GCodeProcessor::process_SET_VELOCITY_LIMIT(const GCodeReader::GCodeLine& li
}
}
pattern = std::regex("\\sACCEL\\s*=\\s*([0-9]*\\.*[0-9]*)");
if (std::regex_search(line.raw(), matches, pattern) && matches.size() == 2) {
static const std::regex accel_pattern("\\sACCEL\\s*=\\s*([0-9]*\\.*[0-9]*)");
if (std::regex_search(line.raw(), matches, accel_pattern) && matches.size() == 2) {
float _accl = 0;
try
{
@@ -5227,8 +5227,8 @@ void GCodeProcessor::process_SET_VELOCITY_LIMIT(const GCodeReader::GCodeLine& li
}
}
pattern = std::regex("\\sVELOCITY\\s*=\\s*([0-9]*\\.*[0-9]*)");
if (std::regex_search(line.raw(), matches, pattern) && matches.size() == 2) {
static const std::regex velocity_pattern("\\sVELOCITY\\s*=\\s*([0-9]*\\.*[0-9]*)");
if (std::regex_search(line.raw(), matches, velocity_pattern) && matches.size() == 2) {
float _speed = 0;
try
{