ATLAS Offline Software
FPEControlSvc.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
11 #include "FPEControlSvc.h"
13 #include <fenv.h>
14 #include <cstring>
15 
16 
22 FPEControlSvc::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),
30  m_feSetRounding("")
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 
115 void FPEControlSvc::onCreate(const IAlgTool*)
116 {
117  setFPU();
118 }
119 
120 
121 namespace {
122 
123 
128 std::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 
153 void 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 }
python.SystemOfUnits.s
int s
Definition: SystemOfUnits.py:131
FPEControlSvc::m_removeInFinalize
bool m_removeInFinalize
boolean to decide to (not) remove the observer in finalize
Definition: FPEControlSvc.h:95
FPEControlSvc::initialize
virtual StatusCode initialize()
Standard initialize method.
Definition: FPEControlSvc.cxx:49
FPEControlSvc::setFPU
void setFPU()
Set the FPU exception masks from m_enabled and m_disabled.
Definition: FPEControlSvc.cxx:216
FPEControlSvc::m_toolSvc
ServiceHandle< IToolSvc > m_toolSvc
Tool service.
Definition: FPEControlSvc.h:80
FPEControlSvc::m_haveEnv
bool m_haveEnv
Flag that we've retrieved the environment.
Definition: FPEControlSvc.h:86
python.AthDsoLogger.out
out
Definition: AthDsoLogger.py:71
excepts.h
Declarations of feenableexcept()/fedisableexcept() functions for MacOSX.
FPEControlSvc::m_disabled
int m_disabled
Mask of disabled exceptions.
Definition: FPEControlSvc.h:92
FPEControlSvc::finalize
virtual StatusCode finalize()
Standard finalize method.
Definition: FPEControlSvc.cxx:92
python.utils.AtlRunQueryLookup.mask
string mask
Definition: AtlRunQueryLookup.py:460
FPEControlSvc::prophand
void prophand(Gaudi::Details::PropertyBase &prop)
Property change handler.
Definition: FPEControlSvc.cxx:153
FPEControlSvc::m_feSetRounding
std::string m_feSetRounding
flag to decide on rounding mode (for stability tests)
Definition: FPEControlSvc.h:98
FPEControlSvc::m_env
fenv_t m_env
The FP environment before we initialize.
Definition: FPEControlSvc.h:83
lumiFormat.i
int i
Definition: lumiFormat.py:85
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
FPEControlSvc::m_exceptions
StringArrayProperty m_exceptions
Property specifying the desired exception mask.
Definition: FPEControlSvc.h:77
AthService
Definition: AthService.h:32
FPEControlSvc.h
Service to enable or disable floating-point exceptions.
CHECK
#define CHECK(...)
Evaluate an expression and check for errors.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:422
Handler::svc
AthROOTErrorHandlerSvc * svc
Definition: AthROOTErrorHandlerSvc.cxx:10
FPEControlSvc::onCreate
virtual void onCreate(const IAlgTool *)
Called after each tool has been created.
Definition: FPEControlSvc.cxx:115
name
std::string name
Definition: Control/AthContainers/Root/debug.cxx:221
errorcheck.h
Helpers for checking error return status codes and reporting errors.
FPEControlSvc::m_enabled
int m_enabled
Mask of enabled exceptions.
Definition: FPEControlSvc.h:89
REPORT_MESSAGE
#define REPORT_MESSAGE(LVL)
Report a message.
Definition: Control/AthenaKernel/AthenaKernel/errorcheck.h:365
python.PyAthena.v
v
Definition: PyAthena.py:154
FPEControlSvc::FPEControlSvc
FPEControlSvc(const std::string &name, ISvcLocator *svcloc)
Constructor.
Definition: FPEControlSvc.cxx:22