Как загрузить баланс простой цикл, используя MPI в C ++ - PullRequest
1 голос
/ 07 апреля 2019

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

Ниже приведен простой и смехотворный пример того, чего я пытаюсь достичь, который достаточно лаконичен, чтобы скомпилировать и продемонстрировать мою проблему;

#include <iostream>
#include <ctime>
#include "mpi.h"

using namespace std;

double int_theta(double E){
    double result = 0;
    for (int k = 0; k < 20000; k++)
        result += E*k;
    return result;
}

int main() 
{
    int n = 3500000;
    int counter = 0;
    time_t timer;
    int start_time = time(&timer);
    int myid, numprocs;
    int k;
    double integrate, result;
    double end = 0.5;
    double start = -2.;
    double E;
    double factor = (end - start)/(n*1.);
    integrate = 0;
    MPI_Init(NULL,NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    for (k = myid; k<n+1; k+=numprocs){
        E = start + k*(end-start)/n;
        if (( k == 0 ) || (k == n))
            integrate += 0.5*factor*int_theta(E);
        else
            integrate += factor*int_theta(E);
        counter++;
    }
    cout<<"process "<<myid<<" took "<<time(&timer)-start_time<<"s"<<endl;
    cout<<"process "<<myid<<" performed "<<counter<<" computations"<<endl;
    MPI_Reduce(&integrate, &result, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    if (myid == 0)
        cout<<result<<endl;
    MPI_Finalize();
    return 0;
}

Я скомпилировал проблему на моем четырехъядерном ноутбуке с

mpiicc test.cpp -std=c++14 -O3 -DMKL_LP64 -lmkl_intel_lp64 - lmkl_sequential -lmkl_core -lpthread -lm -ldl

и я получаю следующий вывод;

$ mpirun -np 4 ./a.out
process 3 took 14s
process 3 performed 875000 computations
process 1 took 15s
process 1 performed 875000 computations
process 2 took 16s
process 2 performed 875000 computations
process 0 took 16s
process 0 performed 875001 computations
-3.74981e+08

$ mpirun -np 3 ./a.out 
process 2 took 11s
process 2 performed 1166667 computations
process 1 took 20s
process 1 performed 1166667 computations
process 0 took 20s
process 0 performed 1166667 computations
-3.74981e+08

$ mpirun -np 2 ./a.out 
process 0 took 16s
process 0 performed 1750001 computations
process 1 took 16s
process 1 performed 1750000 computations
-3.74981e+08

Мне кажется, что где-то должен быть барьер, о котором я не знаю. Я получаю более высокую производительность с 2 процессорами по 3. Пожалуйста, кто-нибудь может дать какой-нибудь совет? Спасибо

1 Ответ

0 голосов
/ 08 апреля 2019

Если я прочитал вывод lscpu, который вы дали правильно (например, с помощью https://unix.stackexchange.com/a/218081),, у вас есть 4 логических процессора, но только 2 аппаратных ядра (1 сокет x 2 ядра на сокет). Используя cat /proc/cpuinfo, вы можете найти марку и модель процессора, чтобы узнать больше.

Четыре логических ЦП могут возникнуть в результате гиперпоточности, что означает, что некоторые аппаратные ресурсы (например, блок FPU, но я не эксперт в этом) распределяются между двумя ядрами. Таким образом, я не ожидал бы хорошего параллельного масштабирования за пределы двух процессов.

Для тестов на масштабируемость вы должны попытаться получить машину с 6 или более аппаратными ядрами, которые лучше оценивают.

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

...