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