ATLAS Offline Software
Loading...
Searching...
No Matches
FPEControlSvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
10
11#include "FPEControlSvc.h"
13#include <fenv.h>
14#include <cstring>
15
16
22FPEControlSvc::FPEControlSvc( const std::string& name, ISvcLocator* svc )
23 : AthService( name, svc ),
24 m_toolSvc ("ToolSvc", name),
25 m_env(),
26 m_haveEnv(false),
27 m_enabled (0),
28 m_disabled (0),
29 m_removeInFinalize(false),
31{
32 declareProperty("Exceptions", m_exceptions);
33 declareProperty("ToolSvc", m_toolSvc);
34 declareProperty("FERoundingMode", m_feSetRounding);
35 m_exceptions.declareUpdateHandler (&FPEControlSvc::prophand, this);
36
37 // Set up the default exceptions.
38 std::vector<std::string> defexc;
39 defexc.push_back ("invalid");
40 defexc.push_back ("divbyzero");
41 defexc.push_back ("overflow");
42 m_exceptions = defexc;
43}
44
45
50{
51 // And change the exception mask.
53
54 // Add ourself as an observer.
55 CHECK( m_toolSvc.retrieve() );
56 m_toolSvc->registerObserver (this);
57
58 if(m_feSetRounding!="")
59 {
60 REPORT_MESSAGE (MSG::INFO) << "FE Rounding mode " << m_feSetRounding << " requested";
61 if(m_feSetRounding=="FE_TONEAREST")
62 {
63 if ( fesetround(FE_TONEAREST) )
64 REPORT_MESSAGE (MSG::WARNING) << "Couldn't change FE Rounding to mode FE_TONEAREST !";
65 }
66 else if(m_feSetRounding=="FE_UPWARD")
67 {
68 if ( fesetround(FE_UPWARD) )
69 REPORT_MESSAGE (MSG::WARNING) << "Couldn't change FE Rounding to mode FE_UPWARD !";
70 }
71 else if(m_feSetRounding=="FE_DOWNWARD")
72 {
73 if ( fesetround(FE_DOWNWARD) )
74 REPORT_MESSAGE (MSG::WARNING) << "Couldn't change FE Rounding to mode FE_DOWNWARD !";
75 }
76 else if(m_feSetRounding=="FE_TOWARDZERO")
77 {
78 if ( fesetround(FE_TOWARDZERO) )
79 REPORT_MESSAGE (MSG::WARNING) << "Couldn't change FE Rounding to mode FE_TOWARDZERO !";
80 }
81 else
82 REPORT_MESSAGE (MSG::WARNING) << "Don't know FE Rounding to mode " << m_feSetRounding;
83 }
84
85 return StatusCode::SUCCESS;
86}
87
88
93{
94 // remove only if requested
96 {
97 // Restore the FP environment to what is was before we ran.
98 fesetenv (&m_env);
99 }
100
101 return StatusCode::SUCCESS;
102}
103
104
115void FPEControlSvc::onCreate(const IAlgTool*)
116{
117 setFPU();
118}
119
120
121namespace {
122
123
128std::string mask_to_string (int mask)
129{
130 std::string out;
131 if (mask & FE_INEXACT)
132 out += "inexact ";
133 if (mask & FE_DIVBYZERO)
134 out += "divbyzero ";
135 if (mask & FE_UNDERFLOW)
136 out += "underflow ";
137 if (mask & FE_OVERFLOW)
138 out += "overflow ";
139 if (mask & FE_INVALID)
140 out += "invalid ";
141 if (out.size() == 0)
142 out = "(none) ";
143 return out;
144}
145
146
147} // anonymous namespace
148
149
153void FPEControlSvc::prophand (Gaudi::Details::PropertyBase& /*prop*/)
154{
155 if (!m_haveEnv) {
156 // Save the current FP environment.
157 fegetenv (&m_env);
158 m_haveEnv = true;
159 }
160 else {
161 // Reset to the FP environment before we started.
162 fesetenv (&m_env);
163 }
164
165 // Figure out which exceptions to enable/disable.
166 m_enabled = 0;
167 m_disabled = 0;
168 const std::vector<std::string>& v = m_exceptions.value();
169 for (size_t i = 0; i < v.size(); i++) {
170 bool onoff = true;
171 const char* s = v[i].c_str();
172 if (!s) continue;
173 if (s[0] == '!') {
174 onoff = false;
175 ++s;
176 }
177 int thisexc = 0;
178 if (strcasecmp (s, "inexact") == 0)
179 thisexc = FE_INEXACT;
180 else if (strcasecmp (s, "divbyzero") == 0)
181 thisexc = FE_DIVBYZERO;
182 else if (strcasecmp (s, "underflow") == 0)
183 thisexc = FE_UNDERFLOW;
184 else if (strcasecmp (s, "overflow") == 0)
185 thisexc = FE_OVERFLOW;
186 else if (strcasecmp (s, "invalid") == 0)
187 thisexc = FE_INVALID;
188 else {
189 REPORT_MESSAGE (MSG::INFO)
190 << "Unknown exception name: " << v[i];
191 continue;
192 }
193
194 if (onoff) {
195 m_enabled |= thisexc;
196 m_disabled &= ~thisexc;
197 }
198 else {
199 m_disabled |= thisexc;
200 m_enabled &= ~thisexc;
201 }
202 }
203
204 // Say what we're doing, and change the masks.
205 REPORT_MESSAGE (MSG::INFO)
206 << "Enable: " << mask_to_string (m_enabled)
207 << "Disable: " << mask_to_string (m_disabled);
208
209 setFPU();
210}
211
212
217{
218 feclearexcept (m_enabled);
219#ifdef __GLIBC__
220 feenableexcept (m_enabled);
221 fedisableexcept (m_disabled);
222#elif defined __APPLE__
223#include "CxxUtils/excepts.h"
224 feenableexcept (m_enabled);
225 fedisableexcept (m_disabled);
226#else
227 // The functions above are gnu-specific.
228 // Without GNU, we do it the harder way.
229 fenv_t newval;
230 fegetenv(&newval);
231
232 // CSR bit on means that the exception is masked.
233
234 newval.__control_word &= ~m_enabled;
235 newval.__control_word |= m_disabled;
236# ifdef __x86_64
237 // SSE floating point uses separate exception masks.
238 newval.__mxcsr &= (~m_enabled) << 7;
239 newval.__mxcsr |= ( m_disabled) << 7;
240# endif
241 fesetenv(&newval);
242#endif
243}
Helpers for checking error return status codes and reporting errors.
#define REPORT_MESSAGE(LVL)
Report a message.
#define CHECK(...)
Evaluate an expression and check for errors.
Service to enable or disable floating-point exceptions.
ServiceHandle< IToolSvc > m_toolSvc
Tool service.
int m_disabled
Mask of disabled exceptions.
bool m_haveEnv
Flag that we've retrieved the environment.
std::string m_feSetRounding
flag to decide on rounding mode (for stability tests)
void setFPU()
Set the FPU exception masks from m_enabled and m_disabled.
void prophand(Gaudi::Details::PropertyBase &prop)
Property change handler.
bool m_removeInFinalize
boolean to decide to (not) remove the observer in finalize
StringArrayProperty m_exceptions
Property specifying the desired exception mask.
int m_enabled
Mask of enabled exceptions.
virtual StatusCode finalize()
Standard finalize method.
FPEControlSvc(const std::string &name, ISvcLocator *svcloc)
Constructor.
virtual void onCreate(const IAlgTool *)
Called after each tool has been created.
virtual StatusCode initialize()
Standard initialize method.
fenv_t m_env
The FP environment before we initialize.
Declarations of feenableexcept()/fedisableexcept() functions for MacOSX.