2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/Conv.h>
19 #include <boost/lexical_cast.hpp>
21 #include <folly/Benchmark.h>
22 #include <folly/Foreach.h>
28 using namespace folly;
30 ////////////////////////////////////////////////////////////////////////////////
31 // Benchmarks for ASCII to int conversion
32 ////////////////////////////////////////////////////////////////////////////////
33 // @author: Rajat Goel (rajat)
35 static int64_t handwrittenAtoi(const char* start, const char* end) {
41 throw std::runtime_error("empty string");
44 while (start < end && isspace(*start)) {
57 while (start < end && *start >= '0' && *start <= '9') {
58 auto const newRetVal = retVal * 10 + (*start++ - '0');
59 if (newRetVal < retVal) {
60 throw std::runtime_error("overflow");
66 throw std::runtime_error("extra chars at the end");
69 return positive ? retVal : -retVal;
72 static StringPiece pc1 = "1234567890123456789";
74 void handwrittenAtoiMeasure(unsigned int n, unsigned int digits) {
75 auto p = pc1.subpiece(pc1.size() - digits, digits);
76 FOR_EACH_RANGE(i, 0, n) {
77 doNotOptimizeAway(handwrittenAtoi(p.begin(), p.end()));
81 void follyAtoiMeasure(unsigned int n, unsigned int digits) {
82 auto p = pc1.subpiece(pc1.size() - digits, digits);
83 FOR_EACH_RANGE(i, 0, n) {
84 doNotOptimizeAway(folly::to<int64_t>(p.begin(), p.end()));
88 void clibAtoiMeasure(unsigned int n, unsigned int digits) {
89 auto p = pc1.subpiece(pc1.size() - digits, digits);
90 assert(*p.end() == 0);
91 static_assert(sizeof(long) == 8, "64-bit long assumed");
92 FOR_EACH_RANGE(i, 0, n) { doNotOptimizeAway(atol(p.begin())); }
95 void clibStrtoulMeasure(unsigned int n, unsigned int digits) {
96 auto p = pc1.subpiece(pc1.size() - digits, digits);
97 assert(*p.end() == 0);
99 FOR_EACH_RANGE(i, 0, n) {
100 doNotOptimizeAway(strtoul(p.begin(), &endptr, 10));
104 void lexicalCastMeasure(unsigned int n, unsigned int digits) {
105 auto p = pc1.subpiece(pc1.size() - digits, digits);
106 assert(*p.end() == 0);
107 FOR_EACH_RANGE(i, 0, n) {
108 doNotOptimizeAway(boost::lexical_cast<uint64_t>(p.begin()));
112 // Benchmarks for unsigned to string conversion, raw
114 unsigned u64ToAsciiTable(uint64_t value, char* dst) {
115 static const char digits[201] =
116 "00010203040506070809"
117 "10111213141516171819"
118 "20212223242526272829"
119 "30313233343536373839"
120 "40414243444546474849"
121 "50515253545556575859"
122 "60616263646566676869"
123 "70717273747576777879"
124 "80818283848586878889"
125 "90919293949596979899";
127 uint32_t const length = digits10(value);
128 uint32_t next = length - 1;
129 while (value >= 100) {
130 auto const i = (value % 100) * 2;
132 dst[next] = digits[i + 1];
133 dst[next - 1] = digits[i];
136 // Handle last 1-2 digits
138 dst[next] = '0' + uint32_t(value);
140 auto i = uint32_t(value) * 2;
141 dst[next] = digits[i + 1];
142 dst[next - 1] = digits[i];
147 void u64ToAsciiTableBM(unsigned int n, uint64_t value) {
148 // This is too fast, need to do 10 times per iteration
150 FOR_EACH_RANGE(i, 0, n) {
151 doNotOptimizeAway(u64ToAsciiTable(value + n, buf));
155 unsigned u64ToAsciiClassic(uint64_t value, char* dst) {
157 char* next = (char*)dst;
160 *next++ = '0' + (value % 10);
162 } while (value != 0);
163 unsigned length = next - start;
167 while (next > start) {
177 void u64ToAsciiClassicBM(unsigned int n, uint64_t value) {
178 // This is too fast, need to do 10 times per iteration
180 FOR_EACH_RANGE(i, 0, n) {
181 doNotOptimizeAway(u64ToAsciiClassic(value + n, buf));
185 void u64ToAsciiFollyBM(unsigned int n, uint64_t value) {
186 // This is too fast, need to do 10 times per iteration
188 FOR_EACH_RANGE(i, 0, n) {
189 doNotOptimizeAway(uint64ToBufferUnsafe(value + n, buf));
193 // Benchmark unsigned to string conversion
195 void u64ToStringClibMeasure(unsigned int n, uint64_t value) {
196 // FOLLY_RANGE_CHECK_TO_STRING expands to std::to_string, except on Android
197 // where std::to_string is not supported
198 FOR_EACH_RANGE(i, 0, n) { FOLLY_RANGE_CHECK_TO_STRING(value + n); }
201 void u64ToStringFollyMeasure(unsigned int n, uint64_t value) {
202 FOR_EACH_RANGE(i, 0, n) { to<std::string>(value + n); }
205 // Benchmark uitoa with string append
207 void u2aAppendClassicBM(unsigned int n, uint64_t value) {
209 FOR_EACH_RANGE(i, 0, n) {
210 // auto buf = &s.back() + 1;
212 s.append(buffer, u64ToAsciiClassic(value, buffer));
213 doNotOptimizeAway(s.size());
217 void u2aAppendFollyBM(unsigned int n, uint64_t value) {
219 FOR_EACH_RANGE(i, 0, n) {
220 // auto buf = &s.back() + 1;
222 s.append(buffer, uint64ToBufferUnsafe(value, buffer));
223 doNotOptimizeAway(s.size());
227 template <class String>
228 struct StringIdenticalToBM {
229 StringIdenticalToBM() {}
230 void operator()(unsigned int n, size_t len) const {
232 BENCHMARK_SUSPEND { s.append(len, '0'); }
233 FOR_EACH_RANGE(i, 0, n) {
234 String result = to<String>(s);
235 doNotOptimizeAway(result.size());
240 template <class String>
241 struct StringVariadicToBM {
242 StringVariadicToBM() {}
243 void operator()(unsigned int n, size_t len) const {
245 BENCHMARK_SUSPEND { s.append(len, '0'); }
246 FOR_EACH_RANGE(i, 0, n) {
247 String result = to<String>(s, nullptr);
248 doNotOptimizeAway(result.size());
253 static size_t bigInt = 11424545345345;
254 static size_t smallInt = 104;
255 static char someString[] = "this is some nice string";
256 static char otherString[] = "this is a long string, so it's not so nice";
257 static char reallyShort[] = "meh";
258 static std::string stdString = "std::strings are very nice";
259 static float fValue = 1.2355;
260 static double dValue = 345345345.435;
262 BENCHMARK(preallocateTestNoFloat, n) {
263 for (size_t i = 0; i < n; ++i) {
264 auto val1 = to<std::string>(bigInt, someString, stdString, otherString);
265 auto val3 = to<std::string>(reallyShort, smallInt);
266 auto val2 = to<std::string>(bigInt, stdString);
267 auto val4 = to<std::string>(bigInt, stdString, dValue, otherString);
268 auto val5 = to<std::string>(bigInt, someString, reallyShort);
272 BENCHMARK(preallocateTestFloat, n) {
273 for (size_t i = 0; i < n; ++i) {
274 auto val1 = to<std::string>(stdString, ',', fValue, dValue);
275 auto val2 = to<std::string>(stdString, ',', dValue);
278 BENCHMARK_DRAW_LINE();
280 static const StringIdenticalToBM<std::string> stringIdenticalToBM;
281 static const StringVariadicToBM<std::string> stringVariadicToBM;
282 static const StringIdenticalToBM<fbstring> fbstringIdenticalToBM;
283 static const StringVariadicToBM<fbstring> fbstringVariadicToBM;
285 #define DEFINE_BENCHMARK_GROUP(n) \
286 BENCHMARK_PARAM(u64ToAsciiClassicBM, n); \
287 BENCHMARK_RELATIVE_PARAM(u64ToAsciiTableBM, n); \
288 BENCHMARK_RELATIVE_PARAM(u64ToAsciiFollyBM, n); \
289 BENCHMARK_DRAW_LINE();
291 DEFINE_BENCHMARK_GROUP(1);
292 DEFINE_BENCHMARK_GROUP(12);
293 DEFINE_BENCHMARK_GROUP(123);
294 DEFINE_BENCHMARK_GROUP(1234);
295 DEFINE_BENCHMARK_GROUP(12345);
296 DEFINE_BENCHMARK_GROUP(123456);
297 DEFINE_BENCHMARK_GROUP(1234567);
298 DEFINE_BENCHMARK_GROUP(12345678);
299 DEFINE_BENCHMARK_GROUP(123456789);
300 DEFINE_BENCHMARK_GROUP(1234567890);
301 DEFINE_BENCHMARK_GROUP(12345678901);
302 DEFINE_BENCHMARK_GROUP(123456789012);
303 DEFINE_BENCHMARK_GROUP(1234567890123);
304 DEFINE_BENCHMARK_GROUP(12345678901234);
305 DEFINE_BENCHMARK_GROUP(123456789012345);
306 DEFINE_BENCHMARK_GROUP(1234567890123456);
307 DEFINE_BENCHMARK_GROUP(12345678901234567);
308 DEFINE_BENCHMARK_GROUP(123456789012345678);
309 DEFINE_BENCHMARK_GROUP(1234567890123456789);
310 DEFINE_BENCHMARK_GROUP(12345678901234567890U);
312 #undef DEFINE_BENCHMARK_GROUP
314 #define DEFINE_BENCHMARK_GROUP(n) \
315 BENCHMARK_PARAM(u64ToStringClibMeasure, n); \
316 BENCHMARK_RELATIVE_PARAM(u64ToStringFollyMeasure, n); \
317 BENCHMARK_DRAW_LINE();
319 DEFINE_BENCHMARK_GROUP(1);
320 DEFINE_BENCHMARK_GROUP(12);
321 DEFINE_BENCHMARK_GROUP(123);
322 DEFINE_BENCHMARK_GROUP(1234);
323 DEFINE_BENCHMARK_GROUP(12345);
324 DEFINE_BENCHMARK_GROUP(123456);
325 DEFINE_BENCHMARK_GROUP(1234567);
326 DEFINE_BENCHMARK_GROUP(12345678);
327 DEFINE_BENCHMARK_GROUP(123456789);
328 DEFINE_BENCHMARK_GROUP(1234567890);
329 DEFINE_BENCHMARK_GROUP(12345678901);
330 DEFINE_BENCHMARK_GROUP(123456789012);
331 DEFINE_BENCHMARK_GROUP(1234567890123);
332 DEFINE_BENCHMARK_GROUP(12345678901234);
333 DEFINE_BENCHMARK_GROUP(123456789012345);
334 DEFINE_BENCHMARK_GROUP(1234567890123456);
335 DEFINE_BENCHMARK_GROUP(12345678901234567);
336 DEFINE_BENCHMARK_GROUP(123456789012345678);
337 DEFINE_BENCHMARK_GROUP(1234567890123456789);
338 DEFINE_BENCHMARK_GROUP(12345678901234567890U);
340 #undef DEFINE_BENCHMARK_GROUP
342 #define DEFINE_BENCHMARK_GROUP(n) \
343 BENCHMARK_PARAM(clibAtoiMeasure, n); \
344 BENCHMARK_RELATIVE_PARAM(lexicalCastMeasure, n); \
345 BENCHMARK_RELATIVE_PARAM(handwrittenAtoiMeasure, n); \
346 BENCHMARK_RELATIVE_PARAM(follyAtoiMeasure, n); \
347 BENCHMARK_DRAW_LINE();
349 DEFINE_BENCHMARK_GROUP(1);
350 DEFINE_BENCHMARK_GROUP(2);
351 DEFINE_BENCHMARK_GROUP(3);
352 DEFINE_BENCHMARK_GROUP(4);
353 DEFINE_BENCHMARK_GROUP(5);
354 DEFINE_BENCHMARK_GROUP(6);
355 DEFINE_BENCHMARK_GROUP(7);
356 DEFINE_BENCHMARK_GROUP(8);
357 DEFINE_BENCHMARK_GROUP(9);
358 DEFINE_BENCHMARK_GROUP(10);
359 DEFINE_BENCHMARK_GROUP(11);
360 DEFINE_BENCHMARK_GROUP(12);
361 DEFINE_BENCHMARK_GROUP(13);
362 DEFINE_BENCHMARK_GROUP(14);
363 DEFINE_BENCHMARK_GROUP(15);
364 DEFINE_BENCHMARK_GROUP(16);
365 DEFINE_BENCHMARK_GROUP(17);
366 DEFINE_BENCHMARK_GROUP(18);
367 DEFINE_BENCHMARK_GROUP(19);
369 #undef DEFINE_BENCHMARK_GROUP
371 #define DEFINE_BENCHMARK_GROUP(T, n) \
372 BENCHMARK_PARAM(T##VariadicToBM, n); \
373 BENCHMARK_RELATIVE_PARAM(T##IdenticalToBM, n); \
374 BENCHMARK_DRAW_LINE();
376 DEFINE_BENCHMARK_GROUP(string, 32);
377 DEFINE_BENCHMARK_GROUP(string, 1024);
378 DEFINE_BENCHMARK_GROUP(string, 32768);
379 DEFINE_BENCHMARK_GROUP(fbstring, 32);
380 DEFINE_BENCHMARK_GROUP(fbstring, 1024);
381 DEFINE_BENCHMARK_GROUP(fbstring, 32768);
383 #undef DEFINE_BENCHMARK_GROUP
385 int main(int argc, char** argv) {
386 gflags::ParseCommandLineFlags(&argc, &argv, true);
387 folly::runBenchmarks();