diff --git a/src/generator/CMakeLists.txt b/src/generator/CMakeLists.txt index d55c92cf..0fd54da2 100644 --- a/src/generator/CMakeLists.txt +++ b/src/generator/CMakeLists.txt @@ -11,8 +11,9 @@ file(GLOB_RECURSE GENERATOR_PUBLIC_HEADER_FILES target_sources(dlplangenerator PRIVATE ${GENERATOR_SRC_FILES} ${GENERATOR_PRIVATE_HEADER_FILES} ${GENERATOR_PUBLIC_HEADER_FILES} - ../utils/logging.cpp - ../utils/countdown_timer.cpp + "../utils/logging.h" "../utils/logging.cpp" + "../utils/countdown_timer.h" "../utils/countdown_timer.cpp" + "../utils/memory.h" "../utils/memory.cpp" ) target_link_libraries(dlplangenerator PUBLIC diff --git a/src/generator/generator.cpp b/src/generator/generator.cpp index 702075a9..a197b6b1 100644 --- a/src/generator/generator.cpp +++ b/src/generator/generator.cpp @@ -1,6 +1,7 @@ #include "../../include/dlplan/generator.h" #include "feature_generator.h" +#include "../utils/memory.h" namespace dlplan::generator { @@ -37,7 +38,14 @@ GeneratedFeatures FeatureGenerator::generate( int distance_numerical_complexity_limit, int time_limit, int feature_limit) { - return m_pImpl->generate(factory, states, concept_complexity_limit, role_complexity_limit, boolean_complexity_limit, count_numerical_complexity_limit, distance_numerical_complexity_limit, time_limit, feature_limit); + + utils::reserve_extra_memory_padding(1); + + auto features = m_pImpl->generate(factory, states, concept_complexity_limit, role_complexity_limit, boolean_complexity_limit, count_numerical_complexity_limit, distance_numerical_complexity_limit, time_limit, feature_limit); + + utils::release_extra_memory_padding(); + + return features; } void FeatureGenerator::set_generate_empty_boolean(bool enable) { diff --git a/src/state_space/CMakeLists.txt b/src/state_space/CMakeLists.txt index 4a4851c4..ba259265 100644 --- a/src/state_space/CMakeLists.txt +++ b/src/state_space/CMakeLists.txt @@ -11,6 +11,7 @@ file(GLOB_RECURSE STATE_SPACE_PUBLIC_HEADER_FILES target_sources(dlplanstatespace PRIVATE ${STATE_SPACE_SRC_FILES} ${STATE_SPACE_PRIVATE_HEADER_FILES} ${STATE_SPACE_PUBLIC_HEADER_FILES} + "../utils/memory.h" "../utils/memory.cpp" ) target_link_libraries(dlplanstatespace diff --git a/src/state_space/state_space.cpp b/src/state_space/state_space.cpp index 495bb638..14ea0fc7 100644 --- a/src/state_space/state_space.cpp +++ b/src/state_space/state_space.cpp @@ -356,8 +356,15 @@ GeneratorResult generate_state_space( core::InstanceIndex index, int max_time, int max_num_states) { + + utils::reserve_extra_memory_padding(1); + generator::generate_state_space_files(domain_file, instance_file, max_time, max_num_states); - return reader::read(vocabulary_info, index); + auto result = reader::read(vocabulary_info, index); + + utils::release_extra_memory_padding(); + + return result; } } diff --git a/src/utils/memory.cpp b/src/utils/memory.cpp new file mode 100644 index 00000000..2826362f --- /dev/null +++ b/src/utils/memory.cpp @@ -0,0 +1,34 @@ +#include "memory.h" + +#include +#include + +namespace dlplan::utils { +static char *extra_memory_padding = nullptr; + +// Save standard out-of-memory handler. +static void (*standard_out_of_memory_handler)() = nullptr; + +static void continuing_out_of_memory_handler() { + release_extra_memory_padding(); + std::cout << "Failed to allocate memory. Released extra memory padding." << std::endl; +} + +void reserve_extra_memory_padding(int memory_in_mb) { + assert(!extra_memory_padding); + extra_memory_padding = new char[memory_in_mb * 1024 * 1024]; + standard_out_of_memory_handler = std::set_new_handler(continuing_out_of_memory_handler); +} + +void release_extra_memory_padding() { + assert(extra_memory_padding); + delete[] extra_memory_padding; + extra_memory_padding = nullptr; + assert(standard_out_of_memory_handler); + std::set_new_handler(standard_out_of_memory_handler); +} + +bool extra_memory_padding_is_reserved() { + return extra_memory_padding; +} +} \ No newline at end of file diff --git a/src/utils/memory.h b/src/utils/memory.h index 06ff2e48..beff4b5c 100644 --- a/src/utils/memory.h +++ b/src/utils/memory.h @@ -1,17 +1,26 @@ #ifndef DLPLAN_SRC_UTILS_MEMORY_H #define DLPLAN_SRC_UTILS_MEMORY_H +#include +#include namespace dlplan::utils { -/** - * Uses swap-trick to free memory of container. - */ -template -void free_memory(CONTAINER_TYPE& container) { - CONTAINER_TYPE().swap(container); -} +/* + Taken from Fast-Downward (https://www.fast-downward.org/) + + Reserve some memory that we can release and be able to continue + afterwards, once we hit the memory limit. Due to memory fragmentation + the planner often doesn't have enough memory to continue if we don't + reserve enough memory. For CEGAR heuristics reserving 75 MB worked + best. + The interface assumes a single user. It is not possible for two parts + of the planner to reserve extra memory padding at the same time. +*/ +extern void reserve_extra_memory_padding(int memory_in_mb); +extern void release_extra_memory_padding(); +extern bool extra_memory_padding_is_reserved(); } #endif