MSFLIB and DFLIB

MSFLIB and DFLIB

thomasglallen's picture

I have some legacy code that uses MSFLIB and DFLIB, which apparently came from COMPAQ fortran.  When I get to the llinking, I get "error LNK2019: unresolved external symbol _f_setmessageqq referenced in the a routine".  I know that I'm using, in the routine, SETMESSAGEQQ(...), and that is the problem.  It either comes from MSLIB or DFLIB, don't know.  I get no error with the statements USE MSLIB and USE DFLIB in the fortran code, so does someone have a listing of intel  statements that are equivalent to the legacy statements in MSLIB and DFLIB.  I've searched and can't find any reference to the routines found in these libraries. Thanks.

Tom

52 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
thomasglallen's picture

In the same code, when I increase the array, I get the error that my variable CMB it too large for NTCOFF (Bigger than 2gb). CMB is a common statement like this:
COMMON /CMB/ CM(IRESRV), IP((2*MAXSEG), IB11, IC11, ID11, NEQMAT, NEQ, NEQ2
Now, above this I have IMPLICIT REAL*8 (A-H,O-Z) and IMPLICIT INTEGER*8 (I-N). Now, the this common statement is located about 5 other subroutines. I added the ALLOCATABLE statement like this:
COMMON ALLOCATABLE /CMB/ ...
and still get the same error (CMB too large for NTCOFF). I tried different methods but got syntaxed errors. Where do I go from here in order to allocate enough memory for the arrays. Thanks.

thomasglallen's picture

Forgot to mention that the values for the arrays, such as IRESRV and MAXSEG are stored in an include file as a parameter (such as PARAMETER (MAXSEG=200000, MAXMAT=7500) and in the code IRESRV=MAXMAT**2 where this variable MAXMAT is defined in the parameter statement in the include file as well). Any help is appreciated. Thanks.

Steve Lionel (Intel)'s picture

You'll have to move away from COMMON. Also, you'll have to build for 64-bits if you aren't already.

ALLOCATABLE is a variable attribute and not compatible with COMMON. I recommend creating a module that declares the allocatable arrays, something like this:


module CMB_MOD

IMPLICIT NONE
real(8), allocatable:: CM(:)

integer(8), allocatable::  IP(:)

integer(8) :: IB11, IC11, ID11, NEQMAT, NEQ, NEQ2

end module CMB_MOD

Now in the places that you INCLUDEd the COMMON definitions, instead say:

use CMB_MOD

(This has to go before any IMPLICIT or other declarations.)

At the start of your program, where you have also done the USE (the definitions of IRESRV and MAXSEG should also go in the module), say:

allocate (CM(IRESRV), IP(2*MAXSEG)

The rest of your program can remain unchanged except for needing the USE.

Steve
dboggs's picture

To address your original Q re the needed libraries: I too have this problem and would like to see such a list. But, the specific problem you describe should have a very fast solution: If you are programming with a valid Intel Visual Fortran installation then you also have contextual access to help, and all you should need to do is look up SETMESSAGEQQ. It will tell you that you need USE IFQWIN. Most of ifqwin overlaps with dflib, but there are differences. There is no problem having USE both in your code (although possibly inefficient, I don't know). If you really want to remember that IFQWIN is only there to solve this one unresolved external, then put USE IFQWIN, ONLY: SETMESSAGEQQ.

Steve Lionel (Intel)'s picture

SETMESSAGEQQ is a QuickWin routine. As I noted above, USE DFLIB should work fine for this in Intel Visual Fortran. We don't support USE MSFLIB. If you want to change to USE IFQWIN, that's fine too. Note that your application needs to be built as a QuickWin project type in order to use that routine.

Steve
thomasglallen's picture

Thanks. I tried it on one portion of the code, and it compiled and linked fine. Now, just want to make sure I understand - the "USE" statement (placed in all the required subroutines) will act as the COMMON statement in that all data will be shared amongst the subroutines. Also, it looked like the ALLOCATE(...) worked when I put it at the end all the COMMON statements in a routine, which I guess is where it should go (also after include, parameters, implicits, declarations). Is this correct? I'll have some other questions later. Thanks again.

Steve Lionel (Intel)'s picture

The USE makes the declarations in the MODULE visible. This includes the variable declarations that replace the COMMON. The ALLOCATE goes somewhere in executable code where you will do that statement before using the array.

Steve
thomasglallen's picture

I've been making the changes as suggest here, compiling and linking with no errors. Now when I run the code (excutable), it says that "allocatable array is already allocated". I suspect that in other subroutines, maybe a Dimenstion statement is being used that shouldn's since I'm allocating the space. I like to have some clues on this, so when it crashes, it dumps 4 columns (PC, Routine, Line, and Source). All columns say UNKNOWN accept for the PC column. Is there a way to turn on something that fills these columns in so I can get a clue as to where the "already allocated" variable is? This would help a lot in converting this code over more quickly. Thanks.

Steve Lionel (Intel)'s picture

/traceback is what you want if you're building from the command line - this should be on by default for VS builds. A DIMENSION attribute would not be relevant here - rather, you have an allocatable array that is previously allocated. Is this a local array to the routine? Is it named in a SAVE statement or is /Qsave enabled?

Steve
thomasglallen's picture

I replaced the COMMON block you suggested with the USE statement for the subroutines that contained the COMMON block. I would imagine it's a local array to the routine. I went ahead and added the /traceback and /Qsave, and ran it again, it gave me again the columns each with 10 rows, but only two of these were filled in with two routines and line numbers, the rest unknowns. The routines it indicated didn't seem to give me any clue about what was be allocated already. What is /QSave? Let me look at this for a bit - I think this is helping me somewhat to trace what is going on here. I'll get back with more specifics. Thanks.

Steve Lionel (Intel)'s picture

Actually, I wanted you to remove /Qsave if it had been added. This is Fortran > Data > Local variable storage > All variables SAVE in VS. This has an unfortunate side-effect on local allocatable variables.

Steve
thomasglallen's picture

I solved this allocate problem (I allocated a variable in main with the USE and did the same in a subroutine, and didn't need it in the subroutine, so I understand what is going on there) Now, I have another COMMON statement that I replaced with a USE. I placed it in one subroutine that had an equivalence statement : EQUIVALENCE (CAB,ALP),(SAB,BET). I obtained the error "attribtes of this name conflict with those made accessible by a USE statement". So I moved the EQUIVALENCE to the USE module, which solved that, but when I compile it, I get "An equivalence data object must not have the ALLOCATABLE or Pointer attribute" and "Variables containing ultimate allocatable array components cannot appear in COMMON or EQUIVALENCE statements. Variables ALP and BET are defined as REAL(8), ALLOCATABLE in module (have to be). Any way around equivalence, or something that is the same in fortran that works with ALLOCATABLE?

thomasglallen's picture

Also wanted to add that the CAB and SAB variables I mentioned above are defined in the subroutine as DIMENSION CAB(1), SAB(1).

thomasglallen's picture

Did some research. THe Fortran EQUIVALENCE was introduced as a means to inform the compiler that two or more different variables (usually arrays) could share the same storage locations because the programmer had arranged to complete the use of one of them before using any of the others. I guess years ago, memory and storage was limited, and newer machines don't have that issue. So I guess I could just comment out the equivalence and keep the Dimension statement - is that OK to do? It compiles or course with no errors.

Steve Lionel (Intel)'s picture

More often, EQUIVALENCE was used to provide access to a variable with a different type or length. You need to look at how the variables named in the EQUIVALENCE were used. If you simply take out the EQUIVALENCE, then instead of one set of data you have two - and probably introduce uninitialized references.

There's no universal answer to your question. It all depends on what the application used EQUIVALENCE for.

Steve
thomasglallen's picture

Now that you mentioned this, the EQUIVALENCE statement is something like this: EQUIVALENCE(CAB, ALP) where CAB and ALP are defined as follows: ALP(MAXSEG), where MAXSEG = 2000 in an include file and DIMENSION CAB(1). These appear to have different lengths. I would imagine you are talking about this. In this particular case, what is going on with the variables in the equivalence in terms of what equals what or what is being shared. If I understand this concept, I'll be able to make some intelligent changes to this code. Thanks.

bmchenry's picture

Some thoughts/ideas on the subject.
modules are not sequential like common storage used to be back in the day.
equivalence to modules does not insure you are 1:1.
to get around that be sure to set equivalence each variable to the array.
for example, if you have in the old code
real something (3)
real one, two, three
In the old days you could say
equivalence (something(1), one)
and it would equate all three items to the something() since they existed in sequence.
not so much anymore.
now you need to be specific about it
equivalence (something(1), one), (something(2), two), (something(3), three)
very tedious to set up but then once set up it works as expected.

thomasglallen's picture

As I'm going through the code making the substitution of USE cases for the COMMON statements, I make one change, run a test case, then make the next, etc. I made one change where I commented out a COMMON, replaced it with a USE, and I got a divide by zero error. I traced it down to a few COMMONs, don't know which one, but here's what I think is going on, and I need some advice just to save me some time:
It looks like the USE statement doesn't appear to work exactly as a COMMON (I replaced a COMMON with a USE and got a divide by zero, restored it, and it was fine). In the code I'm trying to convert over to 64-bit with large arrays, some subroutines apparently when called have variables that are initialized and the COMMON captures these values in the subroutine, and these values are used/passed by other subroutines that contain these values. Now, worst yet, some of these subroutines contain an "if" statement, which can change the stored values in the COMMON statement when called by another subroutine that passes the value that satisfies the “if”. Now, in the module, I have the arrays as allocatable, non-arrays as either integer(8) or real(8) (as described above), and I allocate the arrays only once in the Main program, and then use the USE in replacement for the COMMON. So, I’m wondering does the USE capture changes to its variables in a subroutines that reassigns that values, or do I need to do something else to make this act exactly like these COMMON statements. As a side note, I compiled this under linux, don’t have the array allocation issues as in Windows. Thanks.

thomasglallen's picture

OK, maybe I talked out of line too soon, below is a test program, and it appears that the module captures changes in both subroutines, the print out should be 3333 and 4444.0, which it is. So, I guess the USE acts exactly as a COMMON, am I correct?

Module myModule
INTEGER i1
REAL f1
END MODULE

PROGRAM myProg
USE myModule
IMPLICIT NONE
C INTEGER i1
C REAL f1
i1=1111
f1=2222
CALL mysub1
WRITE(*,*) 'FROM mysbu1', i1, f1
CALL mysub2
WRITE(*,*) 'FROM mysub2', i1, f1
END
C
C
SUBROUTINE mysub1
USE myModule
IMPLICIT NONE
C
i1=3333
f1=4444
END
C
SUBROUTINE mysub2
USE myModule
IMPLICIT NONE

i1=5555
f1=6666
CALL mysub1
END

Steve Lionel (Intel)'s picture

I would not say that USE is "exactly like COMMON", though, as has been suggested in this thread, module variables made accessible by USE are usually a suitable replacement for COMMON as it is normally used.

COMMON declares a layout of variables that overlay other declarations of the same named COMMON in other program units. If all of these COMMON layouts are the same and each variable is accessed individually, then it is pretty much the same as module variables. But COMMON allows different layouts in different program units (for named COMMON, all must be the same length) and it establishes a "storage sequence" of the variables as a group, which USE does not.

Steve
thomasglallen's picture

As I’m going through this code that I mentioned earlier, I’ve come up against the following error (tried a variety of things but can’t seem to resolve it):
Test.f(648): error #6401: The attributes of this name conflict with those made accessible by a USE statement. [SI]
EQUIVALENCE (X2(1),SI(1)), (Y2(1),ALP(1)), (Z2(1),BET(1))
-------------------------^
Test.f(648): error #6401: The attributes of this name conflict with those made accessible by a USE statement. [ALP]
EQUIVALENCE (X2(1),SI(1)), (Y2(1),ALP(1)), (Z2(1),BET(1))
----------------------------------------^
Test.f(648): error #6401: The attributes of this name conflict with those made accessible by a USE s
tatement. [BET]
EQUIVALENCE (X2(1),SI(1)), (Y2(1),ALP(1)), (Z2(1),BET(1))
--------------------------------------------------------^
compilation aborted for Test.f (code 1)

I have the following module that I’m using as a USE statement (I call it DATA_MOD):

module DATA_MOD
IMPLICIT NONE
REAL(8), ALLOCATABLE::X(:),Y(:),Z(:),SI(:), BI(:), ALP(:),
& BET(:),SALP(:),T2X(:),T2Y(:), T2Z(:)
REAL(8)::CAB,SAB
INTEGER(8), ALLOCATABLE::ICON1(:),ICON2(:),ITAG(:),ICONX(:)
INTEGER(8)::IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP
END module DATA_MOD

This substitutes the COMMON block named /DATA/:
COMMON /DATA/ X(MAXSEG),Y(MAXSEG),Z(MAXSEG),SI(MAXSEG),BI(MAXSEG),
&ALP(MAXSEG),BET(MAXSEG),SALP(MAXSEG),T2X(MAXSEG),T2Y(MAXSEG),
&T2Z(MAXSEG),ICON1(MAXSEG),ICON2(MAXSEG),ITAG(MAXSEG),
&ICONX(MAXSEG),IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP
.
Now, Main (where the Program name is) is where I allocated these values as follows:
ALLOCATE (X(MAXSEG),Y(MAXSEG),Z(MAXSEG),SI(MAXSEG),BI(MAXSEG),
&ALP(MAXSEG),BET(MAXSEG),SALP(MAXSEG),T2X(MAXSEG),T2Y(MAXSEG),
&T2Z(MAXSEG),ICON1(MAXSEG),ICON2(MAXSEG),ITAG(MAXSEG),
&ICONX(MAXSEG))
Where the value of MAXSEG is defined in a PARAMETER statement as an include file (the USE is placed before the include statement).

The subroutine the error is occuring is in this routine:

SUBROUTINE CATNRY(XW1,YW1,ZW1,XW2,YW2,ZW2,RAD,ICT,RHMP,ZMP,NS,ITG)
USE DATA_MOD
INCLUDE 'NECPAR.INC'
IMPLICIT REAL*8 (A-H,O-Z)
! COMMON /DATA/ X(MAXSEG),Y(MAXSEG),Z(MAXSEG),SI(MAXSEG),BI(MAXSEG),
! &ALP(MAXSEG),BET(MAXSEG),SALP(MAXSEG),T2X(MAXSEG),T2Y(MAXSEG),
! &T2Z(MAXSEG),ICON1(MAXSEG),ICON2(MAXSEG),ITAG(MAXSEG),
! &ICONX(MAXSEG),IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP
DIMENSION X2(1), Y2(1), Z2(1) !Moved to Data Module
EQUIVALENCE (X2(1),SI(1)), (Y2(1),ALP(1)), (Z2(1),BET(1))

This gives you enough information I believe. I trued moving the equivalence statement to the module, but still got the same error. Any suggestions as to how to fix this error. Thanks.

Steve Lionel (Intel)'s picture

Move the EQUIVALENCE (and declarations of any variables mentioned there) to the module. You can't EQUIVALENCE variables that became visible through USE.

Steve
thomasglallen's picture

When I move the EQUIVALENCE to the MODULE, in order for the EQUIVALENCE to work, I have to change the arrays associated in the EQUIVALENCE to static. I would like the EQUIVALENCE to have arrays that are dynamic using the ALLOCATION statement because the MAXSEG variable is of interest to me, because this is the one we want to make as big as possible. Is there a way to use EQUIVALENCE and ALLOCATION? If not, is there another way to handle this issue. Also, the EQUIVALENCE as shown above and in subsequent routines as I have found through examination is that it equivalences two corresponding elements (e.g., X2(1),SI(1)) and will let the array be referred to by either X2 or SI. As I said, anyway to use ALLOCATABLE/ALLOCATE with EQUIVALENCE or is their another way to do this using the allocation option. Thanks for your help.

Steve Lionel (Intel)'s picture

You can't use EQUIVALENCE with ALLOCATABLE. I suggest rewriting the code to not use EQUIVALENCE.

Steve
thomasglallen's picture

What would be the best way to right an EQUIVALENCE. Just want to get some ideas here so that I don't start drawing on straws. I thought of pointers and DO/WHILE loops. Also, if you have any references from others who have had this problem would be greatly appreciated as well.

Steve Lionel (Intel)'s picture

I don't think there's any one way to do this - it depends on what the program was trying to do. From the snippets you posted, it seems at best that the program was trying to avoid array bounds checking. I haven't seen enough of the program to know if that's the case. Ideally you'd want to eliminate the idea of aliases at all. It's probably a lot of work.

Steve
thomasglallen's picture

At the moment, I'm trying to understand how EQUIVALENCE statements work. Given the example above, consider the following:
DIMENSION X2(1), Y2(1), Z2(1) !Moved to Data Module
EQUIVALENCE (X2(1),SI(1)), (Y2(1),ALP(1)), (Z2(1),BET(1))
Now, SI,ALP, and BET are in the COMMON statements and are in some sense GLOBAL and visible to all subroutines that have COMMON/DATA/. Now, S1 is of size S1(MAXSEG), which, by EQUIVALENCING X2 to S1, makes X2 of size X2(MAXSEG). This is what is happening in the code. This I understand. But, by EQUIVALENCING X2 to S1, does X2 now become visible to other routines that contain the common COMMON/DATA/, like the variables in the COMMON/DATA/? It appears something like this is happening in this code because when I comment out the EQUIVALENCE, I get an error (an error that is caught by the code itself, it has some error checking - don't need to go into details), but when I uncomment the EQUIVALENCE, it runs normally. Thanks.

mecej4's picture

EQUIVALENCE has been in Fortran for decades, and it had its uses given the limitations of older versions of the language. Now that we have modules in the language, it is best if EQUIVALENCE is retired, given the numerous restrictions on its usage and the complicated side-effects caused by using it. If, however, you have old code and it is not feasible to remove the usage of EQUIVALENCE in it, you have to become aware of all the properties of the statement.

Perhaps this analogy will help: think of memory as a row of mailboxes. Variable names correspond to labels on some of the mailboxes. EQUIVALENCE allows you to put additional labels on the same mailboxes. It does not allocate more mailboxes to a person (variable).

Quote:

Now, S1 is of size S1(MAXSEG), which, by EQUIVALENCING X2 to S1, makes X2 of size X2(MAXSEG).
This is a misconception. Consider this example (no COMMON used, to keep things simple)


program tequivalence

implicit none

integer :: x(3),y(6),i

equivalence (x(2),y(4))

do i=1,6

   y(i)=i

end do

write(*,*)x

write(*,*)y

end program tequivalence

The output of the program:


 3 4 5

 1 2 3 4 5 6

Note that the EQUIVALENCE specification did not change the length of array x or that of array y.

thomasglallen's picture

OK, then what I understand you saying (again, taking the code shown above), is that in the following statements (set MAXSEG equal to 2000):
IMPLICIT REAL*8 (A-H,O-Z)
COMMON /DATA/ X(MAXSEG),Y(MAXSEG),Z(MAXSEG),SI(MAXSEG),BI(MAXSEG),
& ALP(MAXSEG),BET(MAXSEG),SALP(MAXSEG),T2X(MAXSEG),T2Y(MAXSEG),
& T2Z(MAXSEG),ICON1(MAXSEG),ICON2(MAXSEG),ITAG(MAXSEG),
&ICONX(MAXSEG),IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP
DIMENSION X2(1), Y2(1), Z2(1) !Moved to Data Module
EQUIVALENCE (X2(1),SI(1)), (Y2(1),ALP(1)), (Z2(1),BET(1))

even though the size of SI,ALP,and BET are size 2000, then X2(1), Y2(1), and Z2(1) are of size one, and therefore their sizes don't change; then, X2(1) is a label for the memory location SI(1), Y2(1) is a label memory location for ALP(1), and Z2(1) is a memory location for BET(1), and so there is no values for X2(2), Y2(2), and Z2(2) - or at least is garbage, all the way up to MAXSEG? Is this correct? Also, since SI,ALP,and BET are available to other subroutines with the COMMON statement, I'm assuming the X2,Y2, and Z2 are also visible to these subroutines, even though they are not explicitly contained in the COMMON statement? Is this correct as well? Also, I would imagine that SI(1),ALP(1), and BET(1) also can take on the values for X2(1), Y2(1), and Z2(1) as well. Is this correct? Sorry for the ignorant questions, but I'm trying to fully understand this EQUIVALENCE - I've written some snippets, but want to make sure this is your understanding as well. Thanks for your help on this matter.
Tom

mecej4's picture

As declared in your code, X2, Y2 and Z2 are aliases for sections (of length 1) of arrays SI, ALP, BET. Once your code is compiled, all these variable names are gone (let's overlook debug symbols, etc.). X2(1) and and SI(1) are represented by the same memory address.

Once X2 has been declared with dimension (1), code using other subscripts is in error, although the compiler need not detect such errors. Furthermore, even though X2(2) is illegal to use, the memory that it would be taken to refer to would be part of another properly allocated array, and referencing it would not cause access violations.

The EQUIVALENCE statement applies only within the scope of the program unit where it occurs. Outside that program unit, the equivalence-d names do not exist. Thus, if you replicate the common block elsewhere, using the same variable names (X, Y, Z, ...), and proceed to reference X2, Y2 and Z2, which are not among the members of the block, these would be undeclared variables, and treated using IMPLICIT type rules if permitted.

Here is an example:


program xeq

IMPLICIT NONE

integer,parameter :: MAXSEG=5

real, dimension(MAXSEG) :: X,Y,Z,SI,BI,ALP,BET,SALP,T2X,T2Y,T2Z

integer, dimension(MAXSEG) :: ICON1,ICON2,ITAG,ICONX

integer :: IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP

COMMON /DATA/ X,Y,Z,SI,BI,ALP,BET,SALP,T2X,T2Y,T2Z,ICON1,ICON2,ITAG, &

              ICONX,IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP

real, dimension(1) :: X2, Y2, Z2

EQUIVALENCE (X2,SI), (Y2,ALP), (Z2,BET)
integer :: i
do i=1,2

   SI(i) = sqrt(2.0*i)

end do

write(*,*)X2      !X2 was never set, but SI(1) was set
X2(2) = 5.5       !subscript out of range error
call sub

end program xeq
subroutine sub

IMPLICIT NONE

integer,parameter :: MAXSEG=5

real, dimension(MAXSEG) :: X,Y,Z,SI,BI,ALP,BET,SALP,T2X,T2Y,T2Z

integer, dimension(MAXSEG) :: ICON1,ICON2,ITAG,ICONX

integer :: IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP

COMMON /DATA/ X,Y,Z,SI,BI,ALP,BET,SALP,T2X,T2Y,T2Z,ICON1,ICON2,ITAG, &

              ICONX,IPSYM,LD,N1,N2,N,NP,M1,M2,M,MP

write(*,*)si

write(*,*)X2    !X2 not declared, compile time error

return
end subroutine

thomasglallen's picture

So far I'm succeeding in converting this code over using allocatable variables; have a handle on the equivalences also.  But I have a question about some other things in the code.  There is a common statement called COMMON /SCRATM/.  Now, some subroutines it's COMMON /SCRATM/ D(2*MAXSEG), other subroutintes it is COMMON /SCRATM/ GAIN(4*MAXSEG), and in others it is COMMON /SCRATM/ Y(2*MAXSEG).  COMMON acts like globals, but there are different variables in this common located in different subroutines.  In a situation like this, does this represent COMMON /SCRATM/ D(2*MAXSEG),GAIN(4*MAXSEG), Y((2*MAXSEG)?  And should I treat it as such.  Again, I'm converting the commons over to modules.  What is the best way to convert this common over to a module?  Also, I don't understand what is being shared here if the common has different variables.  This looks like very bad programming, unless you have a good explanation.  Or is something else going on here I don't understand?  Thanks for your help. 

thomasglallen's picture

One more thing, it compiles and runs as it should as well with no warnings or errorrs - I just discovered this today as I'm converting commons over to modules.

thomasglallen's picture

One more item forgot to mention, the GAIN variable is a real value, the other ones (D and Y) are defined as COMPLEX*16.  So what is going on here also?

mecej4's picture

Quote:

Also, I don't understand what is being shared here if the common has different variables.

The names of variables in a COMMON block are local in scope. COMMONality is by offset from the base of the COMMON block, not by name. For example, if the following statements occur in different subprograms

subroutine subA
REAL a,b,c
COMMON /XYZ/a,b,c
...
subroutine subX
REAL p,q,r
COMMON /XYZ/p,q,r

variable pairs (a, p), (b, q), (c, r) differ only in name. Variable 'a' in SubA has the same value as 'p' in SubX, etc.

When COMMON block members differ in type from one declaration to another, it gets "interesting".

John Campbell's picture

I'd expect that what you are describing is basically a memory sharing strategy. Non-conforming, but very effective when there was limited available memory.
.
You might be able to use the POINTER attribute to replace the EQUIVALENCE between these arrays.
I'd expect that EQUIVALENCE is being used to share memory for arrays that arn't used at the same time.
.
If you are mixing the TYPE or KIND of the variables, then the previous values were probably overwritten. However, if in this case, the values are being retained, such as mixing real and complex addressing, then the use of POINTER attribute might be more challenging.
.
With increased memory available, the clean solution might be to not share the storage locations, but use them independently.
.
Alternatively, EQUIVALENCE was used to allow memory locations to be re-named. This could allow addressing of storage with different rank arrays. Reducing the array rank was a way of improving performance. This is possibly no longer required and could be removed. (POINTER might be used in this case.)
.
All this involves changing old, non-standard code, with the associated problems of introducing new coding bugs, that need to be tested.
.
Handle with care !
.
John

thomasglallen's picture

Have another issue: in the application discussed above, there is something like this declared: Complex *16 CM and below is Dimenstion CM(NR,*).  Now, NR is not defined anywhere in the routine, to include "include" statement.  Of course, everything comples and runs OK, so what is assumed here for the integer varialbe NR?

Steve Lionel (Intel)'s picture

Please show the actual code. Your description is not likely to be correct. In this context, NR could be a PARAMETER constant or the name of a dummy argument, COMMON variable or USE or host-associated variable. If CM is a dummy argument, then (unless NR is a PARAMETER), it is an "adjustable array" where the first bound is taken from the current value of NR. If it is not a dummy, then it is an "automatic" array, allocated on the stack (by default) with a first dimension of NR.

Steve
mecej4's picture

For a declaration such as CM(NR,*) that was accepted by the compiler, it is probable that both CM and NR are dummy arguments to a subprogram. Please check your sources.

thomasglallen's picture

Thanks.  I'm busy with a few other items here at work, and will upload the snipets of the code (enough to evaluate) some time this week.

thomasglallen's picture

I figured it out - been looking at this code too long.  The value of the array is coming in via the subroutine call it's under.  Sorry for the inconvenience.  I have another one: In many places in this code, an array is defined as an asterisk (wild card I'm assuming).  So you have something like this:

Complex*16, E

Dimension E(*)

Will the following be the same (want to make sure):

Complex(8), Dimension(:), Allocatable::E

Allocate(E(0))   ! size zero to start with

Also, if the array is a double array, then is "...Dimension(:,:) ... Allocate(E(0,0)) OK to use?  I think it is, but want your opinion.

One more question: I have allocations every which way but loose in the code (in modules, subroutines).  When it returns to main and exits, is there a wild card that I can use to deallocate the memory, or does it automatically deallocate when it exits?  Thanks.

 

thomasglallen's picture

One other question not related to the above one (or might be).  I have the code working with dynamic arrays.  This may have reference to deallocation, not sure.  But before conversion, I used an input file and runs in about a few minutes.  After conversion (converting to modules, allocation statements), I increased the arrays by 10x to test the dynamic arrays, and using the same input file, it runs much, much longer.  Should I be deallocating every time the code exits a subroutine to speed things up, or is there something else I can do to speed the code up.  Any suggestions would be appreciated.  Thanks.

Steve Lionel (Intel)'s picture

A zero sized allocation is allowed.

When your program exits, all allocated memory is automatically deallocated by the OS. Also if you declare local allocatable variables in a subroutine or function, and don't give them the SAVE attribute, they are automatically deallocated when the procedure exits.

I can't really tell from your last post what is happening. The actual allocate/deallocate step is pretty fast, but maybe you are using more memory than in the other version and starting to swap if RAM is insufficient. If you are using allocatable (and not pointer) arrays, memory leaks are, theoretically, impossible, but one never knows.

I suggest running the program under a performance profiler such as Intel VTune Amplifier XE (free 30 day trial available) and see where the program is spending the most time.

Steve
thomasglallen's picture

You're correct on the swaping of memory.  This code will eventually run on machines with 512 gigbyte memory, so I think it's OK.  Getting back to the  Dimension E(*) statement above - I replaced Dimension E(*) with what I said above - it compiled OK, ran it and entered the input file, and it gave me a program exception - access violation where the code was replaced with the allocation statements.  It runs fine with just Dimension E(*), but when changed to the allocation option, it crashes.  Do I need to add something else here to the allocation statements to make it equivalent to Dimension E(*).  Thanks.

thomasglallen's picture

One other question related to the IDE.  The program is compiled under the DOS prompt, and looks like this:

ifort /traceback /fpe:0 test.f CMB.FOR ZLOAD.FOR NETDEF.FOR NETWRK.FOR SORCES.FOR INSCOM.FOR SEGJ.FOR.SMAT.FOR DATA.FOR CRNT.FOR JNQCOM.FOR SCRATM.FOR IRESRV.FOR /exe:test.exe /map:test.map

The *.FOR are the module files that use to be COMMON files.  There is also an include file called NEC.inc. 

Now when I start a project in the IDE, I choose the command prompt and I get header files, resources files, and source files.  I added the files to the sources file (*.FOR, *.f, *.inc) and ran "Start Debugging" and get all sorts of errors; it compiles and links fine at the DOS prompt shown above.  The project is called WINNEC, and the property pages looks correct.  Can you give me any guidance on setting this up correctly in the IDE environment.  Just trying to save some time here.  Thanks

Steve Lionel (Intel)'s picture

I am not sure what you mean by "choose the command prompt".

You want to create a new project of type Fortran Console Application, with "Empty Project". Add all the source files to the project. Right click on the project, select Properties. Go to Fortran > Floating Point. Change Configuration to "All configurations". Set Floating-Point exception handling to the option that includes /fpe0, then click OK. Select Build > Build Solution. It should compile and link. Then set a breakpoint at a convenient place in the program (such as the first executable line) and start debugging by pressing F5. Note that when the program exits, the console window will go away.

Steve
thomasglallen's picture

Sorry for saying command prompt; I meant to say the project file column instead.  I had to choose no under Fortran->Diagnostics->Generate Interface Blocks in order to get the Fortran program to compile cleanly as in my command line statement shown above.  It runs and gives the same answers as when it was compiled under DOS.  The "Generate Interface Blocks" when set to yes gives a few warnings and errors that might be of concern, so I plan to look at that later and I might ask more questions about that.  At the moment, everything appears to run fine.

Right now, I've developed a C# interface for the fortran program, and runs the fortran executable from the C# GUI.  I need something more versatile than the Intel GUI that is provided (I plan to use threading and plot routines under C#). This is just a test GUI for the moment.  Is there a way to interface C# with the source code in fortran in any way?  The program outputs various information to a text file, and it would be more efficient if I can access this information via my C# GUI directly from the Fortran program rather than access the information when the fortran  outputs the finished file to disk.  If you have any ideas or direct references that would be even better. 

Steve Lionel (Intel)'s picture

There are two general options. One is to write the Fortran code as a DLL that is called "unmanaged" from C#, passed arguments and the results received back. The other is to write the Fortran code as a "COM Server" and use COM to communicate between the C# and Fortran code. The latter is a complex subject with no C# examples and is not something I would recommend starting out with, though I know of people who have used it successfully.

Steve
thomasglallen's picture

One other question.  I have the following include file that is used for array sizes (with the module replacement suggested earlier in this forum, I can now use as large of an array as memory allows):

Parameter (MAXSEG=2000, MAXMAT=7500)

There are additional similar parameter statements.  If I want to say, change the MAXSEG to 20000, I have top recompile the main program and link in the modules.  I want to avoid this and have the user input the values of this array only, and run the executable without recompiling every time the values in the parameter are changed.  What's the best way to do this under Fortran?  As a note, I'm using the ALLOCATE statement in the main Fortran program to allocate the array size, e.g., ALLOCATE(ZARRAY(MAXSEG), LDTYPE(MAXMAT),...) - there are many more of these allocate statements.  Thanks.

Steve Lionel (Intel)'s picture

Just make MAXSEG and MAXMAT integer variables and prompt the user for them. The ALLOCATE statements can stay the same.

Steve
fortrino's picture

Hello everybody,

I am converting a program from CVF 6.6 to IVF 11.1 and I am looking for an equivalent to this part of the code below :

1. What library should I call instead of MSFLIB ? Should I modify the functions used in the program FULLPATHQQ, ... ?

2. This program is used to open a data file named "inputData.txt", if this file does not exist in the correct directory, the line 15 (err=9001) call a window which allow to search fo a file manually (the same "open with" window that we have generally in all programs).

3. How can I change lines 15,16 ?

Thank you

  1.     USE msflib
  2.     CHARACTER($MAXPATH) pathin
  3.     CHARACTER($MAXPATH) filein
  4.     CHARACTER(2) drive
  5.     CHARACTER($MAXPATH) dir,workdir
  6.     CHARACTER($MAXPATH) namein
  7.     CHARACTER(4) ext
  8.     INTEGER*4 leng1,leng2,leng3
  9.     LOGICAl(4) result
  10.     ienter=1  
  11.     OPEN (ienter,FILE='inputData.txt',status='old',err=9001)
  12.     call Function
  13.     goto 1
  14.         
  15. 9001    open(ienter,file='',status='old',err=9000)
  16.     INQUIRE(ienter,name=filein)
  17.     leng1=FULLPATHQQ(filein,pathin)
  18.     IF(leng1.EQ.0)STOP
  19.     IF(leng1.GT.0)THEN
  20.         leng2=SPLITPATHQQ(pathin,drive,dir,namein,ext)
  21.         IF(leng2.EQ.0)THEN
  22.               WRITE(*,*) 'Can''t split path'
  23.             STOP
  24.         ENDIF
  25.     ELSE
  26.         WRITE(*,*)'Can''t get full path'
  27.         STOP
  28.     ENDIF
  29.     
  30.     RETURN
  31. 9000    WRITE(*,*) 'Reading error'

Pages

Login to leave a comment.