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