xref: /aosp_15_r20/external/libcxx/utils/google-benchmark/test/output_test.h (revision 58b9f456b02922dfdb1fad8a988d5fd8765ecb80)
1*58b9f456SAndroid Build Coastguard Worker #ifndef TEST_OUTPUT_TEST_H
2*58b9f456SAndroid Build Coastguard Worker #define TEST_OUTPUT_TEST_H
3*58b9f456SAndroid Build Coastguard Worker 
4*58b9f456SAndroid Build Coastguard Worker #undef NDEBUG
5*58b9f456SAndroid Build Coastguard Worker #include <functional>
6*58b9f456SAndroid Build Coastguard Worker #include <initializer_list>
7*58b9f456SAndroid Build Coastguard Worker #include <memory>
8*58b9f456SAndroid Build Coastguard Worker #include <sstream>
9*58b9f456SAndroid Build Coastguard Worker #include <string>
10*58b9f456SAndroid Build Coastguard Worker #include <utility>
11*58b9f456SAndroid Build Coastguard Worker #include <vector>
12*58b9f456SAndroid Build Coastguard Worker 
13*58b9f456SAndroid Build Coastguard Worker #include "../src/re.h"
14*58b9f456SAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
15*58b9f456SAndroid Build Coastguard Worker 
16*58b9f456SAndroid Build Coastguard Worker #define CONCAT2(x, y) x##y
17*58b9f456SAndroid Build Coastguard Worker #define CONCAT(x, y) CONCAT2(x, y)
18*58b9f456SAndroid Build Coastguard Worker 
19*58b9f456SAndroid Build Coastguard Worker #define ADD_CASES(...) int CONCAT(dummy, __LINE__) = ::AddCases(__VA_ARGS__)
20*58b9f456SAndroid Build Coastguard Worker 
21*58b9f456SAndroid Build Coastguard Worker #define SET_SUBSTITUTIONS(...) \
22*58b9f456SAndroid Build Coastguard Worker   int CONCAT(dummy, __LINE__) = ::SetSubstitutions(__VA_ARGS__)
23*58b9f456SAndroid Build Coastguard Worker 
24*58b9f456SAndroid Build Coastguard Worker enum MatchRules {
25*58b9f456SAndroid Build Coastguard Worker   MR_Default,  // Skip non-matching lines until a match is found.
26*58b9f456SAndroid Build Coastguard Worker   MR_Next,     // Match must occur on the next line.
27*58b9f456SAndroid Build Coastguard Worker   MR_Not  // No line between the current position and the next match matches
28*58b9f456SAndroid Build Coastguard Worker           // the regex
29*58b9f456SAndroid Build Coastguard Worker };
30*58b9f456SAndroid Build Coastguard Worker 
31*58b9f456SAndroid Build Coastguard Worker struct TestCase {
32*58b9f456SAndroid Build Coastguard Worker   TestCase(std::string re, int rule = MR_Default);
33*58b9f456SAndroid Build Coastguard Worker 
34*58b9f456SAndroid Build Coastguard Worker   std::string regex_str;
35*58b9f456SAndroid Build Coastguard Worker   int match_rule;
36*58b9f456SAndroid Build Coastguard Worker   std::string substituted_regex;
37*58b9f456SAndroid Build Coastguard Worker   std::shared_ptr<benchmark::Regex> regex;
38*58b9f456SAndroid Build Coastguard Worker };
39*58b9f456SAndroid Build Coastguard Worker 
40*58b9f456SAndroid Build Coastguard Worker enum TestCaseID {
41*58b9f456SAndroid Build Coastguard Worker   TC_ConsoleOut,
42*58b9f456SAndroid Build Coastguard Worker   TC_ConsoleErr,
43*58b9f456SAndroid Build Coastguard Worker   TC_JSONOut,
44*58b9f456SAndroid Build Coastguard Worker   TC_JSONErr,
45*58b9f456SAndroid Build Coastguard Worker   TC_CSVOut,
46*58b9f456SAndroid Build Coastguard Worker   TC_CSVErr,
47*58b9f456SAndroid Build Coastguard Worker 
48*58b9f456SAndroid Build Coastguard Worker   TC_NumID  // PRIVATE
49*58b9f456SAndroid Build Coastguard Worker };
50*58b9f456SAndroid Build Coastguard Worker 
51*58b9f456SAndroid Build Coastguard Worker // Add a list of test cases to be run against the output specified by
52*58b9f456SAndroid Build Coastguard Worker // 'ID'
53*58b9f456SAndroid Build Coastguard Worker int AddCases(TestCaseID ID, std::initializer_list<TestCase> il);
54*58b9f456SAndroid Build Coastguard Worker 
55*58b9f456SAndroid Build Coastguard Worker // Add or set a list of substitutions to be performed on constructed regex's
56*58b9f456SAndroid Build Coastguard Worker // See 'output_test_helper.cc' for a list of default substitutions.
57*58b9f456SAndroid Build Coastguard Worker int SetSubstitutions(
58*58b9f456SAndroid Build Coastguard Worker     std::initializer_list<std::pair<std::string, std::string>> il);
59*58b9f456SAndroid Build Coastguard Worker 
60*58b9f456SAndroid Build Coastguard Worker // Run all output tests.
61*58b9f456SAndroid Build Coastguard Worker void RunOutputTests(int argc, char* argv[]);
62*58b9f456SAndroid Build Coastguard Worker 
63*58b9f456SAndroid Build Coastguard Worker // Count the number of 'pat' substrings in the 'haystack' string.
64*58b9f456SAndroid Build Coastguard Worker int SubstrCnt(const std::string& haystack, const std::string& pat);
65*58b9f456SAndroid Build Coastguard Worker 
66*58b9f456SAndroid Build Coastguard Worker // Run registered benchmarks with file reporter enabled, and return the content
67*58b9f456SAndroid Build Coastguard Worker // outputted by the file reporter.
68*58b9f456SAndroid Build Coastguard Worker std::string GetFileReporterOutput(int argc, char* argv[]);
69*58b9f456SAndroid Build Coastguard Worker 
70*58b9f456SAndroid Build Coastguard Worker // ========================================================================= //
71*58b9f456SAndroid Build Coastguard Worker // ------------------------- Results checking ------------------------------ //
72*58b9f456SAndroid Build Coastguard Worker // ========================================================================= //
73*58b9f456SAndroid Build Coastguard Worker 
74*58b9f456SAndroid Build Coastguard Worker // Call this macro to register a benchmark for checking its results. This
75*58b9f456SAndroid Build Coastguard Worker // should be all that's needed. It subscribes a function to check the (CSV)
76*58b9f456SAndroid Build Coastguard Worker // results of a benchmark. This is done only after verifying that the output
77*58b9f456SAndroid Build Coastguard Worker // strings are really as expected.
78*58b9f456SAndroid Build Coastguard Worker // bm_name_pattern: a name or a regex pattern which will be matched against
79*58b9f456SAndroid Build Coastguard Worker //                  all the benchmark names. Matching benchmarks
80*58b9f456SAndroid Build Coastguard Worker //                  will be the subject of a call to checker_function
81*58b9f456SAndroid Build Coastguard Worker // checker_function: should be of type ResultsCheckFn (see below)
82*58b9f456SAndroid Build Coastguard Worker #define CHECK_BENCHMARK_RESULTS(bm_name_pattern, checker_function) \
83*58b9f456SAndroid Build Coastguard Worker   size_t CONCAT(dummy, __LINE__) = AddChecker(bm_name_pattern, checker_function)
84*58b9f456SAndroid Build Coastguard Worker 
85*58b9f456SAndroid Build Coastguard Worker struct Results;
86*58b9f456SAndroid Build Coastguard Worker typedef std::function<void(Results const&)> ResultsCheckFn;
87*58b9f456SAndroid Build Coastguard Worker 
88*58b9f456SAndroid Build Coastguard Worker size_t AddChecker(const char* bm_name_pattern, ResultsCheckFn fn);
89*58b9f456SAndroid Build Coastguard Worker 
90*58b9f456SAndroid Build Coastguard Worker // Class holding the results of a benchmark.
91*58b9f456SAndroid Build Coastguard Worker // It is passed in calls to checker functions.
92*58b9f456SAndroid Build Coastguard Worker struct Results {
93*58b9f456SAndroid Build Coastguard Worker   // the benchmark name
94*58b9f456SAndroid Build Coastguard Worker   std::string name;
95*58b9f456SAndroid Build Coastguard Worker   // the benchmark fields
96*58b9f456SAndroid Build Coastguard Worker   std::map<std::string, std::string> values;
97*58b9f456SAndroid Build Coastguard Worker 
ResultsResults98*58b9f456SAndroid Build Coastguard Worker   Results(const std::string& n) : name(n) {}
99*58b9f456SAndroid Build Coastguard Worker 
100*58b9f456SAndroid Build Coastguard Worker   int NumThreads() const;
101*58b9f456SAndroid Build Coastguard Worker 
102*58b9f456SAndroid Build Coastguard Worker   double NumIterations() const;
103*58b9f456SAndroid Build Coastguard Worker 
104*58b9f456SAndroid Build Coastguard Worker   typedef enum { kCpuTime, kRealTime } BenchmarkTime;
105*58b9f456SAndroid Build Coastguard Worker 
106*58b9f456SAndroid Build Coastguard Worker   // get cpu_time or real_time in seconds
107*58b9f456SAndroid Build Coastguard Worker   double GetTime(BenchmarkTime which) const;
108*58b9f456SAndroid Build Coastguard Worker 
109*58b9f456SAndroid Build Coastguard Worker   // get the real_time duration of the benchmark in seconds.
110*58b9f456SAndroid Build Coastguard Worker   // it is better to use fuzzy float checks for this, as the float
111*58b9f456SAndroid Build Coastguard Worker   // ASCII formatting is lossy.
DurationRealTimeResults112*58b9f456SAndroid Build Coastguard Worker   double DurationRealTime() const {
113*58b9f456SAndroid Build Coastguard Worker     return NumIterations() * GetTime(kRealTime);
114*58b9f456SAndroid Build Coastguard Worker   }
115*58b9f456SAndroid Build Coastguard Worker   // get the cpu_time duration of the benchmark in seconds
DurationCPUTimeResults116*58b9f456SAndroid Build Coastguard Worker   double DurationCPUTime() const {
117*58b9f456SAndroid Build Coastguard Worker     return NumIterations() * GetTime(kCpuTime);
118*58b9f456SAndroid Build Coastguard Worker   }
119*58b9f456SAndroid Build Coastguard Worker 
120*58b9f456SAndroid Build Coastguard Worker   // get the string for a result by name, or nullptr if the name
121*58b9f456SAndroid Build Coastguard Worker   // is not found
GetResults122*58b9f456SAndroid Build Coastguard Worker   const std::string* Get(const char* entry_name) const {
123*58b9f456SAndroid Build Coastguard Worker     auto it = values.find(entry_name);
124*58b9f456SAndroid Build Coastguard Worker     if (it == values.end()) return nullptr;
125*58b9f456SAndroid Build Coastguard Worker     return &it->second;
126*58b9f456SAndroid Build Coastguard Worker   }
127*58b9f456SAndroid Build Coastguard Worker 
128*58b9f456SAndroid Build Coastguard Worker   // get a result by name, parsed as a specific type.
129*58b9f456SAndroid Build Coastguard Worker   // NOTE: for counters, use GetCounterAs instead.
130*58b9f456SAndroid Build Coastguard Worker   template <class T>
131*58b9f456SAndroid Build Coastguard Worker   T GetAs(const char* entry_name) const;
132*58b9f456SAndroid Build Coastguard Worker 
133*58b9f456SAndroid Build Coastguard Worker   // counters are written as doubles, so they have to be read first
134*58b9f456SAndroid Build Coastguard Worker   // as a double, and only then converted to the asked type.
135*58b9f456SAndroid Build Coastguard Worker   template <class T>
GetCounterAsResults136*58b9f456SAndroid Build Coastguard Worker   T GetCounterAs(const char* entry_name) const {
137*58b9f456SAndroid Build Coastguard Worker     double dval = GetAs<double>(entry_name);
138*58b9f456SAndroid Build Coastguard Worker     T tval = static_cast<T>(dval);
139*58b9f456SAndroid Build Coastguard Worker     return tval;
140*58b9f456SAndroid Build Coastguard Worker   }
141*58b9f456SAndroid Build Coastguard Worker };
142*58b9f456SAndroid Build Coastguard Worker 
143*58b9f456SAndroid Build Coastguard Worker template <class T>
GetAs(const char * entry_name)144*58b9f456SAndroid Build Coastguard Worker T Results::GetAs(const char* entry_name) const {
145*58b9f456SAndroid Build Coastguard Worker   auto* sv = Get(entry_name);
146*58b9f456SAndroid Build Coastguard Worker   CHECK(sv != nullptr && !sv->empty());
147*58b9f456SAndroid Build Coastguard Worker   std::stringstream ss;
148*58b9f456SAndroid Build Coastguard Worker   ss << *sv;
149*58b9f456SAndroid Build Coastguard Worker   T out;
150*58b9f456SAndroid Build Coastguard Worker   ss >> out;
151*58b9f456SAndroid Build Coastguard Worker   CHECK(!ss.fail());
152*58b9f456SAndroid Build Coastguard Worker   return out;
153*58b9f456SAndroid Build Coastguard Worker }
154*58b9f456SAndroid Build Coastguard Worker 
155*58b9f456SAndroid Build Coastguard Worker //----------------------------------
156*58b9f456SAndroid Build Coastguard Worker // Macros to help in result checking. Do not use them with arguments causing
157*58b9f456SAndroid Build Coastguard Worker // side-effects.
158*58b9f456SAndroid Build Coastguard Worker 
159*58b9f456SAndroid Build Coastguard Worker // clang-format off
160*58b9f456SAndroid Build Coastguard Worker 
161*58b9f456SAndroid Build Coastguard Worker #define _CHECK_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value) \
162*58b9f456SAndroid Build Coastguard Worker     CONCAT(CHECK_, relationship)                                        \
163*58b9f456SAndroid Build Coastguard Worker     (entry.getfn< var_type >(var_name), (value)) << "\n"                \
164*58b9f456SAndroid Build Coastguard Worker     << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n"     \
165*58b9f456SAndroid Build Coastguard Worker     << __FILE__ << ":" << __LINE__ << ": "                              \
166*58b9f456SAndroid Build Coastguard Worker     << "expected (" << #var_type << ")" << (var_name)                   \
167*58b9f456SAndroid Build Coastguard Worker     << "=" << (entry).getfn< var_type >(var_name)                       \
168*58b9f456SAndroid Build Coastguard Worker     << " to be " #relationship " to " << (value) << "\n"
169*58b9f456SAndroid Build Coastguard Worker 
170*58b9f456SAndroid Build Coastguard Worker // check with tolerance. eps_factor is the tolerance window, which is
171*58b9f456SAndroid Build Coastguard Worker // interpreted relative to value (eg, 0.1 means 10% of value).
172*58b9f456SAndroid Build Coastguard Worker #define _CHECK_FLOAT_RESULT_VALUE(entry, getfn, var_type, var_name, relationship, value, eps_factor) \
173*58b9f456SAndroid Build Coastguard Worker     CONCAT(CHECK_FLOAT_, relationship)                                  \
174*58b9f456SAndroid Build Coastguard Worker     (entry.getfn< var_type >(var_name), (value), (eps_factor) * (value)) << "\n" \
175*58b9f456SAndroid Build Coastguard Worker     << __FILE__ << ":" << __LINE__ << ": " << (entry).name << ":\n"     \
176*58b9f456SAndroid Build Coastguard Worker     << __FILE__ << ":" << __LINE__ << ": "                              \
177*58b9f456SAndroid Build Coastguard Worker     << "expected (" << #var_type << ")" << (var_name)                   \
178*58b9f456SAndroid Build Coastguard Worker     << "=" << (entry).getfn< var_type >(var_name)                       \
179*58b9f456SAndroid Build Coastguard Worker     << " to be " #relationship " to " << (value) << "\n"                \
180*58b9f456SAndroid Build Coastguard Worker     << __FILE__ << ":" << __LINE__ << ": "                              \
181*58b9f456SAndroid Build Coastguard Worker     << "with tolerance of " << (eps_factor) * (value)                   \
182*58b9f456SAndroid Build Coastguard Worker     << " (" << (eps_factor)*100. << "%), "                              \
183*58b9f456SAndroid Build Coastguard Worker     << "but delta was " << ((entry).getfn< var_type >(var_name) - (value)) \
184*58b9f456SAndroid Build Coastguard Worker     << " (" << (((entry).getfn< var_type >(var_name) - (value))         \
185*58b9f456SAndroid Build Coastguard Worker                /                                                        \
186*58b9f456SAndroid Build Coastguard Worker                ((value) > 1.e-5 || value < -1.e-5 ? value : 1.e-5)*100.) \
187*58b9f456SAndroid Build Coastguard Worker     << "%)"
188*58b9f456SAndroid Build Coastguard Worker 
189*58b9f456SAndroid Build Coastguard Worker #define CHECK_RESULT_VALUE(entry, var_type, var_name, relationship, value) \
190*58b9f456SAndroid Build Coastguard Worker     _CHECK_RESULT_VALUE(entry, GetAs, var_type, var_name, relationship, value)
191*58b9f456SAndroid Build Coastguard Worker 
192*58b9f456SAndroid Build Coastguard Worker #define CHECK_COUNTER_VALUE(entry, var_type, var_name, relationship, value) \
193*58b9f456SAndroid Build Coastguard Worker     _CHECK_RESULT_VALUE(entry, GetCounterAs, var_type, var_name, relationship, value)
194*58b9f456SAndroid Build Coastguard Worker 
195*58b9f456SAndroid Build Coastguard Worker #define CHECK_FLOAT_RESULT_VALUE(entry, var_name, relationship, value, eps_factor) \
196*58b9f456SAndroid Build Coastguard Worker     _CHECK_FLOAT_RESULT_VALUE(entry, GetAs, double, var_name, relationship, value, eps_factor)
197*58b9f456SAndroid Build Coastguard Worker 
198*58b9f456SAndroid Build Coastguard Worker #define CHECK_FLOAT_COUNTER_VALUE(entry, var_name, relationship, value, eps_factor) \
199*58b9f456SAndroid Build Coastguard Worker     _CHECK_FLOAT_RESULT_VALUE(entry, GetCounterAs, double, var_name, relationship, value, eps_factor)
200*58b9f456SAndroid Build Coastguard Worker 
201*58b9f456SAndroid Build Coastguard Worker // clang-format on
202*58b9f456SAndroid Build Coastguard Worker 
203*58b9f456SAndroid Build Coastguard Worker // ========================================================================= //
204*58b9f456SAndroid Build Coastguard Worker // --------------------------- Misc Utilities ------------------------------ //
205*58b9f456SAndroid Build Coastguard Worker // ========================================================================= //
206*58b9f456SAndroid Build Coastguard Worker 
207*58b9f456SAndroid Build Coastguard Worker namespace {
208*58b9f456SAndroid Build Coastguard Worker 
209*58b9f456SAndroid Build Coastguard Worker const char* const dec_re = "[0-9]*[.]?[0-9]+([eE][-+][0-9]+)?";
210*58b9f456SAndroid Build Coastguard Worker 
211*58b9f456SAndroid Build Coastguard Worker }  //  end namespace
212*58b9f456SAndroid Build Coastguard Worker 
213*58b9f456SAndroid Build Coastguard Worker #endif  // TEST_OUTPUT_TEST_H
214