Actual source code: fp.c

petsc-3.3-p7 2013-05-11
  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: struct PetscFPTrapLink {
 26:   PetscFPTrap trapmode;
 27:   struct PetscFPTrapLink *next;
 28: };
 29: static PetscFPTrap _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode */
 30: static struct PetscFPTrapLink *_trapstack;        /* Any pushed states of _trapmode */

 34: /*@
 35:    PetscFPTrapPush - push a floating point trapping mode, to be restored using PetscFPTrapPop()

 37:    Not Collective

 39:    Input Arguments:
 40: . trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF

 42:    Level: advanced

 44: .seealso: PetscFPTrapPop(), PetscSetFPTrap()
 45: @*/
 46: PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
 47: {
 49:   struct PetscFPTrapLink *link;

 52:   PetscMalloc(sizeof *link,&link);
 53:   link->trapmode = _trapmode;
 54:   link->next = _trapstack;
 55:   _trapstack = link;
 56:   if (trap != _trapmode) {PetscSetFPTrap(trap);}
 57:   return(0);
 58: }

 62: /*@
 63:    PetscFPTrapPop - push a floating point trapping mode, to be restored using PetscFPTrapPop()

 65:    Not Collective

 67:    Level: advanced

 69: .seealso: PetscFPTrapPush(), PetscSetFPTrap()
 70: @*/
 71: PetscErrorCode PetscFPTrapPop(void)
 72: {
 74:   struct PetscFPTrapLink *link;

 77:   if (_trapstack->trapmode != _trapmode) {PetscSetFPTrap(_trapstack->trapmode);}
 78:   link = _trapstack;
 79:   _trapstack = _trapstack->next;
 80:   PetscFree(link);
 81:   return(0);
 82: }

 84: /*--------------------------------------- ---------------------------------------------------*/
 85: #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
 86: #include <floatingpoint.h>

 88: EXTERN_C_BEGIN
 89: PetscErrorCode ieee_flags(char*,char*,char*,char**);
 90: PetscErrorCode ieee_handler(char *,char *,sigfpe_handler_type(int,int,struct sigcontext*,char *));
 91: EXTERN_C_END

 93: static struct { int code_no; char *name; } error_codes[] = {
 94:            { FPE_INTDIV_TRAP        ,"integer divide" },
 95:            { FPE_FLTOPERR_TRAP        ,"IEEE operand error" },
 96:            { FPE_FLTOVF_TRAP        ,"floating point overflow" },
 97:            { FPE_FLTUND_TRAP        ,"floating point underflow" },
 98:            { FPE_FLTDIV_TRAP        ,"floating pointing divide" },
 99:            { FPE_FLTINEX_TRAP        ,"inexact floating point result" },
100:            { 0                        ,"unknown error" }
101: } ;
102: #define SIGPC(scp) (scp->sc_pc)

106: sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
107: {
109:   int err_ind = -1,j;

112:   for (j = 0 ; error_codes[j].code_no ; j++) {
113:     if (error_codes[j].code_no == code) err_ind = j;
114:   }

116:   if (err_ind >= 0) {
117:     (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
118:   } else {
119:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
120:   }
121:   PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
122:   MPI_Abort(PETSC_COMM_WORLD,0);
123:   return(0);
124: }

128: /*@
129:    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
130:                     This option may not work on certain machines.

132:    Not Collective

134:    Input Parameters:
135: .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.

137:    Options Database Keys:
138: .  -fp_trap - Activates floating point trapping

140:    Level: advanced

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

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

157:    Caution:
158:    On certain machines, in particular the IBM rs6000, floating point 
159:    trapping is VERY slow!

161:    Concepts: floating point exceptions^trapping
162:    Concepts: divide by zero

164: .seealso: PetscFPTrapPush(), PetscFPTrapPop()
165: @*/
166: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
167: {
168:   char *out;

171:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
172:   (void) ieee_flags("clear","exception","all",&out);
173:   if (flag == PETSC_FP_TRAP_ON) {
174:     if (ieee_handler("set","common",PetscDefaultFPTrap)) {
175:       /*
176:         To trap more fp exceptions, including undrflow, change the above line to
177:         if (ieee_handler("set","all",PetscDefaultFPTrap)) {
178:       */
179:       (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
180:     }
181:   } else {
182:     if (ieee_handler("clear","common",PetscDefaultFPTrap)) {
183:       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
184:     }
185:   }
186:   _trapmode = flag;
187:   return(0);
188: }

190: /* -------------------------------------------------------------------------------------------*/
191: #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
192: #include <sunmath.h>
193: #include <floatingpoint.h>
194: #include <siginfo.h>
195: #include <ucontext.h>

197: static struct { int code_no; char *name; } error_codes[] = {
198:   {  FPE_FLTINV,"invalid floating point operand"},
199:   {  FPE_FLTRES,"inexact floating point result"},
200:   {  FPE_FLTDIV,"division-by-zero"},
201:   {  FPE_FLTUND,"floating point underflow"},
202:   {  FPE_FLTOVF,"floating point overflow"},
203:   {  0,         "unknown error"}
204: };
205: #define SIGPC(scp) (scp->si_addr)

209: void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
210: {
211:   int err_ind,j,code = scp->si_code;

215:   err_ind = -1 ;
216:   for (j = 0 ; error_codes[j].code_no ; j++) {
217:     if (error_codes[j].code_no == code) err_ind = j;
218:   }

220:   if (err_ind >= 0) {
221:     (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
222:   } else {
223:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));
224:   }
225:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
226:   MPI_Abort(PETSC_COMM_WORLD,0);
227: }

231: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
232: {
233:   char *out;

236:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
237:   (void) ieee_flags("clear","exception","all",&out);
238:   if (flag == PETSC_FP_TRAP_ON) {
239:     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap)) {
240:       (*PetscErrorPrintf)("Can't set floating point handler\n");
241:     }
242:   } else {
243:     if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) {
244:      (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
245:     }
246:   }
247:   _trapmode = flag;
248:   return(0);
249: }

251: /* ------------------------------------------------------------------------------------------*/

253: #elif defined (PETSC_HAVE_IRIX_STYLE_FPTRAP)
254: #include <sigfpe.h>
255: static struct { int code_no; char *name; } error_codes[] = {
256:        { _INVALID   ,"IEEE operand error" },
257:        { _OVERFL    ,"floating point overflow" },
258:        { _UNDERFL   ,"floating point underflow" },
259:        { _DIVZERO   ,"floating point divide" },
260:        { 0          ,"unknown error" }
261: } ;
264: void PetscDefaultFPTrap(unsigned exception[],int val[])
265: {
266:   int err_ind,j,code;

269:   code = exception[0];
270:   err_ind = -1 ;
271:   for (j = 0 ; error_codes[j].code_no ; j++){
272:     if (error_codes[j].code_no == code) err_ind = j;
273:   }
274:   if (err_ind >= 0){
275:     (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
276:   } else{
277:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);
278:   }
279:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
280:   MPI_Abort(PETSC_COMM_WORLD,0);
281: }

285: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
286: {
288:   if (flag == PETSC_FP_TRAP_ON) {
289:     handle_sigfpes(_ON,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
290:   } else {
291:     handle_sigfpes(_OFF,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);
292:   }
293:   _trapmode = flag;
294:   return(0);
295: }
296: /*----------------------------------------------- --------------------------------------------*/
297: /* In "fast" mode, floating point traps are imprecise and ignored.
298:    This is the reason for the fptrap(FP_TRAP_SYNC) call */
299: #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP) 
300: struct sigcontext;
301: #include <fpxcp.h>
302: #include <fptrap.h>
303: #include <stdlib.h>
304: #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
305: #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
306: #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
307: #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
308: #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)

310: static struct { int code_no; char *name; } error_codes[] = {
311:            {FPE_FLTOPERR_TRAP        ,"IEEE operand error" },
312:            { FPE_FLTOVF_TRAP        ,"floating point overflow" },
313:            { FPE_FLTUND_TRAP        ,"floating point underflow" },
314:            { FPE_FLTDIV_TRAP        ,"floating point divide" },
315:            { FPE_FLTINEX_TRAP        ,"inexact floating point result" },
316:            { 0                        ,"unknown error" }
317: } ;
318: #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
319: /* 
320:    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
321:    it looks like it should from the include definitions.  It is probably
322:    some strange interaction with the "POSIX_SOURCE" that we require.
323: */

327: void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
328: {
330:   int      err_ind,j;
331:   fp_ctx_t flt_context;

334:   fp_sh_trap_info(scp,&flt_context);
335: 
336:   err_ind = -1 ;
337:   for (j = 0 ; error_codes[j].code_no ; j++) {
338:     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
339:   }

341:   if (err_ind >= 0){
342:     (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
343:   } else{
344:     (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);
345:   }
346:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
347:   MPI_Abort(PETSC_COMM_WORLD,0);
348: }

352: PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
353: {
355:   if (on == PETSC_FP_TRAP_ON) {
356:     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
357:     fp_trap(FP_TRAP_SYNC);
358:     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
359:     /* fp_enable(mask) for individual traps.  Values are:
360:        TRP_INVALID
361:        TRP_DIV_BY_ZERO
362:        TRP_OVERFLOW
363:        TRP_UNDERFLOW
364:        TRP_INEXACT
365:        Can OR then together.
366:        fp_enable_all(); for all traps.
367:     */
368:   } else {
369:     signal(SIGFPE,SIG_DFL);
370:     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
371:     fp_trap(FP_TRAP_OFF);
372:   }
373:   _trapmode = on;
374:   return(0);
375: }

377: #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
378: /*
379:    C99 style floating point environment.

381:    Note that C99 merely specifies how to save, restore, and clear the floating
382:    point environment as well as defining an enumeration of exception codes.  In
383:    particular, C99 does not specify how to make floating point exceptions raise
384:    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
385:    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
386: */
387: #include <fenv.h>
388: typedef struct {int code; const char *name;} FPNode;
389: static const FPNode error_codes[] = {
390:     {FE_DIVBYZERO,"divide by zero"},
391:     {FE_INEXACT,  "inexact floating point result"},
392:     {FE_INVALID,  "invalid floating point arguments (domain error)"},
393:     {FE_OVERFLOW, "floating point overflow"},
394:     {FE_UNDERFLOW,"floating point underflow"},
395:     {0           ,"unknown error"}
396: };
397: EXTERN_C_BEGIN
400: void PetscDefaultFPTrap(int sig)
401: {
402:   const FPNode *node;
403:   int          code;
404:   PetscBool    matched = PETSC_FALSE;

407:   /* Note: While it is possible for the exception state to be preserved by the
408:    * kernel, this seems to be rare which makes the following flag testing almost
409:    * useless.  But on a system where the flags can be preserved, it would provide
410:    * more detail.
411:    */
412:   code = fetestexcept(FE_ALL_EXCEPT);
413:   for (node=&error_codes[0]; node->code; node++) {
414:     if (code & node->code) {
415:       matched = PETSC_TRUE;
416:       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
417:       code &= ~node->code; /* Unset this flag since it has been processed */
418:     }
419:   }
420:   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
421:     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
422:     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
423:     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
424:     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
425:     (*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);
426:   }

428:   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
429: #if defined(PETSC_USE_DEBUG)
430:   if (!PetscStackActive) {
431:     (*PetscErrorPrintf)("  or try option -log_stack\n");
432:   } else {
433:     (*PetscErrorPrintf)("likely location of problem given in stack below\n");
434:     (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
435:     PetscStackView(PETSC_VIEWER_STDOUT_SELF);
436:   }
437: #endif
438: #if !defined(PETSC_USE_DEBUG)
439:   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
440:   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
441: #endif
442:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
443:   MPI_Abort(PETSC_COMM_WORLD,0);
444: }
445: EXTERN_C_END

449: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
450: {
452:   if (on == PETSC_FP_TRAP_ON) {
453:     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
454:     if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n");
455: #if defined FE_NOMASK_ENV
456:     /* We could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
457:     if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n");
458: #elif defined PETSC_HAVE_XMMINTRIN_H
459:     _MM_SET_EXCEPTION_MASK(_MM_MASK_INEXACT);
460: #else
461:     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
462: #endif
463:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
464:   } else {
465:     if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
466:     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
467:   }
468:   _trapmode = on;
469:   return(0);
470: }

472: /* -------------------------Default -----------------------------------*/
473: #else 
474: EXTERN_C_BEGIN
477: void PetscDefaultFPTrap(int sig)
478: {
480:   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
481:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file","Unknown directory",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
482:   MPI_Abort(PETSC_COMM_WORLD,0);
483: }
484: EXTERN_C_END
487: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
488: {
490:   if (on == PETSC_FP_TRAP_ON) {
491:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) {
492:       (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
493:     }
494:   } else {
495:     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) {
496:       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
497:     }
498:   }
499:   _trapmode = on;
500:   return(0);
501: }
502: #endif