diff --git a/test/yulPhaser/AlgorithmRunner.cpp b/test/yulPhaser/AlgorithmRunner.cpp index 831cb360a..fa87579dd 100644 --- a/test/yulPhaser/AlgorithmRunner.cpp +++ b/test/yulPhaser/AlgorithmRunner.cpp @@ -19,6 +19,7 @@ #include #include +#include #include @@ -277,6 +278,111 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_whole_initial_population_even_if_only_t BOOST_TEST(m_output.peek() == EOF); } +BOOST_FIXTURE_TEST_CASE(run_should_print_cache_stats_if_requested, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 4; + m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + m_options.showCacheStats = true; + RandomisingAlgorithm algorithm; + + vector sourceStreams = { + CharStream("{mstore(10, 20)}", ""), + CharStream("{mstore(10, 20)\nsstore(10, 20)}", ""), + }; + vector programs = { + get(Program::load(sourceStreams[0])), + get(Program::load(sourceStreams[1])), + }; + vector> caches = { + make_shared(programs[0]), + make_shared(programs[1]), + }; + shared_ptr fitnessMetric = make_shared(vector>{ + make_shared(nullopt, caches[0]), + make_shared(nullopt, caches[1]), + }); + Population population = Population::makeRandom(fitnessMetric, 2, 0, 5); + + AlgorithmRunner runner(population, caches, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(caches[0]->currentRound() == m_options.maxRounds.value()); + BOOST_TEST(caches[1]->currentRound() == m_options.maxRounds.value()); + + CacheStats stats = caches[0]->gatherStats() + caches[1]->gatherStats(); + + for (size_t i = 0; i < m_options.maxRounds.value() - 1; ++i) + { + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + if (i > 0) + BOOST_TEST(nextLineMatches(m_output, regex(R"(Round\d+:\d+entries)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Round\d+:\d+entries)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalhits:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalmisses:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Sizeofcachedcode:\d+)"))); + } + + BOOST_REQUIRE(stats.roundEntryCounts.size() == 2); + BOOST_REQUIRE(stats.roundEntryCounts.count(m_options.maxRounds.value() - 1) == 1); + BOOST_REQUIRE(stats.roundEntryCounts.count(m_options.maxRounds.value()) == 1); + + size_t round = m_options.maxRounds.value(); + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + BOOST_TEST(nextLineMatches(m_output, regex("Round" + toString(round - 1) + ":" + toString(stats.roundEntryCounts[round - 1]) + "entries"))); + BOOST_TEST(nextLineMatches(m_output, regex("Round" + toString(round) + ":" + toString(stats.roundEntryCounts[round]) + "entries"))); + BOOST_TEST(nextLineMatches(m_output, regex("Totalhits:" + toString(stats.hits)))); + BOOST_TEST(nextLineMatches(m_output, regex("Totalmisses:" + toString(stats.misses)))); + BOOST_TEST(nextLineMatches(m_output, regex("Sizeofcachedcode:" + toString(stats.totalCodeSize)))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_message_if_cache_stats_requested_but_cache_disabled, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + m_options.showCacheStats = true; + RandomisingAlgorithm algorithm; + + AlgorithmRunner runner(m_population, {nullptr}, m_options, m_output); + runner.run(algorithm); + + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + BOOST_TEST(nextLineMatches(m_output, regex(stripWhitespace("Program cache disabled")))); + BOOST_TEST(m_output.peek() == EOF); +} + +BOOST_FIXTURE_TEST_CASE(run_should_print_partial_stats_and_message_if_some_caches_disabled, AlgorithmRunnerFixture) +{ + m_options.maxRounds = 1; + m_options.showInitialPopulation = false; + m_options.showRoundInfo = false; + m_options.showOnlyTopChromosome = true; + m_options.showCacheStats = true; + RandomisingAlgorithm algorithm; + + CharStream sourceStream = CharStream("{}", ""); + shared_ptr cache = make_shared(get(Program::load(sourceStream))); + + AlgorithmRunner runner(m_population, {cache, nullptr}, m_options, m_output); + BOOST_REQUIRE(cache->gatherStats().roundEntryCounts.size() == 0); + + runner.run(algorithm); + BOOST_TEST(nextLineMatches(m_output, regex(".*"))); + BOOST_TEST(nextLineMatches(m_output, regex("-+CACHESTATS-+"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalhits:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Totalmisses:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(R"(Sizeofcachedcode:\d+)"))); + BOOST_TEST(nextLineMatches(m_output, regex(stripWhitespace("Program cache disabled for 1 out of 2 programs")))); + BOOST_TEST(m_output.peek() == EOF); +} + BOOST_FIXTURE_TEST_CASE(run_should_save_initial_population_to_file_if_autosave_file_specified, AlgorithmRunnerAutosaveFixture) { m_options.maxRounds = 0; diff --git a/tools/yulPhaser/AlgorithmRunner.cpp b/tools/yulPhaser/AlgorithmRunner.cpp index 9ddce41bc..5e03e2820 100644 --- a/tools/yulPhaser/AlgorithmRunner.cpp +++ b/tools/yulPhaser/AlgorithmRunner.cpp @@ -44,6 +44,7 @@ void AlgorithmRunner::run(GeneticAlgorithm& _algorithm) randomiseDuplicates(); printRoundSummary(round, roundTimeStart, totalTimeStart); + printCacheStats(); populationAutosave(); } } @@ -90,6 +91,39 @@ void AlgorithmRunner::printInitialPopulation() const m_outputStream << m_population; } +void AlgorithmRunner::printCacheStats() const +{ + if (!m_options.showCacheStats) + return; + + CacheStats totalStats{}; + size_t disabledCacheCount = 0; + for (size_t i = 0; i < m_programCaches.size(); ++i) + if (m_programCaches[i] != nullptr) + totalStats += m_programCaches[i]->gatherStats(); + else + ++disabledCacheCount; + + m_outputStream << "---------- CACHE STATS ----------" << endl; + + if (disabledCacheCount < m_programCaches.size()) + { + for (auto& [round, count]: totalStats.roundEntryCounts) + m_outputStream << "Round " << round << ": " << count << " entries" << endl; + m_outputStream << "Total hits: " << totalStats.hits << endl; + m_outputStream << "Total misses: " << totalStats.misses << endl; + m_outputStream << "Size of cached code: " << totalStats.totalCodeSize << endl; + } + + if (disabledCacheCount == m_programCaches.size()) + m_outputStream << "Program cache disabled" << endl; + else if (disabledCacheCount > 0) + { + m_outputStream << "Program cache disabled for " << disabledCacheCount << " out of "; + m_outputStream << m_programCaches.size() << " programs" << endl; + } +} + void AlgorithmRunner::populationAutosave() const { if (!m_options.populationAutosaveFile.has_value()) diff --git a/tools/yulPhaser/AlgorithmRunner.h b/tools/yulPhaser/AlgorithmRunner.h index 7c6946391..d1cffb30a 100644 --- a/tools/yulPhaser/AlgorithmRunner.h +++ b/tools/yulPhaser/AlgorithmRunner.h @@ -51,6 +51,7 @@ public: bool showInitialPopulation = false; bool showOnlyTopChromosome = false; bool showRoundInfo = true; + bool showCacheStats = false; }; AlgorithmRunner( @@ -76,6 +77,7 @@ private: std::chrono::steady_clock::time_point _totalTimeStart ) const; void printInitialPopulation() const; + void printCacheStats() const; void populationAutosave() const; void randomiseDuplicates(); void cacheClear(); diff --git a/tools/yulPhaser/Phaser.cpp b/tools/yulPhaser/Phaser.cpp index 0bfd6a433..6e6ec7a3f 100644 --- a/tools/yulPhaser/Phaser.cpp +++ b/tools/yulPhaser/Phaser.cpp @@ -576,6 +576,11 @@ Phaser::CommandLineDescription Phaser::buildCommandLineDescription() po::bool_switch(), "Hide information about the current round (round number and elapsed time)." ) + ( + "show-cache-stats", + po::bool_switch(), + "Print information about cache size and effectiveness after each round." + ) ; keywordDescription.add(outputDescription); @@ -631,6 +636,7 @@ AlgorithmRunner::Options Phaser::buildAlgorithmRunnerOptions(po::variables_map c _arguments["show-initial-population"].as(), _arguments["show-only-top-chromosome"].as(), !_arguments["hide-round"].as(), + _arguments["show-cache-stats"].as(), }; }