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:
bubnikv 2020-04-01 13:42:26 +02:00
parent f4cc0ce075
commit 31b0ae164d
2 changed files with 78 additions and 99 deletions

View file

@ -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 {