Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.

Fortran DLL - incorrect array size

Goicochea__Javier
3,321 Views

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

0 Kudos
16 Replies
Goicochea__Javier
3,321 Views

Screenshot

0 Kudos
Lorri_M_Intel
Employee
3,321 Views

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

0 Kudos
Goicochea__Javier
3,321 Views

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

 

0 Kudos
IanH
Honored Contributor III
3,321 Views

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.)
 

0 Kudos
Goicochea__Javier
3,321 Views

Lorri and IanH, 

I have tried your suggestion of using ubound. In the new screen shot you can see that the array size is >>8. 

What could be the reason?

Thank you in advance, Javier

 

0 Kudos
IanH
Honored Contributor III
3,321 Views

You have a break point set on a line that has no statement.  How have you managed that?

0 Kudos
Goicochea__Javier
3,321 Views

Hi IanH, 

Here is the updated screen shot. I think this happens when the source is not fully synchronized with the built or compiled version. Still the error remains. 

Thank you, Javier

 

0 Kudos
IanH
Honored Contributor III
3,321 Views

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.

0 Kudos
Goicochea__Javier
3,321 Views

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

 

0 Kudos
IanH
Honored Contributor III
3,321 Views

Sorry - I meant something like WRITE (40,*) ubound(zn,1), ubound(xn, 1), ...

 

0 Kudos
FortranFan
Honored Contributor III
3,321 Views

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,

ass.png

0 Kudos
Goicochea__Javier
3,321 Views

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!

0 Kudos
Goicochea__Javier
3,321 Views

Just a small clarification about the attached file. The file includes results from several calls to the subroutine (about 20 calls). Regards, Javier

0 Kudos
IanH
Honored Contributor III
3,321 Views

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.
 

0 Kudos
Goicochea__Javier
3,321 Views

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

0 Kudos
Lorri_M_Intel
Employee
3,321 Views

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

0 Kudos
Reply