According to Does try-catch block decrease performance, I understand that if we wrap some rarely throw codes into a try catch block, there is almost no cost, since compilers tend to optimize for the normal path. However, if an exception should throw, there will be a larger penalty.
I write the following codes to verify this
#include <iostream>
#include <stdexcept>
#include <exception>
#include <thread>
#include <chrono>
#include <cstdio>
#include <vector>
using std::chrono::high_resolution_clock;
using std::chrono::duration_cast;
using std::chrono::duration;
using std::chrono::milliseconds;
std::vector<int> global_vec;
int exception_call_all_throw_inner(int a) {
throw std::runtime_error("throw");
return 1;
}
int exception_all_throw_call(int & a) {
try
{
exception_call_all_throw_inner(a);
} catch (...) {
a = (a + 1) % 10000;
if (a % 100 == 0) {
global_vec.push_back(a);
}
if (a == 9999) {
global_vec.clear();
}
if (a % 100 == 55) {
a += global_vec.size();
}
}
return a;
}
int exception_call_no_throw_inner(int a) {
if (a == 10010) {
// Which will never happen
throw std::runtime_error("prevent optimization");
}
return 1;
}
int exception_no_throw_call(int & a) {
a = (a + 1) % 10000;
if (a % 100 == 0) {
global_vec.push_back(a);
}
if (a == 9999) {
global_vec.clear();
}
try
{
exception_call_no_throw_inner(a);
} catch (...) {
printf("error");
}
if (a % 100 == 55) {
a += global_vec.size();
}
return a;
}
int no_exception_call(int & a) {
a = (a + 1) % 10000;
if (a % 100 == 0) {
global_vec.push_back(a);
}
if (a == 9999) {
global_vec.clear();
}
if (a % 100 == 55) {
a += global_vec.size();
}
return a;
}
template<typename F>
int loop_main(F f) {
int a = 1;
global_vec.clear();
for(int i = 0; i < 19999933; i++) {
f(a);
}
printf("%d\n", a);
return 0;
}
int main() {
int ms_inte_no;
int ms_inte_all;
int ms_intnoe;
{
auto t1 = high_resolution_clock::now();
loop_main(exception_no_throw_call);
auto t2 = high_resolution_clock::now();
ms_inte_no = duration_cast<milliseconds>(t2 - t1).count();
printf("exception no throw cost %d vec %lu\n", ms_inte_no, global_vec.size());
}
{
auto t1 = high_resolution_clock::now();
loop_main(exception_all_throw_call);
auto t2 = high_resolution_clock::now();
ms_inte_all = duration_cast<milliseconds>(t2 - t1).count();
printf("exception all throw cost %d vec %lu\n", ms_inte_all, global_vec.size());
}
{
auto t1 = high_resolution_clock::now();
loop_main(no_exception_call);
auto t2 = high_resolution_clock::now();
ms_intnoe = duration_cast<milliseconds>(t2 - t1).count();
printf("no exception cost %d vec %lu\n", ms_intnoe, global_vec.size());
}
printf("loss exception no throw %f\n", (ms_inte_no - ms_intnoe) * 1.0 / ms_intnoe);
printf("loss exception all throw %f\n", (ms_inte_all - ms_intnoe) * 1.0 / ms_intnoe);
}
And I compile and run it with -O2
, and find the above post is true. The cost of normal path is quite low, however, the penalty of exception path is very high.
./exception_test
1619
exception no throw cost 118 vec 45
1619
exception all throw cost 21453 vec 45
1619
no exception cost 114 vec 45
loss exception no throw 0.035088
loss exception all throw 187.184211
Though my test is very extreme, we either all throw or no throw. However, I wonder if the exception is more often to be thrown, is there any way that we can somehow reduce the penalty of the exception path?