Implementing callback functionality for exception routines
[folly.git] / folly / experimental / exception_tracer / test / ExceptionCounterTest.cpp
1 /*
2  * Copyright 2016 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 <stdexcept>
18 #include <typeinfo>
19 #include <thread>
20 #include <mutex>
21 #include <condition_variable>
22 #include <sstream>
23
24 #include <gtest/gtest.h>
25
26 #include <folly/experimental/exception_tracer/ExceptionCounterLib.h>
27
28 struct MyException {};
29
30 void bar() { throw std::runtime_error("hello"); }
31
32 void foo() { throw MyException(); }
33
34 void baz() { foo(); }
35
36 using namespace folly::exception_tracer;
37
38 template <typename F>
39 void throwAndCatch(F f) {
40   try {
41     f();
42   } catch (...) {
43     // ignore
44   }
45 }
46
47 TEST(ExceptionCounter, oneThread) {
48   throwAndCatch(foo);
49   for (int i = 0; i < 10; ++i) {
50     throwAndCatch(bar);
51   }
52
53   auto stats = getExceptionStatistics();
54   EXPECT_EQ(stats.size(), 2);
55   EXPECT_EQ(stats[0].count, 10);
56   EXPECT_EQ(stats[1].count, 1);
57   EXPECT_EQ(*(stats[0].info.type), typeid(std::runtime_error));
58   EXPECT_EQ(*(stats[1].info.type), typeid(MyException));
59 }
60
61 TEST(ExceptionCounter, testClearExceptionStatistics) {
62   throwAndCatch(foo);
63   auto stats = getExceptionStatistics();
64   EXPECT_EQ(stats.size(), 1);
65   stats = getExceptionStatistics();
66   EXPECT_EQ(stats.size(), 0);
67 }
68
69 TEST(ExceptionCounter, testDifferentStacks) {
70   throwAndCatch(foo);
71   throwAndCatch(baz);
72   auto stats = getExceptionStatistics();
73   EXPECT_EQ(stats.size(), 2);
74 }
75
76 TEST(ExceptionCounter, multyThreads) {
77   constexpr size_t kNumIterations = 10000;
78   constexpr size_t kNumThreads = 10;
79   std::vector<std::thread> threads;
80   threads.resize(kNumThreads);
81
82   std::mutex preparedMutex;
83   std::mutex finishedMutex;
84   std::condition_variable preparedBarrier;
85   std::condition_variable finishedBarrier;
86   int preparedThreads = 0;
87   bool finished = false;
88
89   for (auto& t : threads) {
90     t = std::thread([&]() {
91       for (size_t i = 0; i < kNumIterations; ++i) {
92         throwAndCatch(foo);
93       }
94
95       {
96         std::unique_lock<std::mutex> lock(preparedMutex);
97         ++preparedThreads;
98         preparedBarrier.notify_one();
99       }
100
101       std::unique_lock<std::mutex> lock(finishedMutex);
102       finishedBarrier.wait(lock, [&]() { return finished; });
103     });
104   }
105
106   {
107     std::unique_lock<std::mutex> lock(preparedMutex);
108     preparedBarrier.wait(lock,
109                          [&]() { return preparedThreads == kNumThreads; });
110   }
111
112   auto stats = getExceptionStatistics();
113   EXPECT_EQ(stats.size(), 1);
114   EXPECT_EQ(stats[0].count, kNumIterations * kNumThreads);
115
116   {
117     std::unique_lock<std::mutex> lock(finishedMutex);
118     finished = true;
119     finishedBarrier.notify_all();
120   }
121
122   for (auto& t : threads) {
123     t.join();
124   }
125 }