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

Capturing Fortran output when running under JNI/Java

longden_loo
Beginner
2,442 Views
We have a big Fortran legacy app which we've repackaged as a DLL to run as a service invoked from a Java GUI via Sun's JNI and the Sun JVM.

This mostly works, but because the Java GUI is driving the process, there's no console window and Fortran PRINT/WRITE statements drop off into space. This doesn't affect the execution of our Fortran application, but you can guess there's quite a lot of reason to want to see Fortran output (and exceptions) which are currently being lost.

Is there a way to redirect Fortran stdout/stderr to a file(s) when running under JNI? We can manually recode the writes to go to a file (albeit a gruelling task), but even then, the occasional divide-by-zero or subscript-out-of-bounds exception would be lost, and we're concerned about those.

Thx, Longden
0 Kudos
18 Replies
Steven_L_Intel1
Employee
2,442 Views
One way would be to call SETENVQQ to set the environment variable FOR_PRINT to be the path to a file. This will redirect PRINT and WRITE * statements. Call this at the entry to the DLL routine. Errors, though, should come up in a message box if there is no console.
0 Kudos
longden_loo
Beginner
2,442 Views
Thanks for the suggestion. I hadn't realized IVF/CVF had a full set of environment variables to support runtime modifications. I'll give it a try when I get back to work. I see that FOR_PRINT was also supported under CVF which is good because we still need to support the app using that compiler level, so hopefully the environment tailoring functions are comparable for both IVF and CVF.

One thing, there's no particular need to set the FOR_PRINT using SETENVQQ specifically is there? I mean the environment variable can just be set prior to starting the JAVA GUI from the same batch file that starts the GUI?

Also, in some cases, the Fortran app (there are several) isn't run as part of a DLL, but is built as a console app (ie, a ".exe" file) and run from the Java GUI using Runtime.exec() ... in those cases, the console information is definitely lost with no accompanying message box when the app hit a subscript out of bounds exception and the companion stacktrace. It wasn't till we manually ran the app in a console window that we were able to determine this ... so some way to redirect or capture stderr would be very helpful there.
0 Kudos
Steven_L_Intel1
Employee
2,442 Views
It should work to set the environment variables from the Java code, but a lot will depend on how Java invokes the DLL. Try it and see.

In the case of the Runtime.exec, I have no idea where that causes stdout to go. If Fortran thinks there is a console, then it will use that. (It looks to see if there is a handle for standard output.)

There is another environment variable, FOR_DIAGNOSTIC_LOG_FILE, that may be of interest.
0 Kudos
drgfthomas
Beginner
2,442 Views

What happens if the Fortran DLL executes a PAUSE or STOP statement in the absence of a console?

Anyways, use the Win API (within your DLL) to allocate a console for Fortran WRITE(*,*)'s/PRINT *'s and free it when you're done.

0 Kudos
longden_loo
Beginner
2,442 Views
I'm mostly a Unix guy and this Win API stuff is still new to me. How does one allocate a console for Fortran writes, or can you point me to a link/reference that describes this?

Thx, Longden
0 Kudos
Steven_L_Intel1
Employee
2,442 Views
Just call the AllocConsole Win32 API function - it takes no arguments. You'll need to add USE KERNEL32. For example:

use kernel32
...
i = AllocConsole()

Of course, that will give you a console all the time and it will stay there until closed (or maybe until the program exits, I'm not sure.)

See here for more info on the function.
0 Kudos
drgfthomas
Beginner
2,442 Views

:

use dfwin

:

logical statConsole

:

statConsole = AllocConsole()

!write(*,*) stuff

statConsole = FreeConsole()

:

0 Kudos
Steven_L_Intel1
Employee
2,442 Views
integer, not logical for statConsole. I suggest kernel32 rather than dfwin as the latter will pull in far more symbols than you need.
0 Kudos
longden_loo
Beginner
2,442 Views
It appears that either suggestion (FOR_PRINT or AllocConsole) will be valuable tools for me.

However, and maybe I'm asking for a bit much now, neither method provides any information when a fatal exception occurs (ie, divide by zero) because the Fortran DLL abort also takes out the parent process, resulting in the loss of the console window (from AllocConsole) and the apparent termination of messages using FOR_PRINT.

So is there anything else I've overlooked, or is the loss of the stack trace a given in this case? I've tried a variety of the environment variables, including FOR_DIAGNOSTIC_LOG_FILE. It might be that once a fatal exception occurs, control passes from the Fortran module back to Windows for the handling of the stack trace?

Anyway, even if there's nothing else I can do about the missing stack trace, thanks to both of you for the suggestions.

- Longden
0 Kudos
Steven_L_Intel1
Employee
2,442 Views
I suggest a thorough reading of the chapter in the Building Applications manual on Exception and Termination Handlers.
0 Kudos
drgfthomas
Beginner
2,442 Views

In the IVF Samplesthere is GETEPTRS, a mixed C - Fortran soln. that detects a fp divide by zero exception and provides a traceback to the line in code at which the infraction occured. Then it STOPs, Fortran's response to unhandled exceptions (it kills the process). Run the sample in the debugger: it appears to exits cleanly. Now change the STOPs to PAUSEs and rerun the app in the debugger: an unhandled exception is raised at the offending line. Ditto if you run the app from a cmd window. The exception can be handled in C or in Fortran (courtesy of C) without the app quiting or crashing.

0 Kudos
longden_loo
Beginner
2,442 Views
I was able to get the GETEPTRS sample to work as you suggested and it does look promising.

Question ... in the routine HAND_FPE (in geteptrs_s2.f90), the test for a floating point zero divide is coded to look for "FPE$ZERODIVIDE" ... where can I find the similar static constants representing conditions like "array out of bounds", and "access violation"?


2nd question ... I also tried the sample code in the IVF Help for coding with TRACEBACKQQ...

__try {
FORTRAN_TEST() ;
}
__except ( CHECK_EXCEPTION_INFO ( GetExceptionInformation() ) )
{
irc = 1;
exit(99);
}

... and that also looked promising since I was able to capture the exception and display the stack trace. However, the CHECK_EXCEPTION_INFO routine (pretty much coded as from the sample with the addition of IF-ELSE structures for more exception conditions) appears to inexplicably repeat itself during an array out of bounds exception.

CHECK_EXCEPTION_INFO = 1 is coded to resume control to the application which should've set irc=1 and then exited with a code=99 .... but instead continued repeating itself (several stack traces). Fortran writes in FORTRAN_TEST and within CHECK_EXCEPTION_INFO confirm that the __try is only being executed once, and the exit(99) (which never happens), confirms the __except clause is never executed.

Am I missing something in how this is supposed to be used?
0 Kudos
Steven_L_Intel1
Employee
2,442 Views
Access violation and array bounds errors are OS-reported exceptions that have nothing to do with the FPE registers.
0 Kudos
longden_loo
Beginner
2,442 Views
The GETEPTRS sample appears to be based on SIGNALQQ ... so is SIGNALQQ only applicable to handling floating point exceptions and not OS-reported ones?

In the IVF Help under "Using SIGNALQQ" ... "For lightweight exception handling requirements, a handler established with SIGNALQQ may meet your needs" ... so it sounded like it should be pretty general. Is there a more general sample than GETEPTRS?
0 Kudos
drgfthomas
Beginner
2,442 Views

A 1. The usual Windows exceptions are contained in the ifwinty/ifport/ et al modules. Do a 'find in files' from the IDE of "...IntelCompilerFortran9.1IA32Include;Entire Solution" to track down these appelations.

A 2. I bet you're using a DLL called by aC/C++ or IVFexe. If you convert the DLL to a static library and link it to a C/C++ DLL (yes, convert the IVF DLL to a C/C++ DLL) or to your C++ exe, you'll find that the approach works. Wierd. Watch out for the tracback issuing 'Stack trace terminated abnormally' with attendant access violations, privilaged instrunction, and the occassional Blue Screen, none of which get picked up by the exception handler. No, you're not missing anything but it's not supposed to be that way, I'm sure.

0 Kudos
longden_loo
Beginner
2,442 Views
We're using something equally perverse. IVF/Fortran built separately as a static library and then called by a C wrapper which is linked with the IVF library into a DLL. The C wrapper also functions as the JNI interface because the DLL is invoked from Java.

I believe the main Java GUI interface drives this arrangement in order to call the Fortran legacy app as a service. But in any case, we are (sort of) doing what you suggest already, which is linking a static IVF library to a C DLL ... except we're calling it from JNI/Java. But you're also right in that looking over the exception output, I now notice the "Stack trace terminated abnormally" message.

Still, it's good to know the "gotchas". Thx.
0 Kudos
longden_loo
Beginner
2,442 Views
As a closure to this thread, we finally got the exception handling to work using the CHECK_EXCEPTION_INFO routine sample documented in the Help, which as Gerry described, had been giving us "Stack trace terminated abnormally" during the execution of TRACEBACKQQ.

What we discovered (inadvertently) was that the __except handing of the filter (ie, CHECK_EXCEPTION_INFO) worked as expected if CHECK_EXCEPTION_INFO was first wrapped by a C routine like this ...

int filter(struct _EXCEPTION_POINTERS *ep) {
return CHECK_EXCEPTION_INFO ( ep );
}

__try {
fortran_driver();
__except ( filter ( GetExceptionInformation() )
{
/* exception handling code that now works */
}

If the "filter()" wrapper code is replaced with an equivalent Fortran routine, the __except statement failed during the stack trace as it did before, so it appears __except has interface issues with a Fortran-based filter, at least under the Java/JNI situation we were constrained to.

I forgot to mention earlier that our work is being done entirely in CVF 6.6 (tho this code will also require a port to IVF this week) ... so it's entirely possible that IVF has resolved the issue with __except.

But thanks for all the help (more questions are forthcoming!)
0 Kudos
drgfthomas
Beginner
2,442 Views

Ah!

I'm currently using IVF 9.1 and myFortran SEH ( thanks to Bill H.) is in C and statically linked to a Dialog form written in Fortran and which loads an IVF DLL. The Fortran SEH is the same as I have used in CVF 6.6C and earlier without a hitch. I've never come across 'Stack terminated abnormally' in CVF. With C/C++ projects in debug mode and under the Code Generationtab two items thatare worth noting, viz., Enable C++ Exceptions (defaults to yes) and Basic Runtime Checks; dig into the latter and turn on /RTCs to check Stack Frames for incompatible calling conventions between IVF and VC++. When I cottoned on to this all was right, until the next time of course, :-).

Thanksalso for this useful dialog.

0 Kudos
Reply