CMS 3D CMS Logo

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