Index: third_party/google_benchmark/test/output_test.h |
diff --git a/third_party/google_benchmark/test/output_test.h b/third_party/google_benchmark/test/output_test.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..897a13866baecbac465bb89dad04df1dcc92e910 |
--- /dev/null |
+++ b/third_party/google_benchmark/test/output_test.h |
@@ -0,0 +1,201 @@ |
+#ifndef TEST_OUTPUT_TEST_H |
+#define TEST_OUTPUT_TEST_H |
+ |
+#undef NDEBUG |
+#include <initializer_list> |
+#include <memory> |
+#include <string> |
+#include <utility> |
+#include <vector> |
+#include <functional> |
+#include <sstream> |
+ |
+#include "../src/re.h" |
+#include "benchmark/benchmark.h" |
+ |
+#define CONCAT2(x, y) x##y |
+#define CONCAT(x, y) CONCAT2(x, y) |
+ |
+#define ADD_CASES(...) int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__) |
+ |
+#define SET_SUBSTITUTIONS(...) \ |
+ int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__) |
+ |
+enum MatchRules { |
+ MR_Default, // Skip non-matching lines until a match is found. |
+ MR_Next, // Match must occur on the next line. |
+ MR_Not // No line between the current position and the next match matches |
+ // the regex |
+}; |
+ |
+struct TestCase { |
+ TestCase(std::string re, int rule = MR_Default); |
+ |
+ std::string regex_str; |
+ int match_rule; |
+ std::string substituted_regex; |
+ std::shared_ptr<benchmark::Regex> regex; |
+}; |
+ |
+enum TestCaseID { |
+ TC_ConsoleOut, |
+ TC_ConsoleErr, |
+ TC_JSONOut, |
+ TC_JSONErr, |
+ TC_CSVOut, |
+ TC_CSVErr, |
+ |
+ TC_NumID // PRIVATE |
+}; |
+ |
+// Add a list of test cases to be run against the output specified by |
+// 'ID' |
+int AddCases(TestCaseID ID, std::initializer_list<TestCase> il); |
+ |
+// Add or set a list of substitutions to be performed on constructed regex's |
+// See 'output_test_helper.cc' for a list of default substitutions. |
+int SetSubstitutions( |
+ std::initializer_list<std::pair<std::string, std::string>> il); |
+ |
+// Run all output tests. |
+void RunOutputTests(int argc, char* argv[]); |
+ |
+// ========================================================================= // |
+// ------------------------- Results checking ------------------------------ // |
+// ========================================================================= // |
+ |
+// Call this macro to register a benchmark for checking its results. This |
+// should be all that's needed. It subscribes a function to check the (CSV) |
+// results of a benchmark. This is done only after verifying that the output |
+// strings are really as expected. |
+// bm_name_pattern: a name or a regex pattern which will be matched against |
+// all the benchmark names. Matching benchmarks |
+// will be the subject of a call to checker_function |
+// checker_function: should be of type ResultsCheckFn (see below) |
+#define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \ |
+ size_t CONCAT(dummy, __LINE__) = AddChecker(bm_name_pattern, checker_function) |
+ |
+struct Results; |
+typedef std::function< void(Results const&) > ResultsCheckFn; |
+ |
+size_t AddChecker(const char* bm_name_pattern, ResultsCheckFn fn); |
+ |
+// Class holding the results of a benchmark. |
+// It is passed in calls to checker functions. |
+struct Results { |
+ |
+ // the benchmark name |
+ std::string name; |
+ // the benchmark fields |
+ std::map< std::string, std::string > values; |
+ |
+ Results(const std::string& n) : name(n) {} |
+ |
+ int NumThreads() const; |
+ |
+ typedef enum { kCpuTime, kRealTime } BenchmarkTime; |
+ |
+ // get cpu_time or real_time in seconds |
+ double GetTime(BenchmarkTime which) const; |
+ |
+ // get the real_time duration of the benchmark in seconds. |
+ // it is better to use fuzzy float checks for this, as the float |
+ // ASCII formatting is lossy. |
+ double DurationRealTime() const { |
+ return GetAs< double >("iterations") * GetTime(kRealTime); |
+ } |
+ // get the cpu_time duration of the benchmark in seconds |
+ double DurationCPUTime() const { |
+ return GetAs< double >("iterations") * GetTime(kCpuTime); |
+ } |
+ |
+ // get the string for a result by name, or nullptr if the name |
+ // is not found |
+ const std::string* Get(const char* entry_name) const { |
+ auto it = values.find(entry_name); |
+ if(it == values.end()) return nullptr; |
+ return &it->second; |
+ } |
+ |
+ // get a result by name, parsed as a specific type. |
+ // NOTE: for counters, use GetCounterAs instead. |
+ template <class T> |
+ T GetAs(const char* entry_name) const; |
+ |
+ // counters are written as doubles, so they have to be read first |
+ // as a double, and only then converted to the asked type. |
+ template <class T> |
+ T GetCounterAs(const char* entry_name) const { |
+ double dval = GetAs< double >(entry_name); |
+ T tval = static_cast< T >(dval); |
+ return tval; |
+ } |
+}; |
+ |
+template <class T> |
+T Results::GetAs(const char* entry_name) const { |
+ auto *sv = Get(entry_name); |
+ CHECK(sv != nullptr && !sv->empty()); |
+ std::stringstream ss; |
+ ss << *sv; |
+ T out; |
+ ss >> out; |
+ CHECK(!ss.fail()); |
+ return out; |
+} |
+ |
+//---------------------------------- |
+// Macros to help in result checking. Do not use them with arguments causing |
+// side-effects. |
+ |
+#define _CHECK_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value) \ |
+ CONCAT(CHECK_, relationship) \ |
+ (entry.getfn< var_type >(var_name), (value)) << "\n" \ |
+ << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \ |
+ << __FILE__ << ":" << __LINE__ << ": " \ |
+ << "expected (" << #var_type << ")" << (var_name) \ |
+ << "=" << (entry).getfn< var_type >(var_name) \ |
+ << " to be " #relationship " to " << (value) << "\n" |
+ |
+// check with tolerance. eps_factor is the tolerance window, which is |
+// interpreted relative to value (eg, 0.1 means 10% of value). |
+#define _CHECK_FLOAT_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value, eps_factor) \ |
+ CONCAT(CHECK_FLOAT_, relationship) \ |
+ (entry.getfn< var_type >(var_name), (value), (eps_factor) * (value)) << "\n" \ |
+ << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n" \ |
+ << __FILE__ << ":" << __LINE__ << ": " \ |
+ << "expected (" << #var_type << ")" << (var_name) \ |
+ << "=" << (entry).getfn< var_type >(var_name) \ |
+ << " to be " #relationship " to " << (value) << "\n" \ |
+ << __FILE__ << ":" << __LINE__ << ": " \ |
+ << "with tolerance of " << (eps_factor) * (value) \ |
+ << " (" << (eps_factor)*100. << "%), " \ |
+ << "but delta was " << ((entry).getfn< var_type >(var_name) - (value)) \ |
+ << " (" << (((entry).getfn< var_type >(var_name) - (value)) \ |
+ / \ |
+ ((value) > 1.e-5 || value < -1.e-5 ? value : 1.e-5)*100.) \ |
+ << "%)" |
+ |
+#define CHECK_RESULT_VALUE(entry, var_type, var_name, relationship, value) \ |
+ _CHECK_RESULT_VALUE(entry, GetAs, var_type, var_name, relationship, value) |
+ |
+#define CHECK_COUNTER_VALUE(entry, var_type, var_name, relationship, value) \ |
+ _CHECK_RESULT_VALUE(entry, GetCounterAs, var_type, var_name, relationship, value) |
+ |
+#define CHECK_FLOAT_RESULT_VALUE(entry, var_name, relationship, value, eps_factor) \ |
+ _CHECK_FLOAT_RESULT_VALUE(entry, GetAs, double, var_name, relationship, value, eps_factor) |
+ |
+#define CHECK_FLOAT_COUNTER_VALUE(entry, var_name, relationship, value, eps_factor) \ |
+ _CHECK_FLOAT_RESULT_VALUE(entry, GetCounterAs, double, var_name, relationship, value, eps_factor) |
+ |
+// ========================================================================= // |
+// --------------------------- Misc Utilities ------------------------------ // |
+// ========================================================================= // |
+ |
+namespace { |
+ |
+const char* const dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?"; |
+ |
+} // end namespace |
+ |
+#endif // TEST_OUTPUT_TEST_H |