Как я могу применить MPI для одной функции - PullRequest
2 голосов
/ 17 января 2020

Мне нужно запустить функцию generator в моем коде параллельно на двух процессорах. В проекте есть два файла main.c & cartes.c, и он работает последовательно.

main.c Файл содержит для l oop, который вызывает функцию generator

main.c:

MPI_Init(&argc, &argv);
int id;
MPI_Comm_rank(MPI_COMM_WORLD, &id);
.
.
.
for (iter_sec = 0; iter_sec < long_of_seq; iter_sec++) { //
    uint64_t Xg1 = generator(&K[0], iter_sec, ratio1, ratio2, ratio3, ratio4, m1, m2, id);
    sequence[iter_sec] = Xg1;
    .
    .
}
useTheSequenceArrayResultFromTheForLoopToCaclulateAndPrintTheFinalResult(sequence);
.
.
.

Файл cartes.c содержит generator функцию

cartes.h

uint64_t generator (key *K,int iter_sec,double  ratio1, double  ratio2,double ratio3, double ratio4,uint64_t m1, uint64_t m2, int id);

cartes.c

.
.
.
uint64_t generator(key* K, int iter_sec, double ratio1, double ratio2, double ratio3, double ratio4, uint64_t m1, uint64_t m2, int id){
    K->X_s = someFunction(...);
    K->X_s = someOtherFunction(...);

    Xresult = K->X_p ^ K->X_s;
    return Xresult;
}
.
.
.

Я пытаюсь вычислить результат функции generator на двух процессорах. Я передаю идентификатор процессора в функцию generator. Если идентификатор ранга 0, мне нужно позвонить someFunction, а если ранг 1, мне нужно позвонить someOtherFunction. В конце мне нужно вернуть XOR ^ результатов от someFunction и someOtherFunction.

Я попытался сделать следующее:

.
.
.
uint64_t generator(key* K, int iter_sec, double ratio1, double ratio2, double ratio3, double ratio4, uint64_t m1, uint64_t m2, int id){
    if (id == 0) {
        K->X_s = someFunction(...);
    }
    else if(id == 1){
        K->X_s = someOtherFunction(...);
    }

    Xresult = K->X_p ^ K->X_s;
    return Xresult;
}
.
.
.

Но измененный вышеуказанная функция не работает.

Когда я пытаюсь запустить код:

mpicc main.c -o saving
mpirun -np 4 ./saving

Весь код выполняется четыре раза, и результат generator не возвращается в for l oop и не сохраняется в массиве sequence.

Как изменить функцию sequence, чтобы она выполняла someFunction и someOtherFunction на разных процессорах и возвращала результат XOR для они оба до for loop в основном файле? После заполнения массива sequence я передам его функции useTheSequenceArrayResultFromTheForLoopToCaclulateAndPrintTheFinalResult для вычисления окончательного результата.

1 Ответ

1 голос
/ 18 января 2020

Вы запускаете четыре экземпляра вашей программы параллельно, но вы забыли собрать все результаты в одном месте, используя MPI_Reduce(...). Ниже вы можете увидеть небольшой пример того, как вы можете это сделать. Но вы должны решить, где вам нужно собрать результаты. Вы можете собирать их где угодно, но разумно собирать их за пределами l oop по соображениям производительности.

#include <stdio.h>
#include <mpi.h>

#define RESULT_1 0x55
#define RESULT_2 0xAA
#define UNDEFINED 0xBB

int calc(int id) {
    if (id == 0) {
        return RESULT_1;
    }
    return RESULT_2;
}

int main (int argc, char* argv[])
{
    int id, local, global = UNDEFINED;

    MPI_Init (&argc, &argv);
    MPI_Comm_rank (MPI_COMM_WORLD, &id);

    local = calc(id);

    MPI_Reduce(&local, &global, 1, MPI_INT, MPI_BXOR, 0, MPI_COMM_WORLD);

    printf("at the moment: local=%02x, global=%02x\n", local, global);

    if (!id) {
        printf("Result is: %02x\n", global);
    }

    MPI_Finalize();
    return 0;
}

ОБНОВЛЕНИЕ # 1

Когда вы запускаете mpirun с аргументом -np 4, вы получаете 4 экземпляра вашей программы, запущенных параллельно. Если ваш компьютер имеет 4 ядра, каждый экземпляр получает различное значение для переменной id.

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

Вы можете вызвать MPI_Reduce(), чтобы объединить значения переменных или массивов из разных экземпляров в одну переменную или массив. Первый аргумент - указатель на источник. Второй - указатель на пункт назначения.

Только экземпляр с id == 0 получит результат. Поэтому, если вы планируете напечатать или использовать результат, вы должны сделать это внутри экземпляра с помощью id == 0.

Вот тот же пример, переписанный для массивов вместо переменных.

#include <stdio.h>
#include <mpi.h>

#define SIZE_OF_ARRAY 16

#define RESULT_1 0x55
#define RESULT_2 0xAA
#define UNDEFINED 0xBB

int calc(int id) {
    if (id == 0) {
        return RESULT_1;
    }
    return RESULT_2;
}

int main (int argc, char* argv[])
{
    int i, id;
    static int local[SIZE_OF_ARRAY];
    static int global[SIZE_OF_ARRAY];

    MPI_Init (&argc, &argv);
    MPI_Comm_rank (MPI_COMM_WORLD, &id);

    for(i = 0; i < SIZE_OF_ARRAY; i++) {
        local[i] = calc(id);   
        global[i] = UNDEFINED; // just to show that this value will be altered
    }

    // for an instance with (id == 0), local elements will have a value of 0x55
    // for an instance with (id != 0), local elements will have a value of 0xAA
    // the value of elements of global is undefined here

    MPI_Reduce(local, global, SIZE_OF_ARRAY, MPI_INT, MPI_BXOR, 0, MPI_COMM_WORLD);

    // after this call the values of elements of global are undefined if (id != 0)
    // if (id == 0) the values of elements of global will be combination of
    // appropriate elements of local arrays from different instances
    // let's denote "var_0" the variable "var" from the instance #0
    // we will get:
    // global_0[i] = local_0[i] ^ local_1[i] ^ local_2[i] ^ local_3[i]

    if (!id) {
        // use the sequence array result from the loop here
        printf("Result is: [%02x", global[0]);
        for(i = 1; i < SIZE_OF_ARRAY; i++) {
            printf(", %02x", global[i]);
        }
        printf(" ]\n");
    }

    MPI_Finalize();
    return 0;
}
...