mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			204 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| 	This file is part of solidity.
 | |
| 
 | |
| 	solidity is free software: you can redistribute it and/or modify
 | |
| 	it under the terms of the GNU General Public License as published by
 | |
| 	the Free Software Foundation, either version 3 of the License, or
 | |
| 	(at your option) any later version.
 | |
| 
 | |
| 	solidity is distributed in the hope that it will be useful,
 | |
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| 	GNU General Public License for more details.
 | |
| 
 | |
| 	You should have received a copy of the GNU General Public License
 | |
| 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| // SPDX-License-Identifier: GPL-3.0
 | |
| 
 | |
| #include <tools/yulPhaser/AlgorithmRunner.h>
 | |
| 
 | |
| #include <tools/yulPhaser/Exceptions.h>
 | |
| 
 | |
| #include <libsolutil/Assertions.h>
 | |
| 
 | |
| #include <cerrno>
 | |
| #include <cstring>
 | |
| #include <fstream>
 | |
| 
 | |
| using namespace std;
 | |
| using namespace solidity::phaser;
 | |
| 
 | |
| void AlgorithmRunner::run(GeneticAlgorithm& _algorithm)
 | |
| {
 | |
| 	populationAutosave();
 | |
| 	printInitialPopulation();
 | |
| 	cacheClear();
 | |
| 
 | |
| 	clock_t totalTimeStart = clock();
 | |
| 	for (size_t round = 0; !m_options.maxRounds.has_value() || round < m_options.maxRounds.value(); ++round)
 | |
| 	{
 | |
| 		clock_t roundTimeStart = clock();
 | |
| 		cacheStartRound(round + 1);
 | |
| 
 | |
| 		m_population = _algorithm.runNextRound(m_population);
 | |
| 		randomiseDuplicates();
 | |
| 
 | |
| 		printRoundSummary(round, roundTimeStart, totalTimeStart);
 | |
| 		printCacheStats();
 | |
| 		populationAutosave();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void AlgorithmRunner::printRoundSummary(
 | |
| 	size_t _round,
 | |
| 	clock_t _roundTimeStart,
 | |
| 	clock_t _totalTimeStart
 | |
| ) const
 | |
| {
 | |
| 	clock_t now = clock();
 | |
| 	double roundTime = static_cast<double>(now - _roundTimeStart) / CLOCKS_PER_SEC;
 | |
| 	double totalTime = static_cast<double>(now - _totalTimeStart) / CLOCKS_PER_SEC;
 | |
| 
 | |
| 	if (!m_options.showOnlyTopChromosome)
 | |
| 	{
 | |
| 		if (m_options.showRoundInfo)
 | |
| 		{
 | |
| 			m_outputStream << "---------- ROUND " << _round + 1;
 | |
| 			m_outputStream << " [round: " << fixed << setprecision(1) << roundTime << " s,";
 | |
| 			m_outputStream << " total: " << fixed << setprecision(1) << totalTime << " s]";
 | |
| 			m_outputStream << " ----------" << endl;
 | |
| 		}
 | |
| 		else if (m_population.individuals().size() > 0)
 | |
| 			m_outputStream << endl;
 | |
| 
 | |
| 		m_outputStream << m_population;
 | |
| 	}
 | |
| 	else if (m_population.individuals().size() > 0)
 | |
| 	{
 | |
| 		if (m_options.showRoundInfo)
 | |
| 		{
 | |
| 			m_outputStream << setw(5) << _round + 1 << " | ";
 | |
| 			m_outputStream << setw(5) << fixed << setprecision(1) << totalTime << " | ";
 | |
| 		}
 | |
| 
 | |
| 		m_outputStream << m_population.individuals()[0] << endl;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void AlgorithmRunner::printInitialPopulation() const
 | |
| {
 | |
| 	if (!m_options.showInitialPopulation)
 | |
| 		return;
 | |
| 
 | |
| 	m_outputStream << "---------- INITIAL POPULATION ----------" << endl;
 | |
| 	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())
 | |
| 		return;
 | |
| 
 | |
| 	ofstream outputStream(m_options.populationAutosaveFile.value(), ios::out | ios::trunc);
 | |
| 	assertThrow(
 | |
| 		outputStream.is_open(),
 | |
| 		FileOpenError,
 | |
| 		"Could not open file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno)
 | |
| 	);
 | |
| 
 | |
| 	for (auto& individual: m_population.individuals())
 | |
| 		outputStream << individual.chromosome << endl;
 | |
| 
 | |
| 	assertThrow(
 | |
| 		!outputStream.bad(),
 | |
| 		FileWriteError,
 | |
| 		"Error while writing to file '" + m_options.populationAutosaveFile.value() + "': " + strerror(errno)
 | |
| 	);
 | |
| }
 | |
| 
 | |
| void AlgorithmRunner::cacheClear()
 | |
| {
 | |
| 	for (auto& cache: m_programCaches)
 | |
| 		if (cache != nullptr)
 | |
| 			cache->clear();
 | |
| }
 | |
| 
 | |
| void AlgorithmRunner::cacheStartRound(size_t _roundNumber)
 | |
| {
 | |
| 	for (auto& cache: m_programCaches)
 | |
| 		if (cache != nullptr)
 | |
| 			cache->startRound(_roundNumber);
 | |
| }
 | |
| 
 | |
| void AlgorithmRunner::randomiseDuplicates()
 | |
| {
 | |
| 	if (m_options.randomiseDuplicates)
 | |
| 	{
 | |
| 		assert(m_options.minChromosomeLength.has_value());
 | |
| 		assert(m_options.maxChromosomeLength.has_value());
 | |
| 
 | |
| 		m_population = randomiseDuplicates(
 | |
| 			m_population,
 | |
| 			m_options.minChromosomeLength.value(),
 | |
| 			m_options.maxChromosomeLength.value()
 | |
| 		);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| Population AlgorithmRunner::randomiseDuplicates(
 | |
| 	Population _population,
 | |
| 	size_t _minChromosomeLength,
 | |
| 	size_t _maxChromosomeLength
 | |
| )
 | |
| {
 | |
| 	if (_population.individuals().size() == 0)
 | |
| 		return _population;
 | |
| 
 | |
| 	vector<Individual> individuals{_population.individuals()[0]};
 | |
| 	size_t duplicateCount = 0;
 | |
| 	for (size_t i = 1; i < _population.individuals().size(); ++i)
 | |
| 		if (_population.individuals()[i].chromosome == _population.individuals()[i - 1].chromosome)
 | |
| 			++duplicateCount;
 | |
| 		else
 | |
| 			individuals.push_back(_population.individuals()[i]);
 | |
| 
 | |
| 	return (
 | |
| 		Population(_population.fitnessMetric(), individuals) +
 | |
| 		Population::makeRandom(_population.fitnessMetric(), duplicateCount, _minChromosomeLength, _maxChromosomeLength)
 | |
| 	);
 | |
| }
 |