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

Warning about misaligned elements in structure

mecej4
Honored Contributor III
7,274 Views

The 16.0 compiler issues the following warning message about a structure:

..\include\dmumps_struc.h(14): warning #6379: The structure contains one or more misaligned fields.   [DMUMPS_STRUC]
      TYPE DMUMPS_STRUC

Although I wish to make this message go away, by inserting padding or rearranging the sequence, in this case the declaration of the structure (i.e., user-defined type) spans 265 lines, causing the number of suspects to be large.

It would help if the compiler flagged (or flagged when requested) the particular structure members that caused the misalignment.

An older version of the file in question: http://mumps.sourcearchive.com/documentation/4.9.2.dfsg/dmumps__struc_8h_source.html .

 

0 Kudos
1 Solution
TimP
Honored Contributor III
7,260 Views

I'm guessing that you're not looking for alignments suitable for vectorization of short (or longer) arrays, and that your message may be about failing to get 8-byte alignment of real64 and the like.  As the build procedure probably has to work for combinations such as ifort and MSVC, there's no chance of automatic padding working, thus SEQUENCE must be in effect, and padding must be explicit.  As Jim said, the traditional rule to avoid padding is to order the elements in decreasing order of size.  The tradition goes back to f77 and earlier, when putting single byte elements in the same structure with larger ones wasn't supported by standards.  Even then, the different padding treatments of real(10) by various compilers were among the reasons for many Fortrans not supporting it.

For 32-bit Windows, mis-aligned 64-bit data used to be routine, and throwing a warning by default would have been annoying.  Some programmers claimed that attempts to get alignment were in violation of the ABI.  Microsoft even advertised a feature whereby their compiler performed all 64-bit moves, including doubles, by pairs of 32-bit integer operations, to mitigate the performance consequences.

I was just looking into whether Windows gcc can support 32-byte alignment.  Apparently, the answer is no, even for 64-bit mode, although I didn't try reconfiguring ld for that purpose.

ifort still doesn't support 32-byte alignment of COMMON (to my knowledge), although Intel compilers do support it for individual arrays, and this was on the wish list from the time when 32-byte alignment became important.

View solution in original post

0 Kudos
30 Replies
TimP
Honored Contributor III
6,988 Views

map option ought to show where components are forced to alignment less than the alignment corresponding to data type. The spots needing padding would be where a larger data type follows a smaller one which ends at an odd address.

0 Kudos
FortranFan
Honored Contributor II
6,988 Views

Would BIND(C) help in such cases?

0 Kudos
IanH
Honored Contributor II
6,988 Views

There's an odd number of character components with an odd length, which isn't particularly odd, but will be odd, if you get my drift.

 

0 Kudos
JVanB
Valued Contributor II
6,988 Views

BIND(C) won't work because the structure has components that won't fit, like CHARACTER(LEN/=1) and ALLOCATABLE or POINTER components. Can you just remove the SEQUENCE attribute, put the structure in a module, and USE the module where required? The compiler will complain if the module isn't USEd where required. The ifort documentation doesn't make clear whether the PACK directive might be useful here.

 

 

0 Kudos
mecej4
Honored Contributor III
6,988 Views

Thanks for the suggestions. The include file is used in the MUMPS sparse linear equation solver, and I encountered the warning with the most recent version of MUMPS (5.0), whereas there was no such warning generated with an older version (4.10). The package consists of a number of C and Fortran files, and I suspect that the SEQUENCE attribute is there to make the two languages work together on common Linux/Unix systems. The Fortran parts do not use BIND(C). I hesitate to change the include file without knowing the dependencies and without some confidence in the makefile being aware of the effect of changing include files on the library build process.

It would be nice to be able to get some kind of listing with offsets as in an assembly listing, but just for variables, common blocks and structures. This may already be possible, as Tim Prince hinted, but I have yet to find the appropriate compiler options.

0 Kudos
TimP
Honored Contributor III
6,988 Views

ifort -help suggests /list /show:map or /map (for the last 2 major versions) (or the Generate Map File option in project linker properties)

0 Kudos
mecej4
Honored Contributor III
6,988 Views

Ah, I see what you meant now. I was puzzled about why I should look at a linker map to see the variables list produced from a single source file. As it turns out, /list is all that is needed, since it generates a source listing and a cross-reference listing. Unfortunately, the members of the structure are shown as if they were separate variables, sorted by name along with all the other variables of the subprogram. For the structure in question, I see

 Name                       Object Declared Type            Bytes Dimen Elements Attributes       References                        
 DMUMPS_STRUC               Type   14                       14691       scalar                    19,265                            

but it is a chore to hunt for the members of the structure, whose names are scattered around in the listing, and reconstruct a list of offsets in order to find the specific item(s) that caused misalignment -- there are 134 structure member names to look at!

I suppose that one could create a dummy subroutine which contained nothing but a declaration of a single variable of the derived type, and look at the listing produced from that subroutine. That would help avoid the clutter caused by the inclusion of all the other variables in the production subroutine source code.

 

0 Kudos
JVanB
Valued Contributor II
6,988 Views

Just import the listing into Excel, chop out the leading and trailing lines and the page headers, and sort by column C. Now everything is in order.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
6,988 Views

Mecej4,

Before you go to the effort of adding pads, make sure that the you are not bunging up the interoperability with MUMPS. It may require the data structure as-is. In this case, you may need a transfer function that copies the data from MUMPS formatted record to one acceptable to your Fortran (and transfer back).

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
6,988 Views

>>Although I wish to make this message go away, by inserting padding or rearranging the sequence, in this case the declaration of the structure (i.e., user-defined type) spans 265 lines, causing the number of suspects to be large.

The "easiest" way to do this is organize the member variables by "pickiness".

real(16)
real(8) & integer(8)
real(4) & integer(4)
integer(2)
everything else

If you have members that have sub-types, then  you may have to padd (or use map).

What I haven't tried, but may be worth experimenting with), is to see if the intrinsic SIZEOF, together with +nn and MOD can be used in the data declaration section to determine the padd (or actually a padded integer(1) array/character variable) as used in MAP. Then you may be able to use FPP and a well crafted macro to assure the alignment.

Jim Dempsey

 

0 Kudos
mecej4
Honored Contributor III
6,988 Views

R.O: Thanks for the tips in #9; one can use a command line sort (such as Cygwin sort) to sort on the third field, taking it as numeric. However, there are severe impediments to making this work. 

  • Only the source line number containing the variable declaration is shown in column 3 of the cross-reference part of the listing. Thus, a declaration such as "INTEGER :: z,y,x,a" will come out in the order "a,x,y,z" in the listing, all with the same line number, with no simple way of recovering the correct order (address of variable).
  • When include files are used, variables declared on line 13 in the included file and variables declared on line 13 of the main source file both come out in the listing as having come from line 13, and it would need more work to trace the origin of each variable -- perhaps we will have the beginnings of a Fortran parser before we get this to work.

Given these impediments and remembering that the penalty for misalignment on X86/X64 is far less than on, say, IA64, I am putting this objective into the "to do later, low priority" category.

0 Kudos
TimP
Honored Contributor III
7,261 Views

I'm guessing that you're not looking for alignments suitable for vectorization of short (or longer) arrays, and that your message may be about failing to get 8-byte alignment of real64 and the like.  As the build procedure probably has to work for combinations such as ifort and MSVC, there's no chance of automatic padding working, thus SEQUENCE must be in effect, and padding must be explicit.  As Jim said, the traditional rule to avoid padding is to order the elements in decreasing order of size.  The tradition goes back to f77 and earlier, when putting single byte elements in the same structure with larger ones wasn't supported by standards.  Even then, the different padding treatments of real(10) by various compilers were among the reasons for many Fortrans not supporting it.

For 32-bit Windows, mis-aligned 64-bit data used to be routine, and throwing a warning by default would have been annoying.  Some programmers claimed that attempts to get alignment were in violation of the ABI.  Microsoft even advertised a feature whereby their compiler performed all 64-bit moves, including doubles, by pairs of 32-bit integer operations, to mitigate the performance consequences.

I was just looking into whether Windows gcc can support 32-byte alignment.  Apparently, the answer is no, even for 64-bit mode, although I didn't try reconfiguring ld for that purpose.

ifort still doesn't support 32-byte alignment of COMMON (to my knowledge), although Intel compilers do support it for individual arrays, and this was on the wish list from the time when 32-byte alignment became important.

0 Kudos
mecej4
Honored Contributor III
6,988 Views

Here is an update on the issue. I think that I have narrowed down the cause of the "misaligned" messages to the fact that variables with the specification "DOUBLE PRECISION, DIMENSION(:), POINTER" occupy 36 bytes in memory when the 32-bit compiler is used, and 36 is not a multiple of 8. Therefore, with the following code the 32-bit Ifort will give a misalignment warning.

      PROGRAM mumps_unsym
      IMPLICIT NONE

      TYPE cSTRUC
        SEQUENCE
        DOUBLE PRECISION, DIMENSION(:), POINTER :: A
        !INTEGER :: IPAD
        DOUBLE PRECISION :: D
      end type

      type(cSTRUC) :: mps
      mps%d=127.783d0
      write(*,*)mps%d

      end program

The component D, because of the SEQUENCE attribute, is not on an 8-byte boundary, and is responsible for the message. With the 64-bit compiler, the preceding item occupies 72 bytes, so the alignment problem does not exist. Activating the line "INTEGER :: IPAD" provides the padding needed to fix the misalignment. I think that there should be (perhaps there is, already, but I don't know how) an easier way to find out the memory footprint of a user-defined data type (C struct) than to look at assembler listings. For the example above, the only clue to the 36-bit size of TYPE cSTRUC was

movsd     QWORD PTR [_MUMPS_UNSYM$MPS.0.1+36], xmm0     ;12.7

after adding the component D and a write statement with that component for the sole purpose of finding the byte offset of D relative to the base of the compound variable.

I spent a good bit of time looking at CHARACTER variables and the numerous padding variables that the package authors had put in place, and could not find any problems there.

Thanks to everyone who wrote on this topic.

0 Kudos
FortranFan
Honored Contributor II
6,988 Views

Ok, your initial comment about Intel Fortran being able to provide better diagnostics around derived type components that lead to misaligned data when SEQUENCE attribute is in effect is alright from a general viewpoint of some users who still need to use SEQUENCE type for whatever reasons.  It will be great if Intel can follow through.

However, it seems to me for your specific need to work with MUMPS, shouldn't you be able to work with current Fortran capabilities for interoperability with C using ISO_C_BINDING and put together a "new and improved" derived type in Fortran using BIND(C) for the C structure whose actual definition may be here: http://mumps.sourcearchive.com/documentation/4.9.2.dfsg/dmumps__c_8h_source.html.  Ok, I have not walked through every element, but a cursory glance suggests current interoperability with C features in Fortran should cover everything.

I don't understand RO's comments in message #5.  Isn't the definition you provide for Fortran type that uses SEQUENCE attribute the pre-Fortran 2003 way of doing things i.e., the "old-fashioned" way to interoperate with C?  Isn't it because of that that some of the components appear not to be interoperable (ref: RO's mention of CHARACTER types with LEN /= 1)?  But if one can start afresh with the base definition which is indeed in C, one should be able to put together a derived type definition in Fortran using BIND(C) that is interoperable.

As other threads on this forum including those from Steve have alluded, I have found (albeit limited) BIND(C) to be a better way to work with C structures than with SEQUENCE types.

I don't know anything about MUMPS but if it is really in C, won't it make sense for you to take another look at using C interoperability features using ISO_C_BINDING and BIND(C) for the DMUMPS structure?  The compiler aspects about data alignment on the Fortran side would become moot; the alignment will be whatever is in the companion C processor.

 

0 Kudos
mecej4
Honored Contributor III
6,988 Views

The home page for MUMPS is http://mumps.enseeiht.fr/ . The package source is mostly Fortran 95, about 11 MB, plus 450 kB of wrappers and glue code to enable being called from C, Matlab, etc. That's too much code to attempt modifying, given my modest goals (comparison of performance with other packages). What I can try to do is to modify the include file sufficiently to get rid of the misalignment, rebuild the libraries, and run some tests. If the results agree with the current set of results, I could report the findings to the authors of the package. If not, there is not much that I can do/want to do.

I have a suspicion, based on the sizes of the Fortran and C portions of the sources, that the SEQUENCE attribute was probably added to make it possible to use MUMPS from Matlab. If so, simply removing SEQUENCE, rebuilding and running tests may work (I don't plan to use MUMPS with Matlab).

[P.S., added a couple of hours later: Removing SEQUENCE and rebuilding the library worked. The misalignment warnings went away, and the code ran a bit faster; more importantly, the results remained unchanged.]

Many Linux distributions provide prebuilt (probably with Gfortran) libraries for MUMPS.

0 Kudos
jimdempseyatthecove
Honored Contributor III
6,988 Views

Mecej4,

As you have found out for yourself, POINTER to type is not a type. Consider it more as a user defined type where you do not know the size. This said, one can assume that it will be a multiple of the intptr_t size for your machine. Therefore, the safest place to place POINTERs is between your 8-byte and 4-byte variables. This said, the use of POINTER, especially to array, within an interoperational structure (MUMPS), is not guaranteed to work across vendors nor version updates. For these, you may need to pass an INTEGER(C_LOC) type.

Jim Dempsey

0 Kudos
mecej4
Honored Contributor III
6,988 Views

Jim,

Thanks for your insights. If the POINTER A(:) were just a pointer in the C sense, it should have occupied just four bytes. That it actually occupies 36 bytes indicates that some type of descriptor is being stored.

I can see that it is going to take some careful rethinking if the alignment problem is to be removed while keeping the source code of the package portable. Perhaps they will use BIND(C) in their next revision of MUMPS.

0 Kudos
jimdempseyatthecove
Honored Contributor III
6,988 Views

It might be best at this time in your development, to provide your own interop functions/subroutines for record exchange. IOW place all the interop exchanges into one module as .dll or .so. While the initial version of your interop library might be able to use data in situ, later revisions to MUMPS or Fortran (internals) may require revision of the .dll/.so to perform a layout conversion (not to mention handling the little-endian/big-endian issue.

Good luck.

Jim Dempsey

0 Kudos
JVanB
Valued Contributor II
6,988 Views

You can maintain alignment after POINTER or ALLOCATABLE components that have size = 4 mod 8 in 32-bit mode by following them with an INTEGER(C_INTPTR_T) component. Or if you don't want to waste 8 bytes in 64-bit mode, by a CHARACTER(MODULO(BIT_SIZE(0_C_INTPTR_T)/BIT_SIZE(0_C_SIGNED_CHAR),8)) component.

 

0 Kudos
mecej4
Honored Contributor III
6,711 Views

Thanks, R.O., I'll keep those points in mind. As of now, however, I see those warnings only in 32-bit mode. Either I don't have a system where 16-byte alignment is needed/beneficial in 64-bit mode or the 16.0 compiler does not care to warn about that, so the 72-byte footprint of a DOUBLE PRECISION, DIMENSION(:), POINTER :: A in 64-bit seems adequate to take care of alignment.

Of course, other and more obvious causes of misalignment may still appear, but those are more easily noticed and fixed.

0 Kudos
Reply