llvm-project/compiler-rt/lib/nsan/nsan_stats.cpp
2024-08-09 16:47:05 -07:00

158 lines
5.0 KiB
C++

//===-- 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_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(); }