CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
EnableFloatingPointExceptions.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Services
4 // Class : EnableFloatingPointExceptions
5 //
6 // Implementation:
7 // <Notes on implementation>
8 //
9 // Original Author: E. Sexton-Kennedy
10 // Created: Tue Apr 11 13:43:16 CDT 2006
11 //
12 
14 
23 
24 #include <cassert>
25 #include <fenv.h>
26 #include <vector>
27 #ifdef __linux__
28 #include <fpu_control.h>
29 #else
30 #ifdef __APPLE__
31 //TAKEN FROM
32 // http://public.kitware.com/Bug/file_download.php?file_id=3215&type=bug
33 static int
34 fegetexcept (void) {
35  fenv_t fenv;
36 
37  return fegetenv (&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT);
38 }
39 
40 static int
41 feenableexcept (unsigned int excepts) {
42  fenv_t fenv;
43  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
44  old_excepts; // previous masks
45 
46  if(fegetenv (&fenv)) return -1;
47  old_excepts = fenv.__control & FE_ALL_EXCEPT;
48 
49  // unmask
50  fenv.__control &= ~new_excepts;
51  fenv.__mxcsr &= ~(new_excepts << 7);
52 
53  return (fesetenv (&fenv) ? -1 : old_excepts);
54 }
55 
56 static int
57 fedisableexcept (unsigned int excepts) {
58  fenv_t fenv;
59  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
60  old_excepts; // all previous masks
61 
62  if(fegetenv (&fenv)) return -1;
63  old_excepts = fenv.__control & FE_ALL_EXCEPT;
64 
65  // mask
66  fenv.__control |= new_excepts;
67  fenv.__mxcsr |= new_excepts << 7;
68 
69  return (fesetenv (&fenv) ? -1 : old_excepts);
70 }
71 
72 #endif
73 #endif
74 
75 namespace edm {
76  namespace service {
77 
81  defaultState_(0),
82  stateMap_(),
83  reportSettings_(false) {
84 
85  reportSettings_ = pset.getUntrackedParameter<bool>("reportSettings", false);
86  bool precisionDouble = pset.getUntrackedParameter<bool>("setPrecisionDouble", true);
87 
88  if(reportSettings_) {
89  LogVerbatim("FPE_Enable") << "\nSettings in EnableFloatingPointExceptions constructor";
90  echoState();
91  }
92 
94 
96 
97  setPrecision(precisionDouble);
98 
99  // Note that we must watch all of the transitions even if there are no module specific settings.
100  // This is because the floating point environment may be modified by code outside of this service.
102 
105 
108 
111 
114 
117 
120 
125 
130 
135 
140  }
141 
142  // Establish an environment for each module; default is handled specially.
143  void
145 
146  // Scan the module name list and set per-module values. Be careful to treat
147  // any user-specified default first. If there is one, use it to override our default.
148  // Then remove it from the list so we don't see it again while handling everything else.
149 
150  typedef std::vector<std::string> VString;
151 
152  std::string const def("default");
153  ParameterSet const empty_PSet;
154  VString const empty_VString;
155  VString moduleNames = pset.getUntrackedParameter<VString>("moduleNames", empty_VString);
156 
157  for(VString::const_iterator it(moduleNames.begin()), itEnd = moduleNames.end(); it != itEnd; ++it) {
158  ParameterSet const& modulePSet = pset.getUntrackedParameterSet(*it, empty_PSet);
159  bool enableDivByZeroEx = modulePSet.getUntrackedParameter<bool>("enableDivByZeroEx", false);
160  bool enableInvalidEx = modulePSet.getUntrackedParameter<bool>("enableInvalidEx", false);
161  bool enableOverFlowEx = modulePSet.getUntrackedParameter<bool>("enableOverFlowEx", false);
162  bool enableUnderFlowEx = modulePSet.getUntrackedParameter<bool>("enableUnderFlowEx", false);
163 
164  fpu_flags_type flags = 0;
165  if(enableDivByZeroEx) flags |= FE_DIVBYZERO;
166  if(enableInvalidEx) flags |= FE_INVALID;
167  if(enableOverFlowEx) flags |= FE_OVERFLOW;
168  if(enableUnderFlowEx) flags |= FE_UNDERFLOW;
169  enableAndDisableExcept(flags);
170 
171  fpu_flags_type fpuState = fegetexcept();
172  assert(flags == fpuState);
173 
174  if(reportSettings_) {
175  LogVerbatim("FPE_Enable") << "\nSettings for module " << *it;
176  echoState();
177  }
178  if(*it == def) {
179  defaultState_ = fpuState;
180  }
181  else {
182  stateMap_[*it] = fpuState;
183  }
184  }
185  }
186 
187  void
189 
190  if(reportSettings_) {
191  LogVerbatim("FPE_Enable") << "\nSettings after endJob ";
192  echoState();
193  }
194  }
195 
196  void
199  preActions(md, "construction");
200  }
201 
202  void
205  postActions(md, "construction");
206  }
207 
208  void
211  preActions(md, "beginJob");
212  }
213 
214  void
217  postActions(md, "beginJob");
218  }
219 
220  void
223  preActions(md, "endJob");
224  }
225 
226  void
229  postActions(md, "endJob");
230  }
231 
232  void
235  preActions(mcc, "beginStream");
236  }
237 
238  void
241  postActions(mcc, "beginStream");
242  }
243 
244  void
247  preActions(mcc, "endStream");
248  }
249 
250  void
253  postActions(mcc, "endStream");
254  }
255 
256  void
259  preActions(mcc, "globalBeginRun");
260  }
261 
262  void
265  postActions(mcc, "globalBeginRun");
266  }
267 
268  void
271  preActions(mcc, "globalEndRun");
272  }
273 
274  void
277  postActions(mcc, "globalEndRun");
278  }
279 
280  void
283  preActions(mcc, "globalBeginLumi");
284  }
285 
286  void
289  postActions(mcc, "globalBeginLumi");
290  }
291 
292  void
295  preActions(mcc, "globalEndLumi");
296  }
297 
298  void
301  postActions(mcc, "globalEndLumi");
302  }
303 
304  void
307  preActions(mcc, "streamBeginRun");
308  }
309 
310  void
313  postActions(mcc, "streamBeginRun");
314  }
315 
316  void
319  preActions(mcc, "streamEndRun");
320  }
321 
322  void
325  postActions(mcc, "streamEndRun");
326  }
327 
328  void
331  preActions(mcc, "streamBeginLumi");
332  }
333 
334  void
337  postActions(mcc, "streamBeginLumi");
338  }
339 
340  void
343  preActions(mcc, "streamEndLumi");
344  }
345 
346  void
349  postActions(mcc, "streamEndLumi");
350  }
351 
352  void
355  preActions(mcc, "event");
356  }
357 
358  void
361  postActions(mcc, "event");
362  }
363 
364  void
368 
369  desc.addUntracked<bool>("reportSettings", false)->setComment(
370  "Log FPE settings at different phases of the job.");
371  desc.addUntracked<bool>("setPrecisionDouble", true)->setComment(
372  "Set the FPU to use double precision");
373 
374  ParameterSetDescription validator;
375  validator.setComment("FPU exceptions to enable/disable for the requested module");
376  validator.addUntracked<bool>("enableDivByZeroEx", false)->setComment(
377  "Enable/disable exception for 'divide by zero'");
378  validator.addUntracked<bool>("enableInvalidEx", false)->setComment(
379  "Enable/disable exception for 'invalid' math operations (e.g. sqrt(-1))");
380  validator.addUntracked<bool>("enableOverFlowEx", false)->setComment(
381  "Enable/disable exception for numeric 'overflow' (value to big for type)");
382  validator.addUntracked<bool>("enableUnderFlowEx", false)->setComment(
383  "Enable/disable exception for numeric 'underflow' (value to small to be represented accurately)");
384 
385  AllowedLabelsDescription<ParameterSetDescription> node("moduleNames", validator, false);
386  node.setComment("Contains the names for PSets where the PSet name matches the label of a module for which you want to modify the FPE");
387  desc.addNode(node);
388 
389  descriptions.add("EnableFloatingPointExceptions", desc);
390  descriptions.setComment("This service allows you to control the FPU and its exceptions on a per module basis.");
391  }
392 
393 
394  void
397  char const* debugInfo) {
398 
399  std::string const& moduleLabel = description.moduleLabel();
400  std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(moduleLabel);
401 
402  fpu_flags_type fpuState = defaultState_;
403 
404  if(iModule != stateMap_.end()) {
405  fpuState = iModule->second;
406  }
407  enableAndDisableExcept(fpuState);
408 
409  if(reportSettings_) {
410  LogVerbatim("FPE_Enable")
411  << "\nSettings for module label \""
412  << moduleLabel
413  << "\" before "
414  << debugInfo;
415  echoState();
416  }
417  }
418 
419  void
421  postActions(ModuleDescription const& description, char const* debugInfo) {
422 
424 
425  if(reportSettings_) {
426  LogVerbatim("FPE_Enable")
427  << "\nSettings for module label \""
428  << description.moduleLabel()
429  << "\" after "
430  << debugInfo;
431  echoState();
432  }
433  }
434 
435  void
438  char const* debugInfo) {
439 
440  std::string const& moduleLabel = mcc.moduleDescription()->moduleLabel();
441  std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(moduleLabel);
442 
443  fpu_flags_type fpuState = defaultState_;
444 
445  if(iModule != stateMap_.end()) {
446  fpuState = iModule->second;
447  }
448  enableAndDisableExcept(fpuState);
449 
450  if(reportSettings_) {
451  LogVerbatim("FPE_Enable")
452  << "\nSettings for module label \""
453  << moduleLabel
454  << "\" before "
455  << debugInfo;
456  echoState();
457  }
458  }
459 
460  void
462  postActions(ModuleCallingContext const& mcc, char const* debugInfo) {
463 
464  fpu_flags_type fpuState = defaultState_;
465 
466  edm::ModuleCallingContext const* previous_mcc = mcc.previousModuleOnThread();
467  if(previous_mcc) {
468  std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(previous_mcc->moduleDescription()->moduleLabel());
469  if(iModule != stateMap_.end()) {
470  fpuState = iModule->second;
471  }
472  }
473  enableAndDisableExcept(fpuState);
474 
475  if(reportSettings_) {
476  LogVerbatim("FPE_Enable")
477  << "\nSettings for module label \""
478  << mcc.moduleDescription()->moduleLabel()
479  << "\" after "
480  << debugInfo;
481  echoState();
482  }
483  }
484 
485 #ifdef __linux__
486 #ifdef __i386__
487  // Note that __i386__ flag is not set on x86_64 architectures.
488  // As far as I know we use the empty version of the setPrecision
489  // function on all architectures CMS currently supports.
490  // Here is my understanding of this from the articles I found with
491  // google. I should warn that none of those articles were directly
492  // from the compiler writers or Intel or any authoritative
493  // source and I am not really an expert on this subject. We use the
494  // setPrecision function to force the math processor to perform floating
495  // point calculations internally with 64 bits of precision and not use
496  // 80 bit extended precision internally for calculations. 80 bit extended
497  // precision is used with the x87 instruction set which is the default
498  // for most 32 bit Intel architectures. When it is used there are problems
499  // of different sorts such as nonreproducible results, mostly due
500  // to rounding issues. This was important before CMS switched from
501  // 32 bit to 64 bit architectures. On 64 bit x86_64 platforms
502  // SSE instructions are used instead of x87 instructions.
503  // The whole issue is obsolete as SSE instructions do not ever
504  // use extended 80 bit precision in floating point calculations. Although
505  // new CPUs still support the x87 instruction set for floating point
506  // calculations for various reasons (mostly backward compatibility I
507  // think), most compilers write SSE instructions only. It might be
508  // that compiler flags can be set to force use of x87 instructions, but
509  // as far as I know we do not do that for CMS.
510  void
511  EnableFloatingPointExceptions::setPrecision(bool precisionDouble) {
512  if(precisionDouble) {
513  fpu_control_t cw;
514  _FPU_GETCW(cw);
515 
516  cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
517  _FPU_SETCW(cw);
518  }
519  }
520 #else
521  void
522  EnableFloatingPointExceptions::setPrecision(bool /*precisionDouble*/) {
523  }
524 #endif
525 #else
526  void
528  }
529 #endif
530 
531  void
533  feclearexcept(FE_ALL_EXCEPT);
534  fpu_flags_type current = fegetexcept();
535  fpu_flags_type exceptionsToModify = current ^ target;
536  fpu_flags_type exceptionsToEnable = 0;
537  fpu_flags_type exceptionsToDisable = 0;
538 
539  if(exceptionsToModify & FE_DIVBYZERO) {
540  if(target & FE_DIVBYZERO) {
541  exceptionsToEnable |= FE_DIVBYZERO;
542  }
543  else {
544  exceptionsToDisable |= FE_DIVBYZERO;
545  }
546  }
547  if(exceptionsToModify & FE_INVALID) {
548  if(target & FE_INVALID) {
549  exceptionsToEnable |= FE_INVALID;
550  }
551  else {
552  exceptionsToDisable |= FE_INVALID;
553  }
554  }
555  if(exceptionsToModify & FE_OVERFLOW) {
556  if(target & FE_OVERFLOW) {
557  exceptionsToEnable |= FE_OVERFLOW;
558  }
559  else {
560  exceptionsToDisable |= FE_OVERFLOW;
561  }
562  }
563  if(exceptionsToModify & FE_UNDERFLOW) {
564  if(target & FE_UNDERFLOW) {
565  exceptionsToEnable |= FE_UNDERFLOW;
566  }
567  else {
568  exceptionsToDisable |= FE_UNDERFLOW;
569  }
570  }
571  if(exceptionsToEnable != 0) {
572  feenableexcept(exceptionsToEnable);
573  }
574  if(exceptionsToDisable != 0) {
575  fedisableexcept(exceptionsToDisable);
576  }
577  }
578 
579  void
581  feclearexcept(FE_ALL_EXCEPT);
582  fpu_flags_type femask = fegetexcept();
583  LogVerbatim("FPE_Enable") << "Floating point exception mask is "
584  << std::showbase << std::hex << femask;
585 
586  if(femask & FE_DIVBYZERO)
587  LogVerbatim("FPE_Enable") << "\tDivByZero exception is on";
588  else
589  LogVerbatim("FPE_Enable") << "\tDivByZero exception is off";
590 
591  if(femask & FE_INVALID)
592  LogVerbatim("FPE_Enable") << "\tInvalid exception is on";
593  else
594  LogVerbatim("FPE_Enable") << "\tInvalid exception is off";
595 
596  if(femask & FE_OVERFLOW)
597  LogVerbatim("FPE_Enable") << "\tOverFlow exception is on";
598  else
599  LogVerbatim("FPE_Enable") << "\tOverflow exception is off";
600 
601  if(femask & FE_UNDERFLOW)
602  LogVerbatim("FPE_Enable") << "\tUnderFlow exception is on";
603  else
604  LogVerbatim("FPE_Enable") << "\tUnderFlow exception is off";
605  }
606 
607  } // namespace edm
608 } // namespace service
void preModuleGlobalEndLumi(GlobalContext const &, ModuleCallingContext const &)
void watchPostModuleGlobalEndLumi(PostModuleGlobalEndLumi::slot_type const &iSlot)
void watchPostModuleConstruction(PostModuleConstruction::slot_type const &iSlot)
void preModuleGlobalBeginLumi(GlobalContext const &, ModuleCallingContext const &)
void watchPreModuleGlobalBeginRun(PreModuleGlobalBeginRun::slot_type const &iSlot)
void setComment(std::string const &value)
T getUntrackedParameter(std::string const &, T const &) const
int def(FILE *, FILE *, int)
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
void postModuleGlobalBeginLumi(GlobalContext const &, ModuleCallingContext const &)
void watchPostEndJob(PostEndJob::slot_type const &iSlot)
void preModuleEvent(StreamContext const &, ModuleCallingContext const &)
void preActions(ModuleDescription const &, char const *debugInfo)
void watchPostModuleEndStream(PostModuleEndStream::slot_type const &iSlot)
void watchPreModuleEvent(PreModuleEvent::slot_type const &iSlot)
void watchPreModuleConstruction(PreModuleConstruction::slot_type const &iSlot)
void preModuleStreamEndRun(StreamContext const &, ModuleCallingContext const &)
void watchPostModuleEvent(PostModuleEvent::slot_type const &iSlot)
ParameterDescriptionNode * addNode(ParameterDescriptionNode const &node)
void watchPostModuleGlobalBeginLumi(PostModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndLumi(PostModuleStreamEndLumi::slot_type const &iSlot)
std::vector< Variable::Flags > flags
Definition: MVATrainer.cc:135
void watchPostModuleStreamBeginRun(PostModuleStreamBeginRun::slot_type const &iSlot)
void preModuleStreamEndLumi(StreamContext const &, ModuleCallingContext const &)
ParameterSet getUntrackedParameterSet(std::string const &name, ParameterSet const &defaultValue) const
void postModuleBeginStream(StreamContext const &, ModuleCallingContext const &)
void watchPreModuleBeginStream(PreModuleBeginStream::slot_type const &iSlot)
std::string const & moduleLabel() const
void watchPreModuleGlobalEndRun(PreModuleGlobalEndRun::slot_type const &iSlot)
tuple node
Definition: Node.py:50
void preModuleStreamBeginLumi(StreamContext const &, ModuleCallingContext const &)
void postModuleStreamBeginLumi(StreamContext const &, ModuleCallingContext const &)
void setComment(std::string const &value)
std::map< std::string, fpu_flags_type > stateMap_
ModuleDescription const * moduleDescription() const
void watchPreModuleEndJob(PreModuleEndJob::slot_type const &iSlot)
void postModuleGlobalEndLumi(GlobalContext const &, ModuleCallingContext const &)
void postModuleStreamEndLumi(StreamContext const &, ModuleCallingContext const &)
void postModuleStreamBeginRun(StreamContext const &, ModuleCallingContext const &)
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
void watchPreModuleBeginJob(PreModuleBeginJob::slot_type const &iSlot)
void postModuleGlobalEndRun(GlobalContext const &, ModuleCallingContext const &)
void watchPreModuleGlobalBeginLumi(PreModuleGlobalBeginLumi::slot_type const &iSlot)
void watchPostModuleStreamEndRun(PostModuleStreamEndRun::slot_type const &iSlot)
void watchPreModuleStreamBeginLumi(PreModuleStreamBeginLumi::slot_type const &iSlot)
void preModuleBeginStream(StreamContext const &, ModuleCallingContext const &)
void setComment(std::string const &value)
tuple description
Definition: idDealer.py:66
void watchPostModuleBeginStream(PostModuleBeginStream::slot_type const &iSlot)
void watchPostModuleGlobalEndRun(PostModuleGlobalEndRun::slot_type const &iSlot)
void watchPostModuleStreamBeginLumi(PostModuleStreamBeginLumi::slot_type const &iSlot)
void watchPreModuleStreamEndLumi(PreModuleStreamEndLumi::slot_type const &iSlot)
void watchPreModuleStreamBeginRun(PreModuleStreamBeginRun::slot_type const &iSlot)
void add(std::string const &label, ParameterSetDescription const &psetDescription)
void watchPreModuleEndStream(PreModuleEndStream::slot_type const &iSlot)
void preModuleEndStream(StreamContext const &, ModuleCallingContext const &)
void postModuleGlobalBeginRun(GlobalContext const &, ModuleCallingContext const &)
void preModuleStreamBeginRun(StreamContext const &, ModuleCallingContext const &)
ModuleCallingContext const * previousModuleOnThread() const
void postModuleEndStream(StreamContext const &, ModuleCallingContext const &)
void postModuleEvent(StreamContext const &, ModuleCallingContext const &)
void watchPreModuleStreamEndRun(PreModuleStreamEndRun::slot_type const &iSlot)
void watchPostModuleBeginJob(PostModuleBeginJob::slot_type const &iSlot)
void watchPostModuleGlobalBeginRun(PostModuleGlobalBeginRun::slot_type const &iSlot)
void preModuleGlobalBeginRun(GlobalContext const &, ModuleCallingContext const &)
void postActions(ModuleDescription const &, char const *debugInfo)
volatile std::atomic< bool > shutdown_flag false
void preModuleGlobalEndRun(GlobalContext const &, ModuleCallingContext const &)
static Interceptor::Registry registry("Interceptor")
void watchPostModuleEndJob(PostModuleEndJob::slot_type const &iSlot)
void postModuleStreamEndRun(StreamContext const &, ModuleCallingContext const &)
void watchPreModuleGlobalEndLumi(PreModuleGlobalEndLumi::slot_type const &iSlot)
EnableFloatingPointExceptions(ParameterSet const &pset, ActivityRegistry &registry)