1 2 /* 3 IEEE error handler for all machines. Since each OS has 4 enough slight differences we have completely separate codes for each one. 5 */ 6 7 /* 8 This feature test macro provides FE_NOMASK_ENV on GNU. It must be defined 9 at the top of the file because other headers may pull in fenv.h even when 10 not strictly necessary. Strictly speaking, we could include ONLY petscconf.h, 11 check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such 12 shenanigans ought to be unnecessary. 13 */ 14 #if !defined(_GNU_SOURCE) 15 #define _GNU_SOURCE 16 #endif 17 18 #include <petsc/private/petscimpl.h> /*I "petscsys.h" I*/ 19 #include <signal.h> 20 21 struct PetscFPTrapLink { 22 PetscFPTrap trapmode; 23 struct PetscFPTrapLink *next; 24 }; 25 static PetscFPTrap _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode; see PetscDetermineInitialFPTrap() */ 26 static struct PetscFPTrapLink *_trapstack; /* Any pushed states of _trapmode */ 27 28 /*@ 29 PetscFPTrapPush - push a floating point trapping mode, restored using PetscFPTrapPop() 30 31 Not Collective 32 33 Input Parameter: 34 . trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF or any of the values passable to `PetscSetFPTrap()` 35 36 Level: advanced 37 38 Notes: 39 This only changes the trapping if the new mode is different than the current mode. 40 41 This routine is called to turn off trapping for certain LAPACK routines that assume that dividing 42 by zero is acceptable. In particular the routine ieeeck(). 43 44 Most systems by default have all trapping turned off, but certain Fortran compilers have 45 link flags that turn on trapping before the program begins. 46 $ gfortran -ffpe-trap=invalid,zero,overflow,underflow,denormal 47 $ ifort -fpe0 48 49 .seealso: `PetscFPTrapPop()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()` 50 @*/ 51 PetscErrorCode PetscFPTrapPush(PetscFPTrap trap) { 52 struct PetscFPTrapLink *link; 53 54 PetscFunctionBegin; 55 PetscCall(PetscNew(&link)); 56 #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP) 57 #pragma omp critical 58 #endif 59 { 60 link->trapmode = _trapmode; 61 link->next = _trapstack; 62 _trapstack = link; 63 } 64 if (trap != _trapmode) PetscCall(PetscSetFPTrap(trap)); 65 PetscFunctionReturn(0); 66 } 67 68 /*@ 69 PetscFPTrapPop - push a floating point trapping mode, to be restored using PetscFPTrapPop() 70 71 Not Collective 72 73 Level: advanced 74 75 .seealso: `PetscFPTrapPush()`, `PetscSetFPTrap()`, `PetscDetermineInitialFPTrap()` 76 @*/ 77 PetscErrorCode PetscFPTrapPop(void) { 78 struct PetscFPTrapLink *link; 79 80 PetscFunctionBegin; 81 if (_trapstack->trapmode != _trapmode) PetscCall(PetscSetFPTrap(_trapstack->trapmode)); 82 #if defined(PETSC_HAVE_THREADSAFETY) && defined(PETSC_HAVE_OPENMP) 83 #pragma omp critical 84 #endif 85 { 86 link = _trapstack; 87 _trapstack = _trapstack->next; 88 } 89 PetscCall(PetscFree(link)); 90 PetscFunctionReturn(0); 91 } 92 93 /*--------------------------------------- ---------------------------------------------------*/ 94 #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP) 95 #include <floatingpoint.h> 96 97 PETSC_EXTERN PetscErrorCode ieee_flags(char *, char *, char *, char **); 98 PETSC_EXTERN PetscErrorCode ieee_handler(char *, char *, sigfpe_handler_type(int, int, struct sigcontext *, char *)); 99 100 static struct { 101 int code_no; 102 char *name; 103 } error_codes[] = { 104 {FPE_INTDIV_TRAP, "integer divide" }, 105 {FPE_FLTOPERR_TRAP, "IEEE operand error" }, 106 {FPE_FLTOVF_TRAP, "floating point overflow" }, 107 {FPE_FLTUND_TRAP, "floating point underflow" }, 108 {FPE_FLTDIV_TRAP, "floating pointing divide" }, 109 {FPE_FLTINEX_TRAP, "inexact floating point result"}, 110 {0, "unknown error" } 111 }; 112 #define SIGPC(scp) (scp->sc_pc) 113 114 /* this function gets called if a trap has occurred and been caught */ 115 sigfpe_handler_type PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp, char *addr) { 116 int err_ind = -1; 117 118 PetscFunctionBegin; 119 for (int j = 0; error_codes[j].code_no; j++) { 120 if (error_codes[j].code_no == code) err_ind = j; 121 } 122 123 if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp)); 124 else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp)); 125 126 (void)PetscError(PETSC_COMM_SELF, PETSC_ERR_FP, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 127 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 128 PetscFunctionReturn(0); 129 } 130 131 /*@ 132 PetscSetFPTrap - Enables traps/exceptions on common floating point errors. This option may not work on certain systems or only a 133 subset of exceptions may be trapable. 134 135 Not Collective 136 137 Input Parameters: 138 . flag - values are 139 .vb 140 PETSC_FP_TRAP_OFF - do not trap any exceptions 141 PETSC_FP_TRAP_ON - all exceptions that are possible on the system except underflow 142 PETSC_FP_TRAP_INDIV - integer divide by zero 143 PETSC_FP_TRAP_FLTOPERR - improper argument to function, for example with real numbers, the square root of a negative number 144 PETSC_FP_TRAP_FLTOVF - overflow 145 PETSC_FP_TRAP_FLTUND - underflow - not trapped by default on most systems 146 PETSC_FP_TRAP_FLTDIV - floating point divide by zero 147 PETSC_FP_TRAP_FLTINEX - inexact floating point result 148 .ve 149 150 Options Database Keys: 151 . -fp_trap <off,on> - turn on or off trapping of floating point exceptions 152 153 Level: advanced 154 155 Notes: 156 Currently only PETSC_FP_TRAP_OFF and PETSC_FP_TRAP_ON are handled. All others are treated as PETSC_FP_TRAP_ON. 157 158 The values are bit values and may be |ed together in the function call 159 160 On systems that support it this routine causes floating point 161 overflow, divide-by-zero, and invalid-operand (e.g., a NaN), but not underflow, to 162 cause a message to be printed and the program to exit. 163 164 On many common systems, the floating 165 point exception state is not preserved from the location where the trap 166 occurred through to the signal handler. In this case, the signal handler 167 will just say that an unknown floating point exception occurred and which 168 function it occurred in. If you run with -fp_trap in a debugger, it will 169 break on the line where the error occurred. On systems that support C99 170 floating point exception handling You can check which 171 exception occurred using fetestexcept(FE_ALL_EXCEPT). See fenv.h 172 (usually at /usr/include/bits/fenv.h) for the enum values on your system. 173 174 Caution: 175 On certain machines, in particular the IBM PowerPC, floating point 176 trapping may be VERY slow! 177 178 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()` 179 @*/ 180 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 181 char *out; 182 183 PetscFunctionBegin; 184 /* Clear accumulated exceptions. Used to suppress meaningless messages from f77 programs */ 185 (void)ieee_flags("clear", "exception", "all", &out); 186 if (flag == PETSC_FP_TRAP_ON) { 187 /* 188 To trap more fp exceptions, including underflow, change the line below to 189 if (ieee_handler("set","all",PetscDefaultFPTrap)) { 190 */ 191 if (ieee_handler("set", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n"); 192 } else if (ieee_handler("clear", "common", PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 193 194 _trapmode = flag; 195 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_SUN4_STYLE_FPTRAP\n")); 196 PetscFunctionReturn(0); 197 } 198 199 /*@ 200 PetscDetermineInitialFPTrap - Attempts to determine the floating point trapping that exists when PetscInitialize() is called 201 202 Not Collective 203 204 Notes: 205 Currently only supported on Linux and MacOS. Checks if divide by zero is enable and if so declares that trapping is on. 206 207 Level: advanced 208 209 .seealso: `PetscFPTrapPush()`, `PetscFPTrapPop()`, `PetscDetermineInitialFPTrap()` 210 @*/ 211 PetscErrorCode PetscDetermineInitialFPTrap(void) { 212 PetscFunctionBegin; 213 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 214 PetscFunctionReturn(0); 215 } 216 217 /* -------------------------------------------------------------------------------------------*/ 218 #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP) 219 #include <sunmath.h> 220 #include <floatingpoint.h> 221 #include <siginfo.h> 222 #include <ucontext.h> 223 224 static struct { 225 int code_no; 226 char *name; 227 } error_codes[] = { 228 {FPE_FLTINV, "invalid floating point operand"}, 229 {FPE_FLTRES, "inexact floating point result" }, 230 {FPE_FLTDIV, "division-by-zero" }, 231 {FPE_FLTUND, "floating point underflow" }, 232 {FPE_FLTOVF, "floating point overflow" }, 233 {0, "unknown error" } 234 }; 235 #define SIGPC(scp) (scp->si_addr) 236 237 void PetscDefaultFPTrap(int sig, siginfo_t *scp, ucontext_t *uap) { 238 int err_ind = -1, code = scp->si_code; 239 240 PetscFunctionBegin; 241 for (int j = 0; error_codes[j].code_no; j++) { 242 if (error_codes[j].code_no == code) err_ind = j; 243 } 244 245 if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n", error_codes[err_ind].name, SIGPC(scp)); 246 else (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n", code, SIGPC(scp)); 247 248 (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 249 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 250 } 251 252 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 253 char *out; 254 255 PetscFunctionBegin; 256 /* Clear accumulated exceptions. Used to suppress meaningless messages from f77 programs */ 257 (void)ieee_flags("clear", "exception", "all", &out); 258 if (flag == PETSC_FP_TRAP_ON) { 259 if (ieee_handler("set", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floating point handler\n"); 260 } else { 261 if (ieee_handler("clear", "common", (sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 262 } 263 _trapmode = flag; 264 PetscCall(PetscInfo(NULL,"Using PETSC_HAVE_SOLARIS_STYLE_FPTRAP\n"); 265 PetscFunctionReturn(0); 266 } 267 268 PetscErrorCode PetscDetermineInitialFPTrap(void) { 269 PetscFunctionBegin; 270 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 271 PetscFunctionReturn(0); 272 } 273 274 /* ------------------------------------------------------------------------------------------*/ 275 #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP) 276 #include <sigfpe.h> 277 static struct { 278 int code_no; 279 char *name; 280 } error_codes[] = { 281 {_INVALID, "IEEE operand error" }, 282 {_OVERFL, "floating point overflow" }, 283 {_UNDERFL, "floating point underflow"}, 284 {_DIVZERO, "floating point divide" }, 285 {0, "unknown error" } 286 }; 287 void PetscDefaultFPTrap(unsigned exception[], int val[]) { 288 int err_ind = -1, code = exception[0]; 289 290 PetscFunctionBegin; 291 for (int j = 0; error_codes[j].code_no; j++) { 292 if (error_codes[j].code_no == code) err_ind = j; 293 } 294 if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name); 295 else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", code); 296 297 (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 298 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 299 } 300 301 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 302 PetscFunctionBegin; 303 if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON, , _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, PetscDefaultFPTrap, _ABORT_ON_ERROR, 0); 304 else handle_sigfpes(_OFF, _EN_UNDERFL | _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, 0, _ABORT_ON_ERROR, 0); 305 _trapmode = flag; 306 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IRIX_STYLE_FPTRAP\n")); 307 PetscFunctionReturn(0); 308 } 309 310 PetscErrorCode PetscDetermineInitialFPTrap(void) { 311 PetscFunctionBegin; 312 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 313 PetscFunctionReturn(0); 314 } 315 316 /*----------------------------------------------- --------------------------------------------*/ 317 #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP) 318 /* In "fast" mode, floating point traps are imprecise and ignored. 319 This is the reason for the fptrap(FP_TRAP_SYNC) call */ 320 struct sigcontext; 321 #include <fpxcp.h> 322 #include <fptrap.h> 323 #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000) 324 #define FPE_FLTOVF_TRAP (fptrap_t)(0x10000000) 325 #define FPE_FLTUND_TRAP (fptrap_t)(0x08000000) 326 #define FPE_FLTDIV_TRAP (fptrap_t)(0x04000000) 327 #define FPE_FLTINEX_TRAP (fptrap_t)(0x02000000) 328 329 static struct { 330 int code_no; 331 char *name; 332 } error_codes[] = { 333 {FPE_FLTOPERR_TRAP, "IEEE operand error" }, 334 {FPE_FLTOVF_TRAP, "floating point overflow" }, 335 {FPE_FLTUND_TRAP, "floating point underflow" }, 336 {FPE_FLTDIV_TRAP, "floating point divide" }, 337 {FPE_FLTINEX_TRAP, "inexact floating point result"}, 338 < {0, "unknown error" } 339 }; 340 #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */ 341 /* 342 For some reason, scp->sc_jmpbuf does not work on the RS6000, even though 343 it looks like it should from the include definitions. It is probably 344 some strange interaction with the "POSIX_SOURCE" that we require. 345 */ 346 347 void PetscDefaultFPTrap(int sig, int code, struct sigcontext *scp) { 348 int err_ind, j; 349 fp_ctx_t flt_context; 350 351 PetscFunctionBegin; 352 fp_sh_trap_info(scp, &flt_context); 353 354 err_ind = -1; 355 for (j = 0; error_codes[j].code_no; j++) { 356 if (error_codes[j].code_no == flt_context.trap) err_ind = j; 357 } 358 359 if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n", error_codes[err_ind].name); 360 else (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n", flt_context.trap); 361 362 (void)PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 363 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 364 } 365 366 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 367 PetscFunctionBegin; 368 if (flag == PETSC_FP_TRAP_ON) { 369 signal(SIGFPE, (void (*)(int))PetscDefaultFPTrap); 370 fp_trap(FP_TRAP_SYNC); 371 /* fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); */ 372 fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW); 373 } else { 374 signal(SIGFPE, SIG_DFL); 375 fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW | TRP_UNDERFLOW); 376 fp_trap(FP_TRAP_OFF); 377 } 378 _trapmode = flag; 379 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_RS6000_STYLE_FPTRAP\n")); 380 PetscFunctionReturn(0); 381 } 382 383 PetscErrorCode PetscDetermineInitialFPTrap(void) { 384 PetscFunctionBegin; 385 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 386 PetscFunctionReturn(0); 387 } 388 389 /* ------------------------------------------------------------*/ 390 #elif defined(PETSC_HAVE_WINDOWS_COMPILERS) 391 #include <float.h> 392 void PetscDefaultFPTrap(int sig) { 393 PetscFunctionBegin; 394 (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 395 PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 396 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 397 } 398 399 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 400 unsigned int cw; 401 402 PetscFunctionBegin; 403 if (flag == PETSC_FP_TRAP_ON) { 404 /* cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW; */ 405 cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW; 406 PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler"); 407 } else { 408 cw = 0; 409 PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler"); 410 } 411 (void)_controlfp(0, cw); 412 _trapmode = flag; 413 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_WINDOWS_COMPILERS FPTRAP\n")); 414 PetscFunctionReturn(0); 415 } 416 417 PetscErrorCode PetscDetermineInitialFPTrap(void) { 418 PetscFunctionBegin; 419 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 420 PetscFunctionReturn(0); 421 } 422 423 /* ------------------------------------------------------------*/ 424 #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus) 425 /* 426 C99 style floating point environment. 427 428 Note that C99 merely specifies how to save, restore, and clear the floating 429 point environment as well as defining an enumeration of exception codes. In 430 particular, C99 does not specify how to make floating point exceptions raise 431 a signal. Glibc offers this capability through FE_NOMASK_ENV (or with finer 432 granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK(). 433 */ 434 #include <fenv.h> 435 typedef struct { 436 int code; 437 const char *name; 438 } FPNode; 439 static const FPNode error_codes[] = { 440 {FE_DIVBYZERO, "divide by zero" }, 441 {FE_INEXACT, "inexact floating point result" }, 442 {FE_INVALID, "invalid floating point arguments (domain error)"}, 443 {FE_OVERFLOW, "floating point overflow" }, 444 {FE_UNDERFLOW, "floating point underflow" }, 445 {0, "unknown error" } 446 }; 447 448 void PetscDefaultFPTrap(int sig) { 449 const FPNode *node; 450 int code; 451 PetscBool matched = PETSC_FALSE; 452 453 PetscFunctionBegin; 454 /* Note: While it is possible for the exception state to be preserved by the 455 * kernel, this seems to be rare which makes the following flag testing almost 456 * useless. But on a system where the flags can be preserved, it would provide 457 * more detail. 458 */ 459 code = fetestexcept(FE_ALL_EXCEPT); 460 for (node = &error_codes[0]; node->code; node++) { 461 if (code & node->code) { 462 matched = PETSC_TRUE; 463 (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n", node->name); 464 code &= ~node->code; /* Unset this flag since it has been processed */ 465 } 466 } 467 if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */ 468 (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n"); 469 (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger. When the\n"); 470 (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n", FE_ALL_EXCEPT); 471 (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n"); 472 (*PetscErrorPrintf)("FE_INVALID=0x%x FE_DIVBYZERO=0x%x FE_OVERFLOW=0x%x FE_UNDERFLOW=0x%x FE_INEXACT=0x%x\n", FE_INVALID, FE_DIVBYZERO, FE_OVERFLOW, FE_UNDERFLOW, FE_INEXACT); 473 } 474 475 (*PetscErrorPrintf)("Try option -start_in_debugger\n"); 476 #if PetscDefined(USE_DEBUG) 477 (*PetscErrorPrintf)("likely location of problem given in stack below\n"); 478 (*PetscErrorPrintf)("--------------------- Stack Frames ------------------------------------\n"); 479 PetscStackView(PETSC_STDOUT); 480 #else 481 (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n"); 482 (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n"); 483 #endif 484 PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_INITIAL, "trapped floating point error"); 485 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 486 } 487 488 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 489 PetscFunctionBegin; 490 if (flag == PETSC_FP_TRAP_ON) { 491 /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */ 492 PetscCheck(!feclearexcept(FE_ALL_EXCEPT), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot clear floating point exception flags"); 493 #if defined(FE_NOMASK_ENV) 494 /* Could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */ 495 /* PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) != -1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions"); */ 496 /* Doesn't work on AArch64 targets. There's a known hardware limitation. Need to detect hardware at configure time? */ 497 PetscCheck(feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) != -1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot activate floating point exceptions"); 498 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with FE_NOMASK_ENV\n")); 499 #elif defined PETSC_HAVE_XMMINTRIN_H 500 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_DIV_ZERO); 501 /* _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_UNDERFLOW); */ 502 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_OVERFLOW); 503 _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~_MM_MASK_INVALID); 504 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP with PETSC_HAVE_XMMINTRIN_H\n")); 505 #else 506 /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */ 507 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_FENV_H FPTRAP\n")); 508 #endif 509 PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler"); 510 } else { 511 PetscCheck(!fesetenv(FE_DFL_ENV), PETSC_COMM_SELF, PETSC_ERR_LIB, "Cannot disable floating point exceptions"); 512 /* can use _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | _MM_MASK_UNDERFLOW); if PETSC_HAVE_XMMINTRIN_H exists */ 513 PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler"); 514 } 515 _trapmode = flag; 516 PetscFunctionReturn(0); 517 } 518 519 PetscErrorCode PetscDetermineInitialFPTrap(void) { 520 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H 521 unsigned int flags; 522 #endif 523 524 PetscFunctionBegin; 525 #if defined(FE_NOMASK_ENV) 526 flags = fegetexcept(); 527 if (flags & FE_DIVBYZERO) { 528 #elif defined PETSC_HAVE_XMMINTRIN_H 529 flags = _MM_GET_EXCEPTION_MASK(); 530 if (!(flags & _MM_MASK_DIV_ZERO)) { 531 #else 532 PetscCall(PetscInfo(NULL, "Floating point trapping unknown, assuming off\n")); 533 PetscFunctionReturn(0); 534 #endif 535 #if defined(FE_NOMASK_ENV) || defined PETSC_HAVE_XMMINTRIN_H 536 _trapmode = PETSC_FP_TRAP_ON; 537 PetscCall(PetscInfo(NULL, "Floating point trapping is on by default %d\n", flags)); 538 } else { 539 _trapmode = PETSC_FP_TRAP_OFF; 540 PetscCall(PetscInfo(NULL, "Floating point trapping is off by default %d\n", flags)); 541 } 542 PetscFunctionReturn(0); 543 #endif 544 } 545 546 /* ------------------------------------------------------------*/ 547 #elif defined(PETSC_HAVE_IEEEFP_H) 548 #include <ieeefp.h> 549 void PetscDefaultFPTrap(int sig) { 550 PetscFunctionBegin; 551 (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 552 PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 553 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 554 } 555 556 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 557 PetscFunctionBegin; 558 if (flag == PETSC_FP_TRAP_ON) { 559 #if defined(PETSC_HAVE_FPPRESETSTICKY) 560 fpresetsticky(fpgetsticky()); 561 #elif defined(PETSC_HAVE_FPSETSTICKY) 562 fpsetsticky(fpgetsticky()); 563 #endif 564 fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_OFL); 565 PetscCheck(SIG_ERR != signal(SIGFPE, PetscDefaultFPTrap), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't set floating point handler"); 566 } else { 567 #if defined(PETSC_HAVE_FPPRESETSTICKY) 568 fpresetsticky(fpgetsticky()); 569 #elif defined(PETSC_HAVE_FPSETSTICKY) 570 fpsetsticky(fpgetsticky()); 571 #endif 572 fpsetmask(0); 573 PetscCheck(SIG_ERR != signal(SIGFPE, SIG_DFL), PETSC_COMM_SELF, PETSC_ERR_LIB, "Can't clear floating point handler"); 574 } 575 _trapmode = flag; 576 PetscCall(PetscInfo(NULL, "Using PETSC_HAVE_IEEEFP_H FPTRAP\n")); 577 PetscFunctionReturn(0); 578 } 579 580 PetscErrorCode PetscDetermineInitialFPTrap(void) { 581 PetscFunctionBegin; 582 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 583 PetscFunctionReturn(0); 584 } 585 586 /* -------------------------Default -----------------------------------*/ 587 #else 588 589 void PetscDefaultFPTrap(int sig) { 590 PetscFunctionBegin; 591 (*PetscErrorPrintf)("*** floating point error occurred ***\n"); 592 PetscError(PETSC_COMM_SELF, 0, NULL, NULL, PETSC_ERR_FP, PETSC_ERROR_REPEAT, "floating point error"); 593 PETSCABORT(MPI_COMM_WORLD, PETSC_ERR_FP); 594 } 595 596 PetscErrorCode PetscSetFPTrap(PetscFPTrap flag) { 597 PetscFunctionBegin; 598 if (flag == PETSC_FP_TRAP_ON) { 599 if (SIG_ERR == signal(SIGFPE, PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n"); 600 } else if (SIG_ERR == signal(SIGFPE, SIG_DFL)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n"); 601 602 _trapmode = flag; 603 PetscCall(PetscInfo(NULL, "Using default FPTRAP\n")); 604 PetscFunctionReturn(0); 605 } 606 607 PetscErrorCode PetscDetermineInitialFPTrap(void) { 608 PetscFunctionBegin; 609 PetscCall(PetscInfo(NULL, "Unable to determine initial floating point trapping. Assuming it is off\n")); 610 PetscFunctionReturn(0); 611 } 612 #endif 613