ExceptionCounterLib.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. #include <folly/experimental/exception_tracer/ExceptionCounterLib.h>
  17. #include <iosfwd>
  18. #include <unordered_map>
  19. #include <folly/Range.h>
  20. #include <folly/Synchronized.h>
  21. #include <folly/ThreadLocal.h>
  22. #include <folly/hash/SpookyHashV2.h>
  23. #include <folly/synchronization/RWSpinLock.h>
  24. #include <folly/experimental/exception_tracer/ExceptionTracerLib.h>
  25. #include <folly/experimental/exception_tracer/StackTrace.h>
  26. #include <folly/experimental/symbolizer/Symbolizer.h>
  27. using namespace folly::exception_tracer;
  28. namespace {
  29. // We use the hash of stack trace and exception type to uniquely
  30. // identify the exception.
  31. using ExceptionId = uint64_t;
  32. using ExceptionStatsHolderType =
  33. std::unordered_map<ExceptionId, ExceptionStats>;
  34. struct ExceptionStatsStorage {
  35. void appendTo(ExceptionStatsHolderType& data) {
  36. ExceptionStatsHolderType tempHolder;
  37. statsHolder->swap(tempHolder);
  38. for (const auto& myData : tempHolder) {
  39. auto inserted = data.insert(myData);
  40. if (!inserted.second) {
  41. inserted.first->second.count += myData.second.count;
  42. }
  43. }
  44. }
  45. folly::Synchronized<ExceptionStatsHolderType, folly::RWSpinLock> statsHolder;
  46. };
  47. class Tag {};
  48. folly::ThreadLocal<ExceptionStatsStorage, Tag> gExceptionStats;
  49. } // namespace
  50. namespace folly {
  51. namespace exception_tracer {
  52. std::vector<ExceptionStats> getExceptionStatistics() {
  53. ExceptionStatsHolderType accumulator;
  54. for (auto& threadStats : gExceptionStats.accessAllThreads()) {
  55. threadStats.appendTo(accumulator);
  56. }
  57. std::vector<ExceptionStats> result;
  58. result.reserve(accumulator.size());
  59. for (auto& item : accumulator) {
  60. result.push_back(std::move(item.second));
  61. }
  62. std::sort(
  63. result.begin(),
  64. result.end(),
  65. [](const ExceptionStats& lhs, const ExceptionStats& rhs) {
  66. return lhs.count > rhs.count;
  67. });
  68. return result;
  69. }
  70. std::ostream& operator<<(std::ostream& out, const ExceptionStats& stats) {
  71. out << "Exception report: \n"
  72. << "Exception count: " << stats.count << "\n"
  73. << stats.info;
  74. return out;
  75. }
  76. } // namespace exception_tracer
  77. } // namespace folly
  78. namespace {
  79. /*
  80. * This handler gathers statistics on all exceptions thrown by the program
  81. * Information is being stored in thread local storage.
  82. */
  83. void throwHandler(void*, std::type_info* exType, void (*)(void*)) noexcept {
  84. // This array contains the exception type and the stack frame
  85. // pointers so they get all hashed together.
  86. uintptr_t frames[kMaxFrames + 1];
  87. frames[0] = reinterpret_cast<uintptr_t>(exType);
  88. auto n = folly::symbolizer::getStackTrace(frames + 1, kMaxFrames);
  89. if (n == -1) {
  90. // If we fail to collect the stack trace for this exception we
  91. // just log it under empty stack trace.
  92. n = 0;
  93. }
  94. auto exceptionId =
  95. folly::hash::SpookyHashV2::Hash64(frames, (n + 1) * sizeof(frames[0]), 0);
  96. gExceptionStats->statsHolder.withWLock([&](auto& holder) {
  97. auto it = holder.find(exceptionId);
  98. if (it != holder.end()) {
  99. ++it->second.count;
  100. } else {
  101. ExceptionInfo info;
  102. info.type = exType;
  103. info.frames.assign(frames + 1, frames + 1 + n);
  104. holder.emplace(exceptionId, ExceptionStats{1, std::move(info)});
  105. }
  106. });
  107. }
  108. struct Initializer {
  109. Initializer() {
  110. registerCxaThrowCallback(throwHandler);
  111. }
  112. };
  113. Initializer initializer;
  114. } // namespace