Fortran execute_command_line ошибка времени выполнения, зависит от потребления памяти - PullRequest
4 голосов
/ 12 марта 2019

Я получаю ошибки времени выполнения при попытке создать каталог с использованием встроенной функции execute_command_line в Fortran. Ошибка возникает как с Ifort (18.0.3 20180410), так и с gfortran (4.8.5). Вот минимальный пример, который не работает с любыми флагами компиляции, которые я использую:

PROGRAM directory_test

    IMPLICIT NONE

    INTEGER :: cstat, estat, i, j
    CHARACTER(LEN=100) :: cmsg

    REAL, DIMENSION(:,:), ALLOCATABLE :: field
    INTEGER, PARAMETER :: fieldsize = 80000

    allocate(field(fieldsize,fieldsize))
    do j=1, fieldsize
        do i=1, fieldsize
            field(i,j) = real(i+j)
        end do
    end do

    call execute_command_line('mkdir -p newdir', WAIT=.true., EXITSTAT=estat, CMDSTAT=cstat, CMDMSG=cmsg)

    write(*,*) 'estat: ', estat
    write(*,*) 'cstat: ', cstat
    write(*,*) 'cmsg:  ', cmsg

END PROGRAM directory_test

Вывод ifort:
оценка: 0
cstat: 124
cmsg: неверная команда передана в EXECUTE_COMMAND_LINE

Выходная мощность:
оценка: -520880432
cstat: 1
cmsg: статус завершения интерпретатора командного языка не может быть получен

Вот подвох: программа работает очень хорошо, пока размер массива достаточно мал. Для меня порог составляет примерно половину используемой физической памяти (отрегулируйте значение «fieldsize», если хотите попробовать код). Если массив больше этого, возникает ошибка. Если массив меньше, код выполняется без ошибок, и каталог создается. Все машины, которые я использовал для тестирования, имеют 2 физических ЦП и 128–255 ГБ ОЗУ.
Что я делаю не так?

ОС: Linux, Opensuse 42,3
оболочка: bash
файловая система: Ext4

Редактировать: проблема не исключает "execute_command_line ()". Пытаясь сделать то же самое с «call system ()», я получаю похожее поведение. Новый каталог не создается в тех случаях, когда оригинальный метод завершается с ошибкой во время выполнения. Дополнительные тесты на небольших / старых компьютерах с двумя сокетами до 48 ГБ доступной оперативной памяти дают те же результаты. Некоторые отказывают раньше, некоторым требуется почти вся физическая память, занятая программой, чтобы выйти из строя. К сожалению, сейчас у меня нет машины с одним сокетом для тестирования.

Ответы [ 2 ]

4 голосов
/ 12 марта 2019

Таким образом, способ EXECUTE_COMMAND_LINE, а также встроенные функции SYSTEM реализованы в Linux, заключается в том, что сначала процесс вызывает системный вызов fork (), который создает клон процесса. Затем дочерний процесс вызовет exec (), который заменит этот процесс новым процессом для выполнения.

Таким образом, даже если второй разветвленный процесс очень недолговечен, прежде чем он будет заменен новым процессом exec (), системе все равно потребуется достаточно виртуальной памяти как для исходного процесса, так и для разветвленного дочернего процесса. В Linux, если у вас есть права суперпользователя, вы можете настроить ограничения (как функцию физической памяти) с помощью различных ручек «overcommit».

Если возможно, один из способов обойти эту проблему - вызвать EXECUTE_COMMAND_LINE перед выделением большого количества памяти или после ее освобождения.

1 голос
/ 12 марта 2019

Вы также опубликовали это на форуме Intel Fortran for Linux .В ответах указывалось, что при выделении массива использовалась вся доступная виртуальная память, а для EXECUTE_COMMAND_LINE или других вариантов памяти было недостаточно.Все три разных компилятора выдавали ошибки в вашем примере - NAGfor был наиболее полезным с ошибкой «недостаточно виртуальной памяти».

...