diff options
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.cpp | 157 |
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(); } |