ATLAS Offline Software
Loading...
Searching...
No Matches
FPEAuditor.cxx
Go to the documentation of this file.
1
2
3/*
4 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
5*/
6
7// FPEAuditor.cxx
8// Implementation file for class FPEAuditor
9// Author: S.Binet<binet@cern.ch>
11
12#include <stdexcept>
13#include <mutex>
14#include <atomic>
15
16// FrameWork includes
17#include "GaudiKernel/INamedInterface.h"
18#include "GaudiKernel/EventContext.h"
19
20#include "FPEAuditor.h"
21
23
24// C includes
25#include <fenv.h>
26
27
28namespace FPEAudit {
29 const int MAXARRAY=100;
35
37
38 std::atomic<bool> s_handlerInstalled = false;
39 std::atomic<bool> s_handlerDisabled = false;
40 struct sigaction s_oldactHandler ATLAS_THREAD_SAFE;
41
42 std::mutex s_mutex;
43 typedef std::lock_guard<std::mutex> lock_t;
44}
45
46
47#if defined(__linux__) && ( defined(__i386__) || defined(__x86_64__) )
48# include "FPEAudit_linux.icc"
49#else
50# include "FPEAudit_dummy.icc"
51#endif
52
53
55// Public methods:
57
58// Constructors
60FPEAuditor::FPEAuditor( const std::string& name,
61 ISvcLocator* pSvcLocator ) :
62 AthCommonMsg<Auditor> ( name, pSvcLocator ),
64 m_env(),
66{
67 declareProperty("NStacktracesOnFPE", m_NstacktracesOnFPE,
68 "Flag to configure, how many stack traces in case of FPE are printed. "
69 "Default: Zero, just report that FPE has happened. "
70 "After collecting the stacktrace, the code has to modify the mcontext_t "
71 "struct to ignore FPEs for the rest of the processing of the algorithm/service "
72 "This part is highly non-portable!" );
73
74 declareProperty("Nstacklines", m_Nstacklines,"Limit how deep we dive into the stack");
75}
76
77// Destructor
79#include <fstream>
80#include <iomanip>
82{
83 //m_msg << MSG::DEBUG << "Calling destructor" << endmsg;
84}
85
87{
88 for ( unsigned int i(0); i<FPEAUDITOR_ARRAYSIZE; ++i )
89 m_CountFPEs[i]=0;
90 //ATH_MSG_INFO("==> initialize");
91 // add a fake node here because we may come alive while the AuditorSvc is
92 // still initializing (so one edge is left orphaned)
94
95 return StatusCode::SUCCESS;
96}
97
99{
100 ATH_MSG_INFO("FPE summary for this job");
101 ATH_MSG_INFO(" FPE OVERFLOWs : " << m_CountFPEs[FPEAUDITOR_OVERFLOW] );
102 ATH_MSG_INFO(" FPE INVALIDs : " << m_CountFPEs[FPEAUDITOR_INVALID]);
103 ATH_MSG_INFO(" FPE DIVBYZEROs : " << m_CountFPEs[FPEAUDITOR_DIVBYZERO]);
104
105 {
109 }
110
111 return StatusCode::SUCCESS;
112}
113
115{
116 // Save the current FP environment.
117 fegetenv (&m_env);
118
119#ifdef __aarch64__
120 ATH_MSG_WARNING("Collecting stack traces for FPES is not supported on aarch64");
124#else
125 struct sigaction act;
126 memset(&act, 0, sizeof act);
127 act.sa_sigaction = FPEAudit::fpe_sig_action;
128 act.sa_flags = SA_SIGINFO;
129 if ( sigaction(SIGFPE, &act, &FPEAudit::s_oldactHandler) != 0 )
130 {
131 ATH_MSG_WARNING ("Printing stacktraces on FPE requested, but unable to install signal handler ! Switched off !");
133 }
135 {
136 ATH_MSG_INFO ("Installed Signalhandler !");
137 FPEAudit::unmask_fpe();
138 }
139 FPEAudit::s_tlsdata.s_array_O[0]=NULL;
140 FPEAudit::s_tlsdata.s_array_I[0]=NULL;
141 FPEAudit::s_tlsdata.s_array_D[0]=NULL;
142
144#endif
145}
146
148{
149 ATH_MSG_INFO("uninstalling SignalHandler");
151
152 feclearexcept(FE_ALL_EXCEPT);
153 fesetenv (&m_env);
154 FPEAudit::mask_fpe();
155
156 // feenableexcept (0);
157 // fedisableexcept (FE_ALL_EXCEPT);
158}
159
160void FPEAuditor::before(const std::string& event, const std::string& /*name*/,
161 const EventContext&)
162{
163 add_fpe_node();
164
165 if ( event==IAuditor::Execute ) {
171 }
172 }
173 }
174}
175
176void FPEAuditor::after(const std::string& event, const std::string& name,
177 const EventContext& ctx, const StatusCode&)
178{
179 report_fpe(event, name, ctx);
180 pop_fpe_node();
181
182 if ( event==IAuditor::Initialize ) {
184 // CoreDumpSvc can also install a FPE handler, grrr.
185 if (name == "CoreDumpSvc") FPEAudit::s_handlerInstalled = false;
189 }
190 }
191}
192
195void
196FPEAuditor::report_fpe(const std::string& step,
197 const std::string& caller,
198 const EventContext& ctx)
199{
200 // store current list of FPE flags which were raised before
201 int raised = fetestexcept(FE_OVERFLOW | FE_INVALID | FE_DIVBYZERO);
202 if (raised) {
203 std::stringstream evStr;
204 if (ctx.valid()) {
205 evStr << " on event " << ctx.eventID().event_number();
206 }
207
208 if (raised & FE_OVERFLOW) {
209 ATH_MSG_WARNING("FPE OVERFLOW in [" << step << "] of [" << caller << "]" << evStr.str() <<
210 " " << m_NstacktracesOnFPE << " " << FPEAudit::s_tlsdata.s_array_O[0]
211 );
213 if ( m_NstacktracesOnFPE && FPEAudit::s_tlsdata.s_array_O[0] != NULL )
214 {
215 for (unsigned int j = 0; j < m_Nstacklines; j++)
216 {
218 if (FPEAudit::s_tlsdata.s_array_O[j]==NULL) break;
219 this->msg(MSG::INFO) << "FPE stacktrace " << j << " :\n";
220 FPEAudit::resolve(FPEAudit::s_tlsdata.s_array_O[j],this->msg());
221 FPEAudit::s_tlsdata.s_array_O[j]=NULL;
222 this->msg(MSG::INFO) << endmsg;
223 }
224 }
225 }
226 if (raised & FE_INVALID) {
227 ATH_MSG_WARNING("FPE INVALID in [" << step << "] of [" << caller << "]" << evStr.str()
228 << " " << m_NstacktracesOnFPE << " " << FPEAudit::s_tlsdata.s_array_I[0]
229 );
231 }
232 if ( m_NstacktracesOnFPE && FPEAudit::s_tlsdata.s_array_I[0] != NULL )
233 {
234 for (unsigned int j = 0; j < m_Nstacklines; j++)
235 {
237 if (FPEAudit::s_tlsdata.s_array_I[j]==NULL) break;
238 this->msg(MSG::INFO) << "FPE stacktrace " << j << " :\n";
239 FPEAudit::resolve(FPEAudit::s_tlsdata.s_array_I[j],this->msg());
240 FPEAudit::s_tlsdata.s_array_I[j]=NULL;
241 this->msg(MSG::INFO) << endmsg;
242 }
243 }
244 if (raised & FE_DIVBYZERO) {
245 ATH_MSG_WARNING("FPE DIVBYZERO in [" << step << "] of [" << caller << "]" << evStr.str()
246 << " " << m_NstacktracesOnFPE << " " << FPEAudit::s_tlsdata.s_array_D[0]
247 );
249 if ( m_NstacktracesOnFPE && FPEAudit::s_tlsdata.s_array_D[0] != NULL )
250 {
252 for (unsigned int j = 0; j < m_Nstacklines; j++)
253 {
254 if (FPEAudit::s_tlsdata.s_array_D[j]==NULL) break;
255 this->msg(MSG::INFO) << "FPE stacktrace " << j << " :\n";
256 FPEAudit::resolve(FPEAudit::s_tlsdata.s_array_D[j],this->msg());
257 FPEAudit::s_tlsdata.s_array_D[j]=NULL;
258 this->msg(MSG::INFO) << endmsg;
259 }
260 }
261 }
262
263
265 if ( --m_nexceptions == 0
268 {
269 fprintf(stderr, "too many SIGFPE detected, will be uninstalling signal handler\n");
271 }
272 }
273}
274
275void
277{
278 // clear FPE status word
279 feclearexcept(FE_ALL_EXCEPT);
280
282 // Make sure exceptions have been masked off if the handler has been
283 // disabled. Yes, this is already done in the signal handler.
284 // But when TBB starts a new task, it resets the FPU control words
285 // to values that were copied when the thread pool was initialized.
286 // FIXME: Do it properly with TBB? Not sure that the current
287 // interfaces allow it.
288 FPEAudit::mask_fpe();
289 }
290}
291
292void
294{
296 FPEAudit::unmask_fpe();
297 }
298}
#define endmsg
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
Define macros for attributes used to control the static checker.
std::atomic< int > m_nexceptions
Definition FPEAuditor.h:92
unsigned int m_NstacktracesOnFPE
Definition FPEAuditor.h:79
@ FPEAUDITOR_INVALID
Definition FPEAuditor.h:75
@ FPEAUDITOR_ARRAYSIZE
Definition FPEAuditor.h:75
@ FPEAUDITOR_DIVBYZERO
Definition FPEAuditor.h:75
@ FPEAUDITOR_OVERFLOW
Definition FPEAuditor.h:75
std::atomic< unsigned int > m_CountFPEs[FPEAUDITOR_ARRAYSIZE]
Definition FPEAuditor.h:77
virtual StatusCode finalize() override
virtual void after(const std::string &event, const std::string &name, const EventContext &ctx, const StatusCode &sc) override
void InstallHandler()
FPEAuditor(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
virtual void before(const std::string &event, const std::string &name, const EventContext &ctx) override
Auditor hooks.
virtual ~FPEAuditor()
Destructor.
void add_fpe_node()
add an fpe node
fenv_t m_env
The FP environment before we initialize.
Definition FPEAuditor.h:90
virtual StatusCode initialize() override
Gaudi hooks.
void report_fpe(const std::string &step, const std::string &caller, const EventContext &ctx)
report fpes which happened during step 'step' on behalf of 'caller'
void UninstallHandler()
unsigned int m_Nstacklines
Definition FPEAuditor.h:81
void pop_fpe_node()
pop an fpe node
std::lock_guard< std::mutex > lock_t
std::mutex s_mutex
struct sigaction s_oldactHandler ATLAS_THREAD_SAFE
FPEAuditTLSData s_tlsdata
std::atomic< bool > s_handlerDisabled
std::atomic< bool > s_handlerInstalled
const int MAXARRAY
void * s_array_D[MAXARRAY]
void * s_array_O[MAXARRAY]
void * s_array_I[MAXARRAY]