CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch9/src/FWCore/Services/src/EnableFloatingPointExceptions.cc

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Package:     Services
00004 // Class  :     EnableFloatingPointExceptions
00005 // 
00006 // Implementation:
00007 //     <Notes on implementation>
00008 //
00009 // Original Author:  E. Sexton-Kennedy
00010 //         Created:  Tue Apr 11 13:43:16 CDT 2006
00011 //
00012 
00013 #include "FWCore/Services/src/EnableFloatingPointExceptions.h"
00014 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00015 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00016 #include "FWCore/ServiceRegistry/interface/ActivityRegistry.h"
00017 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00018 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
00019 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00020 #include "FWCore/ParameterSet/interface/AllowedLabelsDescription.h"
00021 
00022 #include <cassert>
00023 #include <fenv.h>
00024 #include <vector>
00025 #ifdef __linux__
00026 #include <fpu_control.h>
00027 #else
00028 #ifdef __APPLE__
00029 //TAKEN FROM
00030 // https://public.kitware.com/Bug/file_download.php?file_id=3215&type=bug
00031 static int
00032 fegetexcept (void)
00033 {
00034   static fenv_t fenv;
00035 
00036   return fegetenv (&fenv) ? -1 : (fenv.__control & FE_ALL_EXCEPT);
00037 }
00038 
00039 static int
00040 feenableexcept (unsigned int excepts)
00041 {
00042   static fenv_t fenv;
00043   unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
00044                old_excepts;  // previous masks
00045 
00046   if ( fegetenv (&fenv) ) return -1;
00047   old_excepts = fenv.__control & FE_ALL_EXCEPT;
00048 
00049   // unmask
00050   fenv.__control &= ~new_excepts;
00051   fenv.__mxcsr   &= ~(new_excepts << 7);
00052 
00053   return ( fesetenv (&fenv) ? -1 : old_excepts );
00054 }
00055 
00056 static int
00057 fedisableexcept (unsigned int excepts)
00058 {
00059   static fenv_t fenv;
00060   unsigned int new_excepts = excepts & FE_ALL_EXCEPT,
00061                old_excepts;  // all previous masks
00062 
00063   if ( fegetenv (&fenv) ) return -1;
00064   old_excepts = fenv.__control & FE_ALL_EXCEPT;
00065 
00066   // mask
00067   fenv.__control |= new_excepts;
00068   fenv.__mxcsr   |= new_excepts << 7;
00069 
00070   return ( fesetenv (&fenv) ? -1 : old_excepts );
00071 }
00072 
00073 #endif
00074 #endif
00075 
00076 namespace edm {
00077   namespace service {
00078 
00079     EnableFloatingPointExceptions::
00080     EnableFloatingPointExceptions(ParameterSet const& pset,
00081                                   ActivityRegistry & registry):
00082       fpuState_(0),
00083       defaultState_(0),
00084       stateMap_(),
00085       stateStack_(),
00086       reportSettings_(false) {
00087 
00088       reportSettings_ = pset.getUntrackedParameter<bool>("reportSettings", false);
00089       bool precisionDouble = pset.getUntrackedParameter<bool>("setPrecisionDouble", true);
00090 
00091       if (reportSettings_)  {
00092         edm::LogVerbatim("FPE_Enable") << "\nSettings in EnableFloatingPointExceptions constructor";
00093         echoState();
00094       }
00095 
00096       establishModuleEnvironments(pset);
00097 
00098       stateStack_.push(defaultState_);
00099       fpuState_ = defaultState_;
00100       enableAndDisableExcept(defaultState_);
00101 
00102       setPrecision(precisionDouble);
00103 
00104       // Note that we must watch all of the transitions even if there are no module specific settings.
00105       // This is because the floating point environment may be modified by code outside of this service.
00106       registry.watchPostEndJob(this,&EnableFloatingPointExceptions::postEndJob);
00107 
00108       registry.watchPreModuleBeginJob(this, &EnableFloatingPointExceptions::preModuleBeginJob);
00109       registry.watchPostModuleBeginJob(this, &EnableFloatingPointExceptions::postModuleBeginJob);
00110       registry.watchPreModuleEndJob(this, &EnableFloatingPointExceptions::preModuleEndJob);
00111       registry.watchPostModuleEndJob(this, &EnableFloatingPointExceptions::postModuleEndJob);
00112 
00113       registry.watchPreModuleBeginRun(this, &EnableFloatingPointExceptions::preModuleBeginRun);
00114       registry.watchPostModuleBeginRun(this, &EnableFloatingPointExceptions::postModuleBeginRun);
00115       registry.watchPreModuleEndRun(this, &EnableFloatingPointExceptions::preModuleEndRun);
00116       registry.watchPostModuleEndRun(this, &EnableFloatingPointExceptions::postModuleEndRun);
00117 
00118       registry.watchPreModuleBeginLumi(this, &EnableFloatingPointExceptions::preModuleBeginLumi);
00119       registry.watchPostModuleBeginLumi(this, &EnableFloatingPointExceptions::postModuleBeginLumi);
00120       registry.watchPreModuleEndLumi(this, &EnableFloatingPointExceptions::preModuleEndLumi);
00121       registry.watchPostModuleEndLumi(this, &EnableFloatingPointExceptions::postModuleEndLumi);
00122 
00123       registry.watchPreModule(this, &EnableFloatingPointExceptions::preModule);
00124       registry.watchPostModule(this, &EnableFloatingPointExceptions::postModule);
00125     }
00126 
00127     // Establish an environment for each module; default is handled specially.
00128     void
00129     EnableFloatingPointExceptions::establishModuleEnvironments(ParameterSet const& pset) {
00130 
00131       // Scan the module name list and set per-module values.  Be careful to treat
00132       // any user-specified default first.  If there is one, use it to override our default.
00133       // Then remove it from the list so we don't see it again while handling everything else.
00134 
00135       typedef std::vector<std::string> VString;
00136 
00137       std::string const def("default");
00138       ParameterSet const empty_PSet;
00139       VString const empty_VString;
00140       VString moduleNames = pset.getUntrackedParameter<VString>("moduleNames", empty_VString);
00141 
00142       for (VString::const_iterator it(moduleNames.begin()), itEnd = moduleNames.end(); it != itEnd; ++it) {
00143         ParameterSet modulePSet = pset.getUntrackedParameter<ParameterSet>(*it, empty_PSet);
00144         bool enableDivByZeroEx  = modulePSet.getUntrackedParameter<bool>("enableDivByZeroEx", false);
00145         bool enableInvalidEx    = modulePSet.getUntrackedParameter<bool>("enableInvalidEx",   false);
00146         bool enableOverFlowEx   = modulePSet.getUntrackedParameter<bool>("enableOverFlowEx",  false);
00147         bool enableUnderFlowEx  = modulePSet.getUntrackedParameter<bool>("enableUnderFlowEx", false);
00148 
00149         fpu_flags_type flags = 0;
00150         if (enableDivByZeroEx) flags |= FE_DIVBYZERO;
00151         if (enableInvalidEx)   flags |= FE_INVALID;
00152         if (enableOverFlowEx)  flags |= FE_OVERFLOW;
00153         if (enableUnderFlowEx) flags |= FE_UNDERFLOW;
00154         enableAndDisableExcept(flags);
00155 
00156         fpuState_ = fegetexcept();
00157         assert(flags == fpuState_);
00158 
00159         if (reportSettings_) {
00160           edm::LogVerbatim("FPE_Enable") << "\nSettings for module " << *it;
00161           echoState();
00162         }
00163         if (*it == def) {
00164           defaultState_ = fpuState_;
00165         }
00166         else {
00167           stateMap_[*it] =  fpuState_;
00168         }
00169       }
00170     }
00171 
00172     void
00173     EnableFloatingPointExceptions::postEndJob() {
00174 
00175       if (reportSettings_) {
00176         edm::LogVerbatim("FPE_Enable") << "\nSettings after endJob ";
00177         echoState();
00178       }
00179     }
00180 
00181     void 
00182     EnableFloatingPointExceptions::
00183     preModuleBeginJob(ModuleDescription const& description) {
00184       preActions(description, "beginJob");
00185     }
00186 
00187     void 
00188     EnableFloatingPointExceptions::
00189     postModuleBeginJob(ModuleDescription const& description) {
00190       postActions(description, "beginJob");
00191     }
00192 
00193     void 
00194     EnableFloatingPointExceptions::
00195     preModuleEndJob(ModuleDescription const& description) {
00196       preActions(description, "endJob");
00197     }
00198 
00199     void 
00200     EnableFloatingPointExceptions::
00201     postModuleEndJob(ModuleDescription const& description) {
00202       postActions(description, "endJob");
00203     }
00204 
00205     void 
00206     EnableFloatingPointExceptions::
00207     preModuleBeginRun(ModuleDescription const& description) {
00208       preActions(description, "beginRun");
00209     }
00210 
00211     void 
00212     EnableFloatingPointExceptions::
00213     postModuleBeginRun(ModuleDescription const& description) {
00214       postActions(description, "beginRun");
00215     }
00216 
00217     void 
00218     EnableFloatingPointExceptions::
00219     preModuleEndRun(ModuleDescription const& description) {
00220       preActions(description, "endRun");
00221     }
00222 
00223     void 
00224     EnableFloatingPointExceptions::
00225     postModuleEndRun(ModuleDescription const& description) {
00226       postActions(description, "endRun");
00227     }
00228 
00229     void
00230     EnableFloatingPointExceptions::
00231     preModuleBeginLumi(ModuleDescription const& description) {
00232       preActions(description, "beginLumi");
00233     }
00234 
00235     void 
00236     EnableFloatingPointExceptions::
00237     postModuleBeginLumi(ModuleDescription const& description) {
00238       postActions(description, "beginLumi");
00239     }
00240 
00241     void 
00242     EnableFloatingPointExceptions::
00243     preModuleEndLumi(ModuleDescription const& description) {
00244       preActions(description, "endLumi");
00245     }
00246 
00247     void 
00248     EnableFloatingPointExceptions::
00249     postModuleEndLumi(ModuleDescription const& description) {
00250       postActions(description, "endLumi");
00251     }
00252 
00253     void 
00254     EnableFloatingPointExceptions::
00255     preModule(ModuleDescription const& description) {
00256       preActions(description, "event");
00257     }
00258 
00259     void 
00260     EnableFloatingPointExceptions::
00261     postModule(ModuleDescription const& description) {
00262       postActions(description, "event");
00263     }
00264 
00265     void
00266     EnableFloatingPointExceptions::
00267     fillDescriptions(edm::ConfigurationDescriptions & descriptions) {
00268       edm::ParameterSetDescription desc;
00269 
00270       desc.addUntracked<bool>("reportSettings", false)->setComment(
00271         "Log FPE settings at different phases of the job."
00272                                                                );
00273       desc.addUntracked<bool>("setPrecisionDouble", true)->setComment(
00274         "Set the FPU to use double precision");
00275 
00276       edm::ParameterSetDescription validator;
00277       validator.setComment("FPU exceptions to enable/disable for the requested module");
00278       validator.addUntracked<bool>("enableDivByZeroEx", false)->setComment(
00279         "Enable/disable exception for 'divide by zero'");
00280       validator.addUntracked<bool>("enableInvalidEx",   false)->setComment(
00281         "Enable/disable exception for 'invalid' math operations (e.g. sqrt(-1))");
00282       validator.addUntracked<bool>("enableOverFlowEx",  false)->setComment(
00283         "Enable/disable exception for numeric 'overflow' (value to big for type)");
00284       validator.addUntracked<bool>("enableUnderFlowEx", false)->setComment(
00285         "Enable/disable exception for numeric 'underflow' (value to small to be represented accurately)");
00286 
00287       edm::AllowedLabelsDescription<edm::ParameterSetDescription> node("moduleNames", validator, false);
00288       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");
00289       desc.addNode(node);
00290 
00291       descriptions.add("EnableFloatingPointExceptions", desc);
00292       descriptions.setComment("This service allows you to control the FPU and its exceptions on a per module basis.");
00293     }
00294 
00295 
00296     void 
00297     EnableFloatingPointExceptions::
00298     preActions(ModuleDescription const& description,
00299                char const* debugInfo) {
00300 
00301       // On entry to a module, find the desired state of the fpu and set it
00302       // accordingly. Note that any module whose label does not appear in
00303       // our list gets the default settings.
00304 
00305       std::string const& moduleLabel = description.moduleLabel();
00306       std::map<std::string, fpu_flags_type>::const_iterator iModule = stateMap_.find(moduleLabel);
00307 
00308       if (iModule == stateMap_.end())  {
00309         fpuState_ = defaultState_;
00310       }
00311       else {
00312         fpuState_ = iModule->second;
00313       }
00314       enableAndDisableExcept(fpuState_);
00315       stateStack_.push(fpuState_);
00316 
00317       if (reportSettings_) {
00318         edm::LogVerbatim("FPE_Enable")
00319           << "\nSettings for module label \""
00320           << moduleLabel
00321           << "\" before "
00322           << debugInfo;
00323         echoState();
00324       }
00325     }
00326 
00327     void 
00328     EnableFloatingPointExceptions::
00329     postActions(ModuleDescription const& description, char const* debugInfo) {
00330       // On exit from a module, set the state of the fpu back to what
00331       // it was before entry
00332       stateStack_.pop();
00333       fpuState_ = stateStack_.top();
00334       enableAndDisableExcept(fpuState_);
00335 
00336       if (reportSettings_) {
00337         edm::LogVerbatim("FPE_Enable")
00338           << "\nSettings for module label \""
00339           << description.moduleLabel()
00340           << "\" after "
00341           << debugInfo;
00342         echoState();
00343       }
00344     }
00345 
00346     void
00347     EnableFloatingPointExceptions::setPrecision(bool precisionDouble) {
00348 #ifdef __linux__
00349 #ifdef __i386__
00350       if (precisionDouble) {
00351         fpu_control_t cw;
00352         _FPU_GETCW(cw);
00353 
00354         cw = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
00355         _FPU_SETCW(cw);
00356       }
00357 #endif
00358 #endif
00359     }
00360 
00361     void
00362     EnableFloatingPointExceptions::enableAndDisableExcept(fpu_flags_type target) {
00363       feclearexcept(FE_ALL_EXCEPT);
00364       fpu_flags_type current = fegetexcept();
00365       fpu_flags_type exceptionsToModify = current ^ target;
00366       fpu_flags_type exceptionsToEnable = 0;
00367       fpu_flags_type exceptionsToDisable = 0;
00368 
00369       if (exceptionsToModify & FE_DIVBYZERO) {
00370         if (target & FE_DIVBYZERO) {
00371           exceptionsToEnable |= FE_DIVBYZERO;
00372         }
00373         else {
00374           exceptionsToDisable |= FE_DIVBYZERO;
00375         }
00376       }
00377       if (exceptionsToModify & FE_INVALID) {
00378         if (target & FE_INVALID) {
00379           exceptionsToEnable |= FE_INVALID;
00380         }
00381         else {
00382           exceptionsToDisable |= FE_INVALID;
00383         }
00384       }
00385       if (exceptionsToModify & FE_OVERFLOW) {
00386         if (target & FE_OVERFLOW) {
00387           exceptionsToEnable |= FE_OVERFLOW;
00388         }
00389         else {
00390           exceptionsToDisable |= FE_OVERFLOW;
00391         }
00392       }
00393       if (exceptionsToModify & FE_UNDERFLOW) {
00394         if (target & FE_UNDERFLOW) {
00395           exceptionsToEnable |= FE_UNDERFLOW;
00396         }
00397         else {
00398           exceptionsToDisable |= FE_UNDERFLOW;
00399         }
00400       }
00401       if (exceptionsToEnable != 0) {
00402         feenableexcept(exceptionsToEnable);
00403       }
00404       if (exceptionsToDisable != 0) {
00405         fedisableexcept(exceptionsToDisable);
00406       }
00407     }
00408 
00409     void
00410     EnableFloatingPointExceptions::echoState() const {
00411       feclearexcept(FE_ALL_EXCEPT);
00412       fpu_flags_type femask = fegetexcept();
00413       edm::LogVerbatim("FPE_Enable") << "Floating point exception mask is " 
00414                                  << std::showbase << std::hex << femask;
00415  
00416       if (femask & FE_DIVBYZERO)
00417         edm::LogVerbatim("FPE_Enable") << "\tDivByZero exception is on";
00418       else
00419         edm::LogVerbatim("FPE_Enable") << "\tDivByZero exception is off";
00420   
00421       if (femask & FE_INVALID)
00422         edm::LogVerbatim("FPE_Enable") << "\tInvalid exception is on";
00423       else
00424         edm::LogVerbatim("FPE_Enable") << "\tInvalid exception is off";
00425  
00426       if (femask & FE_OVERFLOW)
00427         edm::LogVerbatim("FPE_Enable") << "\tOverFlow exception is on";
00428       else
00429         edm::LogVerbatim("FPE_Enable") << "\tOverflow exception is off";
00430   
00431       if (femask & FE_UNDERFLOW)
00432         edm::LogVerbatim("FPE_Enable") << "\tUnderFlow exception is on";
00433       else
00434         edm::LogVerbatim("FPE_Enable") << "\tUnderFlow exception is off";
00435     }
00436 
00437   } // namespace edm
00438 } // namespace service