1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstdint>
16 #include <cstring>
17
18 #include "benchmark/benchmark.h"
19 #include "absl/algorithm/algorithm.h"
20
21 namespace {
22
23 // The range of sequence sizes to benchmark.
24 constexpr int kMinBenchmarkSize = 1024;
25 constexpr int kMaxBenchmarkSize = 8 * 1024 * 1024;
26
27 // A user-defined type for use in equality benchmarks. Note that we expect
28 // std::memcmp to win for this type: libstdc++'s std::equal only defers to
29 // memcmp for integral types. This is because it is not straightforward to
30 // guarantee that std::memcmp would produce a result "as-if" compared by
31 // operator== for other types (example gotchas: NaN floats, structs with
32 // padding).
33 struct EightBits {
EightBits__anon5bc12b9d0111::EightBits34 explicit EightBits(int /* unused */) : data(0) {}
operator ==__anon5bc12b9d0111::EightBits35 bool operator==(const EightBits& rhs) const { return data == rhs.data; }
36 uint8_t data;
37 };
38
39 template <typename T>
BM_absl_equal_benchmark(benchmark::State & state)40 void BM_absl_equal_benchmark(benchmark::State& state) {
41 std::vector<T> xs(state.range(0), T(0));
42 std::vector<T> ys = xs;
43 while (state.KeepRunning()) {
44 const bool same = absl::equal(xs.begin(), xs.end(), ys.begin(), ys.end());
45 benchmark::DoNotOptimize(same);
46 }
47 }
48
49 template <typename T>
BM_std_equal_benchmark(benchmark::State & state)50 void BM_std_equal_benchmark(benchmark::State& state) {
51 std::vector<T> xs(state.range(0), T(0));
52 std::vector<T> ys = xs;
53 while (state.KeepRunning()) {
54 const bool same = std::equal(xs.begin(), xs.end(), ys.begin());
55 benchmark::DoNotOptimize(same);
56 }
57 }
58
59 template <typename T>
BM_memcmp_benchmark(benchmark::State & state)60 void BM_memcmp_benchmark(benchmark::State& state) {
61 std::vector<T> xs(state.range(0), T(0));
62 std::vector<T> ys = xs;
63 while (state.KeepRunning()) {
64 const bool same =
65 std::memcmp(xs.data(), ys.data(), xs.size() * sizeof(T)) == 0;
66 benchmark::DoNotOptimize(same);
67 }
68 }
69
70 // The expectation is that the compiler should be able to elide the equality
71 // comparison altogether for sufficiently simple types.
72 template <typename T>
BM_absl_equal_self_benchmark(benchmark::State & state)73 void BM_absl_equal_self_benchmark(benchmark::State& state) {
74 std::vector<T> xs(state.range(0), T(0));
75 while (state.KeepRunning()) {
76 const bool same = absl::equal(xs.begin(), xs.end(), xs.begin(), xs.end());
77 benchmark::DoNotOptimize(same);
78 }
79 }
80
81 BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint8_t)
82 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
83 BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint8_t)
84 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
85 BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint8_t)
86 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
87 BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint8_t)
88 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
89
90 BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint16_t)
91 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
92 BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint16_t)
93 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
94 BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint16_t)
95 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
96 BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint16_t)
97 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
98
99 BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint32_t)
100 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
101 BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint32_t)
102 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
103 BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint32_t)
104 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
105 BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint32_t)
106 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
107
108 BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, uint64_t)
109 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
110 BENCHMARK_TEMPLATE(BM_std_equal_benchmark, uint64_t)
111 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
112 BENCHMARK_TEMPLATE(BM_memcmp_benchmark, uint64_t)
113 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
114 BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, uint64_t)
115 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
116
117 BENCHMARK_TEMPLATE(BM_absl_equal_benchmark, EightBits)
118 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
119 BENCHMARK_TEMPLATE(BM_std_equal_benchmark, EightBits)
120 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
121 BENCHMARK_TEMPLATE(BM_memcmp_benchmark, EightBits)
122 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
123 BENCHMARK_TEMPLATE(BM_absl_equal_self_benchmark, EightBits)
124 ->Range(kMinBenchmarkSize, kMaxBenchmarkSize);
125
126 } // namespace
127