Actual source code: fp.c

  2: /*
  3: *        IEEE error handler for all machines. Since each machine has 
  4: *   enough slight differences we have completely separate codes for each one.
  5: *
  6: */

  8: /*
  9:   This feature test macro provides FE_NOMASK_ENV on GNU.  It must be defined
 10:   at the top of the file because other headers may pull in fenv.h even when
 11:   not strictly necessary.  Strictly speaking, we could include ONLY petscconf.h,
 12:   check PETSC_HAVE_FENV_H, and only define _GNU_SOURCE in that case, but such
 13:   shenanigans ought to be unnecessary.
 14: */
 15: #ifndef _GNU_SOURCE
 16: #define _GNU_SOURCE
 17: #endif

 19: #include <petscsys.h>           /*I  "petscsys.h"  I*/
 20: #include <signal.h>
 21: #if defined(PETSC_HAVE_STDLIB_H)
 22: #include <stdlib.h>
 23: #endif

 25: /*--------------------------------------- ---------------------------------------------------*/
 26: #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
 27: #include <floatingpoint.h>

 30: PetscErrorCode ieee_flags(char*,char*,char*,char**);
 31: PetscErrorCode ieee_handler(char *,char *,sigfpe_handler_type(int,int,struct sigcontext*,char *));

 34: static struct { int code_no; char *name; } error_codes[] = {
 35:            { FPE_INTDIV_TRAP        ,"integer divide" },
 36:            { FPE_FLTOPERR_TRAP        ,"IEEE operand error" },
 37:            { FPE_FLTOVF_TRAP        ,"floating point overflow" },
 38:            { FPE_FLTUND_TRAP        ,"floating point underflow" },
 39:            { FPE_FLTDIV_TRAP        ,"floating pointing divide" },
 40:            { FPE_FLTINEX_TRAP        ,"inexact floating point result" },
 41:            { 0                        ,"unknown error" }
 42: } ;
 43: #define SIGPC(scp) (scp->sc_pc)

 47: sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
 48: {
 50:   int err_ind = -1,j;

 53:   for (j = 0 ; error_codes[j].code_no ; j++) {
 54:     if (error_codes[j].code_no == code) err_ind = j;
 55:   }

 57:   if (err_ind >= 0) {
 58:     (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
 59:   } else {
 60:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
 61:   }
 62:   PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
 63:   MPI_Abort(PETSC_COMM_WORLD,0);
 64:   return(0);
 65: }

 69: /*@
 70:    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
 71:                     This option may not work on certain machines.

 73:    Not Collective

 75:    Input Parameters:
 76: .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.

 78:    Options Database Keys:
 79: .  -fp_trap - Activates floating point trapping

 81:    Level: advanced

 83:    Description:
 84:    On systems that support it, this routine causes floating point
 85:    overflow, divide-by-zero, and invalid-operand (e.g., a NaN) to
 86:    cause a message to be printed and the program to exit.

 88:    Note:
 89:    On many common systems including x86 and x86-64 Linux, the floating
 90:    point exception state is not preserved from the location where the trap
 91:    occurred through to the signal handler.  In this case, the signal handler
 92:    will just say that an unknown floating point exception occurred and which
 93:    function it occurred in.  If you run with -fp_trap in a debugger, it will
 94:    break on the line where the error occurred.  You can check which
 95:    exception occurred using fetestexcept(FE_ALL_EXCEPT).  See fenv.h
 96:    (usually at /usr/include/bits/fenv.h) for the enum values on your system.

 98:    Caution:
 99:    On certain machines, in particular the IBM rs6000, floating point 
100:    trapping is VERY slow!

102:    Concepts: floating point exceptions^trapping
103:    Concepts: divide by zero

105: @*/
106: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
107: {
108:   char *out;

111:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
112:   (void) ieee_flags("clear","exception","all",&out);
113:   if (flag == PETSC_FP_TRAP_ON) {
114:     if (ieee_handler("set","common",PetscDefaultFPTrap)) {
115:       /*
116:         To trap more fp exceptions, including undrflow, change the above line to
117:         if (ieee_handler("set","all",PetscDefaultFPTrap)) {
118:       */
119:       (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
120:     }
121:   } else {
122:     if (ieee_handler("clear","common",PetscDefaultFPTrap)) {
123:       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
124:     }
125:   }
126:   return(0);
127: }

129: /* -------------------------------------------------------------------------------------------*/
130: #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
131: #include <sunmath.h>
132: #include <floatingpoint.h>
133: #include <siginfo.h>
134: #include <ucontext.h>

136: static struct { int code_no; char *name; } error_codes[] = {
137:   {  FPE_FLTINV,"invalid floating point operand"},
138:   {  FPE_FLTRES,"inexact floating point result"},
139:   {  FPE_FLTDIV,"division-by-zero"},
140:   {  FPE_FLTUND,"floating point underflow"},
141:   {  FPE_FLTOVF,"floating point overflow"},
142:   {  0,         "unknown error"}
143: };
144: #define SIGPC(scp) (scp->si_addr)

148: void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
149: {
150:   int err_ind,j,code = scp->si_code;

154:   err_ind = -1 ;
155:   for (j = 0 ; error_codes[j].code_no ; j++) {
156:     if (error_codes[j].code_no == code) err_ind = j;
157:   }

159:   if (err_ind >= 0) {
160:     (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
161:   } else {
162:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
163:   }
164:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
165:   MPI_Abort(PETSC_COMM_WORLD,0);
166: }

170: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
171: {
172:   char *out;

175:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
176:   (void) ieee_flags("clear","exception","all",&out);
177:   if (flag == PETSC_FP_TRAP_ON) {
178:     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap)) {
179:       (*PetscErrorPrintf)("Can't set floating point handler\n");
180:     }
181:   } else {
182:     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) {
183:      (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
184:     }
185:   }
186:   return(0);
187: }

189: /* ------------------------------------------------------------------------------------------*/

191: #elif defined (PETSC_HAVE_IRIX_STYLE_FPTRAP)
192: #include <sigfpe.h>
193: static struct { int code_no; char *name; } error_codes[] = {
194:        { _INVALID   ,"IEEE operand error" },
195:        { _OVERFL    ,"floating point overflow" },
196:        { _UNDERFL   ,"floating point underflow" },
197:        { _DIVZERO   ,"floating point divide" },
198:        { 0          ,"unknown error" }
199: } ;
202: void PetscDefaultFPTrap(unsigned exception[],int val[])
203: {
204:   int err_ind,j,code;

207:   code = exception[0];
208:   err_ind = -1 ;
209:   for (j = 0 ; error_codes[j].code_no ; j++){
210:     if (error_codes[j].code_no == code) err_ind = j;
211:   }
212:   if (err_ind >= 0){
213:     (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
214:   } else{
215:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);
216:   }
217:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
218:   MPI_Abort(PETSC_COMM_WORLD,0);
219: }

223: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
224: {
226:   if (flag == PETSC_FP_TRAP_ON) {
227:     handle_sigfpes(_ON,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
228:   } else {
229:     handle_sigfpes(_OFF,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);
230:   }
231:   return(0);
232: }
233: /*----------------------------------------------- --------------------------------------------*/
234: /* In "fast" mode, floating point traps are imprecise and ignored.
235:    This is the reason for the fptrap(FP_TRAP_SYNC) call */
236: #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP) 
237: struct sigcontext;
238: #include <fpxcp.h>
239: #include <fptrap.h>
240: #include <stdlib.h>
241: #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
242: #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
243: #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
244: #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
245: #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)

247: static struct { int code_no; char *name; } error_codes[] = {
248:            {FPE_FLTOPERR_TRAP        ,"IEEE operand error" },
249:            { FPE_FLTOVF_TRAP        ,"floating point overflow" },
250:            { FPE_FLTUND_TRAP        ,"floating point underflow" },
251:            { FPE_FLTDIV_TRAP        ,"floating point divide" },
252:            { FPE_FLTINEX_TRAP        ,"inexact floating point result" },
253:            { 0                        ,"unknown error" }
254: } ;
255: #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
256: /* 
257:    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
258:    it looks like it should from the include definitions.  It is probably
259:    some strange interaction with the "POSIX_SOURCE" that we require.
260: */

264: void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
265: {
267:   int      err_ind,j;
268:   fp_ctx_t flt_context;

271:   fp_sh_trap_info(scp,&flt_context);
272: 
273:   err_ind = -1 ;
274:   for (j = 0 ; error_codes[j].code_no ; j++) {
275:     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
276:   }

278:   if (err_ind >= 0){
279:     (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
280:   } else{
281:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);
282:   }
283:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,1,"floating point error");
284:   MPI_Abort(PETSC_COMM_WORLD,0);
285: }

289: PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
290: {
292:   if (on == PETSC_FP_TRAP_ON) {
293:     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
294:     fp_trap(FP_TRAP_SYNC);
295:     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
296:     /* fp_enable(mask) for individual traps.  Values are:
297:        TRP_INVALID
298:        TRP_DIV_BY_ZERO
299:        TRP_OVERFLOW
300:        TRP_UNDERFLOW
301:        TRP_INEXACT
302:        Can OR then together.
303:        fp_enable_all(); for all traps.
304:     */
305:   } else {
306:     signal(SIGFPE,SIG_DFL);
307:     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
308:     fp_trap(FP_TRAP_OFF);
309:   }
310:   return(0);
311: }

313: #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
314: /*
315:    C99 style floating point environment.

317:    Note that C99 merely specifies how to save, restore, and clear the floating
318:    point environment as well as defining an enumeration of exception codes.  In
319:    particular, C99 does not specify how to make floating point exceptions raise
320:    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
321:    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
322: */
323: #include <fenv.h>
324: typedef struct {int code; const char *name;} FPNode;
325: static const FPNode error_codes[] = {
326:     {FE_DIVBYZERO,"divide by zero"},
327:     {FE_INEXACT,  "inexact floating point result"},
328:     {FE_INVALID,  "invalid floating point arguments (domain error)"},
329:     {FE_OVERFLOW, "floating point overflow"},
330:     {FE_UNDERFLOW,"floating point underflow"},
331:     {0           ,"unknown error"}
332: };
336: void PetscDefaultFPTrap(int sig)
337: {
338:   const FPNode *node;
339:   int          code;
340:   PetscBool    matched = PETSC_FALSE;

343:   /* Note: While it is possible for the exception state to be preserved by the
344:    * kernel, this seems to be rare which makes the following flag testing almost
345:    * useless.  But on a system where the flags can be preserved, it would provide
346:    * more detail.
347:    */
348:   code = fetestexcept(FE_ALL_EXCEPT);
349:   for (node=&error_codes[0]; node->code; node++) {
350:     if (code & node->code) {
351:       matched = PETSC_TRUE;
352:       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
353:       code &= ~node->code; /* Unset this flag since it has been processed */
354:     }
355:   }
356:   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
357:     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
358:     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
359:     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
360:     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
361:     (*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);
362:   }

364:   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
365: #if defined(PETSC_USE_DEBUG) && !defined(PETSC_USE_PTHREAD)
366:   if (!PetscStackActive) {
367:     (*PetscErrorPrintf)("  or try option -log_stack\n");
368:   } else {
369:     (*PetscErrorPrintf)("likely location of problem given in stack below\n");
370:     (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
371:     PetscStackView(PETSC_VIEWER_STDOUT_SELF);
372:   }
373: #endif
374: #if !defined(PETSC_USE_DEBUG)
375:   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
376:   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
377: #endif
378:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
379:   MPI_Abort(PETSC_COMM_WORLD,0);
380: }

385: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
386: {
388:   if (on == PETSC_FP_TRAP_ON) {
389:     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
390:     if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n");
391: #if defined FE_NOMASK_ENV
392:     /* We could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
393:     if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n");
394: #elif defined PETSC_HAVE_XMMINTRIN_H
395:     _MM_SET_EXCEPTION_MASK(_MM_MASK_INEXACT);
396: #else
397:     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
398: #endif
399:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
400:   } else {
401:     if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
402:     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
403:   }
404:   return(0);
405: }

407: /* -------------------------Default -----------------------------------*/
408: #else 
412: void PetscDefaultFPTrap(int sig)
413: {
415:   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
416:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
417:   MPI_Abort(PETSC_COMM_WORLD,0);
418: }
422: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
423: {
425:   if (on == PETSC_FP_TRAP_ON) {
426:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) {
427:       (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
428:     }
429:   } else {
430:     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) {
431:       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
432:     }
433:   }
434:   return(0);
435: }
436: #endif