#include <folly/debugging/exception_tracer/ExceptionCounterLib.h>
#include <iosfwd>
#include <unordered_map>
#include <folly/Range.h>
#include <folly/Synchronized.h>
#include <folly/ThreadLocal.h>
#include <folly/hash/SpookyHashV2.h>
#include <folly/synchronization/RWSpinLock.h>
#include <folly/debugging/exception_tracer/ExceptionTracerLib.h>
#include <folly/debugging/exception_tracer/StackTrace.h>
#include <folly/experimental/symbolizer/Symbolizer.h>
#if FOLLY_HAVE_ELF && FOLLY_HAVE_DWARF
#if defined(__GLIBCXX__)
using namespace folly::exception_tracer;
namespace {
using ExceptionId = uint64_t;
using ExceptionStatsHolderType =
std::unordered_map<ExceptionId, ExceptionStats>;
struct ExceptionStatsStorage {
void appendTo(ExceptionStatsHolderType& data) {
ExceptionStatsHolderType tempHolder;
statsHolder.wlock()->swap(tempHolder);
for (const auto& myData : tempHolder) {
auto inserted = data.insert(myData);
if (!inserted.second) {
inserted.first->second.count += myData.second.count;
}
}
}
folly::Synchronized<ExceptionStatsHolderType, folly::RWSpinLock> statsHolder;
};
class Tag {};
folly::ThreadLocal<ExceptionStatsStorage, Tag> gExceptionStats;
}
namespace folly {
namespace exception_tracer {
std::vector<ExceptionStats> getExceptionStatistics() {
ExceptionStatsHolderType accumulator;
for (auto& threadStats : gExceptionStats.accessAllThreads()) {
threadStats.appendTo(accumulator);
}
std::vector<ExceptionStats> result;
result.reserve(accumulator.size());
for (auto& item : accumulator) {
result.push_back(std::move(item.second));
}
std::sort(
result.begin(),
result.end(),
[](const ExceptionStats& lhs, const ExceptionStats& rhs) {
return lhs.count > rhs.count;
});
return result;
}
std::ostream& operator<<(std::ostream& out, const ExceptionStats& stats) {
out << "Exception report: \n"
<< "Exception count: " << stats.count << "\n"
<< stats.info;
return out;
}
}
}
namespace {
void throwHandler(void*, std::type_info* exType, void (**)(void*)) noexcept {
uintptr_t frames[kMaxFrames + 1];
frames[0] = reinterpret_cast<uintptr_t>(exType);
auto n = folly::symbolizer::getStackTrace(frames + 1, kMaxFrames);
if (n == -1) {
n = 0;
}
auto exceptionId =
folly::hash::SpookyHashV2::Hash64(frames, (n + 1) * sizeof(frames[0]), 0);
gExceptionStats->statsHolder.withWLock([&](auto& holder) {
auto it = holder.find(exceptionId);
if (it != holder.end()) {
++it->second.count;
} else {
ExceptionInfo info;
info.type = exType;
info.frames.assign(frames + 1, frames + 1 + n);
holder.emplace(exceptionId, ExceptionStats{1, std::move(info)});
}
});
}
struct Initializer {
Initializer() { registerCxaThrowCallback(throwHandler); }
};
Initializer initializer;
}
#endif
#endif