1 //===-- nsan_stats.cc -----------------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of NumericalStabilitySanitizer.
11 // NumericalStabilitySanitizer statistics.
12 //===----------------------------------------------------------------------===//
14 #include "nsan_stats.h"
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"
25 using namespace __sanitizer
;
26 using namespace __nsan
;
29 check_and_warnings
.Initialize(0);
30 TrackedLoads
.Initialize(0);
33 Stats::~Stats() { Printf("deleting nsan stats\n"); }
35 static uptr
Key(CheckTypeT CheckType
, u32 StackId
) {
36 return static_cast<uptr
>(CheckType
) +
37 StackId
* static_cast<uptr
>(CheckTypeT::kMaxCheckType
);
40 template <typename MapT
, typename VectorT
, typename Fn
>
41 static 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
));
48 if (Handle
.created()) {
49 typename
VectorT::value_type entry
;
50 entry
.stack_id
= stack_id
;
51 entry
.check_ty
= check_ty
;
53 vector
->push_back(entry
);
55 auto &entry
= (*vector
)[*Handle
];
60 void 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
) {
65 if (rel_err
> entry
.max_relative_err
) {
66 entry
.max_relative_err
= rel_err
;
71 void 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
) {
76 if (rel_err
> entry
.max_relative_err
) {
77 entry
.max_relative_err
= rel_err
;
82 void Stats::AddInvalidLoadTrackingEvent(uptr pc
, uptr bp
) {
83 UpdateEntry(CheckTypeT::kLoad
, pc
, bp
, &LoadTrackingMap
, &TrackedLoads
,
85 [](LoadTrackingValue
&entry
) { ++entry
.num_invalid
; });
88 void Stats::AddUnknownLoadTrackingEvent(uptr pc
, uptr bp
) {
89 UpdateEntry(CheckTypeT::kLoad
, pc
, bp
, &LoadTrackingMap
, &TrackedLoads
,
91 [](LoadTrackingValue
&entry
) { ++entry
.num_unknown
; });
94 static const char *CheckTypeDisplay(CheckTypeT CheckType
) {
96 case CheckTypeT::kUnknown
:
98 case CheckTypeT::kRet
:
100 case CheckTypeT::kArg
:
102 case CheckTypeT::kLoad
:
104 case CheckTypeT::kStore
:
106 case CheckTypeT::kInsert
:
107 return "vector insert";
108 case CheckTypeT::kUser
:
109 return "user-initiated";
110 case CheckTypeT::kFcmp
:
112 case CheckTypeT::kMaxCheckType
:
115 assert(false && "unknown CheckType case");
119 void Stats::Print() const {
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) {
127 snprintf(RelErrBuf
, sizeof(RelErrBuf
) - 1, "%f",
128 entry
.max_relative_err
* 100.0);
129 Printf("(max relative error: %s%%) ", RelErrBuf
);
132 StackDepotGet(entry
.stack_id
).Print();
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();
148 "There were %llu/%llu floating-point loads where the shadow type was "
149 "invalid/unknown.\n",
150 TotalInvalidLoadTracking
, TotalUnknownLoadTracking
);
154 alignas(64) static char stats_placeholder
[sizeof(Stats
)];
155 Stats
*__nsan::nsan_stats
= nullptr;
157 void __nsan::InitializeStats() { nsan_stats
= new (stats_placeholder
) Stats(); }