158 lines · cpp
1//===-- nsan_stats.cc -----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of NumericalStabilitySanitizer.10//11// NumericalStabilitySanitizer statistics.12//===----------------------------------------------------------------------===//13 14#include "nsan_stats.h"15 16#include "sanitizer_common/sanitizer_common.h"17#include "sanitizer_common/sanitizer_placement_new.h"18#include "sanitizer_common/sanitizer_stackdepot.h"19#include "sanitizer_common/sanitizer_stacktrace.h"20#include "sanitizer_common/sanitizer_symbolizer.h"21 22#include <assert.h>23#include <stdio.h>24 25using namespace __sanitizer;26using namespace __nsan;27 28Stats::Stats() {29 check_and_warnings.Initialize(0);30 TrackedLoads.Initialize(0);31}32 33Stats::~Stats() { Printf("deleting nsan stats\n"); }34 35static uptr Key(CheckTypeT CheckType, u32 StackId) {36 return static_cast<uptr>(CheckType) +37 StackId * static_cast<uptr>(CheckTypeT::kMaxCheckType);38}39 40template <typename MapT, typename VectorT, typename Fn>41static void UpdateEntry(CheckTypeT check_ty, uptr pc, uptr bp, MapT *map,42 VectorT *vector, Mutex *mutex, Fn F) {43 BufferedStackTrace Stack;44 Stack.Unwind(pc, bp, nullptr, false);45 u32 stack_id = StackDepotPut(Stack);46 typename MapT::Handle Handle(map, Key(check_ty, stack_id));47 Lock L(mutex);48 if (Handle.created()) {49 typename VectorT::value_type entry;50 entry.stack_id = stack_id;51 entry.check_ty = check_ty;52 F(entry);53 vector->push_back(entry);54 } else {55 auto &entry = (*vector)[*Handle];56 F(entry);57 }58}59 60void Stats::AddCheck(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) {61 UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings,62 &check_and_warning_mutex,63 [rel_err](CheckAndWarningsValue &entry) {64 ++entry.num_checks;65 if (rel_err > entry.max_relative_err) {66 entry.max_relative_err = rel_err;67 }68 });69}70 71void Stats::AddWarning(CheckTypeT check_ty, uptr pc, uptr bp, double rel_err) {72 UpdateEntry(check_ty, pc, bp, &CheckAndWarningsMap, &check_and_warnings,73 &check_and_warning_mutex,74 [rel_err](CheckAndWarningsValue &entry) {75 ++entry.num_warnings;76 if (rel_err > entry.max_relative_err) {77 entry.max_relative_err = rel_err;78 }79 });80}81 82void Stats::AddInvalidLoadTrackingEvent(uptr pc, uptr bp) {83 UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads,84 &TrackedLoadsMutex,85 [](LoadTrackingValue &entry) { ++entry.num_invalid; });86}87 88void Stats::AddUnknownLoadTrackingEvent(uptr pc, uptr bp) {89 UpdateEntry(CheckTypeT::kLoad, pc, bp, &LoadTrackingMap, &TrackedLoads,90 &TrackedLoadsMutex,91 [](LoadTrackingValue &entry) { ++entry.num_unknown; });92}93 94static const char *CheckTypeDisplay(CheckTypeT CheckType) {95 switch (CheckType) {96 case CheckTypeT::kUnknown:97 return "unknown";98 case CheckTypeT::kRet:99 return "return";100 case CheckTypeT::kArg:101 return "argument";102 case CheckTypeT::kLoad:103 return "load";104 case CheckTypeT::kStore:105 return "store";106 case CheckTypeT::kInsert:107 return "vector insert";108 case CheckTypeT::kUser:109 return "user-initiated";110 case CheckTypeT::kFcmp:111 return "fcmp";112 case CheckTypeT::kMaxCheckType:113 return "[max]";114 }115 assert(false && "unknown CheckType case");116 return "";117}118 119void Stats::Print() const {120 {121 Lock L(&check_and_warning_mutex);122 for (const auto &entry : check_and_warnings) {123 Printf("warned %llu times out of %llu %s checks ", entry.num_warnings,124 entry.num_checks, CheckTypeDisplay(entry.check_ty));125 if (entry.num_warnings > 0) {126 char RelErrBuf[64];127 snprintf(RelErrBuf, sizeof(RelErrBuf) - 1, "%f",128 entry.max_relative_err * 100.0);129 Printf("(max relative error: %s%%) ", RelErrBuf);130 }131 Printf("at:\n");132 StackDepotGet(entry.stack_id).Print();133 }134 }135 136 {137 Lock L(&TrackedLoadsMutex);138 u64 TotalInvalidLoadTracking = 0;139 u64 TotalUnknownLoadTracking = 0;140 for (const auto &entry : TrackedLoads) {141 TotalInvalidLoadTracking += entry.num_invalid;142 TotalUnknownLoadTracking += entry.num_unknown;143 Printf("invalid/unknown type for %llu/%llu loads at:\n",144 entry.num_invalid, entry.num_unknown);145 StackDepotGet(entry.stack_id).Print();146 }147 Printf(148 "There were %llu/%llu floating-point loads where the shadow type was "149 "invalid/unknown.\n",150 TotalInvalidLoadTracking, TotalUnknownLoadTracking);151 }152}153 154alignas(64) static char stats_placeholder[sizeof(Stats)];155Stats *__nsan::nsan_stats = nullptr;156 157void __nsan::InitializeStats() { nsan_stats = new (stats_placeholder) Stats(); }158