1

かなり大きなコード (天気予報モデル) の Intel Fortran 互換性に取り組んでいます。インテル Fortran (およびインテル Fortranのみ) では、一部の文字データがスクランブルされてループし、文字ポインターがそれを指しているように見えます。最終的な文字には 0 と 9 しか含まれていません。文字列の内容cは単純"00:00:00:16 (whitespace padding....)"です。

(デッド) OpenMP コードをインクルードし、コンパイラ フラグ使用するたびに発生する問題を再現することができました。-fopenmp私はここで何が起こっているのか少し迷っています。次の最小再現器でプログラミング エラーを検出できますか? そうでない場合は、コンパイラのバグを報告すると思います。

再生器

ミニマル.f90

module foo
    implicit none

    type pointer_character
    character, pointer :: c
    end type
    type(pointer_character), allocatable :: ptr_c(:)
    integer(4) :: idx_c

    contains

    subroutine grpbcast_set_c(c)
        implicit none
        character(*), intent(in), target :: c
        integer(4) :: cloc

        allocate(ptr_c( 256 ))
        idx_c = 0

        do cloc = 1, len(c)
            idx_c = idx_c + 1
            ptr_c( idx_c )%c => c( cloc:cloc )
        end do

        print *, "testprint-2", c
        print *, "testprint-3.1", ptr_c( 1 )%c
        print *, "testprint-3.2", ptr_c( 2 )%c
        print *, "testprint-3.3", ptr_c( 3 )%c
        print *, "testprint-3.4", ptr_c( 11 )%c

    end subroutine

    ! The following subroutine is never called, but if we include it in the module foo, it will lead to the data corruption documented in
    ! http://stackoverflow.com/questions/42359258/intel-fortran-substring-access-with-convert-big-endian
    ! If the subroutine is commented it will work
    !
    ! In other words:
    ! if we comment this subroutine out, the output will be
    ! =====================================================
    ! testprint-2
    ! 00:00:00:16



    ! testprint-3.10
    ! testprint-3.20
    ! testprint-3.3:
    ! testprint-3.46
    ! =====================================================
    ! However if we include it, the output will be
    ! testprint-2
    ! 00:00:00:16



    ! testprint-3.10
    ! testprint-3.20
    ! testprint-3.30
    ! testprint-3.40
    ! =====================================================
    !
    ! tested with: ifort 17.0.1 20161005
    subroutine scatter_one_record()
     implicit none
     integer(4) :: k

!$OMP PARALLEL DO
    do k = 1, 5
    end do
!$OMP END PARALLEL DO
    end subroutine

end module foo

program main
    use foo, only: grpbcast_set_c
    implicit none

    character(len=256), target:: run_period
    run_period = "00:00:00:16"

    call grpbcast_set_c(run_period)
end program

メイクファイル

.PHONY: all

all: minimal

minimal.o: minimal.f90
    ifort -fopenmp -c minimal.f90 -o minimal.o

minimal: minimal.o
    ifort -fopenmp -o minimal -L./ minimal.o

フォート版

> ifort --version
ifort (IFORT) 17.0.1 20161005

コンパイルして実行

make
./minimal

..

..

以前の分析、この質問のコメント チェーンを理解するためだけにここに

問題のループ

subroutine grpbcast_set_c(c)
 use nrtype, only : rp => rp
 implicit none
 character(*), intent(in), target :: c
 integer(4) :: cloc

 do cloc = 1, len(c)
  idx_c = idx_c + 1
  if (idx_c > max_ptr_gbcast) stop 9
  ptr_c( idx_c )%c => c( cloc:cloc )
 end do
end subroutine

モジュールでのptr_cの指定

type pointer_character
   character, pointer :: c
end type

type(pointer_character), private, allocatable, save :: ptr_c(:)

デバッガーに表示されるデータ (TotalView)

実行時のデータ

コンパイラ コマンド

> mpif90 -O0 -no-ipo -g -convert big_endian -fopenmp -r8 -DUSE_MPI -I/usr/apps.sp3/mpi/openmpi/1.6.5/i2013.1.046/include -I/usr/apps.sp3/mpi/openmpi/1.6.5/i2013.1.046/lib -I [NUSDAS13_PATH]/src -I [NETCDF_PATH]/include -DUSE_MPI -c mpi_comm.f90 -o mpi_comm.o

> mpif90 --version
ifort (IFORT) 14.0.2 20140120
Copyright (C) 1985-2014 Intel Corporation.  All rights reserved.

アップデート

最新の Intel コンパイラ バージョンで同じことを試しました。

> mpif90 --version
> ifort (IFORT) 17.0.1 20161005

結果はまだ間違っていますが、違います! 今回はすべての文字をゼロにします。

最新のインテル

最新のインテル - 配列の始まり

更新 2

最小限の再現ツール (以下を参照) を使用して問題を再現しようとしましたが、これまでのところうまくいきません。つまり、この方法で実行してもエラーは表示されません。ただし、興味深い点が 1 つあります。TotalView では、配列の最初のアドレスがわずかに異なって表示されます。

作業配列ポインタを使用

cが入力された時点でデバッガーに正しく表示されますが、入力に問題があるに違いないと思いますgrpcast_set_c

module foo
    implicit none

    type pointer_character
        character, pointer :: c
    end type
    type(pointer_character), allocatable, save :: ptr_c(:)
    integer(4), save :: idx_c
contains

    subroutine parmread_bcast_a( mt, aout, chktag )
        implicit none
        integer(4), intent(in):: mt
        character(*), intent(out):: aout
        character(*), intent(in):: chktag

        call filetool_cardread_a( mt, aout, chktag )
        write(6,'("* ",a28," = ", a)') chktag, trim(aout)

        call set_ptr_c(aout)
        return
    end subroutine parmread_bcast_a

    subroutine filetool_cardread_a( imt, aout, chktag )
        implicit none
        integer(4), intent(in):: imt
        character(*), intent(out):: aout
        character(*), intent(in), optional:: chktag

        character(len=256):: tag
        character(len=256):: val
        character(len=256):: buff
        integer(4):: idxeql
        integer(4) :: is_debug = 0

        cardread: do
            read( imt, "(a)" ) buff
            if( buff(1:1) /= "*" ) then
                idxeql = index(buff, "=")
                tag = adjustl(buff(:idxeql-1))
                if (is_debug == 1) then
                write(6,*) 'buff', trim(buff)
                endif
                if ( present( chktag ) ) then
                if ( trim(chktag) /= trim(tag) ) then
                    write(6,*)"WARNING !!! the record is for ", trim(tag), &
                    & ", while you specified ", trim(chktag)
                    cycle cardread
                endif
                endif
                val = adjustl(buff(idxeql+1:))
                aout = val
                return
            end if
        end do cardread
    end subroutine filetool_cardread_a

    subroutine set_ptr_c(c)
        implicit none
        character(*), intent(in), target :: c
        integer(4) :: cloc

        do cloc = 1, len(c)
            idx_c = idx_c + 1
            if (idx_c > 10000) stop 9
            ptr_c( idx_c )%c => c( cloc:cloc )
        end do
    end subroutine
end module

program main
    use foo, only: ptr_c, idx_c, parmread_bcast_a
    implicit none

    character(len=256), save:: run_period

    allocate(ptr_c( 10000 ))
    idx_c = 0

    open( 100, file='sample.conf', form='formatted')
    call parmread_bcast_a(100, run_period, "run_period")

    print *, "run period", run_period

    print *, ptr_c( 1 )%c
    print *, ptr_c( 2 )%c
    print *, ptr_c( 3 )%c
    print *, ptr_c( 11 )%c
end program

sample.conf

  run_period               =    00:00:00:16
4

1 に答える 1