diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b40123..e552fbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.25) -project(blt-gp VERSION 0.1.37) +project(blt-gp VERSION 0.1.40) include(CTest) diff --git a/examples/symbolic_regression.cpp b/examples/symbolic_regression.cpp index e9b3d76..b63d37f 100644 --- a/examples/symbolic_regression.cpp +++ b/examples/symbolic_regression.cpp @@ -106,35 +106,15 @@ int main() { BLT_TRACE("------------{Begin Generation %ld}------------", program.get_current_generation()); BLT_TRACE("Creating next generation"); - -#ifdef BLT_TRACK_ALLOCATIONS - auto gen_alloc = blt::gp::tracker.start_measurement(); -#endif - BLT_START_INTERVAL("Symbolic Regression", "Gen"); program.create_next_generation(); BLT_END_INTERVAL("Symbolic Regression", "Gen"); - -#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()); - auto fitness_alloc = blt::gp::tracker.start_measurement(); -#endif - BLT_TRACE("Move to next generation"); BLT_START_INTERVAL("Symbolic Regression", "Fitness"); program.next_generation(); BLT_TRACE("Evaluate Fitness"); program.evaluate_fitness(); BLT_END_INTERVAL("Symbolic Regression", "Fitness"); - -#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()); -#endif - BLT_TRACE("----------------------------------------------"); std::cout << std::endl; } @@ -164,6 +144,24 @@ int main() #ifdef BLT_TRACK_ALLOCATIONS BLT_TRACE("Total Allocations: %ld times with a total of %s", blt::gp::tracker.getAllocations(), blt::byte_convert_t(blt::gp::tracker.getAllocatedBytes()).convert_to_nearest_type().to_pretty_string().c_str()); + auto crossover_calls_v = blt::gp::crossover_calls.get_calls(); + auto crossover_allocations_v = blt::gp::crossover_allocations.get_calls(); + auto mutation_calls_v = blt::gp::mutation_calls.get_calls(); + 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 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()); + BLT_TRACE("Percent Crossover calls allocate? %lf%%", + static_cast(crossover_allocations_v) / static_cast(crossover_calls_v == 0 ? 1 : crossover_calls_v) * 100); + BLT_TRACE("Percent Mutation calls allocate? %lf%%", + static_cast(mutation_allocations_v) / static_cast(mutation_calls_v == 0 ? 1 : mutation_calls_v) * 100); + BLT_TRACE("Percent Reproduction calls allocate? %lf%%", + static_cast(reproduction_allocations_v) / static_cast(reproduction_calls_v == 0 ? 1 : reproduction_calls_v) * 100); #endif return 0; diff --git a/include/blt/gp/fwdecl.h b/include/blt/gp/fwdecl.h index 24319e0..5e751e2 100644 --- a/include/blt/gp/fwdecl.h +++ b/include/blt/gp/fwdecl.h @@ -28,7 +28,15 @@ namespace blt::gp { +#ifdef BLT_TRACK_ALLOCATIONS inline allocation_tracker_t tracker; + inline call_tracker_t crossover_calls; + inline call_tracker_t mutation_calls; + inline call_tracker_t reproduction_calls; + inline call_tracker_t crossover_allocations; + inline call_tracker_t mutation_allocations; + inline call_tracker_t reproduction_allocations; +#endif class gp_program; @@ -60,9 +68,14 @@ namespace blt::gp template class tracked_allocator_t; - + +#ifdef BLT_TRACK_ALLOCATIONS template using tracked_vector = std::vector>; +#else + template + using tracked_vector = std::vector; +#endif // using operation_vector_t = tracked_vector; // using individual_vector_t = tracked_vector>; diff --git a/include/blt/gp/program.h b/include/blt/gp/program.h index d682ee5..8c3c1e3 100644 --- a/include/blt/gp/program.h +++ b/include/blt/gp/program.h @@ -362,10 +362,6 @@ namespace blt::gp #ifdef BLT_TRACK_ALLOCATIONS auto gen_alloc = blt::gp::tracker.start_measurement(); #endif - BLT_ASSERT_MSG(current_pop.get_individuals().size() == config.population_size, - ("cur pop size: " + std::to_string(current_pop.get_individuals().size())).c_str()); - BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size, - ("next pop size: " + std::to_string(next_pop.get_individuals().size())).c_str()); // should already be empty thread_helper.next_gen_left.store(config.population_size, std::memory_order_release); (*thread_execution_service)(0); @@ -378,10 +374,6 @@ namespace blt::gp void next_generation() { - BLT_ASSERT_MSG(current_pop.get_individuals().size() == config.population_size, - ("cur pop size: " + std::to_string(current_pop.get_individuals().size())).c_str()); - BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size, - ("next pop size: " + std::to_string(next_pop.get_individuals().size())).c_str()); std::swap(current_pop, next_pop); current_generation++; } @@ -406,6 +398,10 @@ namespace blt::gp current_pop = config.pop_initializer.get().generate( {*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); next_pop = population_t(current_pop); + BLT_ASSERT_MSG(current_pop.get_individuals().size() == config.population_size, + ("cur pop size: " + std::to_string(current_pop.get_individuals().size())).c_str()); + BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size, + ("next pop size: " + std::to_string(next_pop.get_individuals().size())).c_str()); if (eval_fitness_now) evaluate_fitness_internal(); } @@ -434,6 +430,10 @@ namespace blt::gp current_pop = config.pop_initializer.get().generate( {*this, root_type, config.population_size, config.initial_min_tree_size, config.initial_max_tree_size}); next_pop = population_t(current_pop); + BLT_ASSERT_MSG(current_pop.get_individuals().size() == config.population_size, + ("cur pop size: " + std::to_string(current_pop.get_individuals().size())).c_str()); + BLT_ASSERT_MSG(next_pop.get_individuals().size() == config.population_size, + ("next pop size: " + std::to_string(next_pop.get_individuals().size())).c_str()); if (config.threads == 1) { BLT_INFO("Starting with single thread variant!"); @@ -593,7 +593,7 @@ namespace blt::gp auto index = config.elites + begin; tree_t& c1 = next_pop.get_individuals()[index].tree; tree_t* c2 = nullptr; - if (index + 1 < end) + if (begin + 1 < end) c2 = &next_pop.get_individuals()[index + 1].tree; begin += func(args, crossover_selection, mutation_selection, reproduction_selection, c1, c2); } diff --git a/include/blt/gp/selection.h b/include/blt/gp/selection.h index a3c3856..958a676 100644 --- a/include/blt/gp/selection.h +++ b/include/blt/gp/selection.h @@ -88,7 +88,9 @@ namespace blt::gp // everyone gets a chance once per loop. if (random.choice(config.crossover_chance)) { -// auto state = tracker.start_measurement(); +#ifdef BLT_TRACK_ALLOCATIONS + auto state = tracker.start_measurement(); +#endif // crossover const tree_t* p1; const tree_t* p2; @@ -97,37 +99,54 @@ namespace blt::gp p1 = &crossover_selection.select(program, current_pop); p2 = &crossover_selection.select(program, current_pop); } while (!config.crossover.get().apply(program, *p1, *p2, c1, *c2)); -// tracker.stop_measurement(state); -// BLT_TRACE("Crossover Allocated %ld times with a total of %s", state.getAllocationDifference(), -// blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); +#ifdef BLT_TRACK_ALLOCATIONS + tracker.stop_measurement(state); + crossover_calls.call(state.getAllocatedByteDifference()); + if (state.getAllocationDifference() != 0) + crossover_allocations.call(state.getAllocatedByteDifference()); +#endif return 2; } break; case 1: if (random.choice(config.mutation_chance)) { -// auto state = tracker.start_measurement(); +#ifdef BLT_TRACK_ALLOCATIONS + auto state = tracker.start_measurement(); +#endif // mutation const tree_t* p; do { p = &mutation_selection.select(program, current_pop); } while (!config.mutator.get().apply(program, *p, c1)); -// tracker.stop_measurement(state); -// BLT_TRACE("Mutation Allocated %ld times with a total of %s", state.getAllocationDifference(), -// blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); +#ifdef BLT_TRACK_ALLOCATIONS + tracker.stop_measurement(state); + mutation_calls.call(state.getAllocatedByteDifference()); + if (state.getAllocationDifference() != 0) + { + mutation_allocations.call(state.getAllocatedByteDifference()); + } +#endif return 1; } break; case 2: if (config.reproduction_chance > 0 && random.choice(config.reproduction_chance)) { -// auto state = tracker.start_measurement(); +#ifdef BLT_TRACK_ALLOCATIONS + auto state = tracker.start_measurement(); +#endif // reproduction c1 = reproduction_selection.select(program, current_pop); -// tracker.stop_measurement(state); -// BLT_TRACE("Reproduction Allocated %ld times with a total of %s", state.getAllocationDifference(), -// blt::byte_convert_t(state.getAllocatedByteDifference()).convert_to_nearest_type().to_pretty_string().c_str()); +#ifdef BLT_TRACK_ALLOCATIONS + tracker.stop_measurement(state); + reproduction_calls.call(state.getAllocatedByteDifference()); + if (state.getAllocationDifference() != 0) + { + reproduction_allocations.call(state.getAllocatedByteDifference()); + } +#endif return 1; } break; diff --git a/include/blt/gp/stats.h b/include/blt/gp/stats.h index 64b3f13..9fda502 100644 --- a/include/blt/gp/stats.h +++ b/include/blt/gp/stats.h @@ -129,6 +129,68 @@ namespace blt::gp std::atomic_uint64_t deallocated_bytes = 0; }; + class call_tracker_t + { + public: + struct call_data_t + { + blt::u64 start_calls = 0; + blt::u64 start_value = 0; + blt::u64 end_calls = 0; + blt::u64 end_value = 0; + + [[nodiscard]] inline auto get_call_difference() const + { + return end_calls - start_calls; + } + + [[nodiscard]] inline auto get_value_difference() const + { + return end_value - start_value; + } + }; + + void value(blt::u64 value) + { + secondary_value += value; + } + + void call() + { + primary_calls++; + } + + void call(blt::u64 v) + { + primary_calls++; + value(v); + } + + [[nodiscard]] auto get_calls() const + { + return primary_calls.load(); + } + + [[nodiscard]] auto get_value() const + { + return secondary_value.load(); + } + + call_data_t start_measurement() + { + return {primary_calls.load(), 0}; + } + + void stop_measurement(call_data_t& data) + { + data.end_calls = primary_calls.load(); + } + + private: + std::atomic_uint64_t primary_calls = 0; + std::atomic_uint64_t secondary_value = 0; + }; + } #endif //BLT_GP_STATS_H diff --git a/lib/blt b/lib/blt index 79e080c..ab482f1 160000 --- a/lib/blt +++ b/lib/blt @@ -1 +1 @@ -Subproject commit 79e080cfd34fb47342f67f19b95ffa27efb0f715 +Subproject commit ab482f1a1c5782bd3501428f26c02f0bb4729946