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