338 lines
8.9 KiB
C++
338 lines
8.9 KiB
C++
|
///
|
||
|
/// \author John Farrier
|
||
|
///
|
||
|
/// \copyright Copyright 2015, 2016, 2017, 2018. 2019 John Farrier
|
||
|
///
|
||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
/// you may not use this file except in compliance with the License.
|
||
|
/// You may obtain a copy of the License at
|
||
|
///
|
||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
///
|
||
|
/// Unless required by applicable law or agreed to in writing, software
|
||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
/// See the License for the specific language governing permissions and
|
||
|
/// limitations under the License.
|
||
|
///
|
||
|
|
||
|
#include <celero/Benchmark.h>
|
||
|
#include <celero/Console.h>
|
||
|
#include <celero/Print.h>
|
||
|
#include <celero/TestVector.h>
|
||
|
#include <celero/Timer.h>
|
||
|
#include <celero/UserDefinedMeasurementCollector.h>
|
||
|
#include <celero/Utilities.h>
|
||
|
#include <algorithm>
|
||
|
#include <chrono>
|
||
|
#include <iomanip>
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <unordered_map>
|
||
|
|
||
|
using namespace celero;
|
||
|
|
||
|
enum PrintConstants : size_t
|
||
|
{
|
||
|
ColumnSeperatorWidth = 3,
|
||
|
DoubleDecimals = 5,
|
||
|
NumberOfColumns = 8,
|
||
|
ColumnWidth = 15
|
||
|
};
|
||
|
|
||
|
///
|
||
|
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||
|
/// Center-aligns string within a field of width w. Pads with blank spaces to enforce alignment.
|
||
|
///
|
||
|
std::string PrintCenter(const std::string& s, const size_t w = PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
std::stringstream ss;
|
||
|
std::stringstream spaces;
|
||
|
|
||
|
// count excess room to pad
|
||
|
auto padding = w - s.size();
|
||
|
|
||
|
for(size_t i = 0; i < padding / 2; ++i)
|
||
|
{
|
||
|
spaces << " ";
|
||
|
}
|
||
|
|
||
|
// format with padding
|
||
|
ss << spaces.str() << s << spaces.str();
|
||
|
|
||
|
// if odd #, add 1 space
|
||
|
if((padding > 0) && (padding % 2 != 0))
|
||
|
{
|
||
|
ss << " ";
|
||
|
}
|
||
|
|
||
|
ss << " | ";
|
||
|
return ss.str();
|
||
|
}
|
||
|
|
||
|
///
|
||
|
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||
|
/// Convert double to string with specified number of places after the decimal and left padding.
|
||
|
///
|
||
|
std::string PrintColumn(const double x, const size_t decDigits = PrintConstants::DoubleDecimals, const size_t width = PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
std::stringstream ss;
|
||
|
ss << std::fixed << std::right;
|
||
|
|
||
|
// fill space around displayed #
|
||
|
ss.fill(' ');
|
||
|
|
||
|
// set width around displayed #
|
||
|
ss.width(width);
|
||
|
|
||
|
// set # places after decimal
|
||
|
ss.precision(decDigits);
|
||
|
ss << x;
|
||
|
|
||
|
return ss.str();
|
||
|
}
|
||
|
|
||
|
///
|
||
|
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||
|
/// Convert double to string with specified number of places after the decimal.
|
||
|
///
|
||
|
std::string PrintColumn(const int64_t x, const size_t width = PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
std::stringstream ss;
|
||
|
ss << std::fixed;
|
||
|
|
||
|
// fill space around displayed #
|
||
|
ss.fill(' ');
|
||
|
|
||
|
// set width around displayed #
|
||
|
ss.width(width);
|
||
|
|
||
|
ss << x << " | ";
|
||
|
return ss.str();
|
||
|
}
|
||
|
|
||
|
///
|
||
|
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||
|
/// Convert double to string with specified number of places after the decimal.
|
||
|
///
|
||
|
std::string PrintColumn(const uint64_t x, const size_t width = PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
std::stringstream ss;
|
||
|
ss << std::fixed;
|
||
|
|
||
|
// fill space around displayed #
|
||
|
ss.fill(' ');
|
||
|
|
||
|
// set width around displayed #
|
||
|
ss.width(width);
|
||
|
|
||
|
ss << x << " | ";
|
||
|
return ss.str();
|
||
|
}
|
||
|
|
||
|
///
|
||
|
/// http://stackoverflow.com/questions/14765155/how-can-i-easily-format-my-data-table-in-c
|
||
|
/// Convert double to string with specified number of places after the decimal.
|
||
|
///
|
||
|
std::string PrintStrColumnAligned(const std::string& x, const size_t width = PrintConstants::ColumnWidth, bool alignLeft = true)
|
||
|
{
|
||
|
std::stringstream ss;
|
||
|
ss << std::fixed << (alignLeft ? std::left : std::right);
|
||
|
|
||
|
// fill space around displayed #
|
||
|
ss.fill(' ');
|
||
|
|
||
|
// set width around displayed #
|
||
|
ss.width(width);
|
||
|
|
||
|
if(x.length() > width)
|
||
|
{
|
||
|
// Truncate
|
||
|
std::string xTrunc = x;
|
||
|
xTrunc = xTrunc.substr(0, width);
|
||
|
ss << xTrunc << " | ";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ss << x << " | ";
|
||
|
}
|
||
|
|
||
|
return ss.str();
|
||
|
}
|
||
|
|
||
|
std::string PrintColumn(const std::string& x, const size_t width = PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
return PrintStrColumnAligned(x, width);
|
||
|
}
|
||
|
|
||
|
std::string PrintColumnRight(const std::string& x, const size_t width = PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
return PrintStrColumnAligned(x, width, false);
|
||
|
}
|
||
|
|
||
|
std::string PrintHRule(const size_t additionalColumns = 0)
|
||
|
{
|
||
|
std::stringstream ss;
|
||
|
std::string column{":"};
|
||
|
|
||
|
while(column.length() < PrintConstants::ColumnWidth)
|
||
|
{
|
||
|
column += "-";
|
||
|
}
|
||
|
|
||
|
std::string firstColumn = column + ":|";
|
||
|
|
||
|
column += "-:|";
|
||
|
|
||
|
ss << "|" << firstColumn;
|
||
|
|
||
|
for(size_t i = 0; i < PrintConstants::NumberOfColumns + additionalColumns - 1; ++i)
|
||
|
{
|
||
|
ss << column;
|
||
|
}
|
||
|
|
||
|
ss << std::endl;
|
||
|
|
||
|
return ss.str();
|
||
|
}
|
||
|
|
||
|
namespace celero
|
||
|
{
|
||
|
void Printer::Console(const std::string& x)
|
||
|
{
|
||
|
std::cout << "Celero: " << x << std::endl;
|
||
|
}
|
||
|
|
||
|
void Printer::TableBanner()
|
||
|
{
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
|
||
|
std::cout << "|" << PrintCenter("Group") << PrintCenter("Experiment") << PrintCenter("Prob. Space") << PrintCenter("Samples")
|
||
|
<< PrintCenter("Iterations") << PrintCenter("Baseline") << PrintCenter("us/Iteration") << PrintCenter("Iterations/sec");
|
||
|
|
||
|
for(size_t i = PrintConstants::NumberOfColumns; i < this->columnWidths.size(); ++i)
|
||
|
{
|
||
|
std::cout << PrintCenter(this->userDefinedColumns[i - PrintConstants::NumberOfColumns], this->columnWidths[i]);
|
||
|
}
|
||
|
|
||
|
std::cout << "\n";
|
||
|
std::cout << PrintHRule(this->userDefinedColumns.size());
|
||
|
}
|
||
|
|
||
|
void Printer::TableRowExperimentHeader(Experiment* x)
|
||
|
{
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
std::cout << "|" << PrintColumn(x->getBenchmark()->getName()) << PrintColumn(x->getName());
|
||
|
}
|
||
|
|
||
|
void Printer::TableRowFailure(const std::string& msg)
|
||
|
{
|
||
|
std::cout << PrintColumnRight("-") << PrintColumnRight("-") << PrintColumnRight("-");
|
||
|
|
||
|
for(size_t i = PrintConstants::NumberOfColumns; i < this->columnWidths.size(); ++i)
|
||
|
{
|
||
|
std::cout << PrintColumnRight("-", this->columnWidths[i]);
|
||
|
}
|
||
|
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Red);
|
||
|
std::cout << msg << std::endl;
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
}
|
||
|
|
||
|
void Printer::TableRowProblemSpaceHeader(std::shared_ptr<celero::ExperimentResult> x)
|
||
|
{
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
|
||
|
if(x->getProblemSpaceValue() == static_cast<int64_t>(TestFixture::Constants::NoProblemSpaceValue))
|
||
|
{
|
||
|
std::cout << PrintColumnRight("Null");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
std::cout << PrintColumn(x->getProblemSpaceValue());
|
||
|
}
|
||
|
|
||
|
std::cout << PrintColumn(x->getExperiment()->getSamples()) << PrintColumn(x->getProblemSpaceIterations());
|
||
|
}
|
||
|
|
||
|
void Printer::TableRowHeader(std::shared_ptr<celero::ExperimentResult> x)
|
||
|
{
|
||
|
TableRowExperimentHeader(x->getExperiment());
|
||
|
TableRowProblemSpaceHeader(x);
|
||
|
}
|
||
|
|
||
|
void Printer::TableResult(std::shared_ptr<celero::ExperimentResult> x)
|
||
|
{
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
|
||
|
celero::console::ConsoleColor temp_color;
|
||
|
|
||
|
// Slower than Baseline
|
||
|
if(x->getBaselineMeasurement() > 1.0)
|
||
|
{
|
||
|
temp_color = celero::console::ConsoleColor::Yellow;
|
||
|
}
|
||
|
else if(x->getBaselineMeasurement() < 1.0)
|
||
|
{
|
||
|
temp_color = celero::console::ConsoleColor::Green;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
temp_color = celero::console::ConsoleColor::Cyan;
|
||
|
}
|
||
|
|
||
|
celero::console::SetConsoleColor(temp_color);
|
||
|
std::cout << PrintColumn(x->getBaselineMeasurement());
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
std::cout << " | ";
|
||
|
|
||
|
celero::console::SetConsoleColor(temp_color);
|
||
|
std::cout << PrintColumn(x->getUsPerCall());
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
std::cout << " | ";
|
||
|
|
||
|
celero::console::SetConsoleColor(temp_color);
|
||
|
std::cout << PrintColumn(x->getCallsPerSecond(), 2);
|
||
|
celero::console::SetConsoleColor(celero::console::ConsoleColor::Default);
|
||
|
std::cout << " | ";
|
||
|
|
||
|
std::unordered_map<std::string, double> udmValues;
|
||
|
|
||
|
auto udmCollector = x->getUserDefinedMeasurements();
|
||
|
for(const auto& entry : udmCollector->getAggregateValues())
|
||
|
{
|
||
|
udmValues[entry.first] = entry.second;
|
||
|
}
|
||
|
|
||
|
for(size_t i = 0; i < this->userDefinedColumns.size(); ++i)
|
||
|
{
|
||
|
const auto& fieldName = this->userDefinedColumns[i];
|
||
|
|
||
|
if(udmValues.find(fieldName) == udmValues.end())
|
||
|
{
|
||
|
std::cout << PrintCenter("---", this->columnWidths[i + PrintConstants::NumberOfColumns]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
std::cout << PrintColumn(udmValues.at(fieldName), 2, this->columnWidths[i + PrintConstants::NumberOfColumns]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::cout << "\n";
|
||
|
}
|
||
|
|
||
|
void Printer::initialize(std::vector<std::string> userDefinedColumnsIn)
|
||
|
{
|
||
|
this->userDefinedColumns = userDefinedColumnsIn;
|
||
|
|
||
|
this->columnWidths.clear();
|
||
|
this->columnWidths.resize(PrintConstants::NumberOfColumns, PrintConstants::ColumnWidth);
|
||
|
|
||
|
for(const auto& name : this->userDefinedColumns)
|
||
|
{
|
||
|
this->columnWidths.push_back(std::max(name.size() + 2, (size_t)PrintConstants::ColumnWidth));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} // namespace celero
|