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

Capturing Fortran output when running under JNI/Java

longden_loo
Principiante
3.826 Vistas
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 Respuestas
Steven_L_Intel1
Empleados
3.826 Vistas
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.
longden_loo
Principiante
3.826 Vistas
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.
Steven_L_Intel1
Empleados
3.826 Vistas
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.
drgfthomas
Principiante
3.826 Vistas

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.

longden_loo
Principiante
3.826 Vistas
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
Steven_L_Intel1
Empleados
3.826 Vistas
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.
drgfthomas
Principiante
3.826 Vistas

:

use dfwin

:

logical statConsole

:

statConsole = AllocConsole()

!write(*,*) stuff

statConsole = FreeConsole()

:

Steven_L_Intel1
Empleados
3.826 Vistas
integer, not logical for statConsole. I suggest kernel32 rather than dfwin as the latter will pull in far more symbols than you need.
longden_loo
Principiante
3.826 Vistas
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
Steven_L_Intel1
Empleados
3.826 Vistas
I suggest a thorough reading of the chapter in the Building Applications manual on Exception and Termination Handlers.
drgfthomas
Principiante
3.826 Vistas

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.

longden_loo
Principiante
3.826 Vistas
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?
Steven_L_Intel1
Empleados
3.826 Vistas
Access violation and array bounds errors are OS-reported exceptions that have nothing to do with the FPE registers.
longden_loo
Principiante
3.826 Vistas
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?
drgfthomas
Principiante
3.826 Vistas

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.

longden_loo
Principiante
3.826 Vistas
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.
longden_loo
Principiante
3.826 Vistas
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!)
drgfthomas
Principiante
3.826 Vistas

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.

Responder