CMS 3D CMS Logo

EnableFloatingPointExceptions.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Services
4 // Class : EnableFloatingPointExceptions
5 //
6 // Package: Services
7 // Class : EnableFloatingPointExceptions
8 //
101 //
102 // Original Author: E. Sexton-Kennedy
103 // Created: Tue Apr 11 13:43:16 CDT 2006
104 //
105 
107 
116 
117 #include <string>
118 #include <map>
119 
120 #include <cassert>
121 #include <fenv.h>
122 #include <vector>
123 #ifdef __linux__
124 #include <fpu_control.h>
125 #else
126 #ifdef __APPLE__
127 //TAKEN FROM
128 // http://public.kitware.com/Bug/file_download.php?file_id=3215&type=bug
129 static int
130 fegetexcept (void) {
131  fenv_t fenv;
132 
133  return fegetenv (&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT);
134 }
135 
136 static int
137 feenableexcept (unsigned int excepts) {
138  fenv_t fenv;
139  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
140  old_excepts; // previous masks
141 
142  if(fegetenv (&fenv)) return -1;
143  old_excepts = fenv.__control & FE_ALL_EXCEPT;
144 
145  // unmask
146  fenv.__control &= ~new_excepts;
147  fenv.__mxcsr &= ~(new_excepts << 7);
148 
149  return (fesetenv (&fenv) ? -1 : old_excepts);
150 }
151 
152 static int
153 fedisableexcept (unsigned int excepts) {
154  fenv_t fenv;
155  unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
156  old_excepts; // all previous masks
157 
158  if(fegetenv (&fenv)) return -1;
159  old_excepts = fenv.__control & FE_ALL_EXCEPT;
160 
161  // mask
162  fenv.__control |= new_excepts;
163  fenv.__mxcsr |= new_excepts << 7;
164 
165  return (fesetenv (&fenv) ? -1 : old_excepts);
166 }
167 
168 #endif
169 #endif
170 
171 namespace edm {
172 
173  namespace service {
174 
176  public:
177 
178  typedef int fpu_flags_type;
179 
182  void postEndJob();
183 
186 
189 
190  void preModuleEndJob(ModuleDescription const& md);
191  void postModuleEndJob(ModuleDescription const& md);
192 
195 
198 
203 
208 
213 
218 
221 
222  static void fillDescriptions(edm::ConfigurationDescriptions & descriptions);
223 
224  private:
225 
227 
228  void preActions(ModuleDescription const&,
229  char const* debugInfo);
230 
231  void postActions(ModuleDescription const&,
232  char const* debugInfo);
233 
234  void preActions(ModuleCallingContext const&,
235  char const* debugInfo);
236 
237  void postActions(ModuleCallingContext const&,
238  char const* debugInfo);
239 
240  void setPrecision(bool precisionDouble);
241 
242  void enableAndDisableExcept(fpu_flags_type target);
243 
244  void echoState() const;
245 
246  fpu_flags_type defaultState_;
247  std::map<std::string, fpu_flags_type> stateMap_;
249  };
250  }
251 }
252 
253 
254 namespace edm {
255  namespace service {
256 
260  defaultState_(0),
261  stateMap_(),
263 
264  reportSettings_ = pset.getUntrackedParameter<bool>("reportSettings", false);
265  bool precisionDouble = pset.getUntrackedParameter<bool>("setPrecisionDouble", true);
266 
267  if(reportSettings_) {
268  LogVerbatim("FPE_Enable") << "\nSettings in EnableFloatingPointExceptions constructor";
269  echoState();
270  }
271 
273 
275 
276  setPrecision(precisionDouble);
277 
278  // Note that we must watch all of the transitions even if there are no module specific settings.
279  // This is because the floating point environment may be modified by code outside of this service.
281 
284 
287 
290 
293 
296 
299 
304 
309 
314 
319  }
320 
321  // Establish an environment for each module; default is handled specially.
322  void
324 
325  // Scan the module name list and set per-module values. Be careful to treat
326  // any user-specified default first. If there is one, use it to override our default.
327  // Then remove it from the list so we don't see it again while handling everything else.
328 
329  typedef std::vector<std::string> VString;
330 
331  std::string const def("default");
332  ParameterSet const empty_PSet;
333  VString const empty_VString;
334  VString moduleNames = pset.getUntrackedParameter<VString>("moduleNames", empty_VString);
335 
336  for(VString::const_iterator it(moduleNames.begin()), itEnd = moduleNames.end(); it != itEnd; ++it) {
337  ParameterSet const& modulePSet = pset.getUntrackedParameterSet(*it, empty_PSet);
338  bool enableDivByZeroEx = modulePSet.getUntrackedParameter<bool>("enableDivByZeroEx", false);
339  bool enableInvalidEx = modulePSet.getUntrackedParameter<bool>("enableInvalidEx", false);
340  bool enableOverFlowEx = modulePSet.getUntrackedParameter<bool>("enableOverFlowEx", false);
341  bool enableUnderFlowEx = modulePSet.getUntrackedParameter<bool>("enableUnderFlowEx", false);
342 
343  fpu_flags_type flags = 0;
344  if(enableDivByZeroEx) flags |= FE_DIVBYZERO;
345  if(enableInvalidEx) flags |= FE_INVALID;
346  if(enableOverFlowEx) flags |= FE_OVERFLOW;
347  if(enableUnderFlowEx) flags |= FE_UNDERFLOW;
348  enableAndDisableExcept(flags);
349 
350  fpu_flags_type fpuState = fegetexcept();
351  assert(flags == fpuState);
352 
353  if(reportSettings_) {
354  LogVerbatim("FPE_Enable") << "\nSettings for module " << *it;
355  echoState();
356  }
357  if(*it == def) {
358  defaultState_ = fpuState;
359  }
360  else {
361  stateMap_[*it] = fpuState;
362  }
363  }
364  }
365 
366  void
368 
369  if(reportSettings_) {
370  LogVerbatim("FPE_Enable") << "\nSettings after endJob ";
371  echoState();
372  }
373  }
374 
375  void
378  preActions(md, "construction");
379  }
380 
381  void
384  postActions(md, "construction");
385  }
386 
387  void
390  preActions(md, "beginJob");
391  }
392 
393  void
396  postActions(md, "beginJob");
397  }
398 
399  void
402  preActions(md, "endJob");
403  }
404 
405  void
408  postActions(md, "endJob");
409  }
410 
411  void
414  preActions(mcc, "beginStream");
415  }
416 
417  void
420  postActions(mcc, "beginStream");
421  }
422 
423  void
426  preActions(mcc, "endStream");
427  }
428 
429  void
432  postActions(mcc, "endStream");
433  }
434 
435  void
438  preActions(mcc, "globalBeginRun");
439  }
440 
441  void
444  postActions(mcc, "globalBeginRun");
445  }
446 
447  void
450  preActions(mcc, "globalEndRun");
451  }
452 
453  void
456  postActions(mcc, "globalEndRun");
457  }
458 
459  void
462  preActions(mcc, "globalBeginLumi");
463  }
464 
465  void
468  postActions(mcc, "globalBeginLumi");
469  }
470 
471  void
474  preActions(mcc, "globalEndLumi");
475  }
476 
477  void
480  postActions(mcc, "globalEndLumi");
481  }
482 
483  void
486  preActions(mcc, "streamBeginRun");
487  }
488 
489  void
492  postActions(mcc, "streamBeginRun");
493  }
494 
495  void
498  preActions(mcc, "streamEndRun");
499  }
500 
501  void
504  postActions(mcc, "streamEndRun");
505  }
506 
507  void
510  preActions(mcc, "streamBeginLumi");
511  }
512 
513  void
516  postActions(mcc, "streamBeginLumi");
517  }
518 
519  void
522  preActions(mcc, "streamEndLumi");
523  }
524 
525  void
528  postActions(mcc, "streamEndLumi");
529  }
530 
531  void
534  preActions(mcc, "event");
535  }
536 
537  void
540  postActions(mcc, "event");
541  }
542 
543  void
547 
548  desc.addUntracked<bool>("reportSettings", false)->setComment(
549  "Log FPE settings at different phases of the job.");
550  desc.addUntracked<bool>("setPrecisionDouble", true)->setComment(
551  "Set the FPU to use double precision");
552 
553  ParameterSetDescription validator;
554  validator.setComment("FPU exceptions to enable/disable for the requested module");
555  validator.addUntracked<bool>("enableDivByZeroEx", false)->setComment(
556  "Enable/disable exception for 'divide by zero'");
557  validator.addUntracked<bool>("enableInvalidEx", false)->setComment(
558  "Enable/disable exception for 'invalid' math operations (e.g. sqrt(-1))");
559  validator.addUntracked<bool>("enableOverFlowEx", false)->setComment(
560  "Enable/disable exception for numeric 'overflow' (value to big for type)");
561  validator.addUntracked<bool>("enableUnderFlowEx", false)->setComment(
562  "Enable/disable exception for numeric 'underflow' (value to small to be represented accurately)");
563 
564  AllowedLabelsDescription<ParameterSetDescription> node("moduleNames", validator, false);
565  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");
566  desc.addNode(node);
567 
568  descriptions.add("EnableFloatingPointExceptions", desc);
569  descriptions.setComment("This service allows you to control the FPU and its exceptions on a per module basis.");
570  }
571 
572 
573  void
576  char const* debugInfo) {
577 
578  std::string const& moduleLabel = description.moduleLabel();
579  std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(moduleLabel);
580 
581  fpu_flags_type fpuState = defaultState_;
582 
583  if(iModule != stateMap_.end()) {
584  fpuState = iModule->second;
585  }
586  enableAndDisableExcept(fpuState);
587 
588  if(reportSettings_) {
589  LogVerbatim("FPE_Enable")
590  << "\nSettings for module label \""
591  << moduleLabel
592  << "\" before "
593  << debugInfo;
594  echoState();
595  }
596  }
597 
598  void
600  postActions(ModuleDescription const& description, char const* debugInfo) {
601 
603 
604  if(reportSettings_) {
605  LogVerbatim("FPE_Enable")
606  << "\nSettings for module label \""
607  << description.moduleLabel()
608  << "\" after "
609  << debugInfo;
610  echoState();
611  }
612  }
613 
614  void
617  char const* debugInfo) {
618 
619  std::string const& moduleLabel = mcc.moduleDescription()->moduleLabel();
620  std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(moduleLabel);
621 
622  fpu_flags_type fpuState = defaultState_;
623 
624  if(iModule != stateMap_.end()) {
625  fpuState = iModule->second;
626  }
627  enableAndDisableExcept(fpuState);
628 
629  if(reportSettings_) {
630  LogVerbatim("FPE_Enable")
631  << "\nSettings for module label \""
632  << moduleLabel
633  << "\" before "
634  << debugInfo;
635  echoState();
636  }
637  }
638 
639  void
641  postActions(ModuleCallingContext const& mcc, char const* debugInfo) {
642 
643  fpu_flags_type fpuState = defaultState_;
644 
645  edm::ModuleCallingContext const* previous_mcc = mcc.previousModuleOnThread();
646  if(previous_mcc) {
647  std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(previous_mcc->moduleDescription()->moduleLabel());
648  if(iModule != stateMap_.end()) {
649  fpuState = iModule->second;
650  }
651  }
652  enableAndDisableExcept(fpuState);
653 
654  if(reportSettings_) {
655  LogVerbatim("FPE_Enable")
656  << "\nSettings for module label \""
657  << mcc.moduleDescription()->moduleLabel()
658  << "\" after "
659  << debugInfo;
660  echoState();
661  }
662  }
663 
664 #ifdef __linux__
665 #ifdef __i386__
666  // Note that __i386__ flag is not set on x86_64 architectures.
667  // As far as I know we use the empty version of the setPrecision
668  // function on all architectures CMS currently supports.
669  // Here is my understanding of this from the articles I found with
670  // google. I should warn that none of those articles were directly
671  // from the compiler writers or Intel or any authoritative
672  // source and I am not really an expert on this subject. We use the
673  // setPrecision function to force the math processor to perform floating
674  // point calculations internally with 64 bits of precision and not use
675  // 80 bit extended precision internally for calculations. 80 bit extended
676  // precision is used with the x87 instruction set which is the default
677  // for most 32 bit Intel architectures. When it is used there are problems
678  // of different sorts such as nonreproducible results, mostly due
679  // to rounding issues. This was important before CMS switched from
680  // 32 bit to 64 bit architectures. On 64 bit x86_64 platforms
681  // SSE instructions are used instead of x87 instructions.
682  // The whole issue is obsolete as SSE instructions do not ever
683  // use extended 80 bit precision in floating point calculations. Although
684  // new CPUs still support the x87 instruction set for floating point
685  // calculations for various reasons (mostly backward compatibility I
686  // think), most compilers write SSE instructions only. It might be
687  // that compiler flags can be set to force use of x87 instructions, but
688  // as far as I know we do not do that for CMS.
689  void
690  EnableFloatingPointExceptions::setPrecision(bool precisionDouble) {
691  if(precisionDouble) {
692  fpu_control_t cw;
693  _FPU_GETCW(cw);
694 
695  cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
696  _FPU_SETCW(cw);
697  }
698  }
699 #else
700  void
701  EnableFloatingPointExceptions::setPrecision(bool /*precisionDouble*/) {
702  }
703 #endif
704 #else
705  void
707  }
708 #endif
709 
710  void
712  feclearexcept(FE_ALL_EXCEPT);
713  fpu_flags_type current = fegetexcept();
714  fpu_flags_type exceptionsToModify = current ^ target;
715  fpu_flags_type exceptionsToEnable = 0;
716  fpu_flags_type exceptionsToDisable = 0;
717 
718  if(exceptionsToModify & FE_DIVBYZERO) {
719  if(target & FE_DIVBYZERO) {
720  exceptionsToEnable |= FE_DIVBYZERO;
721  }
722  else {
723  exceptionsToDisable |= FE_DIVBYZERO;
724  }
725  }
726  if(exceptionsToModify & FE_INVALID) {
727  if(target & FE_INVALID) {
728  exceptionsToEnable |= FE_INVALID;
729  }
730  else {
731  exceptionsToDisable |= FE_INVALID;
732  }
733  }
734  if(exceptionsToModify & FE_OVERFLOW) {
735  if(target & FE_OVERFLOW) {
736  exceptionsToEnable |= FE_OVERFLOW;
737  }
738  else {
739  exceptionsToDisable |= FE_OVERFLOW;
740  }
741  }
742  if(exceptionsToModify & FE_UNDERFLOW) {
743  if(target & FE_UNDERFLOW) {
744  exceptionsToEnable |= FE_UNDERFLOW;
745  }
746  else {
747  exceptionsToDisable |= FE_UNDERFLOW;
748  }
749  }
750  if(exceptionsToEnable != 0) {
751  feenableexcept(exceptionsToEnable);
752  }
753  if(exceptionsToDisable != 0) {
754  fedisableexcept(exceptionsToDisable);
755  }
756  }
757 
758  void
760  feclearexcept(FE_ALL_EXCEPT);
761  fpu_flags_type femask = fegetexcept();
762  LogVerbatim("FPE_Enable") << "Floating point exception mask is "
763  << std::showbase << std::hex << femask;
764 
765  if(femask & FE_DIVBYZERO)
766  LogVerbatim("FPE_Enable") << "\tDivByZero exception is on";
767  else
768  LogVerbatim("FPE_Enable") << "\tDivByZero exception is off";
769 
770  if(femask & FE_INVALID)
771  LogVerbatim("FPE_Enable") << "\tInvalid exception is on";
772  else
773  LogVerbatim("FPE_Enable") << "\tInvalid exception is off";
774 
775  if(femask & FE_OVERFLOW)
776  LogVerbatim("FPE_Enable") << "\tOverFlow exception is on";
777  else
778  LogVerbatim("FPE_Enable") << "\tOverflow exception is off";
779 
780  if(femask & FE_UNDERFLOW)
781  LogVerbatim("FPE_Enable") << "\tUnderFlow exception is on";
782  else
783  LogVerbatim("FPE_Enable") << "\tUnderFlow exception is off";
784  }
785 
786  } // namespace edm
787 } // namespace service
788 
789 #if defined(__linux__)
792 #endif
793 
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
#define DEFINE_FWK_SERVICE_MAKER(concrete, maker)
Definition: ServiceMaker.h:117
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)
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)
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
HLT enums.
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)
void preModuleGlobalEndRun(GlobalContext const &, ModuleCallingContext const &)
static Interceptor::Registry registry("Interceptor")
JetCorrectorParameters::Definitions def
Definition: classes.h:6
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)