-
Notifications
You must be signed in to change notification settings - Fork 36
Address performance issues related to large objects workflows #898
Description
I would like to propose a couple of enhancements that address multiple performance issues, one related to a performance issue in GVM and a couple related to deepcopy when using flow ports between states. I understand that the RAFCON team has previously expressed a preference to retain the use of deepcopy for safety reasons. However, I propose the introduction of optional configuration flags to provide users with greater flexibility in optimizing performance while preserving the current behavior by default.
Below are the specific instances where significant performance bottlenecks have been observed:
1. Global Variable Manager - gvm.set_variable delay
File: source/rafcon/core/global_variable_manager.py:112
Issue:
When setting a global variable, the following line serializes the value to generate a message string. For large objects, this serialization takes several seconds to complete:
logger.debug("Global variable '{}' was set to value '{}' with type '{}'".format(key, value, data_type.__name__))Proposed Solution:
Serialize the message only if debug logging is enabled, as shown below:
if logger.isEnabledFor(10): # DEBUG level is 10
logger.debug("Global variable '{}' was set to value '{}' with type '{}'".format(key, value, data_type.__name__))This change avoids unnecessary serialization when debug logging is disabled, leading to significant performance improvements.
2. Output Port Delay
File: source/rafcon/core/execution/execution_history_items.py:176
Issue:
When generating ScopedDataItem for use in the data flow, a deepcopy is performed, which takes around 500-800 ms per trajectory (using MoveIt2 trajectories as a large complex object):
self.child_state_input_output_data = copy.deepcopy(child_state_input_output_data)Proposed Solution:
Introduce an option to skip deepcopy for users who do not require it.
if use_deepcopy: # use_deepcopy could be a configurable flag in the execution context
self.child_state_input_output_data = copy.deepcopy(child_state_input_output_data)
else:
self.child_state_input_output_data = child_state_input_output_dataThis change would maintain backward compatibility, as use_deepcopy would default to True, but allow users to enable somehow this flag for significant performance gains.
3. Input Port Delay
File: source/rafcon/core/states/container_state.py:1474
Issue:
When retrieving input data for state execution, a deepcopy is performed on ScopedDataItem data from the data flow, leading to an additional 500-800 ms delay in our case sending a moveit2 trajectory:
actual_value = deepcopy(self.scoped_data[key].value)Proposed Solution:
Optionally disable deepcopy using a similar approach to the output port delay fix:
if use_deepcopy: # use_deepcopy could be a configurable flag in the execution context
actual_value = deepcopy(self.scoped_data[key].value)
else:
actual_value = self.scoped_data[key].valueAgain, this approach maintains current behavior by default but gives users the flexibility to avoid the deepcopy overhead.
These proposed changes offer a significant reduction in execution time, especially for workflows with large data objects or high-frequency state transitions.
Benefits:
- Backwards Compatibility: Defaults to the current behavior (deepcopy enabled).
- Performance Improvement: Reduces delays in input/output processing and global variable handling.
- User Flexibility: Provides configurable flags for advanced users who can guarantee data immutability.
I would like to know if there is a feasible way to introduce this flag in the mentioned cases. Additionally, I propose applying the fix for point 1 directly, as it provides immediate performance benefits. Please let me know if this approach aligns with RAFCON's design principles, and I would be happy to assist in implementing or testing these changes.