Fortran程序有时会在将大文件写入磁盘时挂起

时间:2015-07-01 08:22:19

标签: file-io fortran large-files

我编写了一个运行良好的网格应用程序,除了一件事: 在将结果写入磁盘时,程序有时挂起。它有效地仍在运行,我可以看到它产生100%的CPU负载并使用top占用内存。但是没有新的数据写入文件,这种状态可能会无限期地持续下去。 这项工作甚至无法杀死,我到目前为止唯一的选择是重新启动机器以摆脱这项工作。

但是,大多数情况下完全相同的作业一直执行到最后没有任何问题。应该注意的是,这仅适用于最终文件大小超过50GB的大型作业。到目前为止,我还没有采取较小的工作来应对这种行为。结果文件每次都写入不同的点。有时它的45GB,有时是60GB或者完全不同的东西。 我使用的工作站运行OpenSuse 13.1,有足够的RAM和磁盘空间可用。然而,在不同的机器上可以观察到相同的行为。

到目前为止我尝试过(除了通常的调试之外)使用Gfortran和英特尔Fortran编译器无济于事。我搞砸了-mcmodel = large编译器选项,但据我所知,这与程序编写的文件大小无关,也没有任何帮助。

我不知道要提供什么信息,因为我真的没有想法可能导致问题。我附加了在这里写入ASCII结果文件的例程,因为它产生了最大的文件大小,但是在编写具有类似例程的未格式化文件时我遇到了同样的问题。 ANY 暗示可能导致此行为的原因值得高度赞赏。

SUBROUTINE write_legacymesh

use types
use parameters
use data

implicit none

INTEGER :: l, n, i, j, k, number, c, neighbor
REAL(DP), DIMENSION(3) :: pos_d
CHARACTER(LEN=100) :: dummy_char
INTEGER(I4B), DIMENSION(26) :: neighborbuffer
LOGICAL :: file_exists

call write_header
call system ('sync')

! create the mesh file
dummy_char = folder_mesh // '/' // file_mesh
write(*,'(A,A)') ' writing mesh:   ', trim(adjustl(dummy_char))
open(unit=20, file=trim(adjustl(dummy_char)), status='replace', action='write')

! write the mesh file
write(20,'(A)') '  LB database'

l = level_max

! write the header for this mesh size
write(20,'(A)') '  number of collision centers'
write(20,'(I16)') nf(l)
write(20,'(A)') '  number of cut links'
write(20,'(I16)') ncut(l)
write(20,'(A)') '  number of boundary collision centers'
write(20,'(I16)') nb(l)
write(20,'(A)') '  dummy value'
write(20,'(I16)') 0
write(20,'(A)') '  number of inflow boundary collision centers'
write(20,'(I16)') nb1(l)
write(20,'(A)') '  number of pressure boundary collision centers'
write(20,'(I16)') nb2(l)
write(20,'(A)') '  number of slip boundary collision centers'
write(20,'(I16)') nb3(l)
write(20,'(A)') '  number of noslip boundary collision centers'
write(20,'(I16)') nb4(l)
write(20,'(A)') '  lattice spacing'
write(20,'(E16.8)') dx(l)*scaling

! write the coordinates
write(20,'(A)') '              cc       RBT value      cc coordinates'
do n=1, nf(l)

    number = order_level(l)%order(n)
    i = levels(l)%blocks(number)%pos(1)
    j = levels(l)%blocks(number)%pos(2)
    k = levels(l)%blocks(number)%pos(3)

    ! rescale and move the geometry to get the original size and position
    pos_d(1) = (real(i,kind=dp) - 0.5_dp) * dx(l) + corner_ibc(1)
    pos_d(2) = (real(j,kind=dp) - 0.5_dp) * dx(l) + corner_ibc(2)
    pos_d(3) = (real(k,kind=dp) - 0.5_dp) * dx(l) + corner_ibc(3)

    write(20,'(2I16,3E20.7)') n, levels(l)%blocks(number)%state, pos_d*scaling

end do

! write the link info
write(20,'(A)') '  link information'
do n=1, nf(l)

    number = order_level(l)%order(n)
    do c=1, nlinks
        neighbor = levels(l)%blocks(number)%neighbors(c)
        if(neighbor .GT. 0) then
            neighborbuffer(c) = levels(l)%blocks(neighbor)%number
        else
            neighborbuffer(c) = neighbor
        end if
    end do

    write(20,'(7I16)') n, neighborbuffer(1:6)
    write(20,'(A,6I16)') '                ', neighborbuffer(7:12)
    write(20,'(A,6I16)') '                ', neighborbuffer(13:18)

end do

! write the q-values
write(20,'(A)') '  q-values'
do n=1, ncut(l)

    write(20,'(I16,E20.7)') n, max(qmin, min(qmax, aux_level(l)%q_values(n)))

end do

write(20,'(A)') '  end of data'

close(unit=20)
END SUBROUTINE write_legacymesh

Edit1:遵循刷新写入缓冲区的建议,我将其添加到每个写入数据的循环中:

if(mod(n,10000000) .EQ. 0) then
    call flush(20)
    close(unit=20)
    call system('sync')
    open(unit=20, file=trim(adjustl(dummy_char)), status='old', position='append', action='write')
end if

这没有改变任何东西,例程仍然在一个随机点挂起,这次是在第一个循环中写入18.5GB数据或211• 016写入事件之后。

Edit2:使用英特尔Fortran编译器(不使用-assume buffered_io标志)取消激活缓冲I / O类型"已解决"问题。但是当然这让我对大文件的缓慢无缓冲写入,这是一种特别令人不快的组合。

Edit3:感谢您提出添加手动写入缓冲区的建议。文件格式不适合有效地使用它们,但它仍然比没有好。无论如何,这是一种遗留的文件格式,我很肯定我可以说服我的同事,不同的文件格式甚至是无格式文件是更好的选择。 虽然我仍然不知道导致错误的原因,但至少我现在有一种可以容忍的方法来避免错误。感谢所有宝贵的建议。

0 个答案:

没有答案