1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BENCHMARKS_BENCHMARK_H_
18 #define BENCHMARKS_BENCHMARK_H_
19 
20 #include <regex.h>
21 #include <stdint.h>
22 
23 #include <string>
24 #include <vector>
25 
26 namespace testing {
27 
28 class Benchmark {
29 public:
Benchmark()30   Benchmark() {
31     List().push_back(this);
32   }
~Benchmark()33   virtual ~Benchmark() {}
34 
35   virtual std::string Name() = 0;
36 
37   virtual size_t RunAllArgs(std::vector<regex_t*>&) = 0;
38 
SetBenchmarkBytesProcessed(uint64_t bytes)39   void SetBenchmarkBytesProcessed(uint64_t bytes) { bytes_processed_ += bytes; }
40   void StopBenchmarkTiming();
41   void StartBenchmarkTiming();
42 
43   // Run all of the benchmarks that have registered.
44   static size_t RunAll(std::vector<regex_t*>&);
45 
46   static std::vector<Benchmark*>& List();
47 
48   static int MaxNameColumnWidth();
49 
50 protected:
51   virtual size_t NameColumnWidth() = 0;
52 
53   uint64_t bytes_processed_;
54   uint64_t total_time_ns_;
55   uint64_t start_time_ns_;
56 
57   static bool header_printed_;
58 
59   static void PrintHeader();
60 };
61 
62 template <typename T>
63 class BenchmarkT : public Benchmark {
64 public:
BenchmarkT()65   BenchmarkT() {}
~BenchmarkT()66   virtual ~BenchmarkT() {}
67 
68 protected:
69   bool ShouldRun(std::vector<regex_t*>&, T arg);
70   void RunWithArg(T arg);
71   virtual void RunIterations(int, T) = 0;
72   virtual std::string GetNameStr(T) = 0;
73 };
74 
75 class BenchmarkWithoutArg : public BenchmarkT<void*> {
76 public:
BenchmarkWithoutArg()77   BenchmarkWithoutArg() {}
~BenchmarkWithoutArg()78   virtual ~BenchmarkWithoutArg() {}
79 
80 protected:
RunAllArgs(std::vector<regex_t * > & regs)81   virtual size_t RunAllArgs(std::vector<regex_t*>& regs) override {
82     size_t benchmarks_run = 0;
83     if (BenchmarkT<void*>::ShouldRun(regs, nullptr)) {
84       PrintHeader();
85       RunWithArg(nullptr);
86       benchmarks_run++;
87     }
88     return benchmarks_run;
89   }
90 
RunIterations(int iters,void *)91   virtual void RunIterations(int iters, void*) override {
92     Run(iters);
93   }
94 
95   virtual void Run(int) = 0;
96 
NameColumnWidth()97   virtual size_t NameColumnWidth() override {
98     return Name().size();
99   }
100 
101   virtual std::string GetNameStr(void *) override;
102 };
103 
104 template<typename T>
105 class BenchmarkWithArg : public BenchmarkT<T> {
106 public:
BenchmarkWithArg()107   BenchmarkWithArg() {}
~BenchmarkWithArg()108   virtual ~BenchmarkWithArg() {}
109 
Arg(T arg)110   BenchmarkWithArg* Arg(T arg) {
111     args_.push_back(arg);
112     return this;
113   }
114 
115 protected:
NameColumnWidth()116   virtual size_t NameColumnWidth() override {
117     size_t max = 0;
118     for (const auto& arg : args_) {
119       max = std::max(max, GetNameStr(arg).size());
120     }
121     return max;
122   }
123 
124   std::string GetNameStr(T arg) override;
125 
RunAllArgs(std::vector<regex_t * > & regs)126   virtual size_t RunAllArgs(std::vector<regex_t*>& regs) override {
127     size_t benchmarks_run = 0;
128     for (T& arg : args_) {
129       if (BenchmarkT<T>::ShouldRun(regs, arg)) {
130         Benchmark::PrintHeader();
131         BenchmarkT<T>::RunWithArg(arg);
132         benchmarks_run++;
133       }
134     }
135     return benchmarks_run;
136   }
137 
RunIterations(int iters,T arg)138   virtual void RunIterations(int iters, T arg) override {
139     Run(iters, arg);
140   }
141 
142   virtual void Run(int iters, T arg) = 0;
143 
144 private:
145   std::vector<T> args_;
146 };
147 
148 }  // namespace testing
149 
150 #define BENCHMARK_START(f, super_class) \
151   class f : public super_class { \
152   public: \
153     f() {} \
154     virtual ~f() {} \
155     virtual std::string Name() override { return #f; } \
156 
157 #define BENCHMARK_NO_ARG(f) \
158   BENCHMARK_START(f, ::testing::BenchmarkWithoutArg) \
159     virtual void Run(int) override; \
160   }; \
161   static ::testing::Benchmark* __benchmark_##f = new f()
162 
163 #define BENCHMARK_WITH_ARG(f, arg_type) \
164   BENCHMARK_START(f, ::testing::BenchmarkWithArg<arg_type>) \
165     virtual void Run(int, arg_type) override; \
166   }; \
167   static ::testing::BenchmarkWithArg<arg_type>* __benchmark_##f = (new f())
168 
169 #endif  // BENCHMARKS_BENCHMARK_H_
170