Optimization of the GCodeTimeEstimator to only keep a fixed number
of trapeziodal blocks around. The number is hard coded to 64, and 3x64 blocks are flushed everytime the queue grows over 4x64 blocks. This time estimator is slightly more close to what the firmware does, which keeps a fixed number of blocks and it recalculates all the blocks every time a new block is added while the oldest block is pushed out of the queue. Therefore this optimization shall produce negligible differences to what the previous code produced.
This commit is contained in:
parent
f4cc0ce075
commit
31b0ae164d
@ -207,11 +207,8 @@ namespace Slic3r {
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (start_from_beginning)
|
||||
{
|
||||
_reset_time();
|
||||
m_last_st_synchronized_block_id = -1;
|
||||
}
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
@ -221,6 +218,7 @@ namespace Slic3r {
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
#if 0
|
||||
void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
|
||||
{
|
||||
reset();
|
||||
@ -229,7 +227,7 @@ namespace Slic3r {
|
||||
[this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
|
||||
{ this->_process_gcode_line(reader, line); });
|
||||
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
@ -244,7 +242,7 @@ namespace Slic3r {
|
||||
reset();
|
||||
|
||||
m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
@ -262,7 +260,7 @@ namespace Slic3r {
|
||||
{ this->_process_gcode_line(reader, line); };
|
||||
for (const std::string& line : gcode_lines)
|
||||
m_parser.parse_line(line, action);
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache});
|
||||
@ -271,6 +269,7 @@ namespace Slic3r {
|
||||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode)
|
||||
{
|
||||
@ -317,25 +316,25 @@ namespace Slic3r {
|
||||
if (data == nullptr)
|
||||
return;
|
||||
|
||||
assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count));
|
||||
const Block* block = nullptr;
|
||||
if (g1_line_id < (int)data->g1_line_ids.size())
|
||||
assert((g1_line_id >= (int)data->g1_times.size()) || (data->g1_times[g1_line_id].first >= (int)g1_lines_count));
|
||||
float elapsed_time = -1.0f;
|
||||
if (g1_line_id < (int)data->g1_times.size())
|
||||
{
|
||||
const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id];
|
||||
const G1LineIdTime& map_item = data->g1_times[g1_line_id];
|
||||
if (map_item.first == g1_lines_count)
|
||||
{
|
||||
if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size()))
|
||||
block = &data->blocks[map_item.second];
|
||||
if (line.has_e())
|
||||
elapsed_time = map_item.second;
|
||||
++g1_line_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ((block != nullptr) && (block->elapsed_time != -1.0f))
|
||||
if (elapsed_time != -1.0f)
|
||||
{
|
||||
float block_remaining_time = data->time - block->elapsed_time;
|
||||
float block_remaining_time = data->time - elapsed_time;
|
||||
if (std::abs(last_recorded_time - block_remaining_time) > interval_sec)
|
||||
{
|
||||
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
gcode_line += line_M73;
|
||||
|
||||
last_recorded_time = block_remaining_time;
|
||||
@ -643,22 +642,6 @@ namespace Slic3r {
|
||||
m_state.extruder_id = m_state.extruder_id_unloaded;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
m_state.additional_time += timeSec;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_additional_time(float timeSec)
|
||||
{
|
||||
m_state.additional_time = timeSec;
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::get_additional_time() const
|
||||
{
|
||||
return m_state.additional_time;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_default()
|
||||
{
|
||||
set_units(Millimeters);
|
||||
@ -788,7 +771,7 @@ namespace Slic3r {
|
||||
{
|
||||
size_t out = sizeof(*this);
|
||||
out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block);
|
||||
out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId);
|
||||
out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_times, G1LineIdTime);
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -807,13 +790,9 @@ namespace Slic3r {
|
||||
if (get_e_local_positioning_type() == Absolute)
|
||||
set_axis_position(E, 0.0f);
|
||||
|
||||
set_additional_time(0.0f);
|
||||
|
||||
reset_extruder_id();
|
||||
reset_g1_line_id();
|
||||
m_g1_line_ids.clear();
|
||||
|
||||
m_last_st_synchronized_block_id = -1;
|
||||
m_g1_times.clear();
|
||||
|
||||
m_needs_custom_gcode_times = false;
|
||||
m_custom_gcode_times.clear();
|
||||
@ -830,17 +809,19 @@ namespace Slic3r {
|
||||
m_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_calculate_time()
|
||||
void GCodeTimeEstimator::_calculate_time(size_t keep_last_n_blocks)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
assert(keep_last_n_blocks <= m_blocks.size());
|
||||
|
||||
_forward_pass();
|
||||
_reverse_pass();
|
||||
_recalculate_trapezoids();
|
||||
|
||||
m_time += get_additional_time();
|
||||
m_custom_gcode_time_cache += get_additional_time();
|
||||
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i)
|
||||
size_t n_blocks_process = m_blocks.size() - keep_last_n_blocks;
|
||||
m_g1_times.reserve(m_g1_times.size() + n_blocks_process);
|
||||
for (size_t i = 0; i < n_blocks_process; ++ i)
|
||||
{
|
||||
Block& block = m_blocks[i];
|
||||
float block_time = 0.0f;
|
||||
@ -848,7 +829,8 @@ namespace Slic3r {
|
||||
block_time += block.cruise_time();
|
||||
block_time += block.deceleration_time();
|
||||
m_time += block_time;
|
||||
block.elapsed_time = m_time;
|
||||
if (block.g1_line_id >= 0)
|
||||
m_g1_times.emplace_back(block.g1_line_id, m_time);
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
MovesStatsMap::iterator it = _moves_stats.find(block.move_type);
|
||||
@ -862,9 +844,10 @@ namespace Slic3r {
|
||||
m_custom_gcode_time_cache += block_time;
|
||||
}
|
||||
|
||||
m_last_st_synchronized_block_id = (int)m_blocks.size() - 1;
|
||||
// The additional time has been consumed (added to the total time), reset it to zero.
|
||||
set_additional_time(0.);
|
||||
if (keep_last_n_blocks)
|
||||
m_blocks.erase(m_blocks.begin(), m_blocks.begin() + n_blocks_process);
|
||||
else
|
||||
m_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
|
||||
@ -1208,8 +1191,11 @@ namespace Slic3r {
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
// adds block to blocks list
|
||||
block.g1_line_id = this->get_g1_line_id();
|
||||
m_blocks.emplace_back(block);
|
||||
m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1));
|
||||
|
||||
if (m_blocks.size() > planner_refresh_if_larger)
|
||||
_calculate_time(planner_queue_size);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
|
||||
@ -1218,8 +1204,9 @@ namespace Slic3r {
|
||||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
float value;
|
||||
float extra_time = 0.f;
|
||||
if (line.has_value('P', value))
|
||||
add_additional_time(value * MILLISEC_TO_SEC);
|
||||
extra_time += value * MILLISEC_TO_SEC;
|
||||
|
||||
// see: http://reprap.org/wiki/G-code#G4:_Dwell
|
||||
if ((dialect == gcfRepetier) ||
|
||||
@ -1228,10 +1215,10 @@ namespace Slic3r {
|
||||
(dialect == gcfRepRap))
|
||||
{
|
||||
if (line.has_value('S', value))
|
||||
add_additional_time(value);
|
||||
extra_time += value;
|
||||
}
|
||||
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(extra_time);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line)
|
||||
@ -1296,7 +1283,7 @@ namespace Slic3r {
|
||||
anyFound = true;
|
||||
}
|
||||
else
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(0.f);
|
||||
|
||||
if (!anyFound)
|
||||
{
|
||||
@ -1310,7 +1297,7 @@ namespace Slic3r {
|
||||
void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(0.f);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
|
||||
@ -1462,9 +1449,9 @@ namespace Slic3r {
|
||||
// MK3 MMU2 specific M code:
|
||||
// M702 C is expected to be sent by the custom end G-code when finalizing a print.
|
||||
// The MK3 unit shall unload and park the active filament into the MMU2 unit.
|
||||
add_additional_time(get_filament_unload_time(get_extruder_id()));
|
||||
float extra_time = get_filament_unload_time(get_extruder_id());
|
||||
reset_extruder_id();
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(extra_time);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1478,10 +1465,10 @@ namespace Slic3r {
|
||||
{
|
||||
// Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating
|
||||
// that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet.
|
||||
add_additional_time(get_filament_unload_time(get_extruder_id()));
|
||||
float extra_time = get_filament_unload_time(get_extruder_id());
|
||||
set_extruder_id(id);
|
||||
add_additional_time(get_filament_load_time(get_extruder_id()));
|
||||
_simulate_st_synchronize();
|
||||
extra_time += get_filament_load_time(get_extruder_id());
|
||||
_simulate_st_synchronize(extra_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1513,7 +1500,9 @@ namespace Slic3r {
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
m_needs_custom_gcode_times = true;
|
||||
_calculate_time();
|
||||
//FIXME this simulates st_synchronize! is it correct?
|
||||
// The estimated time may be longer than the real print time.
|
||||
_simulate_st_synchronize(0.f);
|
||||
if (m_custom_gcode_time_cache != 0.0f)
|
||||
{
|
||||
m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache});
|
||||
@ -1521,34 +1510,26 @@ namespace Slic3r {
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize()
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize(float extra_time)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_calculate_time();
|
||||
m_time += extra_time;
|
||||
m_custom_gcode_time_cache += extra_time;
|
||||
_calculate_time(0);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_forward_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (m_blocks.size() > 1)
|
||||
{
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i)
|
||||
{
|
||||
_planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i + 1 < (int)m_blocks.size(); ++i)
|
||||
_planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reverse_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (m_blocks.size() > 1)
|
||||
{
|
||||
for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i)
|
||||
{
|
||||
_planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]);
|
||||
}
|
||||
}
|
||||
for (int i = (int)m_blocks.size() - 1; i > 0; -- i)
|
||||
_planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr)
|
||||
@ -1598,7 +1579,7 @@ namespace Slic3r {
|
||||
Block* curr = nullptr;
|
||||
Block* next = nullptr;
|
||||
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i)
|
||||
for (size_t i = 0; i < m_blocks.size(); ++ i)
|
||||
{
|
||||
Block& b = m_blocks[i];
|
||||
|
||||
@ -1657,7 +1638,7 @@ namespace Slic3r {
|
||||
{
|
||||
char buffer[64];
|
||||
|
||||
int minutes = std::round(time_in_secs / 60.);
|
||||
int minutes = int(std::round(time_in_secs / 60.));
|
||||
if (minutes <= 0) {
|
||||
::sprintf(buffer, "%ds", (int)time_in_secs);
|
||||
} else {
|
||||
|
@ -85,7 +85,6 @@ namespace Slic3r {
|
||||
// hard limit for the acceleration, to which the firmware will clamp.
|
||||
float max_acceleration; // mm/s^2
|
||||
float retract_acceleration; // mm/s^2
|
||||
float additional_time; // s
|
||||
float minimum_feedrate; // mm/s
|
||||
float minimum_travel_feedrate; // mm/s
|
||||
float extrude_factor_override_percentage;
|
||||
@ -160,7 +159,9 @@ namespace Slic3r {
|
||||
|
||||
FeedrateProfile feedrate;
|
||||
Trapezoid trapezoid;
|
||||
float elapsed_time;
|
||||
|
||||
// Ordnary index of this G1 line in the file.
|
||||
int g1_line_id { -1 };
|
||||
|
||||
Block();
|
||||
|
||||
@ -217,16 +218,13 @@ namespace Slic3r {
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
public:
|
||||
typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
|
||||
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
|
||||
typedef std::pair<int, float> G1LineIdTime;
|
||||
typedef std::vector<G1LineIdTime> G1LineIdsTimes;
|
||||
|
||||
struct PostProcessData
|
||||
{
|
||||
const G1LineIdToBlockIdMap& g1_line_ids;
|
||||
const BlocksList& blocks;
|
||||
const G1LineIdsTimes& g1_times;
|
||||
float time;
|
||||
|
||||
PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {}
|
||||
};
|
||||
|
||||
private:
|
||||
@ -236,10 +234,14 @@ namespace Slic3r {
|
||||
Feedrates m_curr;
|
||||
Feedrates m_prev;
|
||||
BlocksList m_blocks;
|
||||
// Map between g1 line id and blocks id, used to speed up export of remaining times
|
||||
G1LineIdToBlockIdMap m_g1_line_ids;
|
||||
// Index of the last block already st_synchronized
|
||||
int m_last_st_synchronized_block_id;
|
||||
// Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks.
|
||||
// Let's be conservative and plan for newer boards with more memory.
|
||||
static constexpr size_t planner_queue_size = 64;
|
||||
// The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added.
|
||||
// We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate.
|
||||
static constexpr size_t planner_refresh_if_larger = planner_queue_size * 4;
|
||||
// Map from g1 line id to its elapsed time from the start of the print.
|
||||
G1LineIdsTimes m_g1_times;
|
||||
float m_time; // s
|
||||
|
||||
// data to calculate custom code times
|
||||
@ -267,13 +269,13 @@ namespace Slic3r {
|
||||
void calculate_time(bool start_from_beginning);
|
||||
|
||||
// Calculates the time estimate from the given gcode in string format
|
||||
void calculate_time_from_text(const std::string& gcode);
|
||||
//void calculate_time_from_text(const std::string& gcode);
|
||||
|
||||
// Calculates the time estimate from the gcode contained in the file with the given filename
|
||||
void calculate_time_from_file(const std::string& file);
|
||||
//void calculate_time_from_file(const std::string& file);
|
||||
|
||||
// Calculates the time estimate from the gcode contained in given list of gcode lines
|
||||
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||
//void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||
|
||||
// Process the gcode contained in the file with the given filename,
|
||||
// replacing placeholders with correspondent new lines M73
|
||||
@ -350,10 +352,6 @@ namespace Slic3r {
|
||||
unsigned int get_extruder_id() const;
|
||||
void reset_extruder_id();
|
||||
|
||||
void add_additional_time(float timeSec);
|
||||
void set_additional_time(float timeSec);
|
||||
float get_additional_time() const;
|
||||
|
||||
void set_default();
|
||||
|
||||
// Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator
|
||||
@ -389,7 +387,7 @@ namespace Slic3r {
|
||||
// Return an estimate of the memory consumed by the time estimator.
|
||||
size_t memory_used() const;
|
||||
|
||||
PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); }
|
||||
PostProcessData get_post_process_data() const { return PostProcessData{ m_g1_times, m_time }; }
|
||||
|
||||
private:
|
||||
void _reset();
|
||||
@ -397,7 +395,7 @@ namespace Slic3r {
|
||||
void _reset_blocks();
|
||||
|
||||
// Calculates the time estimate
|
||||
void _calculate_time();
|
||||
void _calculate_time(size_t keep_last_n_blocks);
|
||||
|
||||
// Processes the given gcode line
|
||||
void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line);
|
||||
@ -470,7 +468,7 @@ namespace Slic3r {
|
||||
void _process_custom_gcode_tag(CustomGcodeType code);
|
||||
|
||||
// Simulates firmware st_synchronize() call
|
||||
void _simulate_st_synchronize();
|
||||
void _simulate_st_synchronize(float additional_time);
|
||||
|
||||
void _forward_pass();
|
||||
void _reverse_pass();
|
||||
|
Loading…
Reference in New Issue
Block a user