31e28f630a6537a5ae1e58a2b6816b0e035120c8
[folly.git] / folly / test / ExceptionWrapperBenchmark.cpp
1 /*
2  * Copyright 2014 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 (int 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 (int i = 0; i < iters; ++i) {
46     auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
47     assert(ew.get());
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 (int 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 (int i = 0; i < iters; ++i) {
83           auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
84           assert(ew.get());
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 (int 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 (int 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 (int i = 0; i < iters; ++i) {
129     auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
130     std::exception* basePtr = static_cast<std::exception*>(ew.get());
131     auto ep = dynamic_cast<std::runtime_error*>(basePtr);
132     assert(ep);
133   }
134 }
135
136
137 BENCHMARK_DRAW_LINE()
138
139 BENCHMARK(exception_ptr_create_and_throw_concurrent, iters) {
140   std::atomic<bool> go(false);
141   std::vector<std::thread> threads;
142   BENCHMARK_SUSPEND {
143     for (int t = 0; t < FLAGS_num_threads; ++t) {
144       threads.emplace_back([&go, iters] {
145         while (!go) { }
146         std::runtime_error e("payload");
147         for (int i = 0; i < iters; ++i) {
148           auto ep = std::make_exception_ptr(e);
149           try {
150             std::rethrow_exception(ep);
151             assert(false);
152           } catch (std::runtime_error& e) {
153           }
154         }
155       });
156     }
157   }
158   go.store(true);
159   for (auto& t : threads) {
160     t.join();
161   }
162 }
163
164 BENCHMARK_RELATIVE(exception_wrapper_create_and_throw_concurrent, iters) {
165   std::atomic<bool> go(false);
166   std::vector<std::thread> threads;
167   BENCHMARK_SUSPEND {
168     for (int t = 0; t < FLAGS_num_threads; ++t) {
169       threads.emplace_back([&go, iters] {
170         while (!go) { }
171         std::runtime_error e("payload");
172         for (int i = 0; i < iters; ++i) {
173           auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
174           try {
175             ew.throwException();
176             assert(false);
177           } catch (std::runtime_error& e) {
178           }
179         }
180       });
181     }
182   }
183   go.store(true);
184   for (auto& t : threads) {
185     t.join();
186   }
187 }
188
189 BENCHMARK_RELATIVE(exception_wrapper_create_and_cast_concurrent, iters) {
190   std::atomic<bool> go(false);
191   std::vector<std::thread> threads;
192   BENCHMARK_SUSPEND {
193     for (int t = 0; t < FLAGS_num_threads; ++t) {
194       threads.emplace_back([&go, iters] {
195         while (!go) { }
196         std::runtime_error e("payload");
197         for (int i = 0; i < iters; ++i) {
198           auto ew = folly::make_exception_wrapper<std::runtime_error>(e);
199           std::exception* basePtr = static_cast<std::exception*>(ew.get());
200           auto ep = dynamic_cast<std::runtime_error*>(basePtr);
201           assert(ep);
202         }
203       });
204     }
205   }
206   go.store(true);
207   for (auto& t : threads) {
208     t.join();
209   }
210 }
211
212 int main(int argc, char *argv[]) {
213   google::ParseCommandLineFlags(&argc, &argv, true);
214   folly::runBenchmarks();
215   return 0;
216 }
217
218 /*
219 _bin/folly/test/exception_wrapper_benchmark --bm_min_iters=100000
220 ============================================================================
221 folly/test/ExceptionWrapperBenchmark.cpp        relative  time/iter  iters/s
222 ============================================================================
223 exception_ptr_create_and_test                                2.03us  492.88K
224 exception_wrapper_create_and_test               2542.59%    79.80ns   12.53M
225 ----------------------------------------------------------------------------
226 exception_ptr_create_and_test_concurrent                   162.39us    6.16K
227 exception_wrapper_create_and_test_concurrent    95847.91%   169.43ns    5.90M
228 ----------------------------------------------------------------------------
229 exception_ptr_create_and_throw                               4.24us  236.06K
230 exception_wrapper_create_and_throw               141.15%     3.00us  333.20K
231 exception_wrapper_create_and_cast               5321.54%    79.61ns   12.56M
232 ----------------------------------------------------------------------------
233 exception_ptr_create_and_throw_concurrent                  330.88us    3.02K
234 exception_wrapper_create_and_throw_concurrent    143.66%   230.32us    4.34K
235 exception_wrapper_create_and_cast_concurrent    194828.54%   169.83ns    5.89M
236 ============================================================================
237 */