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

Fixed-length strings in coarrays

Dave_Allured
New Contributor I
2,431 Views

This program shows unexpected behavior of fixed-length strings as coarrays.  I included some regular, non-coarray strings to compare.  I am surprised because I thought basic behavior would be the same, and the coarray strings would be right padded to the specified length.

program coar_char3
   character (len=15) :: xyz(3)
   character (len=15) :: str[*]	! coarray
   integer img, x
   sync all
   img = this_image()
   xyz(1) = 'alpha'
   xyz(2) = 'delta'
   xyz(3) = 'omicron'
   if (img == 1) then
      if (num_images() >= 1) str[1] = 'alpha'
      if (num_images() >= 2) str[2] = 'delta'
      if (num_images() >= 3) str[3] = 'omicron'
   end if
   sync all
   if (img <= 3) then
      print '(a,i0,3a)', 'image = ', img, ', xyz = [', xyz(img), ']'
   end if
   if (img == 1) call execute_command_line ('sleep 1')
   if (img == 1) print *, '-----------------'
   sync all
   if (img <= 3) then
      print '(a,i0,3a)', 'image = ', img, ', str = [', str, ']'
   end if
end
ifort -g -O0 -coarray coar_char3.f90
setenv FOR_COARRAY_NUM_IMAGES 3
./a.out

The output was the same with several combinations of these versions on a Linux HPC system:

* ifort 18.0.5, 19.0.5.281, 19.1.0.166, 19.1.2.254, and 2021.3.0

* impi 2018 Update 4, 2019 Update 5

image = 1, xyz = [alpha          ]
image = 2, xyz = [delta          ]
image = 3, xyz = [omicron        ]
 -----------------
image = 1, str = [alphadelta]
image = 2, str = [deltaomicron]
image = 3, str = [omicronimage =]

 So, is this a legal fortran program, or a compiler bug?  Is there something I do not understand about behavior of strings in coarrays?

0 Kudos
19 Replies
FortranFan
Honored Contributor III
2,402 Views

@Dave_Allured ,

Given your interest in coarrays that is a standard Fortran facility, you may also want to follow the Fortran Discourse site where there have been several recent discussions on the topic:

https://fortran-lang.discourse.group/

 

See also a thread there where the comments are applicable to the code you show in the original post.

A quick glance at your program suggests you may have intended to do the following instead?

   character(len=15) :: s[*]
   integer :: i
   select case ( this_image() ) 
      case ( 1 )
         s = "alpha"
      case ( 2 )
         s = "delta"
      case ( 3 )
         s = "omicron"
      case default
         ! handling elided 
   end select
   if ( this_image() == 1 ) then
      print "(g0,t10,g0)", "Image", "String"
      do i = 1, num_images()
         print "(g0,t10,g0)", i, s[i]
      end do
   end if
end

with IFORT giving you the following response:

C:\temp>ifort /standard-semantics /Qcoarray=shared /Qcoarray-num-images=3 p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
Image    String
1        alpha
2        delta
3        omicron

C:\temp>
0 Kudos
Dave_Allured
New Contributor I
2,387 Views

@FortranFan, thank you for your alternative test program, and for the references to Discourse!  I will take a closer look at those discussions.

No, my original version is what was intended.  I am working on push transfers from image 1 to other images.  I ran into this problem with simple string coarrays.  As far as I can tell, assignments like this are legal fortran, yet malfunctioning with recent Intel versions.

if (img == 1) then ... str[2] = 'delta'
Output:  image = 2, str = [deltaomicron]

This looks like string length under the hood is mismanaged, and there are memory overruns.  From other evidence, I suspect this particular problem is due to the source expression being a character constant of shorter length than the target coarray element.

My original program is slightly more than minimal because I wanted to demo two different things in the same program, also because I added some guards to keep it sane if run with various numbers of images.

Is the original program legal fortran?  Is there a compiler bug?

0 Kudos
FortranFan
Honored Contributor III
2,374 Views

@Dave_Allured ,

Re: "is this a legal fortran program, or a compiler bug?" hopefully someone with better understanding of the standard and also time to cross-check the wordings can provide you with useful feedback on your inquiry.

But immediately do note your program departs from the "spirit" of coarrays in Fortran which is to avoid remote defines as much as possible.   I don't know yet whether the "letter" of the standard is strict enough to deem your code nonconforming or if it allows enough of a room to fit your case.

However, along the lines of some of the recent threads at the Fortran Discourse site, note a good coarray program makes a basic set of program data available to each image in a suitably shared manner and then each image does its own thing while avoiding remote writes (and reads) as much as possible.  In your simple case, the philosophy is illustrable with a named constant, in other situations it may be data for which each image has a definable copy.  You can try this out:

   character(len=*), parameter :: xyz(*) = [ character(len=15) :: "alpha", "delta", "omicron" ]
   character(len=15) :: s[*]
   integer :: i
   s = xyz( this_image() ) !<-- avoid remote define
   sync all
   if ( this_image() == 1 ) then
      print "(g0,t10,g0)", "Image", "String"
      do i = 1, num_images()
         print "(g0,t10,g0)", i, s[i]
      end do
   end if
end

 

0 Kudos
Steve_Lionel
Honored Contributor III
2,366 Views

I think the behavior you show is a bug.

0 Kudos
Dave_Allured
New Contributor I
2,348 Views

@FortranFan, I understand your point about remote writes.  I think push style writing is a feasible alternative in some cases, if the compiler will support it.  Unfortunately one of my first such exercises with Intel is not going well.  For my own real application, I first tried pull style.  I ran into an unwanted side effect, so now I am adventuring into push style.

@Steve_Lionel, thank you for supporting my suspicion.  I will attempt a service center report and see how that goes.

0 Kudos
OP1
New Contributor III
2,332 Views

With ifort classic 2021.5.0 the behavior of the code is as expected (correct padding of the strings).

0 Kudos
Dave_Allured
New Contributor I
2,324 Views

@OP1, thank you for reporting corrected behavior in 2021.5.0.  I hope this correction extends to string variable assignments of unequal length, as described in my last post.

@OP1 wrote:

With ifort classic 2021.5.0 the behavior of the code is as expected (correct padding of the strings).

0 Kudos
Dave_Allured
New Contributor I
2,329 Views

This problem is not limited to character constants on the right side of an assignment.  The same faulty behavior is demonstrated when assigning a character variable to a longer coarray character variable.  This is a minor modification of my original demo.

program coar_char6
   character (len=10) :: xyz(3)
   character (len=15) :: str[*]	! coarray
   integer img, x
   sync all
   img = this_image()
   xyz(1) = 'alpha'
   xyz(2) = 'delta'
   xyz(3) = 'omicron'
   if (img == 1) then
      if (num_images() >= 1) str[1] = xyz(1)
      if (num_images() >= 2) str[2] = xyz(2)
      if (num_images() >= 3) str[3] = xyz(3)
   end if
   sync all
   if (img <= 3) then
      print '(a,i0,3a)', 'image = ', img, ', xyz = [', xyz(img), ']'
   end if
   if (img == 1) call execute_command_line ('sleep 1')
   if (img == 1) print *, '-----------------'
   sync all
   if (img <= 3) then
      print '(a,i0,3a)', 'image = ', img, ', str = [', str, ']'
   end if
end
ifort -g -O0 -coarray coar_char6.f90
setenv FOR_COARRAY_NUM_IMAGES 3
./a.out

 Output:

image = 1, xyz = [alpha     ]
image = 2, xyz = [delta     ]
image = 3, xyz = [omicron   ]
 -----------------
image = 2, str = [delta     omicr]
image = 3, str = [omicron   alp]
image = 1, str = [alpha     delta]

 Once again, it appears that the program is using the target string length to copy from source memory, and ignoring the memory bounds of the source string.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,277 Views

>>it appears that the program is using the target string length to copy from source memory, and ignoring the memory bounds of the source string.

That statement is backwards. 

The target string is str[n], (len=15)

the source string is xyz(n), (len=10)

Only source string len bytes transfered

 

<< it appears that the program is using the source string length to copy from source memory, and ignoring the memory bounds of the target string.

 

Jim Dempsey

 

0 Kudos
Dave_Allured
New Contributor I
2,270 Views

Jim, you might be right.  However, the stray characters in the right hand side of the result strings are evidence.  In my last example, where do you think the last three characters in this result are coming from?  And how do you explain the displayed length here is 13, not 15?

image = 3, str = [omicron   alp]

 Here is an easier question.  In my first example, where do you think the last seven characters in this result are coming from?

image = 3, str = [omicronimage =]

 

0 Kudos
OP1
New Contributor III
2,311 Views

For your second example, with the latest ifort 2021.5.0, I get different behaviors for Release x64 and Debug x64 builds of the code:

 

Release x64:

image = 2, xyz = [delta     ]
image = 1, xyz = [alpha     ]
image = 3, xyz = [omicron   ]
'sleep' is not recognized as an internal or external command,
operable program or batch file.
 -----------------
image = 2, str = [delta     omicr]
image = 3, str = [omicron        ]
image = 1, str = [alpha     delta]
Press any key to continue . . .

 

Debug x64:

image = 2, xyz = [delta     ]
image = 1, xyz = [alpha     ]
image = 3, xyz = [omicron   ]
'sleep' is not recognized as an internal or external command,
operable program or batch file.
 -----------------
image = 2, str = [delta     omicr]
image = 3, str = [omicron   ╠╠╠╠╠]
image = 1, str = [alpha     delta]
Press any key to continue . . .

 

The Intel support team should probably look into this.

0 Kudos
OP1
New Contributor III
2,308 Views

... and for the first example, I take back my comment saying it's fixed: I get results that are not always repeatable!

0 Kudos
Dave_Allured
New Contributor I
2,302 Views

Yikes!  @OP1, thank you for testing my cases on the latest Intel version.  I am embarrassed that I can not try this myself, but my HPC center is not updating as quickly as I would like.

The "sleep" thing is something I added when under some Intel versions, it looked like fortran standard out was operating outside the control of "sync all".  My output lines were interleaved in ways that did not make sense.  A delay cured this.  If you want to prettify the output, you can either insert a time delay that works on your system, or just delete that sleep statement.  This is not important to the main topic.

I will change this topic back to "not solved" if I can figure out how to do that.

0 Kudos
Dave_Allured
New Contributor I
2,291 Views

@FortranFan , on your advice I can see how to convert my main application to use coarray pull transfers for string data, and resort to push transfers only for the main numeric data arrays.  One of my objectives is to conserve memory.  The string data is only labeling info.  More to the point, it is tiny compared to the numeric data, so I can handle it differently.  Thanks again for this advice.

Based on this test experience, I am changing course on the notion that pull transfers for strings will ultimately be more robust and portable than push transfers in my application.

0 Kudos
FortranFan
Honored Contributor III
2,224 Views

@Dave_Allured , please note also there remains a nascent aspect to coarrays in Fortran compiler implementations and as you know, the subsurface complexity i.e., beyond the simple coarray standard syntax is multidimensional and monumental.  As you will appreciate, it crosses hardware and software considerations (CPU/GPUs, OS, shared and distributed memory, MPI/PGAS libraries, etc.).

But even otherwise with the simplest of instructions in any standards-based code whether C or C++ or Fortran or Ada, etc., it often makes sense to analyze, evaluate, and validate the code instructions  in the programs of one's interest using multiple processors.

Under the circumstances then, if you are pursuing coarrays in earnest, please keep an eye out for as many Fortran implementations as possible to check out your programs - gfortran OpenCoarrays, NAG Fortran, etc.

0 Kudos
Ron_Green
Moderator
2,285 Views

We'll get a bug report going on the coarray of characters example. 

0 Kudos
Barbara_P_Intel
Employee
2,256 Views

@Dave_Allured, I just filed a bug report for you, CMPLRIL0-34610. I'll let you know its progress to a fix.

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,235 Views

After thinking about it a bit more, your first statemen was correct

The data copied from the source (xyz(n) wit len=10), used the len of the target (len=15), essentially causing the transfer to read beyond the end of the string input.

the xyz array, contiguously was:

"delta     alpha     omicron     ...junk...."

where ...junk... is whatever lies beyond.

 

Interesting bug, nice job on the reproducer.

 

work around suggestion:

   if (img == 1) then
      if (num_images() >= 1) str[1] = xyz(1)//repeat(' ',len(str))               
      if (num_images() >= 2) str[2] = xyz(2)//repeat(' ',len(str))
      if (num_images() >= 3) str[3] = xyz(3)//repeat(' ',len(str))
   end if

   

Jim Dempsey

0 Kudos
Barbara_P_Intel
Employee
1,808 Views

This coarray issue with character strings that you reported with ifort is fixed in the latest compiler, 2021.7.0. It is part of oneAPI HPC Toolkit 2022.3 that was recently released.

And, as an added bonus, your reproducer also works with ifx. ifx in this release supports coarrays!

Please try it out!



0 Kudos
Reply