00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00030
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;
00045
00046 if ( fegetenv (&fenv) ) return -1;
00047 old_excepts = fenv.__control & FE_ALL_EXCEPT;
00048
00049
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;
00062
00063 if ( fegetenv (&fenv) ) return -1;
00064 old_excepts = fenv.__control & FE_ALL_EXCEPT;
00065
00066
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
00105
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
00128 void
00129 EnableFloatingPointExceptions::establishModuleEnvironments(ParameterSet const& pset) {
00130
00131
00132
00133
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
00302
00303
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
00331
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 }
00438 }