diff --git a/benchmark.hpp b/benchmark.hpp index 31881ff..9b6dcb8 100644 --- a/benchmark.hpp +++ b/benchmark.hpp @@ -1,8 +1,24 @@ -//ProjectEulerCPP/benchmark.hpp -//Mattrixwv +//ProjectEuler/ProjectEulerCPP/benchmark.hpp +//Matthew Ellison // Created: 07-08-20 -//Modified: 07-08-20 -//This is a program that runs a problem several times to get the average time it takes to run +//Modified: 07-09-20 +//These are functions that help determine an average run time for the problems +/* + Copyright (C) 2020 Matthew Ellison + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ #ifndef BENCHMARK_HPP @@ -13,18 +29,23 @@ #include "ProblemSelection.hpp" -void printBenchmarkMenu(); //Prints the menu to the screen +void printBenchmarkMenu(); //Print the benchmark menu int getBenchmarkMenuSelection(); //Returns a valid menu option bool isValidBenchmarkMenu(int selection); //Determines if a value is a valid menu option. Helper for getBenchmarkMenuSelection void runSpecific(); //Determines which problem user wants to run and runs it void runAllShort(); //Runs all problems except a few that are specified because of run length void runAll(); //Runs all problems unsigned int getNumberOfTimesToRun(); //Asks how many times a problem is supposed to run and returns the value +double runProblem(Problem* problem, unsigned int timesToRun); //Runs the problem the given number of times +std::string getBenchmarkResults(Problem* problem, double totalTime, unsigned int timesRan); //Prints the benchmark results of a problem +//Variables +//Valid menu options enum BENCHMARK_OPTIONS {RUN_SPECIFIC = 1, RUN_ALL_SHORT, RUN_ALL, BENCHMARK_EXIT, BENCHMARK_SIZE}; -std::vector tooLong = {15}; +std::vector tooLong = {15}; //The list of problems that take "too long" to run. (Over 1 second on my machine) +//The driver function for the benchmark selection void benchmarkMenu(){ int selection = 0; @@ -39,6 +60,7 @@ void benchmarkMenu(){ } } +//Print the benchmark menu void printBenchmarkMenu(){ std::cout << "1. Run a specific problem\n" << "2. Run all problems that have a reasonably short run time\n" @@ -46,6 +68,7 @@ void printBenchmarkMenu(){ << "4. Exit the menu" << std::endl; } +//Returns a valid menu option int getBenchmarkMenuSelection(){ int selection = 0; std::cin >> selection; @@ -59,6 +82,7 @@ int getBenchmarkMenuSelection(){ return selection; } +//Determines if a value is a valid menu option. Helper for getBenchmarkMenuSelection bool isValidBenchmarkMenu(int selection){ if((selection > 0) && (selection < BENCHMARK_OPTIONS::BENCHMARK_SIZE)){ return true; @@ -68,96 +92,79 @@ bool isValidBenchmarkMenu(int selection){ } } +//Determines which problem user wants to run and runs it void runSpecific(){ - double totalTime = 0; //Ask which problem the user wants to run unsigned int problemNumber = getProblemNumber(); //Ask how many times to run the problem unsigned int timesToRun = getNumberOfTimesToRun(); - //Get the problem + + //Get the problem and print its description Problem* problem = getProblem(problemNumber); + std::cout << problemNumber << ". " << problem->getDescription() << '\n'; + //Run the problem the specific number of times - std::cout << problemNumber << ". " << problem->getDescription() - << "\nSolving"; - for(unsigned int cnt = 0;cnt < timesToRun;++cnt){ - //Reset the data so you are actually counting the run time a second time - problem->reset(); - (std::cout << '.').flush(); - //Solve the problem - problem->solve(); - //Get the time data - totalTime += problem->getTimer().getNano(); - } - //Calculate the average run time - totalTime /= timesToRun; - std::string timeResults = mee::Stopwatch::getStr(totalTime); + double totalTime = runProblem(problem, timesToRun); + //Print the results - std::cout << "\n\n" << problem->getString(); - std::cout << "\nIt took an average of " << timeResults << " to run this problem through " << timesToRun << " iterations\n\n" << std::endl; + std::cout << getBenchmarkResults(problem, totalTime, timesToRun); + + //Release the memory the problem is in + delete problem; } +//Runs all problems except a few that are specified because of run length void runAllShort(){ //Ask how many times to run the problem unsigned int timesToRun = getNumberOfTimesToRun(); + //Run through all valid problem numbers, skipping a few that are in the tooLong vector for(unsigned int cnt = 1;cnt < PROBLEM_NUMBERS.size();++cnt){ unsigned int problemNumber = PROBLEM_NUMBERS[cnt]; - double totalTime = 0; //If the problem number is contained in the list of problems that take too long skip it if(mee::isFound(tooLong, problemNumber)){ continue; } - //Get the problem + + //Get the problem and print its description Problem* problem = getProblem(problemNumber); - //Run each problem the specified number of times - std::cout << problemNumber << ". " << problem->getDescription() - << "\nSolving"; - for(unsigned int cnt = 0;cnt < timesToRun;++cnt){ - //Reset the data so you are actually counting the run time a second time - problem->reset(); - (std::cout << '.').flush(); - //Solve the problem - problem->solve(); - //Get the time data - totalTime += (problem->getTimer()).getNano(); - } - //Calculate the average run time of the problem - totalTime /= timesToRun; - std::string timeResults = mee::Stopwatch::getStr(totalTime); + std::cout << problemNumber << ". " << problem->getDescription() << '\n'; + + //Run the problem the specified number of times + double totalTime = runProblem(problem, timesToRun); + //Print the results - std::cout << "\n\n" << problem->getString(); - std::cout << "\nIt took an average of " << timeResults << " to run this problem over " << timesToRun << " iterations\n\n" << std::endl; + std::cout << getBenchmarkResults(problem, totalTime, timesToRun); + + //Release the memory the problem is in + delete problem; } } +//Runs all problems void runAll(){ //Ask how many times to run the problem unsigned int timesToRun = getNumberOfTimesToRun(); + //Run through all valid problem numbers, skipping a few that are in the tooLong vector for(unsigned int cnt = 1;cnt < PROBLEM_NUMBERS.size();++cnt){ unsigned int problemNumber = PROBLEM_NUMBERS[cnt]; double totalTime = 0; + //Get the problem Problem* problem = getProblem(problemNumber); - //Run each problem the specified number of times - std::cout << problemNumber << ". " << problem->getDescription() - << "\nSolving"; - for(unsigned int cnt = 0;cnt < timesToRun;++cnt){ - //Reset the data so you are actually counting the run time a second time - problem->reset(); - (std::cout << '.').flush(); - //Solve the problem - problem->solve(); - //Get the time data - totalTime += (problem->getTimer()).getNano(); - } - //Calculate the average run time of the problem - totalTime /= timesToRun; - std::string timeResults = mee::Stopwatch::getStr(totalTime); + + //Run the problem the specified number of times + std::cout << problemNumber << ". " << problem->getDescription() << '\n'; + runProblem(problem, timesToRun); + //Print the results - std::cout << "\n\n" << problem->getString(); - std::cout << "\nIt took an average of " << timeResults << " to run this problem over " << timesToRun << " iterations\n\n" << std::endl; + std::cout << getBenchmarkResults(problem, totalTime, timesToRun); + + //Release the memory the problem is in + delete problem; } } +//Asks how many times a problem is supposed to run and returns the value unsigned int getNumberOfTimesToRun(){ unsigned int numOfTimesToRun = 1; std::cout << "How many times do you want to run this problem? "; @@ -170,4 +177,33 @@ unsigned int getNumberOfTimesToRun(){ return numOfTimesToRun; } +//Runs the problem the given number of times +double runProblem(Problem* problem, unsigned int timesToRun){ + double totalTime = 0; + std::cout << "Solving"; + for(unsigned int cnt = 0;cnt < timesToRun;++cnt){ + //Reset the data so you are actually counting the run time a second time + problem->reset(); + (std::cout << '.').flush(); + //Solve the problem + problem->solve(); + //Get the time data + totalTime += (problem->getTimer()).getNano(); + } + return totalTime; +} + +//Prints the benchmark results of a problem +std::string getBenchmarkResults(Problem* problem, double totalTime, unsigned int timesRan){ + //Calculate the average run time of the problem + totalTime /= timesRan; + std::string timeResults = mee::Stopwatch::getStr(totalTime); + //Tally the results + std::stringstream results; + results << "\n\n" << problem->getString(); + results << "\nIt took an average of " << timeResults << " to run this problem over " << timesRan << " iterations\n\n" << std::endl; + return results.str(); +} + + #endif //BENCHMARK_HPP