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