#ifndef __HAYAI_CONSOLEOUTPUTTER #define __HAYAI_CONSOLEOUTPUTTER #include "hayai_outputter.hpp" #include "hayai_console.hpp" namespace hayai { /// Console outputter. /// Prints the result to standard output. class ConsoleOutputter : public Outputter { public: /// Initialize console outputter. /// @param stream Output stream. Must exist for the entire duration of /// the outputter's use. ConsoleOutputter(std::ostream& stream = std::cout) : _stream(stream) { } virtual void Begin(const std::size_t& enabledCount, const std::size_t& disabledCount) { _stream << std::fixed; _stream << Console::TextGreen << "[==========]" << Console::TextDefault << " Running " << enabledCount << (enabledCount == 1 ? " benchmark." : " benchmarks"); if (disabledCount) _stream << ", skipping " << disabledCount << (disabledCount == 1 ? " benchmark." : " benchmarks"); else _stream << "."; _stream << std::endl; } virtual void End(const std::size_t& executedCount, const std::size_t& disabledCount) { _stream << Console::TextGreen << "[==========]" << Console::TextDefault << " Ran " << executedCount << (executedCount == 1 ? " benchmark." : " benchmarks"); if (disabledCount) _stream << ", skipped " << disabledCount << (disabledCount == 1 ? " benchmark." : " benchmarks"); else _stream << "."; _stream << std::endl; } inline void BeginOrSkipTest(const std::string& fixtureName, const std::string& testName, const TestParametersDescriptor& parameters, const std::size_t& runsCount, const std::size_t& iterationsCount, const bool skip) { if (skip) _stream << Console::TextCyan << "[ DISABLED ]"; else _stream << Console::TextGreen << "[ RUN ]"; _stream << Console::TextYellow << " "; WriteTestNameToStream(_stream, fixtureName, testName, parameters); _stream << Console::TextDefault << " (" << runsCount << (runsCount == 1 ? " run, " : " runs, ") << iterationsCount << (iterationsCount == 1 ? " iteration per run)" : " iterations per run)") << std::endl; } virtual void BeginTest(const std::string& fixtureName, const std::string& testName, const TestParametersDescriptor& parameters, const std::size_t& runsCount, const std::size_t& iterationsCount) { BeginOrSkipTest(fixtureName, testName, parameters, runsCount, iterationsCount, false); } virtual void SkipDisabledTest( const std::string& fixtureName, const std::string& testName, const TestParametersDescriptor& parameters, const std::size_t& runsCount, const std::size_t& iterationsCount ) { BeginOrSkipTest(fixtureName, testName, parameters, runsCount, iterationsCount, true); } virtual void EndTest(const std::string& fixtureName, const std::string& testName, const TestParametersDescriptor& parameters, const TestResult& result) { #define PAD(x) _stream << std::setw(34) << x << std::endl; #define PAD_DEVIATION(description, \ deviated, \ average, \ unit) \ { \ double _d_ = \ double(deviated) - double(average); \ \ PAD(description << \ deviated << " " << unit << " (" << \ (deviated < average ? \ Console::TextRed : \ Console::TextGreen) << \ (deviated > average ? "+" : "") << \ _d_ << " " << unit << " / " << \ (deviated > average ? "+" : "") << \ (_d_ * 100.0 / average) << " %" << \ Console::TextDefault << ")"); \ } #define PAD_DEVIATION_INVERSE(description, \ deviated, \ average, \ unit) \ { \ double _d_ = \ double(deviated) - double(average); \ \ PAD(description << \ deviated << " " << unit << " (" << \ (deviated > average ? \ Console::TextRed : \ Console::TextGreen) << \ (deviated > average ? "+" : "") << \ _d_ << " " << unit << " / " << \ (deviated > average ? "+" : "") << \ (_d_ * 100.0 / average) << " %" << \ Console::TextDefault << ")"); \ } _stream << Console::TextGreen << "[ DONE ]" << Console::TextYellow << " "; WriteTestNameToStream(_stream, fixtureName, testName, parameters); _stream << Console::TextDefault << " (" << std::setprecision(6) << (result.TimeTotal() / 1000000.0) << " ms)" << std::endl; _stream << Console::TextBlue << "[ RUNS ] " << Console::TextDefault << " Average time: " << std::setprecision(3) << result.RunTimeAverage() / 1000.0 << " us " << "(" << Console::TextBlue << "~" << result.RunTimeStdDev() / 1000.0 << " us" << Console::TextDefault << ")" << std::endl; PAD_DEVIATION_INVERSE("Fastest time: ", (result.RunTimeMinimum() / 1000.0), (result.RunTimeAverage() / 1000.0), "us"); PAD_DEVIATION_INVERSE("Slowest time: ", (result.RunTimeMaximum() / 1000.0), (result.RunTimeAverage() / 1000.0), "us"); PAD("Median time: " << result.RunTimeMedian() / 1000.0 << " us (" << Console::TextCyan << "1st quartile: " << result.RunTimeQuartile1() / 1000.0 << " us | 3rd quartile: " << result.RunTimeQuartile3() / 1000.0 << " us" << Console::TextDefault << ")"); _stream << std::setprecision(5); PAD(""); PAD("Average performance: " << result.RunsPerSecondAverage() << " runs/s"); PAD_DEVIATION("Best performance: ", result.RunsPerSecondMaximum(), result.RunsPerSecondAverage(), "runs/s"); PAD_DEVIATION("Worst performance: ", result.RunsPerSecondMinimum(), result.RunsPerSecondAverage(), "runs/s"); PAD("Median performance: " << result.RunsPerSecondMedian() << " runs/s (" << Console::TextCyan << "1st quartile: " << result.RunsPerSecondQuartile1() << " | 3rd quartile: " << result.RunsPerSecondQuartile3() << Console::TextDefault << ")"); PAD(""); _stream << Console::TextBlue << "[ITERATIONS] " << Console::TextDefault << std::setprecision(3) << " Average time: " << result.IterationTimeAverage() / 1000.0 << " us " << "(" << Console::TextBlue << "~" << result.IterationTimeStdDev() / 1000.0 << " us" << Console::TextDefault << ")" << std::endl; PAD_DEVIATION_INVERSE("Fastest time: ", (result.IterationTimeMinimum() / 1000.0), (result.IterationTimeAverage() / 1000.0), "us"); PAD_DEVIATION_INVERSE("Slowest time: ", (result.IterationTimeMaximum() / 1000.0), (result.IterationTimeAverage() / 1000.0), "us"); PAD("Median time: " << result.IterationTimeMedian() / 1000.0 << " us (" << Console::TextCyan << "1st quartile: " << result.IterationTimeQuartile1() / 1000.0 << " us | 3rd quartile: " << result.IterationTimeQuartile3() / 1000.0 << " us" << Console::TextDefault << ")"); _stream << std::setprecision(5); PAD(""); PAD("Average performance: " << result.IterationsPerSecondAverage() << " iterations/s"); PAD_DEVIATION("Best performance: ", (result.IterationsPerSecondMaximum()), (result.IterationsPerSecondAverage()), "iterations/s"); PAD_DEVIATION("Worst performance: ", (result.IterationsPerSecondMinimum()), (result.IterationsPerSecondAverage()), "iterations/s"); PAD("Median performance: " << result.IterationsPerSecondMedian() << " iterations/s (" << Console::TextCyan << "1st quartile: " << result.IterationsPerSecondQuartile1() << " | 3rd quartile: " << result.IterationsPerSecondQuartile3() << Console::TextDefault << ")"); #undef PAD_DEVIATION_INVERSE #undef PAD_DEVIATION #undef PAD } std::ostream& _stream; }; } #endif