Тип операции в надстроек MPI коллективных операций - PullRequest
0 голосов
/ 24 апреля 2020

В boost::mpi некоторые коллективные операции, такие как уменьшение , требуют передачи операции в подпрограмму. Я не уверен, какой именно должен быть тип этой операции.

Следующий минимальный пример компилируется без предупреждений.

#include <iostream>
#include <boost/mpi/collectives.hpp>

int mysum(int a, int b) { return a + b; }

int main()
{
  boost::mpi::environment env;
  boost::mpi::communicator world;

  int data = world.rank() + 1;
  int data_reduced;
  boost::mpi::reduce(world, data, data_reduced, mysum, 0);
  if (world.rank() == 0)
    std::cout << data_reduced << std::endl;

  return 0;
}

Однако при выполнении более 1 задач происходит сбой

$ mpirun -n 2 ./mpi
munmap_chunk(): invalid pointer
...

Изменение кода следующим образом заставит программу работать без сбоев.

#include <iostream>
#include <boost/mpi/collectives.hpp>

struct mysum {
  int operator()(int a, int b) { return a + b; }
};

int main()
{
  boost::mpi::environment env;
  boost::mpi::communicator world;

  int data = world.rank() + 1;
  int data_reduced;
  boost::mpi::reduce(world, data, data_reduced, mysum{}, 0);
  if (world.rank() == 0)
    std::cout << data_reduced << std::endl;

  return 0;
}

(я знаю, что это эквивалентно std :: plus , программа просто пример)

$ mpirun -n 2 ./mpi
3

В чем разница и почему работает вторая версия?

Редактировать

Вопрос возникает также потому, что оба варианты mysum можно назвать mysum(....), т. е. оба варианта callable . Таким образом, в обоих случаях работает код, подобный следующему.

template <class Callable, class ArgType>
auto dosomething(ArgType a, ArgType b, Callable&& L) { return L(a, b); }

auto x = dosomething(mysum, 1, 2);

(Это по сути эквивалентно std :: invoke )

1 Ответ

1 голос
/ 25 апреля 2020

Похоже, это то, что boost::mpi ожидает!

Если вы mimi c boost/mpi/operations.h, ваш пользовательский оператор сокращения можно записать так:

template<typename T>
struct mysum
{
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef T result_type;
  const T& operator()(const T& x, const T& y) const
  {
    return x + y;
  }
};

и тогда ваш вызов Reduc будет выглядеть так:

boost::mpi::reduce(world, data, data_reduced, std::plus<int>(), 0);

Нижняя строка, даже если ваш mysum - это то, что нужно для перехода на простую C MPI_Op_create(), это не то, чего ожидает boost::mpi .

...