MPI_Recv перезаписывает части памяти, к которым он не должен обращаться

#fortran #mpi

#fortran #mpi

Вопрос:

В следующем коде значение xysize изменяется, если я не объявляю его как параметр (чего я обычно не могу сделать). Это происходит только с оптимизациями -O2 и более в gfortran 4.7.2 и OpenMPI 1.6. Как это возможно? Я не могу найти точный интерфейс, из которого я импортирую mpi.mod , но в прототипе C четко указано, что count он передается по значению, следовательно, он не может измениться.

      write(*,*) im,"receiving from",image_index([iim,jim,kim 1]),"size",amp;
      size(D%A(D%starti:D%endi,D%startj:D%endj,D%endk)),xysize

    call MPI_RECV(D%A(D%starti:D%endi,D%startj:D%endj,D%endk 1),xysize , MPI_REAL, image_index([iim,jim,kim 1])-1,amp;
           5000, comm, status, ierr)

    write(*,*) im,"received size",amp;
      size(D%A(D%starti:D%endi,D%startj:D%endj,D%endk)),xysize
  

вывод:

 1 receiving from           2 size        4096        4096
1 received size        4096        5000
  

Комментарии:

1. Из любопытства, что вы получаете от mpi_get_count(status,MPI_REAL,n,ierr); print*, n — мне действительно интересно, получаете ли вы переполнение буфера, которое вызывает забавное поведение…

2. Спасибо за это предложение! Проблема, по-видимому, заключалась в объявлении в status, которое было обычным скалярным целым числом. Я не знаю, почему он скомпилирован MPI_Recv , потому что проверка интерфейса MPI_Get_count обнаружила это.

3. Странно. Я рад, что он поймал это. MPI_Recv может иметь интерфейс, объявленный как integer status(*) , чтобы он мог принимать скаляр или массив. Таким образом, MPI_STATUS_IGNORE это может быть скаляр… Кажется MPI_STATUS_SIZE , что это было бы достаточно мало, чтобы это не имело значения, но, я полагаю, библиотека пытается эффективно использовать память или что-то в этом роде… MPI_Get_count с другой стороны, не может принять MPI_STATUS_IGNORE

4. @mgilson, MPI_RECV (как и любая другая процедура, которая принимает пользовательские буферы данных в качестве аргументов) может принимать миллиарды различных типов данных в качестве своего первого аргумента и по этой причине почти никогда не присутствует в интерфейсе модуля. Нужно скомпилировать открытый MPI со специальными флагами, чтобы можно было генерировать интерфейсы таких подпрограмм. Тогда компиляция занимает ОЧЕНЬ МНОГО времени и охватывает только относительно небольшое подмножество возможных типов. В MPI 3.0 появляется промежуточное решение — определены новые привязки F2008, которые используют TYPE(*), DIMENSION(..) функцию F2008.

5. Также другая особенность F2008 ASYNCHRONOUS используется в новых интерфейсах MPI 3.0 для неблокирующих вызовов, таких как MPI_Isend . Это означает, что с полностью совместимым с F2008 компилятором в palce можно было бы безопасно передавать подразделы массива неблокирующим вызовам.

Ответ №1:

Ради будущих посетителей, я полагаю, я отвечу на это, хотя все ответы даны в комментариях выше.

Насколько мне известно, если ваша программа работает правильно, вы не можете изменить значение этого параметра («count») при вызове MPI_Recv .

Ваш аргумент status слишком мал, он должен быть массивом status(MPI_STATUS_SIZE) , и вы получаете переполнение буфера — это часто приводит к ошибке сегментации, но иногда (в зависимости от того, как компилятор упаковал переменные в память), это может привести к забавному поведению, подобному этому.

Комментарии:

1. В основном это происходит, когда переменные стека используются в качестве параметров вызова, и ни один используемый указатель не перезаписывается / не повреждается (таким указателем является адрес возврата во фрейме стека вызывающей функции).

2. @HristoIliev — Очевидно, вы не работали с некоторыми кодами, которые у меня есть ;-). Старое управление памятью в стиле f77, где все equivalence объединено в 1 большой массив, который разделяется при передаче подпрограммам … 🙂

3. Эй, это 2012 год, у нас есть как GCC … и файлы cookie 🙂