Actual source code: fp.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      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: #if !defined(_GNU_SOURCE)
     16: #define _GNU_SOURCE
     17: #endif

     19: #include <petscsys.h>           /*I  "petscsys.h"  I*/
     20: #include <signal.h>

     22: struct PetscFPTrapLink {
     23:   PetscFPTrap            trapmode;
     24:   struct PetscFPTrapLink *next;
     25: };
     26: static PetscFPTrap            _trapmode = PETSC_FP_TRAP_OFF; /* Current trapping mode */
     27: static struct PetscFPTrapLink *_trapstack;                   /* Any pushed states of _trapmode */

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

     34:    Not Collective

     36:    Input Arguments:
     37: . trap - PETSC_FP_TRAP_ON or PETSC_FP_TRAP_OFF

     39:    Level: advanced

     41: .seealso: PetscFPTrapPop(), PetscSetFPTrap()
     42: @*/
     43: PetscErrorCode PetscFPTrapPush(PetscFPTrap trap)
     44: {
     45:   PetscErrorCode         ierr;
     46:   struct PetscFPTrapLink *link;

     49:   PetscNew(&link);
     50:   link->trapmode = _trapmode;
     51:   link->next     = _trapstack;
     52:   _trapstack     = link;
     53:   if (trap != _trapmode) {PetscSetFPTrap(trap);}
     54:   return(0);
     55: }

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

     62:    Not Collective

     64:    Level: advanced

     66: .seealso: PetscFPTrapPush(), PetscSetFPTrap()
     67: @*/
     68: PetscErrorCode PetscFPTrapPop(void)
     69: {
     70:   PetscErrorCode         ierr;
     71:   struct PetscFPTrapLink *link;

     74:   if (_trapstack->trapmode != _trapmode) {PetscSetFPTrap(_trapstack->trapmode);}
     75:   link       = _trapstack;
     76:   _trapstack = _trapstack->next;
     77:   PetscFree(link);
     78:   return(0);
     79: }

     81: /*--------------------------------------- ---------------------------------------------------*/
     82: #if defined(PETSC_HAVE_SUN4_STYLE_FPTRAP)
     83: #include <floatingpoint.h>

     85: PETSC_EXTERN PetscErrorCode ieee_flags(char*,char*,char*,char**);
     86: PETSC_EXTERN PetscErrorCode ieee_handler(char*,char*,sigfpe_handler_type(int,int,struct sigcontext*,char*));

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

    101: sigfpe_handler_type PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp,char *addr)
    102: {
    104:   int            err_ind = -1,j;

    107:   for (j = 0; error_codes[j].code_no; j++) {
    108:     if (error_codes[j].code_no == code) err_ind = j;
    109:   }

    111:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
    112:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));

    114:   PetscError(PETSC_COMM_SELF,PETSC_ERR_FP,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
    115:   MPI_Abort(PETSC_COMM_WORLD,0);
    116:   return(0);
    117: }

    121: /*@
    122:    PetscSetFPTrap - Enables traps/exceptions on common floating point errors.
    123:                     This option may not work on certain machines.

    125:    Not Collective

    127:    Input Parameters:
    128: .  flag - PETSC_FP_TRAP_ON, PETSC_FP_TRAP_OFF.

    130:    Options Database Keys:
    131: .  -fp_trap - Activates floating point trapping

    133:    Level: advanced

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

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

    150:    Caution:
    151:    On certain machines, in particular the IBM rs6000, floating point
    152:    trapping is VERY slow!

    154:    Concepts: floating point exceptions^trapping
    155:    Concepts: divide by zero

    157: .seealso: PetscFPTrapPush(), PetscFPTrapPop()
    158: @*/
    159: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
    160: {
    161:   char *out;

    164:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
    165:   (void) ieee_flags("clear","exception","all",&out);
    166:   if (flag == PETSC_FP_TRAP_ON) {
    167:     /*
    168:       To trap more fp exceptions, including underflow, change the line below to
    169:       if (ieee_handler("set","all",PetscDefaultFPTrap)) {
    170:     */
    171:     if (ieee_handler("set","common",PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
    172:   } else if (ieee_handler("clear","common",PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");

    174:   _trapmode = flag;
    175:   return(0);
    176: }

    178: /* -------------------------------------------------------------------------------------------*/
    179: #elif defined(PETSC_HAVE_SOLARIS_STYLE_FPTRAP)
    180: #include <sunmath.h>
    181: #include <floatingpoint.h>
    182: #include <siginfo.h>
    183: #include <ucontext.h>

    185: static struct { int code_no; char *name; } error_codes[] = {
    186:   { FPE_FLTINV,"invalid floating point operand"},
    187:   { FPE_FLTRES,"inexact floating point result"},
    188:   { FPE_FLTDIV,"division-by-zero"},
    189:   { FPE_FLTUND,"floating point underflow"},
    190:   { FPE_FLTOVF,"floating point overflow"},
    191:   { 0,         "unknown error"}
    192: };
    193: #define SIGPC(scp) (scp->si_addr)

    197: void PetscDefaultFPTrap(int sig,siginfo_t *scp,ucontext_t *uap)
    198: {
    199:   int            err_ind,j,code = scp->si_code;

    203:   err_ind = -1;
    204:   for (j = 0; error_codes[j].code_no; j++) {
    205:     if (error_codes[j].code_no == code) err_ind = j;
    206:   }

    208:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred at pc=%X ***\n",error_codes[err_ind].name,SIGPC(scp));
    209:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred at pc=%X ***\n",code,SIGPC(scp));

    211:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
    212:   MPI_Abort(PETSC_COMM_WORLD,0);
    213: }

    217: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
    218: {
    219:   char *out;

    222:   /* Clear accumulated exceptions.  Used to suppress meaningless messages from f77 programs */
    223:   (void) ieee_flags("clear","exception","all",&out);
    224:   if (flag == PETSC_FP_TRAP_ON) {
    225:     if (ieee_handler("set","common",(sigfpe_handler_type)PetscDefaultFPTrap))        (*PetscErrorPrintf)("Can't set floating point handler\n");
    226:   } else if (ieee_handler("clear","common",(sigfpe_handler_type)PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");
    227:   _trapmode = flag;
    228:   return(0);
    229: }

    231: /* ------------------------------------------------------------------------------------------*/

    233: #elif defined(PETSC_HAVE_IRIX_STYLE_FPTRAP)
    234: #include <sigfpe.h>
    235: static struct { int code_no; char *name; } error_codes[] = {
    236:   { _INVALID   ,"IEEE operand error" },
    237:   { _OVERFL    ,"floating point overflow" },
    238:   { _UNDERFL   ,"floating point underflow" },
    239:   { _DIVZERO   ,"floating point divide" },
    240:   { 0          ,"unknown error" }
    241: } ;
    244: void PetscDefaultFPTrap(unsigned exception[],int val[])
    245: {
    246:   int err_ind,j,code;

    249:   code    = exception[0];
    250:   err_ind = -1;
    251:   for (j = 0; error_codes[j].code_no; j++) {
    252:     if (error_codes[j].code_no == code) err_ind = j;
    253:   }
    254:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
    255:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",code);

    257:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
    258:   MPI_Abort(PETSC_COMM_WORLD,0);
    259: }

    263: PetscErrorCode PetscSetFPTrap(PetscFPTrap flag)
    264: {
    266:   if (flag == PETSC_FP_TRAP_ON) handle_sigfpes(_ON,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,PetscDefaultFPTrap,_ABORT_ON_ERROR,0);
    267:   else                          handle_sigfpes(_OFF,_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,0,_ABORT_ON_ERROR,0);

    269:   _trapmode = flag;
    270:   return(0);
    271: }
    272: /*----------------------------------------------- --------------------------------------------*/
    273: /* In "fast" mode, floating point traps are imprecise and ignored.
    274:    This is the reason for the fptrap(FP_TRAP_SYNC) call */
    275: #elif defined(PETSC_HAVE_RS6000_STYLE_FPTRAP)
    276: struct sigcontext;
    277: #include <fpxcp.h>
    278: #include <fptrap.h>
    279: #define FPE_FLTOPERR_TRAP (fptrap_t)(0x20000000)
    280: #define FPE_FLTOVF_TRAP   (fptrap_t)(0x10000000)
    281: #define FPE_FLTUND_TRAP   (fptrap_t)(0x08000000)
    282: #define FPE_FLTDIV_TRAP   (fptrap_t)(0x04000000)
    283: #define FPE_FLTINEX_TRAP  (fptrap_t)(0x02000000)

    285: static struct { int code_no; char *name; } error_codes[] = {
    286:   {FPE_FLTOPERR_TRAP   ,"IEEE operand error" },
    287:   { FPE_FLTOVF_TRAP    ,"floating point overflow" },
    288:   { FPE_FLTUND_TRAP    ,"floating point underflow" },
    289:   { FPE_FLTDIV_TRAP    ,"floating point divide" },
    290:   { FPE_FLTINEX_TRAP   ,"inexact floating point result" },
    291:   { 0                  ,"unknown error" }
    292: } ;
    293: #define SIGPC(scp) (0) /* Info MIGHT be in scp->sc_jmpbuf.jmp_context.iar */
    294: /*
    295:    For some reason, scp->sc_jmpbuf does not work on the RS6000, even though
    296:    it looks like it should from the include definitions.  It is probably
    297:    some strange interaction with the "POSIX_SOURCE" that we require.
    298: */

    302: void PetscDefaultFPTrap(int sig,int code,struct sigcontext *scp)
    303: {
    305:   int            err_ind,j;
    306:   fp_ctx_t       flt_context;

    309:   fp_sh_trap_info(scp,&flt_context);

    311:   err_ind = -1;
    312:   for (j = 0; error_codes[j].code_no; j++) {
    313:     if (error_codes[j].code_no == flt_context.trap) err_ind = j;
    314:   }

    316:   if (err_ind >= 0) (*PetscErrorPrintf)("*** %s occurred ***\n",error_codes[err_ind].name);
    317:   else              (*PetscErrorPrintf)("*** floating point error 0x%x occurred ***\n",flt_context.trap);

    319:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
    320:   MPI_Abort(PETSC_COMM_WORLD,0);
    321: }

    325: PetscErrorCode PetscSetFPTrap(PetscFPTrap on)
    326: {
    328:   if (on == PETSC_FP_TRAP_ON) {
    329:     signal(SIGFPE,(void (*)(int))PetscDefaultFPTrap);
    330:     fp_trap(FP_TRAP_SYNC);
    331:     fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
    332:     /* fp_enable(mask) for individual traps.  Values are:
    333:        TRP_INVALID
    334:        TRP_DIV_BY_ZERO
    335:        TRP_OVERFLOW
    336:        TRP_UNDERFLOW
    337:        TRP_INEXACT
    338:        Can OR then together.
    339:        fp_enable_all(); for all traps.
    340:     */
    341:   } else {
    342:     signal(SIGFPE,SIG_DFL);
    343:     fp_disable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW);
    344:     fp_trap(FP_TRAP_OFF);
    345:   }
    346:   _trapmode = on;
    347:   return(0);
    348: }

    350: #elif defined(PETSC_HAVE_FENV_H) && !defined(__cplusplus)
    351: /*
    352:    C99 style floating point environment.

    354:    Note that C99 merely specifies how to save, restore, and clear the floating
    355:    point environment as well as defining an enumeration of exception codes.  In
    356:    particular, C99 does not specify how to make floating point exceptions raise
    357:    a signal.  Glibc offers this capability through FE_NOMASK_ENV (or with finer
    358:    granularity, feenableexcept()), xmmintrin.h offers _MM_SET_EXCEPTION_MASK().
    359: */
    360: #include <fenv.h>
    361: typedef struct {int code; const char *name;} FPNode;
    362: static const FPNode error_codes[] = {
    363:   {FE_DIVBYZERO,"divide by zero"},
    364:   {FE_INEXACT,  "inexact floating point result"},
    365:   {FE_INVALID,  "invalid floating point arguments (domain error)"},
    366:   {FE_OVERFLOW, "floating point overflow"},
    367:   {FE_UNDERFLOW,"floating point underflow"},
    368:   {0           ,"unknown error"}
    369: };

    373: void PetscDefaultFPTrap(int sig)
    374: {
    375:   const FPNode *node;
    376:   int          code;
    377:   PetscBool    matched = PETSC_FALSE;

    380:   /* Note: While it is possible for the exception state to be preserved by the
    381:    * kernel, this seems to be rare which makes the following flag testing almost
    382:    * useless.  But on a system where the flags can be preserved, it would provide
    383:    * more detail.
    384:    */
    385:   code = fetestexcept(FE_ALL_EXCEPT);
    386:   for (node=&error_codes[0]; node->code; node++) {
    387:     if (code & node->code) {
    388:       matched = PETSC_TRUE;
    389:       (*PetscErrorPrintf)("*** floating point error \"%s\" occurred ***\n",node->name);
    390:       code &= ~node->code; /* Unset this flag since it has been processed */
    391:     }
    392:   }
    393:   if (!matched || code) { /* If any remaining flags are set, or we didn't process any flags */
    394:     (*PetscErrorPrintf)("*** unknown floating point error occurred ***\n");
    395:     (*PetscErrorPrintf)("The specific exception can be determined by running in a debugger.  When the\n");
    396:     (*PetscErrorPrintf)("debugger traps the signal, the exception can be found with fetestexcept(0x%x)\n",FE_ALL_EXCEPT);
    397:     (*PetscErrorPrintf)("where the result is a bitwise OR of the following flags:\n");
    398:     (*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);
    399:   }

    401:   (*PetscErrorPrintf)("Try option -start_in_debugger\n");
    402: #if defined(PETSC_USE_DEBUG)
    403:   if (!PetscStackActive()) (*PetscErrorPrintf)("  or try option -log_stack\n");
    404:   else {
    405:     (*PetscErrorPrintf)("likely location of problem given in stack below\n");
    406:     (*PetscErrorPrintf)("---------------------  Stack Frames ------------------------------------\n");
    407:     PetscStackView(PETSC_STDOUT);
    408:   }
    409: #endif
    410: #if !defined(PETSC_USE_DEBUG)
    411:   (*PetscErrorPrintf)("configure using --with-debugging=yes, recompile, link, and run \n");
    412:   (*PetscErrorPrintf)("with -start_in_debugger to get more information on the crash.\n");
    413: #endif
    414:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_INITIAL,"trapped floating point error");
    415:   MPI_Abort(PETSC_COMM_WORLD,0);
    416: }

    420: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
    421: {
    423:   if (on == PETSC_FP_TRAP_ON) {
    424:     /* Clear any flags that are currently set so that activating trapping will not immediately call the signal handler. */
    425:     if (feclearexcept(FE_ALL_EXCEPT)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot clear floating point exception flags\n");
    426: #if defined FE_NOMASK_ENV
    427:     /* We could use fesetenv(FE_NOMASK_ENV), but that causes spurious exceptions (like gettimeofday() -> PetscLogDouble). */
    428:     if (feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) == -1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot activate floating point exceptions\n");
    429: #elif defined PETSC_HAVE_XMMINTRIN_H
    430:     _MM_SET_EXCEPTION_MASK(_MM_MASK_INEXACT | _MM_MASK_UNDERFLOW);
    431: #else
    432:     /* C99 does not provide a way to modify the environment so there is no portable way to activate trapping. */
    433: #endif
    434:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't set floating point handler\n");
    435:   } else {
    436:     if (fesetenv(FE_DFL_ENV)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Cannot disable floating point exceptions");
    437:     if (SIG_ERR == signal(SIGFPE,SIG_DFL)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Can't clear floating point handler\n");
    438:   }
    439:   _trapmode = on;
    440:   return(0);
    441: }

    443: /* -------------------------Default -----------------------------------*/
    444: #else

    448: void PetscDefaultFPTrap(int sig)
    449: {
    451:   (*PetscErrorPrintf)("*** floating point error occurred ***\n");
    452:   PetscError(PETSC_COMM_SELF,0,"User provided function","Unknown file",PETSC_ERR_FP,PETSC_ERROR_REPEAT,"floating point error");
    453:   MPI_Abort(PETSC_COMM_WORLD,0);
    454: }

    458: PetscErrorCode  PetscSetFPTrap(PetscFPTrap on)
    459: {
    461:   if (on == PETSC_FP_TRAP_ON) {
    462:     if (SIG_ERR == signal(SIGFPE,PetscDefaultFPTrap)) (*PetscErrorPrintf)("Can't set floatingpoint handler\n");
    463:   } else if (SIG_ERR == signal(SIGFPE,SIG_DFL))       (*PetscErrorPrintf)("Can't clear floatingpoint handler\n");

    465:   _trapmode = on;
    466:   return(0);
    467: }
    468: #endif