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

Issue with MOVE_ALLOC

OP1
New Contributor II
4,587 Views

I tried to post about this yesterday but my post was marked as spam, yikes. So here is try #2.

In the example below I don't understand why the call to MOVE_ALLOC returns a negative ERROR value (-858993460 to be precise) when it seems that the call was successful. This is with ifort classic 2021.5.0 (Windows platform, x64).

It also seems that MESSAGE contains some non-printable character somewhere - but this may be a different problem.

Any thoughts on this?

 

MODULE M
IMPLICIT NONE
TYPE T
    INTEGER, ALLOCATABLE :: A(:)
    CONTAINS
        PROCEDURE P
END TYPE T
CONTAINS
SUBROUTINE P(SELF, A)
CLASS(T), INTENT(INOUT) :: SELF
INTEGER, ALLOCATABLE, INTENT(INOUT) :: A(:)
INTEGER :: ERROR
CHARACTER(LEN = 132) :: MESSAGE
CALL MOVE_ALLOC(A, SELF%A, STAT = ERROR, ERRMSG = MESSAGE)
WRITE(*, *) ERROR, (TRIM(MESSAGE) == ''), TRIM(MESSAGE), ALLOCATED(SELF%A), SIZE(SELF%A)
END SUBROUTINE P
END MODULE M

PROGRAM P
USE M
IMPLICIT NONE
TYPE(T) :: VAR
INTEGER, ALLOCATABLE :: A(:)
ALLOCATE(A(1))
CALL VAR%P(A)
END PROGRAM P

 

 

0 Kudos
1 Solution
Ron_Green
Moderator
4,268 Views

I opened a case on this.  But in testing I found that the error is already fixed in the IFX and IFORT coming out in the next update release at the end of this month.  I tested on Linux but found the same issue with the current 2021.5 compiler like you reported;

more move_allocTest.f90
program movalloctest
    implicit none
    integer, allocatable :: x(:)
    integer, allocatable :: b(:)
    integer :: istat
    character (len=132) :: message = 'The bean bag and the cornhole'
    x = [ 42 , 43 ]
    istat = -99
    call move_alloc( x, b, stat=istat, errmsg=message )
    print *, "istat = ", istat
    if (istat /= 0) print *, "message = ", message
end program

ifort -V -o move_allocTest move_allocTest.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.

 Intel(R) Fortran 2021.5.0-1068
GNU ld version 2.30-108.el8_5.1
[rwgreen@orcsle162 q05399693]$ ./move_allocTest 
 istat =          -99
 message = 
 The bean bag and the cornhole                                                  
                              

Then with the new IFX or IFORT

 

ifort -V -o move_allocTest move_allocTest.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.6.0 Build 20220227_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

 Intel(R) Fortran 2021.6.0-1299
GNU ld version 2.30-108.el8_5.1

./move_allocTest 
 istat =            0

 

I don't show the IFX results but they are the same since ifort and ifx use the same FRTL.

So wait for the update coming out end of this month.

View solution in original post

0 Kudos
34 Replies
JNichols
New Contributor I
1,262 Views

I understand what you are saying, but is the work done by the function faster - what is the internals of move_alloc?

It achieves what the developer of Fortran wanted simplicity to code, but is it faster or just a simple restatement of your C++ code  with a simpler interface?  

So what is the move_alloc code doing inside?   If it is no faster than your code then it is a simplification as  Backus wanted and it is achieved, but hiding the code behind a nice function call is not a functionality improvement.  

As I say to my students, prove what you are claiming, is it faster and does move_alloc take less time, if not it is just a simplification and syntactic sugar. 

 So what is the speed difference? And what does the code look like? 

The hypothesis is thus move_alloc improves Fortran -- prove it is what I am saying.  

 

0 Kudos
JNichols
New Contributor I
1,270 Views

@jimdempseyatthecove , I am not trying to be difficult.  Saying something is self evident is not the same as proving it. 

 

I saw a young lad argue with my physics professor about a self evident statement, the professor took 50 minutes to prove it was self evident, the 100 other students just sat stupefied.  

0 Kudos
OP1
New Contributor II
1,265 Views

@JNichols wrote:

The hypothesis is thus move_alloc improves Fortran -- prove it is what I am saying.  


At this point in the thread I doubt anybody cares about what you're saying - your syntactic sugar malarkey is of little value for the discussion, despite efforts by multiple posters to convince you otherwise. You should probably, as an educator, be a bit more open-minded regarding the modern features of fortran that your students would benefit learning about.

0 Kudos
JNichols
New Contributor I
1,202 Views

We are usually politely than your last statement on this forum.  

0 Kudos
JNichols
New Contributor I
1,197 Views

I took the move_alloc example from the Intel Fortran documentation. 

I ran it in a loop on a core7 machine and measured the run time of 9.687 seconds for 100000 loops

I changed the code along the lines of Jim's C++ suggestion, dropped the move_alloc and got 9.547 seconds

The difference is  -1.6%. 

Move_alloc on the documentation sample loses 1.6% -- I fail to see how that adds functionality.  

 

0 Kudos
andrew_4619
Honored Contributor II
1,153 Views

John, I disagree with you but if you want to make a reasoned argument please post your example cases for review. 

0 Kudos
JNichols
New Contributor I
1,099 Views

Andrew:

https://comp.lang.fortran.narkive.com/MYd0RMuT/move-alloc-question

 

Provides some indications of some of the problems with move_alloc.  

The Intel Fortran Documentation provides the central part of this code:

I added the astat, any astat, as has been discussed above, should return zero on proper operation.  

It is trivial to make the changes outlined by Jim and the code runs faster.  

The real question is not does this provide one method to do the copy, of course Y is deallocated, I may not want that operation, but is it better?  

I have been on many standards committees and this function has the feel of someone wanted a slight simplification on the old three variable problem to swap two variables, that is a problem we have all grappled with since we learnt Fortran.   They got what they wanted, a quick look at the comments on move_alloc on the different forums, point to problems with the code.  

What is inside the compiler with the move_alloc code, if it  just does what Jim showed, then why add the code overhead to call the function.  I have programs where a 1.6% increase would be a problem. 

Fortran is trim, C# is not trim and it is a pain to look at all the different functions that get added for little benefit.  

So if you want use move_alloc do so, I merely asked why it was in Fortran,  I have never seen it in any code I have looked at and the fact that it has taken this long to fix the astat would suggest that it is not commonly used. 

But with all scientific stuff I could be wrong, but that is the joy of science you are allowed to be wrong and then argue.  As I was writing this comment I was sent this saying,  sometimes random things can bring a smile.   Have a nice day.  

The best revenge is to be unlike him who performed the injury.

Marcus Aurelius

 

John

 

 

  ! This program uses MOVE_ALLOC to make an allocated array X bigger and
    ! keep the old values of X in the variable X. Only one copy of the old values
    ! of X is needed.
    program a
    implicit none
    integer j
    REAL time_begin, time_end

    CALL CPU_TIME ( time_begin )

    do j = 1, 100000

        call copy()

    end do

    CALL CPU_TIME ( time_end )
    WRITE (*,*) 'Time of operation was ', time_end - time_begin, ' seconds'

    end




    subroutine copy()
    implicit none

    integer m , j
    integer :: I, N = 2

    integer astat
    real, allocatable :: X(:), Y(:)
    allocate (X(N), Y(2*N))         ! Y is twice as big as X
    astat = -1
    X = (/(I,I=1,N)/)       ! put "old values" into X
    Y = -1                  ! put different "old values" into Y
    print *, ' allocated of X is ', allocated (X)
    print *, ' allocated of Y is ', allocated (Y)
    print *, ' old X is ', X
    print *, ' old Y is ', Y
    Y (1:N) = X             ! copy all of X into the first half of Y
    ! this is the only copying of values required
    print *, ' new Y is ', Y
    call move_alloc (Y, X, stat = astat)  ! X is now twice as big as it was, Y is
    ! deallocated, the values were not copied from Y to X
    print *, ' astat is ', astat
    print *, ' allocated of X is ', allocated (X)
    print *, ' allocated of Y is ', allocated (Y)
    print *, ' new X is ', X
    return
    end

 

PS very few schools teach Fortran, most teach Python or MATLAB or Mathematica.  

 

 

 

0 Kudos
andrew_4619
Honored Contributor II
1,081 Views

"The real question is not does this provide one method to do the copy, of course Y is deallocated, I may not want that operation, but is it better?  "

 

This fundamentally show you have not read and understood what several contributors have said in this thread.  The usage case is not to 'swap', it's is to redefine (often increase) the size of an existing array of any rank and size to an array whilst preserving the data stored in it.  To compare with some C code is silly as we are talking about Fortran code. You did not show a Fortan code for the alternative method that demonstrate it is 'syntactic sugar'.

It is further a nonsense to make  a test case with an array of size 2 and do it 100,000 times It  would make more sense to do an array where N was several millions and do that once.

 

0 Kudos
JNichols
New Contributor I
1,063 Views

I am sorry, but I really object to be told what I do is silly, etc.. 

I understand your points, I respectfully disagree with the statement is adds functionality, all it does can be done in a few steps and is shown in Jim's C code.   If you cannot compare C code to Fortran I am sorry. The code changes to test it are trivial. 

It is the sample provided in the Intel Documentation, I used their sample.   

If you wish to believe it adds functionality that is your right, as it is my right to disagree.  It is a poorly thought out function but you can use it to your heart's content.  

I have no interest in this function and it is a silly function, it could have a lot of uses with a simple switch, but to say it resizes an array is important or necessary is your thoughts, not mine.   

At this stage I am rather tired of talking to people about a silly function that has vey limited use.  Use it,  enjoy it, but understand some people prefer speed over simplicity.  

 

-------------------------------------------------------------------------------------------------------------------------------------------

The original author said: 

In the example below I don't understand why the call to MOVE_ALLOC returns a negative ERROR value (-858993460 to be precise) when it seems that the call was successful. This is with ifort classic 2021.5.0 (Windows platform, x64).

 

He should be aware from following this forum that that Intel Fortran assigns -858993460 to all unassigned integers - see picture -- 

He should have assigned a known value to error before he sent it into the function.  He realized there was something wrong as Intel confirmed.  

The fact that this has not been found challenges the comment that is used a lot.  

Finally :

call move_alloc (Y, X)  ! X is now twice as big as it was, Y is
                                ! deallocated, the values were not copied from Y to X

 

The comment says Y is not copied into X, but the example text says it is?  It would be nice if the documentation was the same in two places.  

 

Screenshot 2022-03-18 173436.png

 

Enjoy your function. 

This has been discussed in the last few months.  

I am calling it quits, sorry, but you are entitled to your view, I do not appreciate disparaging people who have a different view.  

 

0 Kudos
IanH
Honored Contributor II
951 Views

@JNichols wrote:

I am sorry, but I really object to be told what I do is silly, etc.. 

I understand your points, I respectfully disagree with the statement is adds functionality, all it does can be done in a few steps and is shown in Jim's C code.   If you cannot compare C code to Fortran I am sorry. The code changes to test it are trivial. ...

As others have said - you cannot implement MOVE_ALLOC in standard complying Fortran code. You (versus a compiler/runtime author) cannot implement MOVE_ALLOC portably in C. Given these two aspects, and the fundamental semantics of the "move" operation - we're firmly in territory that justifies a language intrinsic.

Jim's code was C++.  As he notes, his C++ code does not implement the full semantics of MOVE_ALLOC, and it also does stuff that MOVE_ALLOC does not do.  I am pretty familiar with all three languages being discussed (though less so with capabilities introduced with and after the 2014 standard revision of C++) - and I have no idea what your test code incorporating Jim's stuff would look like.

...He should be aware from following this forum that that Intel Fortran assigns -858993460 to all unassigned integers - see picture -- 

He should have assigned a known value to error before he sent it into the function.  He realized there was something wrong as Intel confirmed.  

The fact that this has not been found challenges the comment that is used a lot.  


STAT and ERRMSG as actual arguments for MOVE_ALLOC were introduced recently in the 2018 Fortran standard revision. The implementation by Intel, and therefore use of that implementation, is recent. The nature of the error conditions that might occur in MOVE_ALLOC, also means that the benefit from use of those actual arguments in F2018 compliant code will be strongly dependent on the context of the code (I don't bother with them - others will make a different decision).  It should not be surprising that the odd compiler/runtime bug pops up, with new features that may not be in ubiquitous use.  

MOVE_ALLOC itself, without STAT and ERRMSG, was introduced in Fortran 2003. You will find it in a lot of modern (F2003+) Fortran code.  Early (and not so early) implementations of the basic functionality had bugs too...

0 Kudos
Steve_Lionel
Honored Contributor III
1,055 Views

MOVE_ALLOC doesn't copy any data - it just plays with descriptors for the allocatable variables, deallocating the TO if needed and then copying the allocation information in. You cannot reproduce this with ordinary Fortran code.

0 Kudos
andrew_4619
Honored Contributor II
1,054 Views
program a
    ! This program uses MOVE_ALLOC to make an allocated array X bigger and keep the old 
    ! values of X in the variable X. Only one copy of the old values of X is needed.
    implicit none
    REAL    :: time_begin, time_end
    integer :: I , nu , istat
    integer, parameter :: N = 10000000
    character(*), parameter :: gfmt = "('Time of operation (s) :: ',f0.7)"
    real, allocatable :: X(:), Y(:)
    !
    allocate (X(N), Y(2*N), stat = istat)         ! Y is twice as big as X
    X = 1.0      ! put "old values" into X
    !
    ! Do a move_alloc test
    open(newunit=nu, file = 'dump.bin', form='unformatted', status='unknown', iostat = istat )
    CALL CPU_TIME ( time_begin )
        Y (1:N) = X                           ! copy all of X into the first half of Y
        call move_alloc (Y, X, stat = istat)  ! X is now twice as big as it was, Y is
    CALL CPU_TIME ( time_end )
    write(nu) X      ! so can't be optimised to oblivion
    WRITE (*,gfmt) time_end - time_begin
    ! set up test without move_alloc to achieve the same final state
    deallocate ( x )
    allocate (X(N), Y(2*N), stat = istat)         ! Y is twice as big as X
    X = 1.0      ! put "old values" into X
    !
    ! Do the same operations without a move_alloc
    CALL CPU_TIME ( time_begin )
        Y (1:N) = X                           ! copy all of X into the first half of Y
        deallocate( x )
        allocate (X(2*N), stat = istat) 
        X = Y (1:N) ! a second copy is needed
        deallocate( y )
    CALL CPU_TIME ( time_end )
    write(nu) X      ! so can't be optimised to oblivion
    WRITE (*,gfmt) time_end - time_begin
    close(nu)
    ! >>>> TEST OUTPUT <<<<
    ! Time of operation (s) :: .0156250
    ! Time of operation (s) :: .0312500
    ! Press any key to continue
end

 

You asserted it is "syntactic sugar" and doesn't add anything. The above code shows a usage of move_alloc. The first timed block shows a typical array expansion with move_alloc and is two lines of code. The exact same result is achieved (In Fortran as that is the subject topic) by the second timed block with 5 lines of code that takes (in an optimised non-debug code) approximately twice as long to run. Less code , faster. That seems worthwhile to me. 

I am sorry you have taken offence, It did not think your test case was a valid comparison and I said so.   It is clear that the main difference is avoiding the second array copy operation and it seem obvious that for small arrays the cost of that copy will be small. It is also clear that for a larger array it is a costly operation.    

 

 

 

 

0 Kudos
JNichols
New Contributor I
897 Views

Move_alloc timing

 

Screenshot 2022-03-20 190418.png

 

move_start - subroutine in module base

 

Screenshot 2022-03-20 190216.png

100 loops - 2000 entries

I fully and completely understand what you are saying.  I cannot see that it is faster, maybe if you get to 1,000,000 entries.  

At 100000 entries, move_alloc is 0.4 seconds slower for 1 loop.  

Please do not reply I am not going to read any further.

 

0 Kudos
IanH
Honored Contributor II
833 Views

I profiled Console27 as provided, using VTune.  About three quarters of the total execution time was spent in functions called to handle input/output (all those print statements).  There's additional array setup overhead that also should ideally be excluded from the timing loop.

Timing results from Andrew's example seem reasonable (I don't think the example is conforming though - is the second half of the expanded variable defined?).  They are consistent with measurements here with a different example (and the optimiser did foil my initial attempts). 

Shortest source code length wise, but likely inefficient runtime wise (unfortunately - Fortran compilers appear to lack the high level transformations for optimising this), for expanding allocatable arrays is simply something like

array = [array, extra_stuff]

 

0 Kudos
Reply