Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28383 Discussions

How to get traceback on floating-point exception in f2py-wrapped code

ChuckG
Beginner
1,053 Views

have a trivial test program that implements one function, INV, which just computes 1/x. Passing 0 for the argument x triggers a zero-division error. When I compile it with ifort (version 2021.3.0), using the flags "/fpe-all:0 /traceback /fp:strict /debug" and run it, I get a traceback like this:

forrtl: error (73): floating divide by zero
Image              PC                Routine            Line        Source
ifort-tst.exe      00007FF7EB0411F0  F_mp_INV                    9  f.f
ifort-tst.exe      00007FF7EB0410A2  MAIN__                      8  tst.f

In my real application, we call Fortran code from a Python process, using f2py.  With a bit of tinkering (had to define macros UPPERCASE_FORTRAN and NO_APPEND_FORTRAN) I was able to compile the same code as a Python module. When I run it from Python, the zero-division causes the program to quit but does not produce the backtrace. If I don't set "/fpe-all:0" the module just returns a NaN instead of aborting, so I know the FPE compiler flags are in effect. I want the program to abort on floating-point exceptions, but I want to see the same type of backtrace that is produced when I run the code as a stand-alone executable.

I suspect that some needed signal handler is not getting registered - with GNU Fortran it's necessary to call a few library initialization functions to make FPE handling work but I was not able to find the equivalent in the Intel Fortran documentation.

|

0 Kudos
6 Replies
Steve_Lionel
Honored Contributor III
1,034 Views

My understanding of how this works is that the traceback is generated by a C++ wrapper around a Fortran main program, and if there is no Fortran (or Intel C++) main, then you don't get tracebacks. You CAN call TRACEBACKQQ at any point to get a traceback, and you might investigate whether adding a call to SIGNALQQ, to register your own handler, gives you a place from which to call TRACEBACKQQ.

Your use of /fpe-all is correct in that without this, the setting of FP exception handling is done in the main program only. /fpe-all adds the call to do this in every procedure. But it doesn't help with traceback.

ChuckG
Beginner
1,017 Views

Thanks Steve, this is exactly the kind of info I was looking for.

 

It seems like a signal handler needs to be set up to trap SIG$FPE. 

 

I followed your suggestion of calling TRACEBACKQQ, this works as expected when I call if from a Fortran main program, but not when I compile the code as a library and call it from Python.  It does cause the program to exit, but the traceback just isn't printed.  If we can figure out why that's happening, I'll be all set.

0 Kudos
ChuckG
Beginner
1,009 Views

On Linux, calling TRACEBACKQQ from an f2py-generated module works - it prints a traceback and aborts.  On Windows, it aborts without printing a traceback. 

 

In neither case do I get a traceback on FPE, even if I call SIGNALQQ(SIG$FPE, TRACEBACK)  where TRACEBACK is a function that calls TRACEBACKQQ. (The wrapper needed to match expected signature for SIGNALQQ).

 

 

 

 

0 Kudos
Steve_Lionel
Honored Contributor III
982 Views

I'm afraid my understanding of this part of things is very superficial - not sure I have more I can add. I think TRACEBACKQQ prints to stderr - maybe it can't open that? I suggest you look more carefully at the documentation of TRACEBACKQQ - it has a bunch of stuff about exception pointers.

0 Kudos
ChuckG
Beginner
930 Views

One small step forward,  TRACEBACKQQ noiw works from f2py wrapper on Windows if I include the line

USE IFCORE

which I had been missing (the code compiles without this, just doesn't print a traceback on Windows).  Still haven't gotten this to work from the FPE handler, though.

 

 -- Chuck

 

0 Kudos
ChuckG
Beginner
927 Views

According to this stackoverflow post ,

"TRACEBACKQQ has optional arguments. It thus requires an interface to be in scope at the calling point. This is achieved by using the IFCORE module"

 

0 Kudos
Reply