blob: 54dbedd35357772d786d121d85cda71a16831b0b [file] [log] [blame]
Austin Schuh36244a12019-09-21 17:52:38 -07001// Copyright 2018 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 <random>
17#include <string>
18#include <type_traits>
19#include <vector>
20
21#include "benchmark/benchmark.h"
22#include "absl/base/internal/raw_logging.h"
23#include "absl/strings/numbers.h"
24
25namespace {
26
27template <typename T>
28void BM_FastIntToBuffer(benchmark::State& state) {
29 const int inc = state.range(0);
30 char buf[absl::numbers_internal::kFastToBufferSize];
31 // Use the unsigned type to increment to take advantage of well-defined
32 // modular arithmetic.
33 typename std::make_unsigned<T>::type x = 0;
34 for (auto _ : state) {
35 absl::numbers_internal::FastIntToBuffer(static_cast<T>(x), buf);
36 x += inc;
37 }
38}
39BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int32_t)->Range(0, 1 << 15);
40BENCHMARK_TEMPLATE(BM_FastIntToBuffer, int64_t)->Range(0, 1 << 30);
41
42// Creates an integer that would be printed as `num_digits` repeated 7s in the
43// given `base`. `base` must be greater than or equal to 8.
44int64_t RepeatedSevens(int num_digits, int base) {
45 ABSL_RAW_CHECK(base >= 8, "");
46 int64_t num = 7;
47 while (--num_digits) num = base * num + 7;
48 return num;
49}
50
51void BM_safe_strto32_string(benchmark::State& state) {
52 const int digits = state.range(0);
53 const int base = state.range(1);
54 std::string str(digits, '7'); // valid in octal, decimal and hex
55 int32_t value = 0;
56 for (auto _ : state) {
57 benchmark::DoNotOptimize(
58 absl::numbers_internal::safe_strto32_base(str, &value, base));
59 }
60 ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
61}
62BENCHMARK(BM_safe_strto32_string)
63 ->ArgPair(1, 8)
64 ->ArgPair(1, 10)
65 ->ArgPair(1, 16)
66 ->ArgPair(2, 8)
67 ->ArgPair(2, 10)
68 ->ArgPair(2, 16)
69 ->ArgPair(4, 8)
70 ->ArgPair(4, 10)
71 ->ArgPair(4, 16)
72 ->ArgPair(8, 8)
73 ->ArgPair(8, 10)
74 ->ArgPair(8, 16)
75 ->ArgPair(10, 8)
76 ->ArgPair(9, 10);
77
78void BM_safe_strto64_string(benchmark::State& state) {
79 const int digits = state.range(0);
80 const int base = state.range(1);
81 std::string str(digits, '7'); // valid in octal, decimal and hex
82 int64_t value = 0;
83 for (auto _ : state) {
84 benchmark::DoNotOptimize(
85 absl::numbers_internal::safe_strto64_base(str, &value, base));
86 }
87 ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
88}
89BENCHMARK(BM_safe_strto64_string)
90 ->ArgPair(1, 8)
91 ->ArgPair(1, 10)
92 ->ArgPair(1, 16)
93 ->ArgPair(2, 8)
94 ->ArgPair(2, 10)
95 ->ArgPair(2, 16)
96 ->ArgPair(4, 8)
97 ->ArgPair(4, 10)
98 ->ArgPair(4, 16)
99 ->ArgPair(8, 8)
100 ->ArgPair(8, 10)
101 ->ArgPair(8, 16)
102 ->ArgPair(16, 8)
103 ->ArgPair(16, 10)
104 ->ArgPair(16, 16);
105
106void BM_safe_strtou32_string(benchmark::State& state) {
107 const int digits = state.range(0);
108 const int base = state.range(1);
109 std::string str(digits, '7'); // valid in octal, decimal and hex
110 uint32_t value = 0;
111 for (auto _ : state) {
112 benchmark::DoNotOptimize(
113 absl::numbers_internal::safe_strtou32_base(str, &value, base));
114 }
115 ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
116}
117BENCHMARK(BM_safe_strtou32_string)
118 ->ArgPair(1, 8)
119 ->ArgPair(1, 10)
120 ->ArgPair(1, 16)
121 ->ArgPair(2, 8)
122 ->ArgPair(2, 10)
123 ->ArgPair(2, 16)
124 ->ArgPair(4, 8)
125 ->ArgPair(4, 10)
126 ->ArgPair(4, 16)
127 ->ArgPair(8, 8)
128 ->ArgPair(8, 10)
129 ->ArgPair(8, 16)
130 ->ArgPair(10, 8)
131 ->ArgPair(9, 10);
132
133void BM_safe_strtou64_string(benchmark::State& state) {
134 const int digits = state.range(0);
135 const int base = state.range(1);
136 std::string str(digits, '7'); // valid in octal, decimal and hex
137 uint64_t value = 0;
138 for (auto _ : state) {
139 benchmark::DoNotOptimize(
140 absl::numbers_internal::safe_strtou64_base(str, &value, base));
141 }
142 ABSL_RAW_CHECK(value == RepeatedSevens(digits, base), "");
143}
144BENCHMARK(BM_safe_strtou64_string)
145 ->ArgPair(1, 8)
146 ->ArgPair(1, 10)
147 ->ArgPair(1, 16)
148 ->ArgPair(2, 8)
149 ->ArgPair(2, 10)
150 ->ArgPair(2, 16)
151 ->ArgPair(4, 8)
152 ->ArgPair(4, 10)
153 ->ArgPair(4, 16)
154 ->ArgPair(8, 8)
155 ->ArgPair(8, 10)
156 ->ArgPair(8, 16)
157 ->ArgPair(16, 8)
158 ->ArgPair(16, 10)
159 ->ArgPair(16, 16);
160
161// Returns a vector of `num_strings` strings. Each string represents a
162// floating point number with `num_digits` digits before the decimal point and
163// another `num_digits` digits after.
164std::vector<std::string> MakeFloatStrings(int num_strings, int num_digits) {
165 // For convenience, use a random number generator to generate the test data.
166 // We don't actually need random properties, so use a fixed seed.
167 std::minstd_rand0 rng(1);
168 std::uniform_int_distribution<int> random_digit('0', '9');
169
170 std::vector<std::string> float_strings(num_strings);
171 for (std::string& s : float_strings) {
172 s.reserve(2 * num_digits + 1);
173 for (int i = 0; i < num_digits; ++i) {
174 s.push_back(static_cast<char>(random_digit(rng)));
175 }
176 s.push_back('.');
177 for (int i = 0; i < num_digits; ++i) {
178 s.push_back(static_cast<char>(random_digit(rng)));
179 }
180 }
181 return float_strings;
182}
183
184template <typename StringType>
185StringType GetStringAs(const std::string& s) {
186 return static_cast<StringType>(s);
187}
188template <>
189const char* GetStringAs<const char*>(const std::string& s) {
190 return s.c_str();
191}
192
193template <typename StringType>
194std::vector<StringType> GetStringsAs(const std::vector<std::string>& strings) {
195 std::vector<StringType> result;
196 result.reserve(strings.size());
197 for (const std::string& s : strings) {
198 result.push_back(GetStringAs<StringType>(s));
199 }
200 return result;
201}
202
203template <typename T>
204void BM_SimpleAtof(benchmark::State& state) {
205 const int num_strings = state.range(0);
206 const int num_digits = state.range(1);
207 std::vector<std::string> backing_strings =
208 MakeFloatStrings(num_strings, num_digits);
209 std::vector<T> inputs = GetStringsAs<T>(backing_strings);
210 float value;
211 for (auto _ : state) {
212 for (const T& input : inputs) {
213 benchmark::DoNotOptimize(absl::SimpleAtof(input, &value));
214 }
215 }
216}
217BENCHMARK_TEMPLATE(BM_SimpleAtof, absl::string_view)
218 ->ArgPair(10, 1)
219 ->ArgPair(10, 2)
220 ->ArgPair(10, 4)
221 ->ArgPair(10, 8);
222BENCHMARK_TEMPLATE(BM_SimpleAtof, const char*)
223 ->ArgPair(10, 1)
224 ->ArgPair(10, 2)
225 ->ArgPair(10, 4)
226 ->ArgPair(10, 8);
227BENCHMARK_TEMPLATE(BM_SimpleAtof, std::string)
228 ->ArgPair(10, 1)
229 ->ArgPair(10, 2)
230 ->ArgPair(10, 4)
231 ->ArgPair(10, 8);
232
233template <typename T>
234void BM_SimpleAtod(benchmark::State& state) {
235 const int num_strings = state.range(0);
236 const int num_digits = state.range(1);
237 std::vector<std::string> backing_strings =
238 MakeFloatStrings(num_strings, num_digits);
239 std::vector<T> inputs = GetStringsAs<T>(backing_strings);
240 double value;
241 for (auto _ : state) {
242 for (const T& input : inputs) {
243 benchmark::DoNotOptimize(absl::SimpleAtod(input, &value));
244 }
245 }
246}
247BENCHMARK_TEMPLATE(BM_SimpleAtod, absl::string_view)
248 ->ArgPair(10, 1)
249 ->ArgPair(10, 2)
250 ->ArgPair(10, 4)
251 ->ArgPair(10, 8);
252BENCHMARK_TEMPLATE(BM_SimpleAtod, const char*)
253 ->ArgPair(10, 1)
254 ->ArgPair(10, 2)
255 ->ArgPair(10, 4)
256 ->ArgPair(10, 8);
257BENCHMARK_TEMPLATE(BM_SimpleAtod, std::string)
258 ->ArgPair(10, 1)
259 ->ArgPair(10, 2)
260 ->ArgPair(10, 4)
261 ->ArgPair(10, 8);
262
263} // namespace