mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 12:06:36 +00:00
158 lines
5.0 KiB
C++
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(); }
|