next up previous contents
Next: Приложение D. Перечень функций Up: Библиография Previous: Приложение B. Языковые привязки   Contents

Приложение С. Версия 1.2 для MPI

Этот раздел содержит уточнения и небольшую коррекцию версии стандарта MPI-1.1. Единственная новая функцияв в MPI-1.2 - это функция, указывающая, какая версия стандарта используется. Между MPI-1 и MPI-1.1 имеются небольшие различия. Между MPI-1.1 и MPI-1.2 имеются очень небольшие различия (только те, которые обсуждены в этом разделе), но разница между MPI-1.1 и MPI-1.2 принципиальная.

С1. Номер версии

Номер версии стандарта можно определить как на этапе компиляции, так и во время исполнения программы. ``Версия'' представляется двумя целыми величинами - для версии и подверсии:

В Си и С++:

# define MPI_VERSION 1 # define MPI_SUBVERSION 2

в языке ФОРТРАН:

INTEGER MPI_VERSION, MPI_SUBVERSION PARAMETER (MPI_VERSION = 1) PARAMETER (MPI\_SUBVERSION = 2)

Для вызова во время исполнения используется функция MPI_GET_VERSION, синтаксис которой представлен ниже.

MPI_GET_VERSION(version, subversion)

OUT version номер версии (целое)  
OUT subversion номер подверсии (целое)  

int MPI_Get_version(int *version, int *subversion) MPI_GET_VERSION(VERSION, SUBVERSION, IERROR) INTEGER VERSION, SUBVERSION, IERROR

MPI_GET_VERSION - одна из немногих функций, которая может быть вызвана перед MPI_INIT и после MPI_FINALIZE.

Привязки для С++ можно найти в приложении В

С2 Уточнения для MPI-1.0 и MPI-1.1

На основе опыта использования версий MPI-1.0 и MPI-1.1 MPI Forum предлагает уточнения для некоторых функций, в дальнейшем эти функции должны использоваться в соответствии с этими уточнениями.

С2.1 Уточнения для MPI_INITIALIZED

MPI_INITIALIZED возвращает true, если вызывающий процесс обращался к MPI_INIT. На поведение MPI_INITIALIZED не влияет тот факт, был ли уже вызван MPI_FINALIZE или нет.

С2.2 Уточнение MPI_FINALIZE

Эта процедура очищает все состояния MPI. Каждый процесс обязан вызвать MPI_FINALIZE перед своим выходом . Если не была вызвана функция MPI_ABORT, каждый процесс должен завершить все неблокирующие ждущие обмены до обращения к MPI_FINALIZE. Более того, на момент обращения к MPI_FINALIZE для всех ждущих посылок должен быть установлен соответствующий прием, и для всех ждущих приемов должна быть установлена соответствующая посылка. Например, следующая программа является корректной:

Process 0 Process 1 --------- --------- MPI_Init(); MPI_Init(); MPI_Send(dest=1); MPI_Recv(src=0); MPI_Finalize(); MPI_Finalize();

Без установления соответствующего приема программа неверна:

Process 0 Process 1 ----------- ----------- MPI_Init(); MPI_Init(); MPI_Send (dest=1); MPI_Finalize(); MPI_Finalize();

Успешное возвращение из операции блокирующего обмена или из MPI_WAIT или MPI_TEST говорит пользователю, что буфер может использоваться повторно, и означает, что операция завершена пользователем, но не гарантирует, что вся работа в локальном процессе завершена. Успешное возвращение из MPI_REQUEST_FREE с дескриптором запроса, сгенерированным MPI_ISEND, обнуляет дескриптор, но не дает гарантии, что операция завершена. MPI_ISEND завершается только тогда, когда он узнает некоторым способом, что соответствующий прием завершен.

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

MPI_FINALIZE не гарантирует ничего относительно ждущих обменов, которые еще не завершены (завершение гарантируется только MPI_WAIT, MPI_TEST, или MPI_REQUEST_FREE совместно с некоторыми другими проверками завершения).

Эта программа верна:

rank 0 rank 1 ===================================================== ... ... MPI_Isend(); MPI_Recv(); MPI_Request_free(); MPI_Barrier(); MPI_Barrier(); MPI_Finalize(); MPI_Finalize(); exit(); exit();

Эта программа неверна и ее поведение является неопределенным:

rank 0 rank 1 ===================================================== ... ... MPI_Isend(); MPI_Recv(); MPI_Request_free(); MPI_Finalize(); MPI_Finalize(); exit(); exit();

Если между MPI_BSEND (или другой буферизованной посылки) и MPI_FINALIZE нет операции MPI_BUFFER_DETACH, MPI_FINALIZE неявно обеспечивает MPI_BUFFER_DETACH.

Нижеследующая программа правильная и после MPI_Finalize все выполняется так, как если бы буфер был подключен:

rank 0 rank 1 ===================================================== ... ... buffer = malloc(1000000); MPI_Recv(); MPI_Buffer_attach(); MPI_Finalize(); MPI_Bsend(); exit(); MPI_Finalize(); free(buffer); exit();

В следующем примере MPI_Iprobe() должен возвратить флаг FALSE. MPI_Test_cancelled() обязан возвратить флаг TRUE, независимо от относительного порядка выполнения MPI_Cancel() в процессе 0 и MPI_Finalize() в процессе 1. Вызов MPI_Iprobe() необходим для создания уверенности, что реализация знает о том, что сообщение ``tag1'' существует на стороне приема.

Номер 0 номер 1 ======================================================== MPI_Init(); MPI_Init(); MPI_Isend(tag1); MPI_Barrier(); MPI_Barrier(); MPI_Iprobe(tag2); MPI_Barrier(); MPI_Barrier(); MPI_Finalize(); exit(); MPI_Cancel(); MPI_Wait(); MPI_Test_cancelled(); MPI_Finalize(); exit();

После того, как MPI_FINALIZE возвратил управление, не могут быть вызваны никакие процедуры MPI (даже MPI_INIT), исключая MPI_GET_VERSION, MPI_INITIALIZED, и MPI-2 функция MPI_FINALIZED. Каждый процесс обязан завершить все ждущие коммуникации, которые он инициировал, до того, как он вызовет MPI_FINALIZE. Если вызов возвращает управление, каждый процесс может продолжать локальные вычисления или осуществить выход, без участия в дальнейших MPI обменах с другими процесами. MPI_FINALIZE является коллективной операцией на коммуникаторе MPI_COMM_WORLD.

Совет разработчикам: Хотя процесс завершил все инициированные коммуникации, такие коммуникации все еще могут быть не завершены с точки зрения более низкого системного уровня MPI. Например, блокирующая посылка может быть уже завершена, хотя данные все еще буферизованы на процессе-отправителе. Реализация MPI обязана гарантировать, что процесс завершает любую инициированную коммуникацию перед возвращением MPI_FINALIZE. Поэтому, если процесс существует после вызова MPI_FINALIZE, это не будет вызывать отказа продолжающегося обмена.

Не требуется, чтобы все процессы возвращали управление из MPI_FINALIZE, однако необходимо, чтобы по крайней мере процесс 0 в MPI_COMM_WORLD возвратил управление, чтобы пользователь знал о том, что порция вычислений завершена.
Следующий пример иллюстрирует требование, чтобы по крайней мере один процесс возвращал управление и чтобы было известно, что процесс 0 - один из таких процессов.

... MPI_Comm_rank(MPI_COMM_WORLD, &myrank); ... MPI_Finalize(); if (myrank == 0) { resultfile = fopen("outfile","w"); dump_results(resultfile); fclose(resultfile); } exit(0);

С2.3 Уточнение статуса после MPI_WAIT и MPI_TEST

Поля в статусном объекте, возвращенные вызовами MPI_WAIT, MPI_TEST или любыми другими производными функциями (MPI_{TEST,WAIT}{ALL,SOME,ANY}), где запрос соответствует вызову посылки, являются неопределенными за двумя исключениями: поле ошибки статусного объекта будет содержать правильную информацию, если вызов wait или test возвратил MPI_ERR_IN_STATUS; и возвращенный статус может быть запрошен вызовом MPI_TEST_CANCELLED.

Коды ошибок, принадлежащие классу MPI_ERR_IN_STATUS, должны быть возвращены только завершающей функцией MPI, которая использует массивы MPI_STATUS. Для функций ( MPI_TEST, MPI_TESTANY, MPI_WAIT, MPI_WAITANY), которые возвращают единственное значение MPI_STATUS, должен быть использован нормальный процесс возврата ошибки ( а не поле MPI_ERROR в аргументе MPI_STATUS).

С2.4 Уточнение MPI_INTERCOMM_CREATE

Проблема : стандарт MPI-1 говорит в дискуссии о MPI_INTERCOMM_CREATE, что: ``Группы должны быть разъединены'' и что ``Лидером может быть тот же самый процесс''.

Причиной требования ``Группы должны быть разъединены'' является озабоченность реализацией MPI_INTERCOMM_CREATE, которая не применима в случае, когда лидером является тот же самый процесс.

Принято: удалить текст: ``(два лидера могут быть тем же самым процессом)'' из дискуссии о MPI_INTERCOMM_CREATE.

Заменить текст ``Все конструкторы интер-коммуникаторов являются блокирующими и требуют, чтобы локальные и удаленные группы были разъединены в таком порядке, чтобы избежать дедлока'' текстом ``Все конструкторы интер-коммуникаторов являются блокирующими и требуют, чтобы локальные и удаленные группы были разъединены''.

Совет пользователям: Группы должны быть разъединены по нескольким причинам. Прежде всего, это цель интер-коммуникаторов - обеспечить коммуникатор для обмена между разъединенными группами. Это отражено в определении MPI_INTERCOMM_MERGE, который позволяет пользователю управлять нумерацией процессов в созданном интер-коммуникаторе; эта нумерация имеет мало смысла, если группы не разъединены. К тому же, естественное расширение на коллективные операции для интер-коммуникаторов имеет наибольший смысл, когда группы разъединены.

С2.5 Уточнение MPI_INTERCOMM_MERGE

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

С.2.6. Уточнение привязок MPI_TYPE_SIZE

Это уточнение необходимо для описания MPI_TYPE_SIZE в MPI-1, поскольку проблема возникает многократно. Это уточнение привязки.

Совет пользователям: Стандарт MPI-1 указывает, что выходной аргумент MPI_TYPE_SIZE в Си имеет тип int. MPI Forum рассмотрел предложение изменить это и решил оставить исходное решение.

С2.7. Уточнение MPI_REDUCE

Текст на стр. 115, строки 25 - 28 стандарта MPI-1.1 (12, июнь, 1995) говорит:

``Аргумент типа данных MPI_REDUCE обязан быть совместим с типом ор. Предопределенные операторы работают только с типами данных из списка, представленного в разделах 4.9.2 и 4.9.3. Операторы, определенные пользователем, могут работать с производными типами данных''.

Этот текст заменен на:

``Аргумент типа данных MPI_REDUCE обязан быть совместим с типом ор. Предопределенные опраторы работают только с типами данных из списка, представленного в разделах 4.9.2 и 4.9.3. Более того, типы данных и ор, данные для предопределенных операторов, обязаны быть одними и теми же на всех процессах''.

Заметим, что пользователь имеет возможность создавать различные определенные пользователем операции в каждом процессе. MPI не определяет, какие операции и с какими операндами используются в этом случае.

Совет пользователям: Пользователи не должны делать никаких предположений о том, как реализован MPI_REDUCE. Защита должна гарантировать, что та же самая функция передается в MPI_REDUCE каждым процессом.

Перекрывающиеся типы данных разрешены в буферах посылки. Перекрывающиеся типы данных в буферах приема ошибочны и могут давать непредсказуемый результат.

С2.8. Уточнение поведения функции Attribute Callback при ошибках

Если функция копирования или удаления атрибута возвращает что-либо, отличное от MPI_SUCCESS, то обращение, которое вызвало эту ситуацию (например, MPI_COMM_FREE), является неверным.

С2.9. Уточнение MPI_PROBE и MPI_IPROBE

Страница 52, строки 1 -3 MPI-1.1 (12, июнь, 1995) устанавливает, что:

``Последующий прием, выполненный с тем же самым коммуникатором, номером процесса-отправителя и тэгом, возвращенным в статус функцией MPI_IPROBE, будет принимать сообщение, которое соответствует пробе, если не имело места никакое другое пересекающееся сообщение после пробы, и посылка не была успешно отменена перед приемом''.

Объяснение: Следующая программа показывает, что определения MPI-1 для отмены и пробы конфликтуют:

Процесс 0 Процесс 1 ---------- ---------- MPI_Init(); MPI_Init(); MPI_Isend(dest=1); MPI_Probe(); MPI_Barrier(); MPI_Barrier(); MPI_Cancel(); MPI_Wait(); MPI_Test_cancelled(); MPI_Barrier(); MPI_Barrier(); MPI_Recv();

Поскольку посылка была отменена процессом 0, ожидание обязано быть локальным (страница 54, строка 13) и обязано возвращать управление перед соответствующим приемом. Чтобы ожидание было локальным, посылка должна быть успешно отменена и поэтому не обязана соответствовать приему в процессе 1 (страница 54, строка 29).

Однако, ясно, что проба на процессе 1 обязана в конечном счете детектировать входное сообщение. На странице 52 в строке 1 ясно говорится, что последующий прием процессом 1 обязан возвратить опробованное сообщение.

Выше выявлено противоречие и поэтому текст ``...и отправка не завершена успешно перед приемом'' обязан быть добавленным к строке 3 на странице 54.

Альтернативное решение (отброшенное) потребовало бы изменения семантики отмены, так как вызов не является локальным, если сообщение уже опробовано. Это увеличивает сложность реализации и добавляет новую концепцию ``состояния'' к сообщению (опробовано или нет). Однако, это сохранило бы ту особенность, что блокирующий прием после пробы является локальным.


next up previous contents
Next: Приложение D. Перечень функций Up: Библиография Previous: Приложение B. Языковые привязки   Contents
Alex Otwagin 2002-12-10