#c #ubuntu #mpi
#c #ubuntu #mpi
Вопрос:
Приведенный ниже код показывает пример pingpong при изучении функции отправки и ответа. Но я не понимаю из parter_rank .
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
const int PING_PONG_LIMIT = 10;
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Find out rank, size
int world_rank;
MPI_Comm_rank(MPI_COMM_WORLD, amp;world_rank);
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, amp;world_size);
// We are assuming 2 processes for this task
if (world_size != 2) {
fprintf(stderr, "World size must be two for %sn", argv[0]);
MPI_Abort(MPI_COMM_WORLD, 1);
}
int ping_pong_count = 0;
int partner_rank = (world_rank 1) % 2;
while (ping_pong_count < PING_PONG_LIMIT) {
if (world_rank == ping_pong_count % 2) {
// Increment the ping pong count before you send it
ping_pong_count ;
MPI_Send(amp;ping_pong_count, 1, MPI_INT, partner_rank, 0, MPI_COMM_WORLD);
printf("%d sent and incremented ping_pong_count %d to %dn", world_rank, ping_pong_count, partner_rank);
} else {
MPI_Recv(amp;ping_pong_count, 1, MPI_INT, partner_rank, 0, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
printf("%d received ping_pong_count %d from %dn",
world_rank, ping_pong_count, partner_rank);}
}
MPI_Finalize();
}
Q1. Очевидно, что MPI_Comm_rank выше определяет его как world_rank, но я не понимаю, что означает partner_rank ниже.
В чем разница между двумя рангами?
Q2. Когда я не понимаю if (world_rank == ping_pong_count % 2)
, не можем ли мы просто написать «rank == 0» и «rank == 1»? Зачем вы ввели туда арифметический оператор?
Я был бы признателен за ваш комментарий.
Комментарии:
1. если вы этого не
if (world_rank == ping_pong_count %2)
сделаете, ваша программа (в том виде, в котором она написана в настоящее время) будет выполнять пинг-пинг вместо пинг-понга. что касается стиля, я думаю, что эта программа немного запутана, но может быть легко адаптирована для выполнения любого четного числа задач MPI.2. Первый счет = 0, и поэтому, если (world_rank=(pingpong_count 1)%2) становится world_rank =0 . Становится ли этот рейтинг партнера равным 1?
3.
partner_rank
является константой:0
партнер является1
и1
партнер является0
. Чтобы выполнить пинг-понг, ранг 0 должен отправлять, recv, отправлять, recv, …, а ранг 1 должен отправлять, отправлять, отправлять, отправлять, отправлять… Это обоснование для этогоif
4. спасибо за ваш комментарий, могу я задать еще один вопрос? Как мне реализовать этот код без partner_rank? Когда мы удалили parter_rank и запустили параметр, который включал parter_rank , только rank =0 отправил сообщение, и программа не завершилась должным образом.
5. мой совет — не делайте этого. но если вы действительно этого хотите, вам нужно будет развернуть свой цикл, например
if (rank == 0) { MPI_Send(); MPI_Recv();} else {MPI_Recv(); MPI_Send();}
Ответ №1:
Причиной этой, казалось бы, ненужной арифметики и введения дополнительных переменных ранга является симметрия кода. То есть, поскольку наиболее распространенный тип программ MPI — это тот, который выполняется как несколько копий одной и той же программы, симметричный код означает код, в котором нет условных операторов, сравнивающих ранг с конкретными константами. Почему это важно? Потому что это делает код более гибким и понятным.
Сравните следующие две эквивалентные спецификации того, как выглядит двухуровневая программа MPI для пинг-понга:
Спецификация 1
- ранг 0 отправляет сообщение рангу 1
- затем ранг 1 отправляет сообщение обратно в ранг 0
- процесс повторяется N раз
Реализация этой спецификации в псевдокоде, подобном C, может быть:
loop N times {
if (rank == 0) {
MPI_Send to 1
MPI_Recv from 1
}
else if (rank == 1) {
MPI_Recv from 0
MPI_Send to 0
}
}
Спецификация 2
- каждый ранг получает от другого ранга
- затем каждый ранг отправляется в другой ранг
- процесс повторяется N-1 раз
- кроме того, ранг 0 запускает процесс, отправляя другому рангу, и завершает процесс, получая последнее сообщение от другого ранга
Возможная реализация в псевдокоде:
other_rank = 1 - rank
if (rank == 0) {
MPI_Send to other_rank
}
loop N-1 times {
MPI_Recv from other_rank
MPI_Send to other_rank
}
if (rank == 0) {
MPI_Recv from other_rank
}
Вторая спецификация (и ее реализация) на первый взгляд может показаться более сложной, но это не так. Его преимущество в том, что он локальный — он не дает глобального предписания того, что должны делать конкретные ранги. Вместо этого он дает предписание того, что делает любой ранг в системе, нарушая симметрию только в начале и в конце процесса, потому что что-то должно запустить цепочку.
Что, если мы хотим расширить систему и иметь не два, а три ранга, передающие сообщения в кольце. Мы хотим, чтобы ранг 0 передавал сообщение в ранг 1, который затем передает его в ранг 2, который, в свою очередь, возвращает его в ранг 0. Расширение спецификации 1 приводит к:
- ранг 0 отправляет на ранг 1
- ранг 0 получает из ранга 2
- ранг 1 получает из ранга 0
- ранг 1 отправляет на ранг 2
- ранг 2 получает из ранга 1
- ранг 2 отправляет на ранг 0
В псевдокоде:
loop N times {
if (rank == 0) {
MPI_Send to 1
MPI_Recv from 2
}
else if (rank == 1) {
MPI_Recv from 0
MPI_Send to 2
}
else if (rank == 2) {
MPI_Recv from 1
MPI_Send to 0
}
}
Попробуйте расширить это до четырех рангов, затем до пяти.
С другой стороны, спецификация 2 естественным образом распространяется на три, четыре … фактически, на любое количество рангов:
- каждый ранг получает от предыдущего ранга
- каждый ранг отправляет на следующий ранг
- ранг 0 запускает процесс путем отправки первого сообщения и завершает процесс получением последнего сообщения
В псевдокоде:
prev_rank = (rank - 1 #ranks) % #ranks
next_rank = (rank 1) % #ranks
if (rank == 0) {
MPI_Send to next_rank
}
loop N-1 times {
MPI_Recv from prev_rank
MPI_Send to next_rank
}
if (rank == 0) {
MPI_Recv from prev_rank
}
Стоит отметить, что спецификация 2 — это не что иное, как конкретный случай этой общей спецификации с #ranks
равным 2
. В этом случае prev_rank
и next_rank
оба равны (rank 1) % 2
, т. Е. Имеют один и тот же ранг. Кроме того, (rank 1) % 2
и 1 - rank
одинаковы, когда ранг принимает значения, которые являются либо 0
или 1
.
Надеюсь, теперь вы видите мотивацию, стоящую не за жестким кодированием конкретных действий для конкретных рангов, а за использованием локальной арифметики для определения того, что делать. В вашем случае каждое четное значение сообщения ping увеличивается на ранг 0, а каждое нечетное значение сообщения ping — на ранг 1, но что, если вы расширите его до кольца рангов? if (rank == ping_value % #ranks) ping_value ;
вроде бы все правильно и работает с любым количеством рангов.
Комментарии:
1. Спасибо за ваш любезный ответ. Спасибо вам, это помогло мне понять код!!!!!
2. Чтобы задать еще один вопрос, можно ли понимать значение ‘local’ как то же значение, что и ‘regional’, используемое в ‘local variable’?
3. Локально, поскольку не включает знания о программе MPI в целом, только текущий ранг и его непосредственное окружение.