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