diff --git a/CMakeLists.txt b/CMakeLists.txt index e552fbb..65e3368 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.1.40) +project(blt-gp VERSION 0.1.41) include(CTest) diff --git a/examples/symbolic_regression.cpp b/examples/symbolic_regression.cpp index 44ce977..ce3206a 100644 --- a/examples/symbolic_regression.cpp +++ b/examples/symbolic_regression.cpp @@ -148,9 +148,9 @@ int main() auto mutation_allocations_v = blt::gp::mutation_allocations.get_calls(); auto reproduction_calls_v = blt::gp::reproduction_calls.get_calls(); auto reproduction_allocations_v = blt::gp::reproduction_allocations.get_calls(); - BLT_TRACE("Total Crossover Calls: %ld Bytes %s", crossover_calls_v, blt::byte_convert_t(blt::gp::crossover_calls.get_value()).convert_to_nearest_type().to_pretty_string().c_str()); - BLT_TRACE("Total Mutation Calls: %ld Bytes %s", mutation_calls_v, blt::byte_convert_t(blt::gp::mutation_calls.get_value()).convert_to_nearest_type().to_pretty_string().c_str()); - BLT_TRACE("Total Reproduction Calls: %ld Bytes %s", reproduction_calls_v, blt::byte_convert_t(blt::gp::reproduction_calls.get_value()).convert_to_nearest_type().to_pretty_string().c_str()); + BLT_TRACE("Total Crossover Calls: %ld", crossover_calls_v); + BLT_TRACE("Total Mutation Calls: %ld", mutation_calls_v); + BLT_TRACE("Total Reproduction Calls: %ld", reproduction_calls_v); BLT_TRACE("Total Crossover Allocations: %ld Bytes %s", crossover_allocations_v, blt::byte_convert_t(blt::gp::crossover_allocations.get_value()).convert_to_nearest_type().to_pretty_string().c_str()); BLT_TRACE("Total Mutation Allocations: %ld Bytes %s", mutation_allocations_v, blt::byte_convert_t(blt::gp::mutation_allocations.get_value()).convert_to_nearest_type().to_pretty_string().c_str()); BLT_TRACE("Total Reproduction Allocations: %ld Bytes %s", reproduction_allocations_v, blt::byte_convert_t(blt::gp::reproduction_allocations.get_value()).convert_to_nearest_type().to_pretty_string().c_str()); diff --git a/include/blt/gp/fwdecl.h b/include/blt/gp/fwdecl.h index 5e751e2..7655dd2 100644 --- a/include/blt/gp/fwdecl.h +++ b/include/blt/gp/fwdecl.h @@ -76,7 +76,7 @@ namespace blt::gp template using tracked_vector = std::vector; #endif - + // using operation_vector_t = tracked_vector; // using individual_vector_t = tracked_vector>; // using tree_vector_t = tracked_vector; diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index 8c3c1e3..ff8fb8e 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -367,8 +367,7 @@ namespace blt::gp (*thread_execution_service)(0); #ifdef BLT_TRACK_ALLOCATIONS blt::gp::tracker.stop_measurement(gen_alloc); - BLT_TRACE("Generation Allocated %ld times with a total of %s", gen_alloc.getAllocationDifference(), - blt::byte_convert_t(gen_alloc.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); + gen_alloc.pretty_print("Generation"); #endif } @@ -386,8 +385,7 @@ namespace blt::gp evaluate_fitness_internal(); #ifdef BLT_TRACK_ALLOCATIONS blt::gp::tracker.stop_measurement(fitness_alloc); - BLT_TRACE("Fitness Allocated %ld times with a total of %s", fitness_alloc.getAllocationDifference(), - blt::byte_convert_t(fitness_alloc.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); + fitness_alloc.pretty_print("Fitness"); #endif } diff --git a/include/blt/gp/selection.h b/include/blt/gp/selection.h index 958a676..029e29b 100644 --- a/include/blt/gp/selection.h +++ b/include/blt/gp/selection.h @@ -89,7 +89,7 @@ namespace blt::gp if (random.choice(config.crossover_chance)) { #ifdef BLT_TRACK_ALLOCATIONS - auto state = tracker.start_measurement(); + auto state = tracker.start_measurement_thread_local(); #endif // crossover const tree_t* p1; @@ -100,10 +100,12 @@ namespace blt::gp p2 = &crossover_selection.select(program, current_pop); } while (!config.crossover.get().apply(program, *p1, *p2, c1, *c2)); #ifdef BLT_TRACK_ALLOCATIONS - tracker.stop_measurement(state); - crossover_calls.call(state.getAllocatedByteDifference()); - if (state.getAllocationDifference() != 0) + tracker.stop_measurement_thread_local(state); + crossover_calls.call(); + if (state.getAllocatedByteDifference() != 0) + { crossover_allocations.call(state.getAllocatedByteDifference()); + } #endif return 2; } @@ -112,7 +114,7 @@ namespace blt::gp if (random.choice(config.mutation_chance)) { #ifdef BLT_TRACK_ALLOCATIONS - auto state = tracker.start_measurement(); + auto state = tracker.start_measurement_thread_local(); #endif // mutation const tree_t* p; @@ -121,8 +123,8 @@ namespace blt::gp p = &mutation_selection.select(program, current_pop); } while (!config.mutator.get().apply(program, *p, c1)); #ifdef BLT_TRACK_ALLOCATIONS - tracker.stop_measurement(state); - mutation_calls.call(state.getAllocatedByteDifference()); + tracker.stop_measurement_thread_local(state); + mutation_calls.call(); if (state.getAllocationDifference() != 0) { mutation_allocations.call(state.getAllocatedByteDifference()); @@ -135,13 +137,13 @@ namespace blt::gp if (config.reproduction_chance > 0 && random.choice(config.reproduction_chance)) { #ifdef BLT_TRACK_ALLOCATIONS - auto state = tracker.start_measurement(); + auto state = tracker.start_measurement_thread_local(); #endif // reproduction c1 = reproduction_selection.select(program, current_pop); #ifdef BLT_TRACK_ALLOCATIONS - tracker.stop_measurement(state); - reproduction_calls.call(state.getAllocatedByteDifference()); + tracker.stop_measurement_thread_local(state); + reproduction_calls.call(); if (state.getAllocationDifference() != 0) { reproduction_allocations.call(state.getAllocatedByteDifference()); diff --git a/include/blt/gp/stats.h b/include/blt/gp/stats.h index 9fda502..4a88012 100644 --- a/include/blt/gp/stats.h +++ b/include/blt/gp/stats.h @@ -20,15 +20,60 @@ #define BLT_GP_STATS_H #include -#include +#include +#include +#include #include +#include +#include +#include namespace blt::gp { - class allocation_tracker_t { public: + class tl_t + { + friend allocation_tracker_t; + public: + [[nodiscard]] blt::u64 getAllocations() const + { + return get_map(allocations); + } + + [[nodiscard]] blt::u64 getDeallocations() const + { + return get_map(deallocations); + } + + [[nodiscard]] blt::u64 getAllocatedBytes() const + { + return get_map(allocated_bytes); + } + + [[nodiscard]] blt::u64 getDeallocatedBytes() const + { + return get_map(deallocated_bytes); + } + + [[nodiscard]] blt::u64 getAllocationDifference() const + { + return std::abs(static_cast(getAllocations()) - static_cast(getDeallocations())); + } + + [[nodiscard]] blt::u64 getCurrentlyAllocatedBytes() const + { + return getAllocatedBytes() - getDeallocatedBytes(); + } + + private: + blt::hashmap_t> allocations; + blt::hashmap_t> deallocations; + blt::hashmap_t> allocated_bytes; + blt::hashmap_t> deallocated_bytes; + }; + struct allocation_data_t { blt::u64 start_allocations = 0; @@ -60,18 +105,33 @@ namespace blt::gp { return end_deallocated_bytes - start_deallocated_bytes; } + + void pretty_print(const std::string& name) const; }; + void reserve() + { + std::scoped_lock lock(mutex); + tl.allocations[std::this_thread::get_id()] = std::make_unique(); + tl.deallocations[std::this_thread::get_id()] = std::make_unique(); + tl.allocated_bytes[std::this_thread::get_id()] = std::make_unique(); + tl.deallocated_bytes[std::this_thread::get_id()] = std::make_unique(); + } + void allocate(blt::size_t bytes) { allocations++; allocated_bytes += bytes; + add_map(tl.allocations, 1); + add_map(tl.allocated_bytes, bytes); } void deallocate(blt::size_t bytes) { deallocations++; deallocated_bytes += bytes; + add_map(tl.deallocations, 1); + add_map(tl.deallocated_bytes, bytes); } [[nodiscard]] blt::u64 getAllocations() const @@ -104,29 +164,73 @@ namespace blt::gp return getAllocatedBytes() - getDeallocatedBytes(); } + allocation_tracker_t::tl_t& get_thread_local() + { + return tl; + } + [[nodiscard]] allocation_data_t start_measurement() const { allocation_data_t data{}; - data.start_allocations = allocations; - data.start_deallocations = deallocations; - data.start_allocated_bytes = allocated_bytes; - data.start_deallocated_bytes = deallocated_bytes; + data.start_allocations = getAllocations(); + data.start_deallocations = getDeallocations(); + data.start_allocated_bytes = getAllocatedBytes(); + data.start_deallocated_bytes = getDeallocatedBytes(); + return data; + } + + [[nodiscard]] allocation_data_t start_measurement_thread_local() const + { + allocation_data_t data{}; + data.start_allocations = tl.getAllocations(); + data.start_deallocations = tl.getDeallocations(); + data.start_allocated_bytes = tl.getAllocatedBytes(); + data.start_deallocated_bytes = tl.getDeallocatedBytes(); return data; } void stop_measurement(allocation_data_t& data) const { - data.end_allocations = allocations; - data.end_deallocations = deallocations; - data.end_allocated_bytes = allocated_bytes; - data.end_deallocated_bytes = deallocated_bytes; + data.end_allocations = getAllocations(); + data.end_deallocations = getDeallocations(); + data.end_allocated_bytes = getAllocatedBytes(); + data.end_deallocated_bytes = getDeallocatedBytes(); + } + + void stop_measurement_thread_local(allocation_data_t& data) const + { + data.end_allocations = tl.getAllocations(); + data.end_deallocations = tl.getDeallocations(); + data.end_allocated_bytes = tl.getAllocatedBytes(); + data.end_deallocated_bytes = tl.getDeallocatedBytes(); } private: + static void add_map(blt::hashmap_t>& map, blt::u64 value) + { + auto l = map.find(std::this_thread::get_id()); + if (l == map.end()) + BLT_ABORT("Thread doesn't exist inside this map!"); + auto& v = *l->second; + v += value; + } + + static blt::u64 get_map(const blt::hashmap_t>& map) + { + auto l = map.find(std::this_thread::get_id()); + if (l == map.end()) + BLT_ABORT("Thread doesn't exist inside this map!"); + return *l->second; + } + + tl_t tl; + std::atomic_uint64_t allocations = 0; std::atomic_uint64_t deallocations = 0; std::atomic_uint64_t allocated_bytes = 0; std::atomic_uint64_t deallocated_bytes = 0; + + std::mutex mutex; }; class call_tracker_t @@ -190,7 +294,6 @@ namespace blt::gp std::atomic_uint64_t primary_calls = 0; std::atomic_uint64_t secondary_value = 0; }; - } #endif //BLT_GP_STATS_H diff --git a/src/program.cpp b/src/program.cpp index 1f310d3..ce96d53 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -58,12 +58,18 @@ namespace blt::gp void gp_program::create_threads() { +#ifdef BLT_TRACK_ALLOCATIONS + tracker.reserve(); +#endif if (config.threads == 0) config.set_thread_count(std::thread::hardware_concurrency()); // main thread is thread0 for (blt::size_t i = 1; i < config.threads; i++) { thread_helper.threads.emplace_back(new std::thread([i, this]() { +#ifdef BLT_TRACK_ALLOCATIONS + tracker.reserve(); +#endif std::function* execution_function = nullptr; while (!should_thread_terminate()) { diff --git a/src/stats.cpp b/src/stats.cpp index d5be6a7..2ee9322 100644 --- a/src/stats.cpp +++ b/src/stats.cpp @@ -17,8 +17,14 @@ */ #include #include +#include "blt/std/format.h" namespace blt::gp { - + + void allocation_tracker_t::allocation_data_t::pretty_print(const std::string& name) const + { + BLT_TRACE("%s Allocations: %ld times with a total of %s", name.c_str(), getAllocationDifference(), + blt::byte_convert_t(getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); + } } \ No newline at end of file diff --git a/src/transformers.cpp b/src/transformers.cpp index 5dc65ea..ab2b7f9 100644 --- a/src/transformers.cpp +++ b/src/transformers.cpp @@ -105,6 +105,9 @@ namespace blt::gp auto copy_ptr_c1 = get_thread_pointer_for_size(c1_total); auto copy_ptr_c2 = get_thread_pointer_for_size(c2_total); + c1_stack.reserve(c1_stack.bytes_in_head() - c1_stack_for_bytes + c2_stack_for_bytes); + c2_stack.reserve(c2_stack.bytes_in_head() - c2_stack_for_bytes + c1_stack_for_bytes); + c1_stack.copy_to(copy_ptr_c1, c1_total); c1_stack.pop_bytes(c1_total);