aboutsummaryrefslogtreecommitdiff
path: root/third_party/include/hayai/hayai_json_outputter.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/include/hayai/hayai_json_outputter.hpp')
1 files changed, 355 insertions, 0 deletions
diff --git a/third_party/include/hayai/hayai_json_outputter.hpp b/third_party/include/hayai/hayai_json_outputter.hpp
new file mode 100755
index 0000000..0f172a5
--- /dev/null
+++ b/third_party/include/hayai/hayai_json_outputter.hpp
@@ -0,0 +1,355 @@
+#ifndef __HAYAI_JSONOUTPUTTER
+#define __HAYAI_JSONOUTPUTTER
+#include <iomanip>
+#include <ostream>
+
+#include "hayai_outputter.hpp"
+
+
+#define JSON_OBJECT_BEGIN "{"
+#define JSON_OBJECT_END "}"
+#define JSON_ARRAY_BEGIN "["
+#define JSON_ARRAY_END "]"
+#define JSON_STRING_BEGIN "\""
+#define JSON_STRING_END "\""
+#define JSON_NAME_SEPARATOR ":"
+#define JSON_VALUE_SEPARATOR ","
+#define JSON_TRUE "true"
+#define JSON_FALSE "false"
+
+namespace hayai
+{
+ /// JSON outputter.
+
+ /// Outputs the result of benchmarks in JSON format with the following
+ /// structure:
+ ///
+ /// {
+ /// "format_version": 1,
+ /// "benchmarks": [{
+ /// "fixture": "DeliveryMan",
+ /// "name": "DeliverPackage",
+ /// "parameters": {
+ /// "declaration": "std::size_t distance",
+ /// "value": "1"
+ /// },
+ /// "iterations_per_run": 10,
+ /// "disabled": false,
+ /// "runs": [{
+ /// "duration": 3801.889831
+ /// }, ..]
+ /// }, {
+ /// "fixture": "DeliveryMan",
+ /// "name": "DisabledTest",
+ /// "iterations_per_run": 10,
+ /// "disabled": true
+ /// }, ..]
+ /// }
+ ///
+ /// All durations are represented as milliseconds.
+ class JsonOutputter
+ : public Outputter
+ {
+ public:
+ /// Initialize JSON outputter.
+
+ /// @param stream Output stream. Must exist for the entire duration of
+ /// the outputter's use.
+ JsonOutputter(std::ostream& stream)
+ : _stream(stream),
+ _firstTest(true)
+ {
+
+ }
+
+
+ virtual void Begin(const std::size_t& enabledCount,
+ const std::size_t& disabledCount)
+ {
+ (void)enabledCount;
+ (void)disabledCount;
+
+ _stream <<
+ JSON_OBJECT_BEGIN
+
+ JSON_STRING_BEGIN "format_version" JSON_STRING_END
+ JSON_NAME_SEPARATOR
+ "1"
+
+ JSON_VALUE_SEPARATOR
+
+ JSON_STRING_BEGIN "benchmarks" JSON_STRING_END
+ JSON_NAME_SEPARATOR
+ JSON_ARRAY_BEGIN;
+ }
+
+
+ virtual void End(const std::size_t& executedCount,
+ const std::size_t& disabledCount)
+ {
+ (void)executedCount;
+ (void)disabledCount;
+
+ _stream <<
+ JSON_ARRAY_END
+ JSON_OBJECT_END;
+ }
+
+
+ virtual void BeginTest(const std::string& fixtureName,
+ const std::string& testName,
+ const TestParametersDescriptor& parameters,
+ const std::size_t& runsCount,
+ const std::size_t& iterationsCount)
+ {
+ BeginTestObject(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)
+ {
+ BeginTestObject(fixtureName,
+ testName,
+ parameters,
+ runsCount,
+ iterationsCount,
+ true);
+ EndTestObject();
+ }
+
+
+ virtual void EndTest(const std::string& fixtureName,
+ const std::string& testName,
+ const TestParametersDescriptor& parameters,
+ const TestResult& result)
+ {
+ (void)fixtureName;
+ (void)testName;
+ (void)parameters;
+
+ _stream <<
+ JSON_VALUE_SEPARATOR
+
+ JSON_STRING_BEGIN "runs" JSON_STRING_END
+ JSON_NAME_SEPARATOR
+ JSON_ARRAY_BEGIN;
+
+ const std::vector<uint64_t>& runTimes = result.RunTimes();
+
+ for (std::vector<uint64_t>::const_iterator it = runTimes.begin();
+ it != runTimes.end();
+ ++it)
+ {
+ if (it != runTimes.begin())
+ _stream << JSON_VALUE_SEPARATOR;
+
+ _stream << JSON_OBJECT_BEGIN
+ JSON_STRING_BEGIN "duration" JSON_STRING_END
+ JSON_NAME_SEPARATOR
+ << std::fixed
+ << std::setprecision(6)
+ << (double(*it) / 1000000.0)
+ << JSON_OBJECT_END;
+ }
+
+ _stream <<
+ JSON_ARRAY_END;
+
+ WriteDoubleProperty("mean", result.RunTimeAverage());
+ WriteDoubleProperty("std_dev", result.RunTimeStdDev());
+ WriteDoubleProperty("median", result.RunTimeMedian());
+ WriteDoubleProperty("quartile_1", result.RunTimeQuartile1());
+ WriteDoubleProperty("quartile_3", result.RunTimeQuartile3());
+
+ EndTestObject();
+ }
+ private:
+ void BeginTestObject(const std::string& fixtureName,
+ const std::string& testName,
+ const TestParametersDescriptor& parameters,
+ const std::size_t& runsCount,
+ const std::size_t& iterationsCount,
+ bool disabled)
+ {
+ (void)runsCount;
+
+ if (_firstTest)
+ _firstTest = false;
+ else
+ _stream << JSON_VALUE_SEPARATOR;
+
+ _stream <<
+ JSON_OBJECT_BEGIN
+
+ JSON_STRING_BEGIN "fixture" JSON_STRING_END
+ JSON_NAME_SEPARATOR;
+
+ WriteString(fixtureName);
+
+ _stream <<
+ JSON_VALUE_SEPARATOR
+
+ JSON_STRING_BEGIN "name" JSON_STRING_END
+ JSON_NAME_SEPARATOR;
+
+ WriteString(testName);
+
+ _stream <<
+ JSON_VALUE_SEPARATOR;
+
+ const std::vector<TestParameterDescriptor>& descs =
+ parameters.Parameters();
+
+ if (!descs.empty())
+ {
+ _stream <<
+ JSON_STRING_BEGIN "parameters" JSON_STRING_END
+ JSON_NAME_SEPARATOR
+ JSON_ARRAY_BEGIN;
+
+ for (std::size_t i = 0; i < descs.size(); ++i)
+ {
+ if (i)
+ _stream << JSON_VALUE_SEPARATOR;
+
+ const TestParameterDescriptor& desc = descs[i];
+
+ _stream <<
+ JSON_OBJECT_BEGIN
+
+ JSON_STRING_BEGIN "declaration" JSON_STRING_END
+ JSON_NAME_SEPARATOR;
+
+ WriteString(desc.Declaration);
+
+ _stream <<
+ JSON_VALUE_SEPARATOR
+
+ JSON_STRING_BEGIN "value" JSON_STRING_END
+ JSON_NAME_SEPARATOR;
+
+ WriteString(desc.Value);
+
+ _stream <<
+ JSON_OBJECT_END;
+ }
+
+ _stream <<
+ JSON_ARRAY_END
+ JSON_VALUE_SEPARATOR;
+ }
+
+ _stream <<
+ JSON_STRING_BEGIN "iterations_per_run" JSON_STRING_END
+ JSON_NAME_SEPARATOR << iterationsCount <<
+
+ JSON_VALUE_SEPARATOR
+
+ JSON_STRING_BEGIN "disabled" JSON_STRING_END
+ JSON_NAME_SEPARATOR << (disabled ? JSON_TRUE : JSON_FALSE);
+ }
+
+
+ inline void EndTestObject()
+ {
+ _stream <<
+ JSON_OBJECT_END;
+ }
+
+
+ /// Write an escaped string.
+
+ /// The escaping is currently very rudimentary and assumes that names,
+ /// parameters etc. are ASCII.
+ ///
+ /// @param str String to write.
+ void WriteString(const std::string& str)
+ {
+ _stream << JSON_STRING_BEGIN;
+
+ std::string::const_iterator it = str.begin();
+ while (it != str.end())
+ {
+ char c = *it++;
+
+ switch (c)
+ {
+ case '\\':
+ case '"':
+ case '/':
+ _stream << "\\" << c;
+ break;
+
+ case '\b':
+ _stream << "\\b";
+ break;
+
+ case '\f':
+ _stream << "\\f";
+ break;
+
+ case '\n':
+ _stream << "\\n";
+ break;
+
+ case '\r':
+ _stream << "\\r";
+ break;
+
+ case '\t':
+ _stream << "\\t";
+ break;
+
+ default:
+ _stream << c;
+ break;
+ }
+ }
+
+ _stream << JSON_STRING_END;
+ }
+
+
+ /// Write a property with a double value.
+
+ /// @param key Property key.
+ /// @param value Property value.
+ void WriteDoubleProperty(const std::string& key, const double value)
+ {
+ _stream << JSON_VALUE_SEPARATOR
+ << JSON_STRING_BEGIN
+ << key
+ << JSON_STRING_END
+ << JSON_NAME_SEPARATOR
+ << std::fixed
+ << std::setprecision(6)
+ << (value / 1000000.0);
+ }
+
+
+ std::ostream& _stream;
+ bool _firstTest;
+ };
+}
+
+#undef JSON_OBJECT_BEGIN
+#undef JSON_OBJECT_END
+#undef JSON_ARRAY_BEGIN
+#undef JSON_ARRAY_END
+#undef JSON_STRING_BEGIN
+#undef JSON_STRING_END
+#undef JSON_NAME_SEPARATOR
+#undef JSON_VALUE_SEPARATOR
+#undef JSON_TRUE
+#undef JSON_FALSE
+
+#endif