00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
00031
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;
00044
00045 if(fegetenv (&fenv)) return -1;
00046 old_excepts = fenv.__control & FE_ALL_EXCEPT;
00047
00048
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;
00060
00061 if(fegetenv (&fenv)) return -1;
00062 old_excepts = fenv.__control & FE_ALL_EXCEPT;
00063
00064
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
00103
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
00126 void
00127 EnableFloatingPointExceptions::establishModuleEnvironments(ParameterSet const& pset) {
00128
00129
00130
00131
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
00299
00300
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
00328
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 ) {
00358 }
00359 #endif
00360 #else
00361 void
00362 EnableFloatingPointExceptions::setPrecision(bool ) {
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 }
00443 }