aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp')
-rw-r--r--contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp157
1 files changed, 157 insertions, 0 deletions
diff --git a/contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp b/contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp
new file mode 100644
index 000000000000..d188df1b1f70
--- /dev/null
+++ b/contrib/llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp
@@ -0,0 +1,157 @@
+//===-- nsan_stats.cc -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of NumericalStabilitySanitizer.
+//
+// NumericalStabilitySanitizer statistics.
+//===----------------------------------------------------------------------===//
+
+#include "nsan/nsan_stats.h"
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_symbolizer.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+using namespace __sanitizer;
+using namespace __nsan;
+
+Stats::Stats() {
+ check_and_warnings.Initialize(0);
+ TrackedLoads.Initialize(0);
+}
+
+Stats::~Stats() { Printf("deleting nsan stats\n"); }
+
+static uptr Key(CheckTypeT CheckType, u32 StackId) {
+ return static_cast<uptr>(CheckType) +
+ StackId * static_cast<uptr>(CheckTypeT::kMaxCheckType);
+}
+
+template <typename MapT, typename VectorT, typename Fn>
+static void UpdateEntry(CheckTypeT check_ty, uptr pc, uptr bp, MapT *map,
+ VectorT *vector, Mutex *mutex, Fn F) {
+ BufferedStackTrace Stack;
+ Stack.Unwind(pc, bp, nullptr, false);
+ u32 stack_id = StackDepotPut(Stack);
+ typename MapT::Handle Handle(map, Key(check_ty, stack_id));
+ Lock L(mutex);
+ if (Handle.created()) {
+ typename VectorT::value_type entry;
+ entry.stack_id = stack_id;
+ entry.check_ty = check_ty;
+ F(entry);
+ vector->push_back(entry);
+ } else {
+ auto &entry = (*vector)[*Handle];
+ F(entry);
+ }
+}
+
+void Stats::AddCheck(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) {
+ UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings,
+ &check_and_warning_mutex,
+ [rel_err](CheckAndWarningsValue &entry) {
+ ++entry.num_checks;
+ if (rel_err > entry.max_relative_err) {
+ entry.max_relative_err = rel_err;
+ }
+ });
+}
+
+void Stats::AddWarning(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) {
+ UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings,
+ &check_and_warning_mutex,
+ [rel_err](CheckAndWarningsValue &entry) {
+ ++entry.num_warnings;
+ if (rel_err > entry.max_relative_err) {
+ entry.max_relative_err = rel_err;
+ }
+ });
+}
+
+void Stats::AddInvalidLoadTrackingEvent(uptr pc, uptr bp) {
+ UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads,
+ &TrackedLoadsMutex,
+ [](LoadTrackingValue &entry) { ++entry.num_invalid; });
+}
+
+void Stats::AddUnknownLoadTrackingEvent(uptr pc, uptr bp) {
+ UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads,
+ &TrackedLoadsMutex,
+ [](LoadTrackingValue &entry) { ++entry.num_unknown; });
+}
+
+static const char *CheckTypeDisplay(CheckTypeT CheckType) {
+ switch (CheckType) {
+ case CheckTypeT::kUnknown:
+ return "unknown";
+ case CheckTypeT::kRet:
+ return "return";
+ case CheckTypeT::kArg:
+ return "argument";
+ case CheckTypeT::kLoad:
+ return "load";
+ case CheckTypeT::kStore:
+ return "store";
+ case CheckTypeT::kInsert:
+ return "vector insert";
+ case CheckTypeT::kUser:
+ return "user-initiated";
+ case CheckTypeT::kFcmp:
+ return "fcmp";
+ case CheckTypeT::kMaxCheckType:
+ return "[max]";
+ }
+ assert(false && "unknown CheckType case");
+ return "";
+}
+
+void Stats::Print() const {
+ {
+ Lock L(&check_and_warning_mutex);
+ for (const auto &entry : check_and_warnings) {
+ Printf("warned %llu times out of %llu %s checks ", entry.num_warnings,
+ entry.num_checks, CheckTypeDisplay(entry.check_ty));
+ if (entry.num_warnings > 0) {
+ char RelErrBuf[64];
+ snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%f",
+ entry.max_relative_err * 100.0);
+ Printf("(max relative error: %s%%) ", RelErrBuf);
+ }
+ Printf("at:\n");
+ StackDepotGet(entry.stack_id).Print();
+ }
+ }
+
+ {
+ Lock L(&TrackedLoadsMutex);
+ u64 TotalInvalidLoadTracking = 0;
+ u64 TotalUnknownLoadTracking = 0;
+ for (const auto &entry : TrackedLoads) {
+ TotalInvalidLoadTracking += entry.num_invalid;
+ TotalUnknownLoadTracking += entry.num_unknown;
+ Printf("invalid/unknown type for %llu/%llu loads at:\n",
+ entry.num_invalid, entry.num_unknown);
+ StackDepotGet(entry.stack_id).Print();
+ }
+ Printf(
+ "There were %llu/%llu floating-point loads where the shadow type was "
+ "invalid/unknown.\n",
+ TotalInvalidLoadTracking, TotalUnknownLoadTracking);
+ }
+}
+
+alignas(64) static char stats_placeholder[sizeof(Stats)];
+Stats *__nsan::nsan_stats = nullptr;
+
+void __nsan::InitializeStats() { nsan_stats = new (stats_placeholder) Stats(); }