From ed0e46bfa0f9b1b246aaaf4a0dd5a686bc86141e Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 6 Aug 2024 01:10:33 +0200 Subject: [PATCH] Generating individuals in parallel --- .gitignore | 1 + build.sh | 3 +- config/evolutionary_preset.ini | 5 +- mt-kahypar/partition/context.h | 1 + mt-kahypar/partition/context_enum_classes.cpp | 4 +- mt-kahypar/partition/context_enum_classes.h | 5 +- mt-kahypar/partition/evo_partitioner.cpp | 115 +++++++++++++++--- .../partition/evolutionary/population.h | 6 + mt-kahypar/partition/multilevel.cpp | 4 +- 9 files changed, 119 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 44067e4e5..1618d9f79 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ clang-debug/* *.cfg~ build/* build2/* +build_debug/* build_numa/* build_nlevel/* build_interleaved/* diff --git a/build.sh b/build.sh index d4dc3a59f..b77c03d24 100755 --- a/build.sh +++ b/build.sh @@ -20,7 +20,8 @@ if [ ! -f build/Makefile ]; then mkdir -p build fi -#cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug $CMAKE_COMMANDS && cd ${ROOT} +#cd build_debug && cmake .. -DCMAKE_BUILD_TYPE=Debug $CMAKE_COMMANDS && cd ${ROOT} +#cmake --build build_debug --parallel "$(get_num_cores)" --target MtKaHyPar cd build && cmake .. -DCMAKE_BUILD_TYPE=Release $CMAKE_COMMANDS && cd ${ROOT} cmake --build build --parallel "$(get_num_cores)" --target MtKaHyPar diff --git a/config/evolutionary_preset.ini b/config/evolutionary_preset.ini index 369605be5..fd588720b 100644 --- a/config/evolutionary_preset.ini +++ b/config/evolutionary_preset.ini @@ -6,7 +6,7 @@ smallest-maxnet-threshold=50000 maxnet-ignore=1000 num-vcycles=0 partition-evolutionary=true -time-limit= 10 +time-limit= 60 #300 # main -> shared_memory s-use-localized-random-shuffle=false @@ -96,7 +96,8 @@ max-steiner-tree-size=4 mapping-largest-he-fraction=0.0 mapping-min-pin-coverage=0.05 #main -> evolutionary -evolutionary.population_size=2; +evolutionary.population_size=1; +#100 evolutionary.dynamic_population_size=false; evolutionary.dynamic_population_amount_of_time=0.15; evolutionary.diversify_interval=1; diff --git a/mt-kahypar/partition/context.h b/mt-kahypar/partition/context.h index 06516d7e9..fe40587af 100644 --- a/mt-kahypar/partition/context.h +++ b/mt-kahypar/partition/context.h @@ -279,6 +279,7 @@ struct EvolutionaryParameters { bool dynamic_population_size; double dynamic_population_amount_of_time; mutable int iteration; + mutable std::chrono::milliseconds time_elapsed; std::string history_file; }; diff --git a/mt-kahypar/partition/context_enum_classes.cpp b/mt-kahypar/partition/context_enum_classes.cpp index 517fb5878..56996ceb4 100644 --- a/mt-kahypar/partition/context_enum_classes.cpp +++ b/mt-kahypar/partition/context_enum_classes.cpp @@ -92,8 +92,10 @@ namespace mt_kahypar { std::ostream& operator<< (std::ostream& os, const ContextType& type) { if (type == ContextType::main) { return os << "main"; - } else { + } else if (type == ContextType::initial_partitioning) { return os << "ip"; + } else { + return os << "evo"; } return os << static_cast(type); } diff --git a/mt-kahypar/partition/context_enum_classes.h b/mt-kahypar/partition/context_enum_classes.h index 133d57708..d91891bd6 100644 --- a/mt-kahypar/partition/context_enum_classes.h +++ b/mt-kahypar/partition/context_enum_classes.h @@ -63,9 +63,10 @@ enum class PresetType : int8_t { UNDEFINED }; -enum class ContextType : bool { +enum class ContextType : uint8_t { main, - initial_partitioning + initial_partitioning, + evolutionary }; enum class Mode : uint8_t { diff --git a/mt-kahypar/partition/evo_partitioner.cpp b/mt-kahypar/partition/evo_partitioner.cpp index 1280643cf..9f1b4b171 100644 --- a/mt-kahypar/partition/evo_partitioner.cpp +++ b/mt-kahypar/partition/evo_partitioner.cpp @@ -1,5 +1,6 @@ #include "evo_partitioner.h" #include "partitioner.cpp" +#include namespace mt_kahypar { @@ -95,6 +96,10 @@ namespace mt_kahypar { //context.evolutionary.dynamic_population_size = true; //context.evolutionary.population_size = 50; utils::Timer& timer = utils::Utilities::instance().getTimer(context.utility_id); + auto start = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); + auto now = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); + auto time_elapsed = now - start; + auto duration = std::chrono::seconds(timelimit); // INITIAL POPULATION if (context.evolutionary.dynamic_population_size) { HighResClockTimepoint start = std::chrono::high_resolution_clock::now(); @@ -112,13 +117,17 @@ namespace mt_kahypar { LOG << context.evolutionary.population_size; LOG << population; } - while (population.size() < context.evolutionary.population_size && - timer.get("evolutionary") <= timelimit) { + while (population.size() < context.evolutionary.population_size && + time_elapsed <= duration) { + //timer.get("evolutionary") <= timelimit) { ++context.evolutionary.iteration; timer.start_timer("evolutionary", "Evolutionary"); generateIndividual(hg, context, target_graph, population); timer.stop_timer("evolutionary"); + now = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); + time_elapsed = now - start; } + context.evolutionary.time_elapsed = time_elapsed; context.partition.verbose_output = true; } @@ -249,6 +258,7 @@ namespace mt_kahypar { auto time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); ret = "" + std::to_string(time.count()) + ", Combine, " + std::to_string(individual.fitness()) + "\n"; } + std::lock_guard lock = population.getLock(); population.insert(std::move(individual), context); return ret; } @@ -301,10 +311,29 @@ namespace mt_kahypar { ret = "" + std::to_string(time.count()) + ", MutateNew, " + std::to_string(individual.fitness()) + "\n"; } } + std::lock_guard lock = population.getLock(); population.insert(std::move(individual), context); return ret; } + inline void disableTimerAndStatsEvo(const Context& context) { + if ( context.type == ContextType::main && context.partition.mode == Mode::direct ) { + utils::Utilities& utils = utils::Utilities::instance(); + parallel::MemoryPool::instance().deactivate_unused_memory_allocations(); + utils.getTimer(context.utility_id).disable(); + utils.getStats(context.utility_id).disable(); + } + } + + inline void enableTimerAndStatsEvo(const Context& context) { + if ( context.type == ContextType::main && context.partition.mode == Mode::direct ) { + utils::Utilities& utils = utils::Utilities::instance(); + parallel::MemoryPool::instance().activate_unused_memory_allocations(); + utils.getTimer(context.utility_id).enable(); + utils.getStats(context.utility_id).enable(); + } + } + template void EvoPartitioner::performEvolution(EvoPartitioner::Hypergraph& hg, Context& context, TargetGraph* target_graph, Population& population) { context.partition.verbose_output = false; @@ -312,33 +341,85 @@ namespace mt_kahypar { utils::Timer& timer = utils::Utilities::instance().getTimer(context.utility_id); int mutations = 0; int combinations = 0; - auto time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); - std::string history = "" + std::to_string(time.count()) + ", Initial, " + std::to_string(population.bestFitness()) + "\n"; - while (timer.get("evolutionary") <= timelimit) { + auto time_start = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); + std::string history = "" + std::to_string(time_start.count()) + ", Initial, " + std::to_string(population.bestFitness()) + "\n"; + std::mutex _history_mutex; + /*while (timer.get("evolutionary") <= timelimit) { ++context.evolutionary.iteration; timer.start_timer("evolutionary", "Evolutionary"); - - tbb::parallel_for(0, 1, [&](const int i) { + tbb::parallel_for(0, 4, [&](const int i) { + Context evo_context(context); + evo_context.type = ContextType::main; + evo_context.utility_id = utils::Utilities::instance().registerNewUtilityObjects(); EvoDecision decision = decideNextMove(context); + EvoPartitioner::Hypergraph hg_copy = hg.copy(); switch (decision) { - case EvoDecision::mutation: - history += performMutation(hg, context, target_graph, population); - mutations++; - break; - case EvoDecision::combine: - history += performCombine(hg, context, target_graph, population); - combinations++; - break; + case EvoDecision::mutation: + { + std::lock_guard lock(_history_mutex); + history += performMutation(hg_copy, evo_context, target_graph, population); + mutations++; + break; + } + case EvoDecision::combine: + { + std::lock_guard lock(_history_mutex); + history += performCombine(hg_copy, evo_context, target_graph, population); + combinations++; + break; + } default: LOG << "Error in evo_partitioner.cpp: Non-covered case in decision making"; std::exit(EXIT_FAILURE); } }); timer.stop_timer("evolutionary"); - } - hg.reset(); + }*/ + + auto duration = std::chrono::seconds(timelimit) - context.evolutionary.time_elapsed; + std::atomic stop_flag(false); + timer.start_timer("evolutionary", "Evolutionary"); + tbb::parallel_for(0, int(context.shared_memory.num_threads), [&](int) { + while(!stop_flag) { + auto now = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); + if (now - time_start >= duration) { + stop_flag = true; + break; + } + Context evo_context(context); + evo_context.type = ContextType::main; + evo_context.utility_id = utils::Utilities::instance().registerNewUtilityObjects(); + EvoDecision decision = decideNextMove(context); + EvoPartitioner::Hypergraph hg_copy = hg.copy(); + switch (decision) { + case EvoDecision::mutation: + { + std::string h = performMutation(hg_copy, evo_context, target_graph, population); + std::lock_guard lock(_history_mutex); + history += h; + mutations++; + ++context.evolutionary.iteration; + break; + } + case EvoDecision::combine: + { + std::lock_guard lock(_history_mutex); + std::string h = performCombine(hg_copy, evo_context, target_graph, population); + combinations++; + history += h; + ++context.evolutionary.iteration; + break; + } + default: + LOG << "Error in evo_partitioner.cpp: Non-covered case in decision making"; + std::exit(EXIT_FAILURE); + } + } + }); + timer.stop_timer("evolutionary"); + context.partition.verbose_output = true; LOG << "Performed " << context.evolutionary.iteration << " Evolutionary Iterations" << "\n"; LOG << " " << (context.evolutionary.iteration - mutations - combinations) diff --git a/mt-kahypar/partition/evolutionary/population.h b/mt-kahypar/partition/evolutionary/population.h index 6280cf4b2..6d1b9363b 100644 --- a/mt-kahypar/partition/evolutionary/population.h +++ b/mt-kahypar/partition/evolutionary/population.h @@ -37,6 +37,7 @@ class Population { public: explicit Population() : + _population_mutex(), _individuals() { } inline size_t insert(Individual&& individual, const Context& context) { @@ -225,6 +226,10 @@ class Population { return output_diff.size(); } + std::lock_guard getLock() { + return std::lock_guard(_population_mutex); + } + private: inline size_t replaceDiverse(Individual&& individual, const bool strong_set) { size_t max_similarity = std::numeric_limits::max(); @@ -248,6 +253,7 @@ class Population { return max_similarity_id; } + std::mutex _population_mutex; std::vector _individuals; }; std::ostream& operator<< (std::ostream& os, const Population& population); diff --git a/mt-kahypar/partition/multilevel.cpp b/mt-kahypar/partition/multilevel.cpp index 3d7544ce8..97e840492 100644 --- a/mt-kahypar/partition/multilevel.cpp +++ b/mt-kahypar/partition/multilevel.cpp @@ -211,7 +211,7 @@ namespace { const TargetGraph* target_graph, const bool is_vcycle, std::unordered_map comm_to_block) { - disableTimerAndStats(context); + //disableTimerAndStats(context); using Hypergraph = typename TypeTraits::Hypergraph; using PartitionedHypergraph = typename TypeTraits::PartitionedHypergraph; PartitionedHypergraph partitioned_hg; @@ -302,7 +302,7 @@ namespace { io::printPartitioningResults(partitioned_hg, context, "Local Search Results:"); - enableTimerAndStats(context); + //enableTimerAndStats(context); return partitioned_hg; } }