У меня есть код, который распараллеливается с использованием openMP (в цикле for). Я хотел бы повторить эту функцию несколько раз и использовать MPI для отправки в кластер машин, сохраняя, чтобы содержимое внутри узла все еще было открытым.Странное поведение при смешивании openMP с openMPI
Когда я использую только openMP, я получаю ускорение, которое я ожидаю (используя в два раза количество процессоров/ядер в течение половины времени). Когда я добавляю в MPI и подчиняюсь только одному процессу MPI, я не получаю эту скорость. Я создал игрушечную проблему, чтобы проверить это и все еще иметь ту же проблему. Вот код
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include "mpi.h"
#include <omp.h>
int main(int argc, char *argv[]) {
int iam=0, np = 1;
long i;
int numprocs, rank, namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
double t1 = MPI_Wtime();
std::cout << "!!!Hello World!!!" << std::endl; // prints !!!Hello World!!!
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Get_processor_name(processor_name, &namelen);
int nThread = omp_get_num_procs();//omp_get_num_threads here returns 1??
printf("nThread = %d\n", nThread);
int *total = new int[nThread];
for (int j=0;j<nThread;j++) {
total[j]=0;
}
#pragma omp parallel num_threads(nThread) default(shared) private(iam, i)
{
np = omp_get_num_threads();
#pragma omp for schedule(dynamic, 1)
for (i=0; i<10000000; i++) {
iam = omp_get_thread_num();
total[iam]++;
}
printf("Hello from thread %d out of %d from process %d out of %d on %s\n",
iam, np, rank, numprocs,processor_name);
}
int grandTotal=0;
for (int j=0;j<nThread;j++) {
printf("Total=%d\n",total[j]);
grandTotal += total[j];
}
printf("GrandTotal= %d\n", grandTotal);
MPI_Finalize();
double t2 = MPI_Wtime();
printf("time elapsed with MPI clock=%f\n", t2-t1);
return 0;
}
Я компиляции с OpenMPI-1.8/bin/КОМП ++, используя -fopenmp флаг. Вот мой сценарий PBS
#PBS -l select=1:ncpus=12
setenv OMP_NUM_THREADS 12
/util/mpi/openmpi-1.8/bin/mpirun -np 1 -hostfile $PBS_NODEFILE --map-by node:pe=$OMP_NUM_THREADS /workspace/HelloWorldMPI/HelloWorldMPI
Я также попытался с #PBS -l узлами = 1: ррп = 12, получаем те же результаты.
При использовании половины сердечников программа работает быстрее (в два раза быстрее!). Когда я уменьшаю количество ядер, я меняю как ncpus, так и OMP_NUM_THREADS. Я попытался увеличить фактическую работу (добавив 10 код 10 вместо 10^7, показанный здесь в коде). Я попытался удалить инструкции printf, задаваясь вопросом, не замедлили ли они что-то, все еще имеют ту же проблему. Топ показывает, что я использую все процессоры (как установлено в ncpus), близкие к 100%. Если я отправлю с помощью -np = 2, он прекрасно распараллеливается на двух машинах, поэтому MPI работает нормально, но openMP не работает
Из идей теперь все, что я могу попробовать. Что я делаю не так?
Я удивлен, что вы получаете любое ускорение вообще. 'schedule (dynamic, 1)' самый худший выбор графика цикла в этом случае, и постоянная запись в соседние элементы массива из нескольких потоков приводит к большому сбою кеша из-за ложного обмена. Вероятно, поэтому он работает быстрее на 6 ядрах, чем на 12 (обратите внимание: одна строка кэша на x86 подходит для 16 'int'-egers). –
Кроме того, наличие 'num_threads (omp_get_num_procs())' эффективно делает установку «OMP_NUM_THREADS» бесполезной, так как ваши параллельные области будут всегда работать с таким количеством потоков, сколько количество логических процессоров (например, ядер, в конечном итоге раз два с гиперпотоком). На самом деле вы не увидите этого в 'top', поскольку' --map-by node: pe = X' связывает ваш MPI-процесс с первыми X-процессорами на узле. –
Каждый поток должен записываться в собственный массив, а не в тот же массив. Это то, что я хочу сделать, укажите, где я пропущу логику. Создайте столько массивов, сколько логических процессоров (omp_get_num_procs()). В каждом потоке каждая работа (добавление в этом случае) выполняется в массиве, специфичном для этого потока (total [ithread]). – Anu