Füllen Sie Histogramme (array-Minderung) in parallele mit OpenMP, ohne einen kritischen Abschnitt

Möchte ich füllen Histogramme parallel mit OpenMP. Ich habe mit zwei verschiedenen Methoden, dies zu tun mit OpenMP in C/C++.

Die erste Methode proccess_data_v1 macht ein eigenes Histogramm variable hist_private für jeden thread, füllt Sie in prallel, und dann Summen die private Histogramme in das gemeinsame Histogramm hist im critical Abschnitt.

Die zweite Methode proccess_data_v2 macht ein shared array von Histogrammen mit array-Größe, die gleich der Anzahl von Fäden, füllt dieses array parallel, und addiert das gemeinsame Histogramm hist parallel.

Die zweite Methode scheint mir überlegen, da es vermeidet einen kritischen Abschnitt dar, und die Summe der Histogramme in parallel. Jedoch, es erfordert die Kenntnis der Anzahl der threads und aufrufen omp_get_thread_num(). Ich in der Regel versuchen, dies zu vermeiden. Gibt es eine bessere Art und Weise zu tun, die zweite Methode, ohne Bezug auf den thread-zahlen und mit einem shared array mit Größe gleich der Anzahl der threads?

void proccess_data_v1(float *data, int *hist, const int n, const int nbins, float max) {
    #pragma omp parallel 
    {
        int *hist_private = new int[nbins];
        for(int i=0; i<nbins; i++) hist_private[i] = 0;
        #pragma omp for nowait
        for(int i=0; i<n; i++) {
            float x = reconstruct_data(data[i]);
            fill_hist(hist_private, nbins, max, x);
        }
        #pragma omp critical 
        {
            for(int i=0; i<nbins; i++) {
                hist[i] += hist_private[i];
            }
        }
        delete[] hist_private;
    }
}

void proccess_data_v2(float *data, int *hist, const int n, const int nbins, float max) {
    const int nthreads = 8;
    omp_set_num_threads(nthreads);
    int *hista = new int[nbins*nthreads];

    #pragma omp parallel 
    {
        const int ithread = omp_get_thread_num();
        for(int i=0; i<nbins; i++) hista[nbins*ithread+i] = 0;
        #pragma omp for
        for(int i=0; i<n; i++) {
            float x = reconstruct_data(data[i]);
            fill_hist(&hista[nbins*ithread], nbins, max, x);
        }

        #pragma omp for
        for(int i=0; i<nbins; i++) {
            for(int t=0; t<nthreads; t++) {
                hist[i] += hista[nbins*t + i];
            }
        }

    }
    delete[] hista;
}

Edit:
Basierend auf einem Vorschlag von @HristoIliev ich erstellt haben eine verbesserte Methode namens process_data_v3

#define ROUND_DOWN(x, s) ((x) & ~((s)-1))
void proccess_data_v2(float *data, int *hist, const int n, const int nbins, float max) {
    int* hista;
    #pragma omp parallel 
    {
        const int nthreads = omp_get_num_threads();
        const int ithread = omp_get_thread_num();

        int lda = ROUND_DOWN(nbins+1023, 1024);  //1024 ints = 4096 bytes -> round to a multiple of page size
        #pragma omp single
        hista = (int*)_mm_malloc(lda*sizeof(int)*nthreads, 4096);  //align memory to page size

        for(int i=0; i<nbins; i++) hista[lda*ithread+i] = 0;
        #pragma omp for
        for(int i=0; i<n; i++) {
            float x = reconstruct_data(data[i]);
            fill_hist(&hista[lda*ithread], nbins, max, x);
        }

        #pragma omp for
        for(int i=0; i<nbins; i++) {
            for(int t=0; t<nthreads; t++) {
                hist[i] += hista[lda*t + i];
            }
        }

    }
    _mm_free(hista);
}
  • Könnten Sie bitte erklären, warum Sie mit verschachtelten parallelen Regionen? (Ich beziehe mich auf Ihre process_data_v1-Ansatz). Vielleicht bin ich ja etwas nicht zu verstehen, aber nach dem code, es scheint mir, dass Sie Sie bitten, für Nthreads**2. Es ist zu sagen, Sie fordern mehr Ressourcen, als die verfügbaren. Ist das richtig? In anderen Worten, können Sie erklären, das Verhalten von parallelen Regionen innerhalb des äußeren ein? Danke...
InformationsquelleAutor | 2013-05-28
Schreibe einen Kommentar