- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Steve and Fortran Masters,
I have a Fortran DLL called from C++ that is used in a chemical process simulator. The subroutines / functions in the DLL are normally called millions of times during the solution of a single process flow sheet.
Problem: In the subroutine below when the variables are passed from C++ the arrays zn, xn, yn, Kvle have an incorrect size. Variables are passed by reference and they should be of size nc = 8, but instead their size is 1000000 (see attached screenshot). The problem is also observed using the bind(C) decoration. Both projects, Fortran and C++ use multi-threaded runtime libraries.
subroutine pkg_KfactorsP(ppkgID, cmpListID, nc, P, T, zn, xn, yn, Kvle) integer(KIND=c_int), intent(in) :: ppkgID integer(KIND=c_int), intent(in) :: cmpListID integer(KIND=c_int), intent(in) :: nc real(KIND=c_double), intent(in) :: P real(KIND=c_double), intent(in) :: T real(KIND=c_double), intent(in) :: zn(nc) real(KIND=c_double), intent(in) :: xn(nc) real(KIND=c_double), intent(in) :: yn(nc) real(KIND=c_double), intent(inout) :: Kvle(nc) !DEC$ ATTRIBUTES DLLEXPORT :: pkg_KfactorsP !DEC$ ATTRIBUTES ALIAS:'_pkg_KfactorsP' :: pkg_KfactorsP !DEC$ ATTRIBUTES REFERENCE :: ppkgID !DEC$ ATTRIBUTES REFERENCE :: cmpListID !DEC$ ATTRIBUTES REFERENCE :: nc !DEC$ ATTRIBUTES REFERENCE :: P !DEC$ ATTRIBUTES REFERENCE :: T !DEC$ ATTRIBUTES REFERENCE :: zn !DEC$ ATTRIBUTES REFERENCE :: xn !DEC$ ATTRIBUTES REFERENCE :: yn !DEC$ ATTRIBUTES REFERENCE :: Kvle ...
The C++ calling function and corresponding declarations are:
pkg_KfactorsP(&ppkgID, &ppkgID, &nComps, &P, &Temp, Comps[poOverall], Comps[poLiquid1], Comps[poVapour], KK);
// External fortran subroutines declaration
extern "C" { // Compute KFactors void pkg_KfactorsP(int *ppkgID, int *cmpListID, int *nComp, double *P, double *T, double *zn, double *xn, double *yn, double *K); }
where Comps[poOverall], Comps[poLiquid1], Comps[poVapour], KK are pointers to arrays.
Note that this happens in Release mode. Debug mode seems to be OK.
Thank you in advance for your suggestions and possible problem identification, Javier
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Javier -
How do you know the size is wrong? I can't tell from your screen shot.
Is it that the array "keeps going" in 'Release' mode, but stops at 8 elements in 'Debug' mode?
If so, then the problem would be related to the debug information available within optimized code.
You can tell what is being used for an upper bound by adding a line to print ubound(zn) (for example).
--Lorri
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Lorri,
Thank you for your help. On the bottom part of the screen shot (Watch 1 window) one could see that the value of nc is equal to 8, however the size reported for the zn, xn and yn arrays is >> 8. Actually VS says that it is about 1.000.000.
In Debug mode, the size of the arrays actually matches nc = 8.
Thank you, Javier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As Lorri suggessts, you need to confirm that your program actually thinks the size of the array is not 8, using some method other than looking at what the debugger is telling you. It is easy for the debugger to get confused with release builds, but this does not necessarily mean the actual program has the wrong information.
(Sometimes the debugger gets confused with debug builds too, such that you need to independently confirm the characteristics of variables if things are looking a little strange.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You have a break point set on a line that has no statement. How have you managed that?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Humour me - try writing those values to a file or the console, if that is available, and checking the value there. If those variables aren't used later in the procedure the compiler's optimisations may well have eliminated them.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
IanH,
Attached you will find a print out of the last calls to the subroutine. From the screen shot before, I have added the writing statements after the ubounds.
ii = ubound(zn, 1) jj = ubound(xn, 1) kk = ubound(yn, 1) nn = ubound(Kvle, 1) write (40,fmt='(30ES16.6E3)') zn(1:30) write (40,fmt='(30ES16.6E3)') xn(1:30) write (40,fmt='(30ES16.6E3)') yn(1:30) write (40,fmt='(30ES16.6E3)') Kvle(1:30) write (40,*) ""
Thank you, Javier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry - I meant something like WRITE (40,*) ubound(zn,1), ubound(xn, 1), ...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Javier,
I think IanH is suggesting is something like this:
module m use, intrinsic :: iso_c_binding, only : c_int implicit none contains subroutine foo( N, x ) bind(C, name="foo") integer(kind=c_int), intent(in), value :: N integer(kind=c_int), intent(in) :: x(N) print *, " foo: N = ", N print *, " foo: lbound(x) = ", lbound(x, dim=1) print *, " foo: ubound(x) = ", ubound(x, dim=1) print *, " x = ", x return end subroutine foo end module m
extern void foo(int, int *); #define N 3 int main() { int x; for (int i=0; i<N; i++) x=i; foo(N, x); return 0; }
Upon execution,
foo: N = 3 foo: lbound(x) = 1 foo: ubound(x) = 3 x = 0 1 2 Press any key to continue . . .
And in the debugger,
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello IanH,
Attached you will find the results of the new print out. Interestingly, the arrays have the correct size! (nc=8).
Question, what would happen if one makes: a = sum(zn)? Would it make the summation from 1 to NC? I suppose it will, but I prefer to ask!
Thank you, Javier
PS: FortranFan thank you for the example!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Just a small clarification about the attached file. The file includes results from several calls to the subroutine (about 20 calls). Regards, Javier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As mentioned above, it is probable that the debugger has just been telling you fibs. Unfortunately it does that from time to time. Another possibility is that adding the print statements changed the code that the optimizer generated, such that the previous problem went away, but I think that unlikely in this case.
If this is just a case of the debugger telling fibs, then the internals of your program do know the correct size of the array and the operations on that array inside your program, like sum, will be doing the right thing.
I suspect (I don't know for sure - this is well outside my comfort zone) that when optimizations are active the compiler has noticed that it doesn't need to separately store the size of the arrays - e.g. because `nc` is intent(in) it can just directly reference that - and so it doesn't bother updating the size in the local descriptor (if it even bothers creating a local descriptor) for the arrays and save a few instructions. However, the debug information still assumes that size information is being maintained in a local descriptor at a certain location in memory - as a result the debug information is referencing nonsense.
Something similar possibly happened when you assigned the result of lbound on the arrays to temporary variables - when optimizing the compiler notices that those temporary variables are not used anywhere else, so it does not allocate storage for them and does not bother actually "calling" lbound.
The above might also be complete nonsense, perhaps the debugger was just feeling mischievous. If there is some element of truth the above, I clearly have zero idea whether this is working as intended.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello IanH,
I understand the points described. The background reason of this post was an ieee exception that was triggered in release mode. Actually the exception was an underflow condition, but it was difficult to understand the source of the problem. Now that I understand the mischievous behavior in release mode I am better prepared to solve the problem.
Thank you for your help and time, Javier
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's like IanH is sitting in our cubicles with us ...
Yes, his description is accurate. We tell the debugger that the bounds information is at location <x> but the optimizer will often change the code to keep the info in registers instead.
In the case of your other variables, again, we told the debugger that symbols named <nn> are at location <xx> but the optimizer discovered that you were never referencing those variables and threw away the code that set the values.
Debugging optimized code is an art.
Generating better debug information for optimized code is an ongoing science!
--Lorri

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page