2012-02-21 19 views
7

Jestem w trakcie równoległego programowania za pomocą OpenMP na 4-rdzeniowym phenom2. Zauważyłem jednak, że moja równoległość nic nie robi dla wydajności. Naturalnie założyłem, że coś przeoczyłem (przeskakiwanie, serializacja przez blokady, ...), jednak nie mogłem znaleźć czegoś takiego. Co więcej, z użycia CPU wydawało się, że program został wykonany tylko na jednym rdzeniu. Z tego, co znalazłem sched_getcpu() powinien dać mi identyfikator rdzenia wątku wykonywania połączenia jest obecnie zaplanowane na. Więc napisałem następujący program testowy:Wątki OpenMP wykonywane na tym samym rdzeniu procesora

#include <iostream> 
#include <sstream> 
#include <omp.h> 
#include <utmpx.h> 
#include <random> 
int main(){ 
    #pragma omp parallel 
    { 
     std::default_random_engine rand; 
     int num = 0; 
    #pragma omp for 
     for(size_t i = 0; i < 1000000000; ++i) num += rand(); 
    auto cpu = sched_getcpu(); 
    std::ostringstream os; 
     os<<"\nThread "<<omp_get_thread_num()<<" on cpu "<<sched_getcpu()<<std::endl; 
     std::cout<<os.str()<<std::flush; 
    std::cout<<num; 
    } 
} 

Na moim komputerze to daje następujący wynik (losowe numery będą się różnić od kursu):

Thread 2 on cpu 0 num 127392776 
Thread 0 on cpu 0 num 1980891664 
Thread 3 on cpu 0 num 431821313 
Thread 1 on cpu 0 num -1976497224 

Od tego zakładam, że wszystkie wątki wykonać na ten sam rdzeń (ten z identyfikatorem 0). Aby być bardziej pewnym spróbowałem także podejścia z this answer. Wyniki są takie same. Dodatkowo użycie #pragma omp parallel num_threads(1) nie spowolniło wykonania (nieco szybciej w rzeczywistości), dodając wiarygodności teorii, że wszystkie wątki używają tego samego procesora, jednak fakt, że procesor jest zawsze wyświetlany jako 0 sprawia, że ​​jestem podejrzany. Dodatkowo sprawdziłem GOMP_CPU_AFFINITY, który początkowo nie był ustawiony, więc próbowałem ustawić go na 0 1 2 3, który powinien związać każdy wątek z innym rdzeniem niż to, co rozumiem. Jednak to nie miało znaczenia.

Odkąd pracuję w systemie Windows, używam Linuksa w Virtualboksie do mojego rozwoju. Więc myślę, że może system wirtualny nie może uzyskać dostępu do wszystkich rdzeni. Jednak sprawdzanie ustawień wirtualnej skrzynki pokazywało, że wirtualna maszyna powinna pobrać wszystkie 4 rdzenie i wykonując mój testowy program 4 razy w tym samym czasie wydaje się używać wszystkich 4 rdzeni, biorąc pod uwagę wykorzystanie procesora (i fakt, że system bardzo przestał reagować) .

Moje pytanie brzmi: co właściwie się tutaj dzieje? Bardziej do rzeczy: Czy moje odliczenie, że wszystkie wątki używają tego samego rdzenia poprawnie? Jeśli tak, jakie mogą być tego powody?

+1

Czy istnieje wspólny błąd, czy ustawiłeś zmienną środowiskową OMP_NUM_THREADS = 4? – pyCthon

+0

@pyCthon: 'OMP_NUM_THREADS' nie wydaje się być ustawiony, jednak ponieważ openmp tworzy 4 wątki, nie sądzę, bym musiał. – Grizzly

+0

Dziwne myślę, że może to być coś z maszyną wirtualną próbowałem tego samego kodu nawet zainstalowany utmpx.h i wydawało się, że działa dobrze na 8 i 16 podstawowych maszynach – pyCthon

Odpowiedz

6

Po kilku eksperymentach odkryłem, że problem polegał na tym, że uruchamiałem mój program z poziomu środowiska IDE Eclipse, które z pozoru ustawiło powinowactwo do używania tylko jednego rdzenia. Myślałem, że mam te same problemy, gdy zaczynam od zewnątrz IDE, ale powtarzany test pokazał, że program działa dobrze, kiedy zaczyna się od terminala zamiast z wnętrza ide.

0

Powinieneś użyć #pragma omp parallel for
I tak, masz rację, że nie potrzebujesz OMP_NUM_THREADS. omp_set_num_threads(4); powinien również zrobić dobrze.

+0

Dlaczego miałbym używać '#pragma omp parallel for', jeśli chcę, aby wątki robiły rzeczy poza pętlą (jak zapisywanie ich id do wyjścia)? I jak już wspomniałem, domyślnie tworzy 4 wątki, wydaje się, że są wykonywane na tym samym rdzeniu – Grizzly

+0

To prawda. btw, jeśli nie powiem omp * parallel * for, to nie nastąpi równoległość w pętli. Ale oczywiście znajdujesz się w sekcji równoległej, więc ... Jedyne inne możliwe wytłumaczenie, jakie mogę wymyślić, to brak wsparcia sprzętowego dla twojej wirtualnej skrzynki. Czy próbowałeś z innymi procesorami? http://superuser.com/questions/33723/getting-2-processors-to-work- with-virtualbox-on-dual-core-celeron – Nav

+0

Ja nie. Jak już wspomniano, możliwe jest użycie wszystkich rdzeni z vboksa, więc brak wsparcia wydaje się mało prawdopodobny. – Grizzly

0

jeśli działa na Windows, spróbuj tego:

c: \ windows \ system32 \ cmd.exe/c start/powinowactwa F ścieżka \ do \ your \ program.exe

/powinowactwa 1 wykorzystuje CPU0

/powinowactwo 2 wykorzystuje CPU1

/powinowactwo 3 wykorzystuje CPU0 i CPU1

/powinowactwo 4 stosuje CPU2

/powinowactwo F wykorzystuje wszystkie 4 rdzenie

Konwertuj liczbę na szesnastkową i zobacz bity od prawej, które są rdzeniami, które mają być użyte.

można sprawdzić powinowactwo podczas jego pracy za pomocą menedżera zadań.

+0

Vbox ma prawidłowe powinowactwo do korzystania z wszystkich rdzeni (sprawdziłem i poza tym, w jaki sposób użyłbym ich wszystkich w moim teście z wieloma początki mojego testu). Ponieważ używam linuxa w VBoxie, które tak naprawdę tam nie pomaga. – Grizzly

1

Skompilowałem twój program za pomocą g ++ 4.6 na Linuksie

g++ --std=c++0x -fopenmp test.cc -o test 

Wyjście było zaskoczeniem:

Thread 2 on cpu 2 

Thread 3 on cpu 1 
910270973 
Thread 1 on cpu 3 
910270973 
Thread 0 on cpu 0 
910270973910270973 

Fakt, że 4 wątki są uruchamiane (jeśli nie ustawić liczbę wątków w dowolny sposób, na przykład za pomocą OMP_NUM_THREADS) powinno oznaczać że program jest w stanie zobaczyć 4 użyteczne procesory. Nie mogę zgadnąć, dlaczego nie używa ich, ale podejrzewam, że problem tkwi w ustawieniach sprzętu/oprogramowania, w niektórych zmiennych środowiskowych lub w opcjach kompilatora.

Powiązane problemy