2011-11-07 11 views
5

Mam bardzo dziwny problem przy użyciu OpenMP w moim kodu C++:OpenMP - Easy Loop, ale wciąż nieskończony?

void update(double *source, double *target, int n) 
{ 
    target[0] = source[0]; 
    target[n-1] = source[n-1]; 
    #pragma omp parallel for 
    for(int i = 1; i < n-1; ++i) 
     target[i] = (1.0/3.0) * (source[i-1] + source[i] + source[i+1]); 
} 

Zarówno źródło i cel są podwójne tablice z n elementów. Kod działa poprawnie, gdy używa się go bez OpenMP. Ale gdy tylko użyję pragmy, kod utknie w tej pętli. Chodzi o to: absolutnie NIE MA POMYSŁU dlaczego. Mam nadzieję, że ktoś mi pomoże

+0

kompiluje i uruchomić grzywny z GCC 4.6.1. Którego kompilatora używasz? –

+0

Czy możesz dodać trochę szczegółów na temat kompilatora i systemu operacyjnego? – talonmies

+0

gcc 4.2.1 na systemie Snow Leopard MacOS, dokładnie: 686-apple-darwin10-g ++ - 4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (kropka 3) – Chris

Odpowiedz

2

Jak duży jest n? Domyślne harmonogramowanie dla dyrektywy OpenMP parallel for jest zależne od implementacji. Wygląda na to, że w GOMP (implementacja OpenMP używana przez gcc) domyślnie jest to (dynamic,1) zgodnie z documentation here. Oznacza to, że każdy wątek uzyskuje dostęp (w lokalizacji i-1 i i+1) do pamięci, które są ładowane przez sąsiednie wątki, co może prowadzić do złego wykorzystania pamięci podręcznej. W nowoczesnych architekturach procesorów takich operacje wzorcowania są często związane z pamięcią i są wrażliwe na buforowanie. Można spróbować określający harmonogram z większymi kawałkami, na przykład z:

#pragma omp parallel for schedule(dynamic,1024) 

Ja tylko używając 1024 tutaj jako przykład. W praktyce powinieneś poeksperymentować, aby znaleźć optymalny współczynnik porcji (lub systematyczne wyszukiwanie za pomocą przeciągnięcia parametru, proces często nazywany "auto-tuningiem"). Lub możesz wybrać wartość opartą więcej w teorii, na przykład przez wyprowadzenie go z rozmiaru pamięci podręcznej L1 lub L2 procesora.

Albo możesz zamiast tego spróbować statycznego planowania, ponieważ ilość obliczeń wewnątrz pętli for jest jednakowa dla wątków, a narzuty dynamicznego programu szeregującego mogą powodować wąskie gardło. Jeśli podasz bez rozmiaru porcji, określony zostanie jeden wątek, zostanie mu przypisany pojedynczy fragment o mniej więcej tym samym rozmiarze.

Wreszcie możesz również przypiąć wątki OpenMP do własnych rdzeni procesora. Możesz to zrobić, używając zmiennej środowiskowej GOMP_CPU_AFFINITY.

Edit:

właśnie gry z następującym programem testowym skompilowane z gcc 4.2.1, i myślę, że dokumentacja związana powyżej jest nieprawidłowy. Wygląda na to, że GOMP domyślnie przyjmuje wartość schedule(static).

#include <stdio.h> 
#include <omp.h> 

int main(int argc, char** argv) 
{ 
    int i; 
    #pragma omp parallel for 
    for (i=0; i<15; i++) { 
     int id = omp_get_thread_num(); 
     printf("%d assigned to thread %d\n", i, id); 
    } 
} 

a wyjście z dwóch nitek jest:

$ ./test_sched | sort -n 
0 assigned to thread 0 
1 assigned to thread 0 
2 assigned to thread 0 
3 assigned to thread 0 
4 assigned to thread 0 
5 assigned to thread 0 
6 assigned to thread 0 
7 assigned to thread 0 
8 assigned to thread 1 
9 assigned to thread 1 
10 assigned to thread 1 
11 assigned to thread 1 
12 assigned to thread 1 
13 assigned to thread 1 
14 assigned to thread 1 
+0

Domyślnie, gdy nie zdefiniowano harmonogramu, zależy to od implementacji, ale AFAIK jest zwykle "statyczny". Łącze GOMP sugerujące '(dynamiczny, 1)' jest domyślnie odnosi się do przypadku, w którym 'schedule (runtime)' jest używany. – eran