Я вижу ошибку MPI_ERR_TRUNCATE
с boost::mpi
при выполнении нескольких передач isend/irecv с тем же тегом с использованием сериализованных данных. Это не параллельные передачи, т.е. Не задействована нить. В то же время существует более одной передачи. Вот небольшая тестовая программа, которая демонстрирует неудачу:
#include <iostream>
#include <string>
#include <vector>
#include <boost/mpi.hpp>
#include <boost/serialization/string.hpp>
static const size_t N = 2;
int main() {
boost::mpi::environment env;
boost::mpi::communicator world;
#if 1
// Serialized types fail.
typedef std::string DataType;
#define SEND_VALUE "how now brown cow"
#else
// Native MPI types succeed.
typedef int DataType;
#define SEND_VALUE 42
#endif
DataType out(SEND_VALUE);
std::vector<DataType> in(N);
std::vector<boost::mpi::request> sends;
std::vector<boost::mpi::request> recvs;
sends.reserve(N);
recvs.reserve(N);
std::cout << "Multiple transfers with different tags\n";
sends.clear();
recvs.clear();
for (size_t i = 0; i < N; ++i) {
sends.push_back(world.isend(0, i, out));
recvs.push_back(world.irecv(0, i, in[i]));
}
boost::mpi::wait_all(sends.begin(), sends.end());
boost::mpi::wait_all(recvs.begin(), recvs.end());
std::cout << "Multiple transfers with same tags\n";
sends.clear();
recvs.clear();
for (size_t i = 0; i < N; ++i) {
sends.push_back(world.isend(0, 0, out));
recvs.push_back(world.irecv(0, 0, in[i]));
}
boost::mpi::wait_all(sends.begin(), sends.end());
boost::mpi::wait_all(recvs.begin(), recvs.end());
return 0;
}
В этой программе я сначала делаю 2 передачи по разным тегам, которые отлично работают. Затем я пытаюсь выполнить 2 передачи по одному и тому же тегу, который не выполняется:
libС++ abi.dylib: завершение с неперехваченным исключением типа boost :: exception_detail :: clone_impl>: MPI_Unpack: MPI_ERR_TRUNCATE: сообщение усечено
Если я использую собственный тип данных MPI, чтобы сериализация не вызывалась, все работает. Я получаю ту же ошибку на MacPorts, увеличивая 1,55 с помощью OpenMPI 1.7.3, а Debian - 1.49 с OpenMPI 1.4.5. Я попробовал несколько передач с тем же тегом непосредственно с интерфейсом API C и, похоже, работал, хотя, конечно, я могу передавать только собственные типы данных MPI.
Мой вопрос заключается в том, является ли наличие нескольких выдающихся переводов на одном и том же теге действительной операцией с boost::mpi
, и если это так, то есть ошибка в моей программе или ошибка в boost::mpi
?
В текущей версии boost, 1.55, boost::mpi
не гарантирует не обгоняющих сообщений. Это в отличие от базового API MPI, который выполняет:
Сообщения заказа не обгоняют: если отправитель отправляет два сообщения подряд одному и тому же адресату, и оба соответствуют одному и тому же приему, тогда эта операция не может получить второе сообщение, если первый из них все еще ожидает ответа. Если получатель отправляет два приема подряд, и оба соответствуют одному и тому же сообщению, то вторая операция приема не может быть удовлетворена этим сообщением, если первый из них все еще ожидает ответа. Это требование облегчает сопоставление отправлений с получателями. Это гарантирует, что код передачи сообщений детерминирован, если процессы однопоточны, а групповой символ MPI_ANY_SOURCE не используется в приемах.
Причина boost::mpi
не гарантирует без обгона, что сериализованные типы данных передаются в двух сообщениях MPI, один для размера и один для полезной нагрузки, а irecv
для второго сообщения не может быть отправлен до тех пор, пока не будет проверено первое сообщение.
Рассматривается предложение об обеспечении без обгона в boost::mpi
. Дальнейшее обсуждение можно найти в списке рассылки boost::mpi
начинающемся здесь.
Проблема может заключаться в том, что вы ожидаете завершения всех ваших отправлений, а затем для всех ваших запросов. MPI ожидает, что ваши посылки и получат соответствие во времени, а также в количестве. Что я имею в виду, когда говорю, что вы не можете закончить все ваши вызовы по пересылке без продолжения ваших вызовов приема.
Способ, которым MPI обычно обрабатывает отправку сообщения, заключается в том, что при вызове send он будет возвращаться после вызова, как только сообщение будет обработано библиотекой. Это может привести к тому, что сообщение было скопировано во внутренний буфер или что сообщение было фактически передано удаленному процессу и получено. В любом случае сообщение должно куда-то идти. Если у вас уже нет ожидающего буфера приема, сообщение должно быть буферизировано внутри. В конце концов, реализация закончится из этих буферов и начнет делать плохие вещи (например, возвратить ошибки пользователю), которые вы, вероятно, видите здесь.
Решение заключается в предварительной отправке буферов приема. В вашем случае вы можете просто нажать все isend
и irecv
в один и тот же вектор и позволить MPI обрабатывать все. Это даст MPI доступ ко всем буферам приема, чтобы ваши сообщения могли куда-то идти.
isend()
иirecv()
которые не используют буферизацию MPI (любая буферизация выполняется вboost::mpi
).