summaryrefslogtreecommitdiff
path: root/util/benchmark.h
blob: d97b49e17f4cb091455d06cd8717e081119caf27 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright 2009 The RE2 Authors.  All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef UTIL_BENCHMARK_H_
#define UTIL_BENCHMARK_H_

#include <stdint.h>
#include <functional>

#include "util/logging.h"
#include "util/util.h"

// Globals for the old benchmark API.
void StartBenchmarkTiming();
void StopBenchmarkTiming();
void SetBenchmarkBytesProcessed(int64_t b);
void SetBenchmarkItemsProcessed(int64_t i);

namespace benchmark {

// The new benchmark API implemented as a layer over the old benchmark API.
// (Please refer to https://github.com/google/benchmark for documentation.)
class State {
 private:
  class Iterator {
   public:
    // Benchmark code looks like this:
    //
    //   for (auto _ : state) {
    //     // ...
    //   }
    //
    // We try to avoid compiler warnings about such variables being unused.
    struct ATTRIBUTE_UNUSED Value {};

    explicit Iterator(int64_t iters) : iters_(iters) {}

    bool operator!=(const Iterator& that) const {
      if (iters_ != that.iters_) {
        return true;
      } else {
        // We are about to stop the loop, so stop timing.
        StopBenchmarkTiming();
        return false;
      }
    }

    Value operator*() const {
      return Value();
    }

    Iterator& operator++() {
      --iters_;
      return *this;
    }

   private:
    int64_t iters_;
  };

 public:
  explicit State(int64_t iters)
      : iters_(iters), arg_(0), has_arg_(false) {}

  State(int64_t iters, int64_t arg)
      : iters_(iters), arg_(arg), has_arg_(true) {}

  Iterator begin() {
    // We are about to start the loop, so start timing.
    StartBenchmarkTiming();
    return Iterator(iters_);
  }

  Iterator end() {
    return Iterator(0);
  }

  void SetBytesProcessed(int64_t b) { SetBenchmarkBytesProcessed(b); }
  void SetItemsProcessed(int64_t i) { SetBenchmarkItemsProcessed(i); }
  int64_t iterations() const { return iters_; }
  // Pretend to support multiple arguments.
  int64_t range(int pos) const { CHECK(has_arg_); return arg_; }

 private:
  int64_t iters_;
  int64_t arg_;
  bool has_arg_;

  State(const State&) = delete;
  State& operator=(const State&) = delete;
};

}  // namespace benchmark

namespace testing {

class Benchmark {
 public:
  Benchmark(const char* name, void (*func)(benchmark::State&))
      : name_(name),
        func_([func](int iters, int arg) {
          benchmark::State state(iters);
          func(state);
        }),
        lo_(0),
        hi_(0),
        has_arg_(false) {
    Register();
  }

  Benchmark(const char* name, void (*func)(benchmark::State&), int lo, int hi)
      : name_(name),
        func_([func](int iters, int arg) {
          benchmark::State state(iters, arg);
          func(state);
        }),
        lo_(lo),
        hi_(hi),
        has_arg_(true) {
    Register();
  }

  // Pretend to support multiple threads.
  Benchmark* ThreadRange(int lo, int hi) { return this; }

  const char* name() const { return name_; }
  const std::function<void(int, int)>& func() const { return func_; }
  int lo() const { return lo_; }
  int hi() const { return hi_; }
  bool has_arg() const { return has_arg_; }

 private:
  void Register();

  const char* name_;
  std::function<void(int, int)> func_;
  int lo_;
  int hi_;
  bool has_arg_;

  Benchmark(const Benchmark&) = delete;
  Benchmark& operator=(const Benchmark&) = delete;
};

}  // namespace testing

#define BENCHMARK(f)                     \
  ::testing::Benchmark* _benchmark_##f = \
      (new ::testing::Benchmark(#f, f))

#define BENCHMARK_RANGE(f, lo, hi)       \
  ::testing::Benchmark* _benchmark_##f = \
      (new ::testing::Benchmark(#f, f, lo, hi))

#endif  // UTIL_BENCHMARK_H_