Copyright 2014->2015
[folly.git] / folly / test / ExceptionWrapperBenchmark.cpp
1 /*
2  * Copyright 2015 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 #include <folly/ExceptionWrapper.h>
17
18 #include <gflags/gflags.h>
19 #include <atomic>
20 #include <exception>
21 #include <vector>
22 #include <stdexcept>
23 #include <thread>
24
25 #include <folly/Benchmark.h>
26
27 DEFINE_int32(num_threads, 32, "Number of threads to run concurrency "
28                               "benchmarks");
29
30 /*
31  * Use case 1: Library wraps errors in either exception_wrapper or
32  * exception_ptr, but user does not care what the exception is after learning
33  * that there is one.
34  */
35 BENCHMARK(exception_ptr_create_and_test, iters) {
36   std::runtime_error e("payload");
37   for (size_t i = 0; i < iters; ++i) {
38     auto ep = std::make_exception_ptr(e);
39     assert(ep);
40   }
41 }
42
43 BENCHMARK_RELATIVE(exception_wrapper_create_and_test, iters) {
44   std::runtime_error e("payload");
45   for (size_t i = 0; i < iters; ++i) {
46     auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
47     assert(ew);
48   }
49 }
50
51 BENCHMARK_DRAW_LINE()
52
53 BENCHMARK(exception_ptr_create_and_test_concurrent, iters) {
54   std::atomic<bool> go(false);
55   std::vector<std::thread> threads;
56   BENCHMARK_SUSPEND {
57     for (int t = 0; t < FLAGS_num_threads; ++t) {
58       threads.emplace_back([&go, iters] {
59         while (!go) { }
60         std::runtime_error e("payload");
61         for (size_t i = 0; i < iters; ++i) {
62           auto ep = std::make_exception_ptr(e);
63           assert(ep);
64         }
65       });
66     }
67   }
68   go.store(true);
69   for (auto& t : threads) {
70     t.join();
71   }
72 }
73
74 BENCHMARK_RELATIVE(exception_wrapper_create_and_test_concurrent, iters) {
75   std::atomic<bool> go(false);
76   std::vector<std::thread> threads;
77   BENCHMARK_SUSPEND {
78     for (int t = 0; t < FLAGS_num_threads; ++t) {
79       threads.emplace_back([&go, iters] {
80         while (!go) { }
81         std::runtime_error e("payload");
82         for (size_t i = 0; i < iters; ++i) {
83           auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
84           assert(ew);
85         }
86       });
87     }
88   }
89   go.store(true);
90   for (auto& t : threads) {
91     t.join();
92   }
93 }
94
95 BENCHMARK_DRAW_LINE()
96
97 /*
98  * Use case 2: Library wraps errors in either exception_wrapper or
99  * exception_ptr, and user wants to handle std::runtime_error. This can be done
100  * either by rehtrowing or with dynamic_cast.
101  */
102 BENCHMARK(exception_ptr_create_and_throw, iters) {
103   std::runtime_error e("payload");
104   for (size_t i = 0; i < iters; ++i) {
105     auto ep = std::make_exception_ptr(e);
106     try {
107       std::rethrow_exception(ep);
108       assert(false);
109     } catch (std::runtime_error& e) {
110     }
111   }
112 }
113
114 BENCHMARK_RELATIVE(exception_wrapper_create_and_throw, iters) {
115   std::runtime_error e("payload");
116   for (size_t i = 0; i < iters; ++i) {
117     auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
118     try {
119       ew.throwException();
120       assert(false);
121     } catch (std::runtime_error& e) {
122     }
123   }
124 }
125
126 BENCHMARK_RELATIVE(exception_wrapper_create_and_cast, iters) {
127   std::runtime_error e("payload");
128   for (size_t i = 0; i < iters; ++i) {
129     auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
130     assert(ew.is_compatible_with<std::runtime_error>());
131   }
132 }
133
134
135 BENCHMARK_DRAW_LINE()
136
137 BENCHMARK(exception_ptr_create_and_throw_concurrent, iters) {
138   std::atomic<bool> go(false);
139   std::vector<std::thread> threads;
140   BENCHMARK_SUSPEND {
141     for (int t = 0; t < FLAGS_num_threads; ++t) {
142       threads.emplace_back([&go, iters] {
143         while (!go) { }
144         std::runtime_error e("payload");
145         for (size_t i = 0; i < iters; ++i) {
146           auto ep = std::make_exception_ptr(e);
147           try {
148             std::rethrow_exception(ep);
149             assert(false);
150           } catch (std::runtime_error& e) {
151           }
152         }
153       });
154     }
155   }
156   go.store(true);
157   for (auto& t : threads) {
158     t.join();
159   }
160 }
161
162 BENCHMARK_RELATIVE(exception_wrapper_create_and_throw_concurrent, iters) {
163   std::atomic<bool> go(false);
164   std::vector<std::thread> threads;
165   BENCHMARK_SUSPEND {
166     for (int t = 0; t < FLAGS_num_threads; ++t) {
167       threads.emplace_back([&go, iters] {
168         while (!go) { }
169         std::runtime_error e("payload");
170         for (size_t i = 0; i < iters; ++i) {
171           auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
172           try {
173             ew.throwException();
174             assert(false);
175           } catch (std::runtime_error& e) {
176           }
177         }
178       });
179     }
180   }
181   go.store(true);
182   for (auto& t : threads) {
183     t.join();
184   }
185 }
186
187 BENCHMARK_RELATIVE(exception_wrapper_create_and_cast_concurrent, iters) {
188   std::atomic<bool> go(false);
189   std::vector<std::thread> threads;
190   BENCHMARK_SUSPEND {
191     for (int t = 0; t < FLAGS_num_threads; ++t) {
192       threads.emplace_back([&go, iters] {
193         while (!go) { }
194         std::runtime_error e("payload");
195         for (size_t i = 0; i < iters; ++i) {
196           auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
197           assert(ew.is_compatible_with<std::runtime_error>());
198         }
199       });
200     }
201   }
202   go.store(true);
203   for (auto& t : threads) {
204     t.join();
205   }
206 }
207
208 int main(int argc, char *argv[]) {
209   gflags::ParseCommandLineFlags(&argc, &argv, true);
210   folly::runBenchmarks();
211   return 0;
212 }
213
214 /*
215 _bin/folly/test/exception_wrapper_benchmark --bm_min_iters=100000
216 ============================================================================
217 folly/test/ExceptionWrapperBenchmark.cpp        relative  time/iter  iters/s
218 ============================================================================
219 exception_ptr_create_and_test                                2.03us  492.88K
220 exception_wrapper_create_and_test               2542.59%    79.80ns   12.53M
221 ----------------------------------------------------------------------------
222 exception_ptr_create_and_test_concurrent                   162.39us    6.16K
223 exception_wrapper_create_and_test_concurrent    95847.91%   169.43ns    5.90M
224 ----------------------------------------------------------------------------
225 exception_ptr_create_and_throw                               4.24us  236.06K
226 exception_wrapper_create_and_throw               141.15%     3.00us  333.20K
227 exception_wrapper_create_and_cast               5321.54%    79.61ns   12.56M
228 ----------------------------------------------------------------------------
229 exception_ptr_create_and_throw_concurrent                  330.88us    3.02K
230 exception_wrapper_create_and_throw_concurrent    143.66%   230.32us    4.34K
231 exception_wrapper_create_and_cast_concurrent    194828.54%   169.83ns    5.89M
232 ============================================================================
233 */