2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <folly/experimental/exception_tracer/ExceptionCounterLib.h>
20 #include <unordered_map>
22 #include <folly/RWSpinLock.h>
23 #include <folly/Synchronized.h>
24 #include <folly/ThreadLocal.h>
26 #include <folly/experimental/exception_tracer/ExceptionTracerLib.h>
27 #include <folly/experimental/exception_tracer/StackTrace.h>
28 #include <folly/experimental/symbolizer/Symbolizer.h>
30 using namespace folly::exception_tracer;
34 // We are using hash of the stack trace to uniquely identify the exception
35 using ExceptionId = uintptr_t;
37 using ExceptionStatsHolderType =
38 std::unordered_map<ExceptionId, ExceptionStats>;
40 struct ExceptionStatsStorage {
41 void appendTo(ExceptionStatsHolderType& data) {
42 ExceptionStatsHolderType tempHolder;
43 SYNCHRONIZED(statsHolder) {
45 swap(statsHolder, tempHolder);
48 for (const auto& myData : tempHolder) {
49 const auto& myStat = myData.second;
51 auto it = data.find(myData.first);
52 if (it != data.end()) {
53 it->second.count += myStat.count;
60 folly::Synchronized<ExceptionStatsHolderType, folly::RWSpinLock> statsHolder;
65 folly::ThreadLocal<ExceptionStatsStorage, Tag> gExceptionStats;
70 namespace exception_tracer {
72 std::vector<ExceptionStats> getExceptionStatistics() {
73 ExceptionStatsHolderType accumulator;
74 for (auto& threadStats : gExceptionStats.accessAllThreads()) {
75 threadStats.appendTo(accumulator);
78 std::vector<ExceptionStats> result;
79 result.reserve(accumulator.size());
80 for (const auto& item : accumulator) {
81 result.push_back(item.second);
84 std::sort(result.begin(),
86 [](const ExceptionStats& lhs, const ExceptionStats& rhs) {
87 return (lhs.count > rhs.count);
93 std::ostream& operator<<(std::ostream& out, const ExceptionStats& stats) {
94 out << "Exception report: " << std::endl;
95 out << "Exception count: " << stats.count << std::endl;
101 } // namespace exception_tracer
107 * This handler gathers statistics on all exceptions thrown by the program
108 * Information is being stored in thread local storage.
110 void throwHandler(void*, std::type_info* exType, void (*)(void*)) noexcept {
113 auto& frames = info.frames;
115 frames.resize(kMaxFrames);
116 auto n = folly::symbolizer::getStackTrace(frames.data(), kMaxFrames);
119 LOG(ERROR) << "Invalid stack frame";
124 auto exceptionId = folly::hash::hash_range(frames.begin(), frames.end());
126 SYNCHRONIZED(holder, gExceptionStats->statsHolder) {
127 auto it = holder.find(exceptionId);
128 if (it != holder.end()) {
131 holder.emplace(exceptionId, ExceptionStats{1, std::move(info)});
137 Initializer() { registerCxaThrowCallback(throwHandler); }
140 Initializer initializer;