[yul-phaser] Require specifying weights for Program::codeSize()

This commit is contained in:
Kamil Śliwak 2020-02-29 21:55:32 +01:00
parent d199fc537b
commit 40dfac7683
10 changed files with 76 additions and 52 deletions

View File

@ -37,6 +37,7 @@ using namespace boost::unit_test::framework;
using namespace boost::test_tools;
using namespace solidity::langutil;
using namespace solidity::util;
using namespace solidity::yul;
namespace fs = boost::filesystem;
@ -299,8 +300,8 @@ BOOST_FIXTURE_TEST_CASE(run_should_print_cache_stats_if_requested, AlgorithmRunn
make_shared<ProgramCache>(programs[1]),
};
shared_ptr<FitnessMetric> fitnessMetric = make_shared<FitnessMetricAverage>(vector<shared_ptr<FitnessMetric>>{
make_shared<ProgramSize>(nullopt, caches[0]),
make_shared<ProgramSize>(nullopt, caches[1]),
make_shared<ProgramSize>(nullopt, caches[0], CodeWeights{}),
make_shared<ProgramSize>(nullopt, caches[1], CodeWeights{}),
});
Population population = Population::makeRandom(fitnessMetric, 2, 0, 5);

View File

@ -62,12 +62,12 @@ protected:
Program optimisedProgram(Program _program) const
{
[[maybe_unused]] size_t originalSize = _program.codeSize();
[[maybe_unused]] size_t originalSize = _program.codeSize(m_weights);
Program result = move(_program);
result.optimise(m_chromosome.optimisationSteps());
// Make sure that the program and the chromosome we have chosen are suitable for the test
assert(result.codeSize() != originalSize);
assert(result.codeSize(m_weights) != originalSize);
return result;
}
@ -77,15 +77,16 @@ protected:
Program m_program = get<Program>(Program::load(m_sourceStream));
Program m_optimisedProgram = optimisedProgram(m_program);
shared_ptr<ProgramCache> m_programCache = make_shared<ProgramCache>(m_program);
static constexpr CodeWeights m_weights{};
};
class FitnessMetricCombinationFixture: public ProgramBasedMetricFixture
{
protected:
vector<shared_ptr<FitnessMetric>> m_simpleMetrics = {
make_shared<ProgramSize>(m_program, nullptr, 1),
make_shared<ProgramSize>(m_program, nullptr, 2),
make_shared<ProgramSize>(m_program, nullptr, 3),
make_shared<ProgramSize>(m_program, nullptr, m_weights, 1),
make_shared<ProgramSize>(m_program, nullptr, m_weights, 2),
make_shared<ProgramSize>(m_program, nullptr, m_weights, 3),
};
vector<size_t> m_fitness = {
m_simpleMetrics[0]->evaluate(m_chromosome),
@ -100,7 +101,7 @@ BOOST_AUTO_TEST_SUITE(ProgramBasedMetricTest)
BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_return_optimised_program_even_if_cache_not_available, ProgramBasedMetricFixture)
{
string code = toString(DummyProgramBasedMetric(m_program, nullptr).optimisedProgram(m_chromosome));
string code = toString(DummyProgramBasedMetric(m_program, nullptr, m_weights).optimisedProgram(m_chromosome));
BOOST_TEST(code != toString(m_program));
BOOST_TEST(code == toString(m_optimisedProgram));
@ -108,7 +109,7 @@ BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_return_optimised_program_even_if
BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_use_cache_if_available, ProgramBasedMetricFixture)
{
string code = toString(DummyProgramBasedMetric(nullopt, m_programCache).optimisedProgram(m_chromosome));
string code = toString(DummyProgramBasedMetric(nullopt, m_programCache, m_weights).optimisedProgram(m_chromosome));
BOOST_TEST(code != toString(m_program));
BOOST_TEST(code == toString(m_optimisedProgram));
@ -117,7 +118,7 @@ BOOST_FIXTURE_TEST_CASE(optimisedProgram_should_use_cache_if_available, ProgramB
BOOST_FIXTURE_TEST_CASE(optimisedProgramNoCache_should_return_optimised_program_even_if_cache_not_available, ProgramBasedMetricFixture)
{
string code = toString(DummyProgramBasedMetric(m_program, nullptr).optimisedProgramNoCache(m_chromosome));
string code = toString(DummyProgramBasedMetric(m_program, nullptr, m_weights).optimisedProgramNoCache(m_chromosome));
BOOST_TEST(code != toString(m_program));
BOOST_TEST(code == toString(m_optimisedProgram));
@ -125,7 +126,7 @@ BOOST_FIXTURE_TEST_CASE(optimisedProgramNoCache_should_return_optimised_program_
BOOST_FIXTURE_TEST_CASE(optimisedProgramNoCache_should_not_use_cache_even_if_available, ProgramBasedMetricFixture)
{
string code = toString(DummyProgramBasedMetric(nullopt, m_programCache).optimisedProgramNoCache(m_chromosome));
string code = toString(DummyProgramBasedMetric(nullopt, m_programCache, m_weights).optimisedProgramNoCache(m_chromosome));
BOOST_TEST(code != toString(m_program));
BOOST_TEST(code == toString(m_optimisedProgram));
@ -137,18 +138,18 @@ BOOST_AUTO_TEST_SUITE(ProgramSizeTest)
BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_size_of_the_optimised_program, ProgramBasedMetricFixture)
{
size_t fitness = ProgramSize(m_program, nullptr).evaluate(m_chromosome);
size_t fitness = ProgramSize(m_program, nullptr, m_weights).evaluate(m_chromosome);
BOOST_TEST(fitness != m_program.codeSize());
BOOST_TEST(fitness == m_optimisedProgram.codeSize());
BOOST_TEST(fitness != m_program.codeSize(m_weights));
BOOST_TEST(fitness == m_optimisedProgram.codeSize(m_weights));
}
BOOST_FIXTURE_TEST_CASE(evaluate_should_be_able_to_use_program_cache_if_available, ProgramBasedMetricFixture)
{
size_t fitness = ProgramSize(nullopt, m_programCache).evaluate(m_chromosome);
size_t fitness = ProgramSize(nullopt, m_programCache, m_weights).evaluate(m_chromosome);
BOOST_TEST(fitness != m_program.codeSize());
BOOST_TEST(fitness == m_optimisedProgram.codeSize());
BOOST_TEST(fitness != m_program.codeSize(m_weights));
BOOST_TEST(fitness == m_optimisedProgram.codeSize(m_weights));
BOOST_TEST(m_programCache->size() == m_chromosome.length());
}
@ -157,21 +158,21 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number
Program const& programOptimisedOnce = m_optimisedProgram;
Program programOptimisedTwice = optimisedProgram(programOptimisedOnce);
ProgramSize metric(m_program, nullptr, 2);
ProgramSize metric(m_program, nullptr, m_weights, 2);
size_t fitness = metric.evaluate(m_chromosome);
BOOST_TEST(fitness != m_program.codeSize());
BOOST_TEST(fitness != programOptimisedOnce.codeSize());
BOOST_TEST(fitness == programOptimisedTwice.codeSize());
BOOST_TEST(fitness != m_program.codeSize(m_weights));
BOOST_TEST(fitness != programOptimisedOnce.codeSize(m_weights));
BOOST_TEST(fitness == programOptimisedTwice.codeSize(m_weights));
}
BOOST_FIXTURE_TEST_CASE(evaluate_should_not_optimise_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture)
{
ProgramSize metric(m_program, nullptr, 0);
ProgramSize metric(m_program, nullptr, m_weights, 0);
size_t fitness = metric.evaluate(m_chromosome);
BOOST_TEST(fitness == m_program.codeSize());
BOOST_TEST(fitness != m_optimisedProgram.codeSize());
BOOST_TEST(fitness == m_program.codeSize(m_weights));
BOOST_TEST(fitness != m_optimisedProgram.codeSize(m_weights));
}
BOOST_AUTO_TEST_SUITE_END()
@ -179,12 +180,18 @@ BOOST_AUTO_TEST_SUITE(RelativeProgramSizeTest)
BOOST_FIXTURE_TEST_CASE(evaluate_should_compute_the_size_ratio_between_optimised_program_and_original_program, ProgramBasedMetricFixture)
{
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize()));
BOOST_TEST(
RelativeProgramSize(m_program, nullptr, 3, m_weights).evaluate(m_chromosome) ==
round(1000.0 * m_optimisedProgram.codeSize(m_weights) / m_program.codeSize(m_weights))
);
}
BOOST_FIXTURE_TEST_CASE(evaluate_should_be_able_to_use_program_cache_if_available, ProgramBasedMetricFixture)
{
BOOST_TEST(RelativeProgramSize(nullopt, m_programCache, 3).evaluate(m_chromosome) == round(1000.0 * m_optimisedProgram.codeSize() / m_program.codeSize()));
BOOST_TEST(
RelativeProgramSize(nullopt, m_programCache, 3, m_weights).evaluate(m_chromosome) ==
round(1000.0 * m_optimisedProgram.codeSize(m_weights) / m_program.codeSize(m_weights))
);
BOOST_TEST(m_programCache->size() == m_chromosome.length());
}
@ -193,17 +200,17 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_repeat_the_optimisation_specified_number
Program const& programOptimisedOnce = m_optimisedProgram;
Program programOptimisedTwice = optimisedProgram(programOptimisedOnce);
RelativeProgramSize metric(m_program, nullptr, 3, 2);
RelativeProgramSize metric(m_program, nullptr, 3, m_weights, 2);
size_t fitness = metric.evaluate(m_chromosome);
BOOST_TEST(fitness != 1000);
BOOST_TEST(fitness != RelativeProgramSize(programOptimisedTwice, nullptr, 3, 1).evaluate(m_chromosome));
BOOST_TEST(fitness == round(1000.0 * programOptimisedTwice.codeSize() / m_program.codeSize()));
BOOST_TEST(fitness != RelativeProgramSize(programOptimisedTwice, nullptr, 3, m_weights, 1).evaluate(m_chromosome));
BOOST_TEST(fitness == round(1000.0 * programOptimisedTwice.codeSize(m_weights) / m_program.codeSize(m_weights)));
}
BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_number_of_repetitions_is_zero, ProgramBasedMetricFixture)
{
RelativeProgramSize metric(m_program, nullptr, 3, 0);
RelativeProgramSize metric(m_program, nullptr, 3, m_weights, 0);
BOOST_TEST(metric.evaluate(m_chromosome) == 1000);
}
@ -213,7 +220,7 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_the_original_program_size_
CharStream sourceStream = CharStream("{}", "");
Program program = get<Program>(Program::load(sourceStream));
RelativeProgramSize metric(program, nullptr, 3);
RelativeProgramSize metric(program, nullptr, 3, m_weights);
BOOST_TEST(metric.evaluate(m_chromosome) == 1000);
BOOST_TEST(metric.evaluate(Chromosome("")) == 1000);
@ -222,12 +229,12 @@ BOOST_FIXTURE_TEST_CASE(evaluate_should_return_one_if_the_original_program_size_
BOOST_FIXTURE_TEST_CASE(evaluate_should_multiply_the_result_by_scaling_factor, ProgramBasedMetricFixture)
{
double sizeRatio = static_cast<double>(m_optimisedProgram.codeSize()) / m_program.codeSize();
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 0).evaluate(m_chromosome) == round(1.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 1).evaluate(m_chromosome) == round(10.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 2).evaluate(m_chromosome) == round(100.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 3).evaluate(m_chromosome) == round(1000.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 4).evaluate(m_chromosome) == round(10000.0 * sizeRatio));
double sizeRatio = static_cast<double>(m_optimisedProgram.codeSize(m_weights)) / m_program.codeSize(m_weights);
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 0, m_weights).evaluate(m_chromosome) == round(1.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 1, m_weights).evaluate(m_chromosome) == round(10.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 2, m_weights).evaluate(m_chromosome) == round(100.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 3, m_weights).evaluate(m_chromosome) == round(1000.0 * sizeRatio));
BOOST_TEST(RelativeProgramSize(m_program, nullptr, 4, m_weights).evaluate(m_chromosome) == round(10000.0 * sizeRatio));
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -398,7 +398,7 @@ BOOST_AUTO_TEST_CASE(codeSize)
CharStream sourceStream(sourceCode, current_test_case().p_name);
Program program = get<Program>(Program::load(sourceStream));
BOOST_TEST(program.codeSize() == CodeSize::codeSizeIncludingFunctions(program.ast()));
BOOST_TEST(program.codeSize(CodeWeights{}) == CodeSize::codeSizeIncludingFunctions(program.ast()));
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -18,6 +18,8 @@
#include <tools/yulPhaser/ProgramCache.h>
#include <tools/yulPhaser/Chromosome.h>
#include <libyul/optimiser/Metrics.h>
#include <liblangutil/CharStream.h>
#include <libsolutil/CommonIO.h>
@ -212,11 +214,11 @@ BOOST_FIXTURE_TEST_CASE(startRound_should_remove_entries_older_than_two_rounds,
BOOST_FIXTURE_TEST_CASE(gatherStats_should_return_cache_statistics, ProgramCacheFixture)
{
size_t sizeI = optimisedProgram(m_program, "I").codeSize();
size_t sizeIu = optimisedProgram(m_program, "Iu").codeSize();
size_t sizeIuO = optimisedProgram(m_program, "IuO").codeSize();
size_t sizeL = optimisedProgram(m_program, "L").codeSize();
size_t sizeLT = optimisedProgram(m_program, "LT").codeSize();
size_t sizeI = optimisedProgram(m_program, "I").codeSize(CodeWeights{});
size_t sizeIu = optimisedProgram(m_program, "Iu").codeSize(CodeWeights{});
size_t sizeIuO = optimisedProgram(m_program, "IuO").codeSize(CodeWeights{});
size_t sizeL = optimisedProgram(m_program, "L").codeSize(CodeWeights{});
size_t sizeLT = optimisedProgram(m_program, "LT").codeSize(CodeWeights{});
m_programCache.optimiseProgram("L");
m_programCache.optimiseProgram("Iu");

View File

@ -23,6 +23,7 @@
using namespace std;
using namespace solidity::util;
using namespace solidity::yul;
using namespace solidity::phaser;
Program const& ProgramBasedMetric::program() const
@ -55,18 +56,18 @@ Program ProgramBasedMetric::optimisedProgramNoCache(Chromosome const& _chromosom
size_t ProgramSize::evaluate(Chromosome const& _chromosome)
{
return optimisedProgram(_chromosome).codeSize();
return optimisedProgram(_chromosome).codeSize(codeWeights());
}
size_t RelativeProgramSize::evaluate(Chromosome const& _chromosome)
{
size_t const scalingFactor = pow(10, m_fixedPointPrecision);
size_t unoptimisedSize = optimisedProgram(Chromosome("")).codeSize();
size_t unoptimisedSize = optimisedProgram(Chromosome("")).codeSize(codeWeights());
if (unoptimisedSize == 0)
return scalingFactor;
size_t optimisedSize = optimisedProgram(_chromosome).codeSize();
size_t optimisedSize = optimisedProgram(_chromosome).codeSize(codeWeights());
return static_cast<size_t>(round(
static_cast<double>(optimisedSize) / unoptimisedSize * scalingFactor

View File

@ -24,6 +24,8 @@
#include <tools/yulPhaser/Program.h>
#include <tools/yulPhaser/ProgramCache.h>
#include <libyul/optimiser/Metrics.h>
#include <cstddef>
#include <optional>
@ -64,10 +66,12 @@ public:
explicit ProgramBasedMetric(
std::optional<Program> _program,
std::shared_ptr<ProgramCache> _programCache,
yul::CodeWeights const& _codeWeights,
size_t _repetitionCount = 1
):
m_program(std::move(_program)),
m_programCache(std::move(_programCache)),
m_codeWeights(_codeWeights),
m_repetitionCount(_repetitionCount)
{
assert(m_program.has_value() == (m_programCache == nullptr));
@ -75,6 +79,7 @@ public:
Program const& program() const;
ProgramCache const* programCache() const { return m_programCache.get(); }
yul::CodeWeights const& codeWeights() const { return m_codeWeights; }
size_t repetitionCount() const { return m_repetitionCount; }
Program optimisedProgram(Chromosome const& _chromosome);
@ -83,6 +88,7 @@ public:
private:
std::optional<Program> m_program;
std::shared_ptr<ProgramCache> m_programCache;
yul::CodeWeights m_codeWeights;
size_t m_repetitionCount;
};
@ -111,9 +117,10 @@ public:
std::optional<Program> _program,
std::shared_ptr<ProgramCache> _programCache,
size_t _fixedPointPrecision,
yul::CodeWeights const& _weights,
size_t _repetitionCount = 1
):
ProgramBasedMetric(std::move(_program), std::move(_programCache), _repetitionCount),
ProgramBasedMetric(std::move(_program), std::move(_programCache), _weights, _repetitionCount),
m_fixedPointPrecision(_fixedPointPrecision) {}
size_t fixedPointPrecision() const { return m_fixedPointPrecision; }

View File

@ -39,6 +39,7 @@ using namespace std;
using namespace solidity;
using namespace solidity::langutil;
using namespace solidity::util;
using namespace solidity::yul;
using namespace solidity::phaser;
namespace po = boost::program_options;
@ -216,6 +217,7 @@ unique_ptr<FitnessMetric> FitnessMetricFactory::build(
metrics.push_back(make_unique<ProgramSize>(
_programCaches[i] != nullptr ? optional<Program>{} : move(_programs[i]),
move(_programCaches[i]),
CodeWeights{},
_options.chromosomeRepetitions
));
@ -228,6 +230,7 @@ unique_ptr<FitnessMetric> FitnessMetricFactory::build(
_programCaches[i] != nullptr ? optional<Program>{} : move(_programs[i]),
move(_programCaches[i]),
_options.relativeMetricScale,
CodeWeights{},
_options.chromosomeRepetitions
));
break;

View File

@ -207,7 +207,7 @@ unique_ptr<Block> Program::applyOptimisationSteps(
return _ast;
}
size_t Program::computeCodeSize(Block const& _ast)
size_t Program::computeCodeSize(Block const& _ast, CodeWeights const& _weights)
{
return CodeSize::codeSizeIncludingFunctions(_ast);
return CodeSize::codeSizeIncludingFunctions(_ast, _weights);
}

View File

@ -41,6 +41,7 @@ namespace solidity::yul
struct AsmAnalysisInfo;
struct Dialect;
struct CodeWeights;
}
@ -78,7 +79,7 @@ public:
static std::variant<Program, langutil::ErrorList> load(langutil::CharStream& _sourceCode);
void optimise(std::vector<std::string> const& _optimisationSteps);
size_t codeSize() const { return computeCodeSize(*m_ast); }
size_t codeSize(yul::CodeWeights const& _weights) const { return computeCodeSize(*m_ast, _weights); }
yul::Block const& ast() const { return *m_ast; }
friend std::ostream& operator<<(std::ostream& _stream, Program const& _program);
@ -113,7 +114,7 @@ private:
std::unique_ptr<yul::Block> _ast,
std::vector<std::string> const& _optimisationSteps
);
static size_t computeCodeSize(yul::Block const& _ast);
static size_t computeCodeSize(yul::Block const& _ast, yul::CodeWeights const& _weights);
std::unique_ptr<yul::Block> m_ast;
yul::Dialect const& m_dialect;

View File

@ -17,6 +17,8 @@
#include <tools/yulPhaser/ProgramCache.h>
#include <libyul/optimiser/Metrics.h>
#include <libyul/optimiser/Suite.h>
using namespace std;
@ -133,7 +135,7 @@ size_t ProgramCache::calculateTotalCachedCodeSize() const
{
size_t size = 0;
for (auto const& pair: m_entries)
size += pair.second.program.codeSize();
size += pair.second.program.codeSize(CodeWeights{});
return size;
}