Fix copyright lines
[folly.git] / folly / experimental / exception_tracer / ExceptionCounterLib.cpp
index d08971b0d2f146a1eb32676916dc65094d77c900..b4090b1adb58699e184e89c40f74b581025ff9e5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2016-present Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 #include <folly/experimental/exception_tracer/ExceptionCounterLib.h>
 
 #include <iosfwd>
 #include <unordered_map>
 
-#include <folly/RWSpinLock.h>
+#include <folly/Range.h>
 #include <folly/Synchronized.h>
 #include <folly/ThreadLocal.h>
+#include <folly/hash/SpookyHashV2.h>
+#include <folly/synchronization/RWSpinLock.h>
 
 #include <folly/experimental/exception_tracer/ExceptionTracerLib.h>
 #include <folly/experimental/exception_tracer/StackTrace.h>
@@ -31,8 +32,9 @@ using namespace folly::exception_tracer;
 
 namespace {
 
-// We are using hash of the stack trace to uniquely identify the exception
-using ExceptionId = uintptr_t;
+// We use the hash of stack trace and exception type to uniquely
+// identify the exception.
+using ExceptionId = uint64_t;
 
 using ExceptionStatsHolderType =
     std::unordered_map<ExceptionId, ExceptionStats>;
@@ -40,19 +42,12 @@ using ExceptionStatsHolderType =
 struct ExceptionStatsStorage {
   void appendTo(ExceptionStatsHolderType& data) {
     ExceptionStatsHolderType tempHolder;
-    SYNCHRONIZED(statsHolder) {
-      using std::swap;
-      swap(statsHolder, tempHolder);
-    }
+    statsHolder->swap(tempHolder);
 
     for (const auto& myData : tempHolder) {
-      const auto& myStat = myData.second;
-
-      auto it = data.find(myData.first);
-      if (it != data.end()) {
-        it->second.count += myStat.count;
-      } else {
-        data.insert(myData);
+      auto inserted = data.insert(myData);
+      if (!inserted.second) {
+        inserted.first->second.count += myData.second.count;
       }
     }
   }
@@ -77,23 +72,24 @@ std::vector<ExceptionStats> getExceptionStatistics() {
 
   std::vector<ExceptionStats> result;
   result.reserve(accumulator.size());
-  for (const auto& item : accumulator) {
-    result.push_back(item.second);
+  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);
-            });
+  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: " << std::endl;
-  out << "Exception count: " << stats.count << std::endl;
-  out << stats.info;
+  out << "Exception report: \n"
+      << "Exception count: " << stats.count << "\n"
+      << stats.info;
 
   return out;
 }
@@ -108,33 +104,38 @@ namespace {
  * Information is being stored in thread local storage.
  */
 void throwHandler(void*, std::type_info* exType, void (*)(void*)) noexcept {
-  ExceptionInfo info;
-  info.type = exType;
-  auto& frames = info.frames;
-
-  frames.resize(kMaxFrames);
-  auto n = folly::symbolizer::getStackTrace(frames.data(), kMaxFrames);
+  // This array contains the exception type and the stack frame
+  // pointers so they get all hashed together.
+  uintptr_t frames[kMaxFrames + 1];
+  frames[0] = reinterpret_cast<uintptr_t>(exType);
+  auto n = folly::symbolizer::getStackTrace(frames + 1, kMaxFrames);
 
   if (n == -1) {
-    LOG(ERROR) << "Invalid stack frame";
-    return;
+    // If we fail to collect the stack trace for this exception we
+    // just log it under empty stack trace.
+    n = 0;
   }
 
-  frames.resize(n);
-  auto exceptionId = folly::hash::hash_range(frames.begin(), frames.end());
+  auto exceptionId =
+      folly::hash::SpookyHashV2::Hash64(frames, (n + 1) * sizeof(frames[0]), 0);
 
   SYNCHRONIZED(holder, gExceptionStats->statsHolder) {
     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() {
+    registerCxaThrowCallback(throwHandler);
+  }
 };
 
 Initializer initializer;