Improve QueueAppender/IOBufQueue performance
[folly.git] / folly / io / test / QueueAppenderBenchmark.cpp
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <folly/Benchmark.h>
18 #include <folly/Format.h>
19 #include <folly/Range.h>
20 #include <folly/io/Cursor.h>
21 #include <folly/io/IOBufQueue.h>
22
23 DECLARE_bool(benchmark);
24
25 using namespace folly::io;
26
27 constexpr size_t kBenchmarkSize = 4096;
28
29 template <class T>
30 void runArithmeticBench(int64_t iters) {
31   while (iters--) {
32     folly::IOBufQueue queue;
33     QueueAppender appender(&queue, kBenchmarkSize);
34     for (size_t i = 0; i < kBenchmarkSize / sizeof(T); ++i) {
35       appender.write((T)0xFB);
36     }
37     folly::doNotOptimizeAway(queue.move());
38   }
39 }
40
41 BENCHMARK(write_uint8, iters) {
42   runArithmeticBench<uint8_t>(iters);
43 }
44
45 BENCHMARK(write_uint16, iters) {
46   runArithmeticBench<uint16_t>(iters);
47 }
48
49 BENCHMARK(write_uint32, iters) {
50   runArithmeticBench<uint32_t>(iters);
51 }
52
53 void runPushBenchmark(int64_t iters, const std::string& str) {
54   constexpr size_t kNumPushPerIter = 1024;
55   while (iters--) {
56     folly::IOBufQueue queue;
57     QueueAppender appender(&queue, kBenchmarkSize);
58     for (size_t i = 0; i < kNumPushPerIter; ++i) {
59       appender.push(reinterpret_cast<const uint8_t*>(str.data()), str.size());
60     }
61     folly::doNotOptimizeAway(queue.move());
62   }
63 }
64
65 BENCHMARK(push_64b, iters) {
66   std::string data;
67   BENCHMARK_SUSPEND {
68     data = std::string(64, 'f');
69   }
70   runPushBenchmark(iters, data);
71 }
72
73 BENCHMARK(push_1024b, iters) {
74   std::string data;
75   BENCHMARK_SUSPEND {
76     data = std::string(1024, 'b');
77   }
78   runPushBenchmark(iters, data);
79 }
80
81 BENCHMARK(append, iters) {
82   constexpr size_t kNumAppendPerIter = 1024;
83
84   std::unique_ptr<folly::IOBuf> largeBuffer;
85   BENCHMARK_SUSPEND {
86     largeBuffer = folly::IOBuf::create(1024);
87     largeBuffer->append(1024);
88   }
89
90   while (iters--) {
91     folly::IOBufQueue queue;
92     QueueAppender appender(&queue, kBenchmarkSize);
93     for (size_t i = 0; i < kNumAppendPerIter; ++i) {
94       appender.insert(largeBuffer->clone());
95     }
96     folly::doNotOptimizeAway(queue.move());
97   }
98 }
99
100 void preallocate_postallocate_bench(int64_t iters, size_t size) {
101   std::string data;
102   BENCHMARK_SUSPEND {
103     data = std::string(size, 'f');
104   }
105   while (iters--) {
106     folly::IOBufQueue queue;
107     for (size_t i = 0; i < kBenchmarkSize; ++i) {
108       auto range = queue.preallocate(size, kBenchmarkSize);
109       memcpy(range.first, data.data(), size);
110       queue.postallocate(size);
111     }
112     folly::doNotOptimizeAway(queue.move());
113   }
114 }
115
116 BENCHMARK(preallocate_postallocate_1b, iters) {
117   preallocate_postallocate_bench(iters, 1);
118 }
119
120 BENCHMARK(preallocate_postallocate_4b, iters) {
121   preallocate_postallocate_bench(iters, 4);
122 }
123
124 BENCHMARK(preallocate_postallocate_32b, iters) {
125   preallocate_postallocate_bench(iters, 32);
126 }
127
128 BENCHMARK(preallocate_postallocate_256b, iters) {
129   preallocate_postallocate_bench(iters, 256);
130 }
131
132 int main(int argc, char** argv) {
133   gflags::ParseCommandLineFlags(&argc, &argv, true);
134   folly::runBenchmarks();
135   return 0;
136 }