C ++ 11 Threads против OpenMP при использовании одного потока - PullRequest
0 голосов
/ 14 сентября 2018

Я пытаюсь распараллелить код, который выполняется много раз (и, следовательно, счетчик миллисекунд).Я хотел бы использовать многопоточность C ++ 11, так как она может работать в Mac OS X без необходимости требовать от пользователя установки OpenMP (например, с помощью Homebrew).Однако я считаю, что производительность OpenMP значительно лучше, чем многопоточность C ++ 11.

Удивительно, но даже когда C ++ 11 использует только один поток, он имеет значительно больше накладных расходов, чем OpenMP.Для приведенного ниже простого цикла у нас есть следующие времена (используя только один поток):

C++11 Multithreading: 57 ms
OpenMP Multithreading: 47 ms
Native for loop: 43 ms

Я вижу более существенные улучшения в скорости для потоков OpenMP по сравнению с C ++ 11 при использовании более 1 потока.Как я могу получить скорости OpenMP-типа с многопоточностью C ++ 11?

Вот некоторый адаптированный код, который более или менее выполняет то, что пытается сделать мой настоящий код.

C++ 11 Многопоточность

#include <stdlib.h>
#include <stdio.h>
#include <thread>
#include <vector>
#include <algorithm>
#include <time.h>

long int diff(timespec start, timespec end)
{
    long int tv_nsec;
    tv_nsec = 1000000000*(end.tv_sec-start.tv_sec)+end.tv_nsec-start.tv_nsec;
    return tv_nsec;
}
int main() {

    int n = 1E6;
    int ndim = 3;
    int nthreads = 1;
    double * arr1 =(double*) malloc(n* sizeof(double));
    double * arr2 =(double*) malloc(n* sizeof(double));
    double * xs=(double*) malloc(n* sizeof(double));
    double * ys =(double*) malloc(n* sizeof(double));
    int * iarr =(int*) malloc(n* sizeof(int));
    double * arr3 =(double*) malloc(n*ndim *sizeof(double));
    for (int i = 0; i++ ; i<n) {
        iarr[i] = i;
        xs[i] = i;
        ys[i] = i; for (int j = 0; j++ ; j<ndim) {
            charges[j*ndim +i] = i*j;
        }
    }

        struct timespec start10,start20, end10, end20;
        clock_gettime(CLOCK_MONOTONIC, &start10);

        {
        std::vector<std::thread> threads(nthreads);
        for (int t = 0; t < nthreads; t++) {
            threads[t] = std::thread(std::bind(
                    [&](const int bi, const int ei, const int t)
                    {
                        for(int i = bi;i<ei;i++)
                        {
                            {
                                arr1[i] = xs[iarr[i]];
                                arr2[i] = ys[iarr[i]];
                                for (int idim=0; idim<ndim; idim++){
                                        arr3[idim*n+i] = charges[idim*n +iarr[i]];
                                }

                            }
                        }
                    },t*n/nthreads,(t+1)==nthreads?n:(t+1)*n/nthreads,t));
        }
        std::for_each(threads.begin(),threads.end(),[](std::thread& x){x.join();});
        }


        clock_gettime(CLOCK_MONOTONIC, &end10);
        printf("Initializing and sorting (%d threads): %.2lf ms\n",nthreads, (diff(start10,end10))/(double)1E6);

OpenMP:

        struct timespec start10,start20, end10, end20;
        clock_gettime(CLOCK_MONOTONIC, &start10);

    #pragma omp parallel num_threads(1)
    {
    #pragma omp for
    for (int i = 0; i<n; i++){

                                arr1[i] = xs[iarr[i]];
                                arr2[i] = ys[iarr[i]];
                                for (int idim=0; idim<ndim; idim++){
                                        arr3[idim*n+i] = charges[idim*n +iarr[i]];
                                }

                            }
    }
        clock_gettime(CLOCK_MONOTONIC, &end10);
        printf("Initializing and sorting (%d threads): %.2lf ms\n",nthreads, (diff(start10,end10))/(double)1E6);
}
...