2012-02-15 25 views
5

Mój procesor to Core i3 330M z 2 rdzeniami i 4 wątkami. Kiedy wykonuję polecenie cat /proc/cpuinfo w moim terminalu, to tak, jakbym miał 4 CPUS. Gdy używam funkcji OpenMP get_omp_num_procs() Mam również 4.OpenMP i rdzenie/wątki

Teraz mam standardową klasę wektorową C++, mam na myśli klasa o podwójnej tablicy o stałym rozmiarze, która nie używa szablonów wyrażeń. Starannie zrównoważyłem wszystkie metody mojej klasy i otrzymałem "oczekiwane" przyspieszenie.

Pytanie brzmi: czy mogę zgadnąć oczekiwane przyspieszenie w tak prostym przypadku? Na przykład, jeśli dodaję dwa wektory bez równoległych pętli for, otrzymam trochę czasu (używając polecenia czasu powłoki). Teraz, jeśli używam OpenMP, czy powinienem uzyskać czas podzielony przez 2 lub 4, w zależności od liczby rdzeni/wątków? Podkreślam, że proszę tylko o ten konkretny prosty problem, w którym nie ma współzależności w danych i wszystko jest liniowe (dodanie wektora).

Oto kod:

Vector Vector::operator+(const Vector& rhs) const 
{ 
    assert(m_size == rhs.m_size); 
    Vector result(m_size); 
    #pragma omp parallel for schedule(static) 
    for (unsigned int i = 0; i < m_size; i++) 
      result.m_data[i] = m_data[i]+rhs.m_data[i]; 

    return result; 
} 

już przeczytać ten post: OpenMP thread mapping to physical cores.

Mam nadzieję, że ktoś powie mi więcej o tym, jak OpenMP wykonuje pracę w tym prostym przypadku. Powinienem powiedzieć, że jestem początkującym w obliczeniach równoległych.

Dzięki!

Odpowiedz

3

EDYCJA: Po dodaniu kodu.

W tym konkretnym przykładzie jest bardzo mało obliczeń i dostęp do pamięci. Tak więc wydajność będzie silnie uzależniona od:

  • Wielkość wektora.
  • Jak to robisz. (Czy masz zewnętrzną pętlę do celów pomiaru czasu)?
  • Czy dane są już w pamięci podręcznej.

W przypadku większych rozmiarów wektorowych najprawdopodobniej okaże się, że wydajność jest ograniczona przez przepustowość pamięci. W takim przypadku równoległość niewiele pomoże. W przypadku mniejszych rozmiarów dominować będzie nadmiar wątków. Jeśli uzyskujesz "oczekiwane" przyspieszenie, prawdopodobnie znajdujesz się gdzieś pomiędzy, gdzie wynik jest optymalny.

Nie chcę podawać twardych liczb, ponieważ ogólnie rzecz biorąc, "zgadywanie" wydajności, szczególnie w aplikacjach wielowątkowych, jest przegraną przyczyną, chyba że masz wcześniejszą wiedzę testową lub poufną znajomość zarówno programu, jak i systemu, na którym działa.

Podobnie jak prosty przykład wzięty z mojego odpowiedź tutaj: How to get 100% CPU usage from a C program

Na Core i7 920 @ 3.5 GHz (4 rdzenie, 8 nici):

Jeśli prowadzony z 4 nici, wynik brzmi:

This machine calculated all 78498 prime numbers under 1000000 in 39.3498 seconds 

Jeśli prowadzony z 4 nici i wyraźny (użyciu programu zadania) pin nici na 4 oddzielne rdzenie fizycznych, wynik brzmi:

This machine calculated all 78498 prime numbers under 1000000 in 30.4429 seconds 

To pokazuje, jak nieprzewidywalne jest to nawet dla bardzo prostej i żenująco równoległej aplikacji. Aplikacje wymagające dużej ilości pamięci i synchronizacji stają się o wiele brzydsze ...

1

Aby dodać do odpowiedzi Mistycznych. Twój problem to czysta przepustowość pamięci ograniczona. Spójrz na STREAM benchmark. Uruchom go na swoim komputerze w pojedynczych i wielowątkowych skrzynkach i spójrz na wyniki Triady - to jest twoja sprawa (no, prawie, ponieważ twój wektor wyjściowy jest jednocześnie jednym z twoich wektorów wejściowych). Oblicz, ile danych przesuniesz, a będziesz dokładnie wiedzieć, jakiej wydajności oczekiwać.

Czy w przypadku tego problemu działa wiele wątków? Tak. Rzadko zdarza się, że pojedynczy rdzeń procesora może nasycić całą przepustowość pamięci systemu. Nowoczesne komputery równoważą dostępną przepustowość pamięci dzięki liczbie dostępnych rdzeni. Z mojego doświadczenia wynika, że ​​będziesz potrzebował około połowy rdzeni do nasycenia przepustowości pamięci za pomocą prostej operacji zapamiętywania. Może trochę potrwać, jeśli wykonasz jakieś obliczenia po drodze.

Należy pamiętać, że w systemach NUMA należy powiązać wątki z rdzeniami procesora i użyć lokalnego przydziału pamięci w celu uzyskania optymalnych wyników. Dzieje się tak dlatego, że w takich systemach każdy procesor ma własną pamięć lokalną, do której dostęp jest najszybszy. Nadal można uzyskać dostęp do całej pamięci systemowej, jak na zwykłych znacznikach SMP, ale wiąże się to z kosztami komunikacji - procesory muszą jawnie wymieniać dane. Związanie wątków z procesorami i używanie alokacji lokalnych jest niezwykle ważne. Niezastosowanie się do tego zabija skalowalność. Sprawdź libnuma, jeśli chcesz to zrobić w systemie Linux.