2014-04-08 13 views
6

Przez ostatnie kilka dni zmagałem się z dziwnym problemem. Tworzymy biblioteki używając GCC 4.8, które statycznie łączą niektóre zależności - np. log4cplus lub boost. Dla tych bibliotek utworzyliśmy powiązania Python za pomocą boost-python.Różnica między łączeniem OpenMP z -fopenmp i -lgomp

Za każdym razem, gdy taka biblioteka korzystała z TLS (np. Log4cplus w swojej statycznej inicjalizacji lub stdlibC++ robi podczas zgłaszania wyjątku - nie tylko podczas fazy inicjalizacji), cała sprawa rozbiła się w segfaultie - i za każdym razem, gdy adres wątku jest lokalny zmienna została 0.

Próbowałem wszystkiego jak rekompilacja, zapewnienie -fPIC jest używane, zapewnienie -tls-model = globalna-dynamiczna jest używana, itp. Brak sukcesu. Wtedy dowiedziałem się, że powodem tych awarii był nasz sposób na połączenie OpenMP. Zrobiliśmy to za pomocą "-lgomp" zamiast po prostu używając "-fopenmp". Odkąd to zmieniłem, wszystko działa dobrze - bez wypadków, bez niczego. W porządku!

Ale naprawdę chciałbym wiedzieć, jaka była przyczyna problemu. Jaka jest więc różnica między tymi dwoma możliwościami połączenia w OpenMP?

Mamy tutaj maszynę CentOS 5, w której zainstalowaliśmy GCC-4.8 w/opt/local/gcc48 i jesteśmy również pewni, że libgomp pochodzący z/opt/local/gcc48 został użyty tak samo jak libstdC++ od tego miejsca (użyty DL_DEBUG).

Wszelkie pomysły? Nie znalazłem nic w Google - lub użyłem niewłaściwych słów kluczowych :)

+0

-pthread lub -lpthread był tam – duselbaer

+1

Skompiluj z '-v' i porównaj dane wyjściowe ... –

+1

Dodanie opcji -v jako opcji linkera pokazuje, że -fopenmp domyślnie dodaje na koniec -lgomp. Wszystko inne pozostaje takie samo. Bez -fopenp mam "-lstdC++ -lm -lgcc_s -lpthread -lc -lgcc_s" i z -fopenmp staje się "-lstdC++ -lm -lgomp -lgcc_s -lpthread -lc -lgcc_s". Nadal nie widzę przyczyny awarii, ponieważ wszystkie te biblioteki są połączone dynamicznie :( – duselbaer

Odpowiedz

6

OpenMP jest pośrednikiem między Twoim kodem a jego wykonaniem. Każde oświadczenie #pragma omp jest konwertowane na wywołania do ich funkcji biblioteki OpenMP i wszystko na nim jest. Wielowątkowe wykonywanie (uruchamianie wątków, łączenie i synchronizowanie ich itp.) Jest zawsze obsługiwane przez system operacyjny (OS). Wszystko, co robi OpenMP, radzi sobie z tymi niskopoziomowymi, zależnymi od systemu operacyjnego wywoływaniami wątków, w krótkim i słodkim interfejsie.

Flaga -fopenmp jest flagą wysokiego poziomu, która nie zawiera implementacji OpenMP GCC (gomp). Ta biblioteka Gomp będzie wymagać więcej bibliotek, aby uzyskać dostęp do funkcji wątków systemu operacyjnego. W systemach zgodnych z POSIX, OpenMP jest zwykle oparty na pthread, który musi być połączony. Może również potrzebować biblioteki rozszerzeń w czasie rzeczywistym (librt) do pracy na niektórych systemach, a nie na innych. Korzystając z dynamicznego linkowania, wszystko powinno zostać wykryte automatycznie, ale kiedy podałeś -static, myślę, że wpadłeś w sytuację opisaną przez Jakuba Jelinka here. Ale obecnie, pthread (i rt w razie potrzeby) powinny być automatycznie połączone, gdy jest używany -static.

Oprócz zależności między linkami, flaga -fopenmp aktywuje także przetwarzanie instrukcji pragma. Możesz zobaczyć cały kod GCC (jako here i here), który bez flagi -fopenmp (która nie jest wyzwalana tylko przez łączenie biblioteki gomp), wiele pragm nie zostanie przekonwertowanych na odpowiednie wywołanie funkcji OpenMP. Po prostu próbowałem z przykładowym kodem i zarówno -lgomp jak i -fopenmp tworzyły działający plik wykonywalny, który łączy się z tymi samymi bibliotekami. Jedyna różnica w moim prostym przykładzie, że -fopenmp ma symbol, który -lgomp nie ma: [email protected]@GOMP_4.0+ (kod here), który jest funkcją inicjującą sekcję równoległą wykonującą widełki żądane przez #pragma omp parallel w moim przykładowym kodzie. Tak więc wersja -lgomp nie przetłumaczyła pragmy na wezwanie do implementacji OpenMP GCC. Oba wyprodukowały działający plik wykonywalny, ale tylko flaga -fopenmp wygenerowała w tym przypadku równoległy plik wykonywalny.

Do uzupełnienia potrzebne jest -fopenmp, aby GCC mógł przetworzyć wszystkie pragmy OpenMP. Bez tego twoje równoległe sekcje nie rozwiążą żadnego wątku, który może siać spustoszenie w zależności od założeń, na których twój wewnętrzny kod został wykonany.

+0

Z twoim przykładem zbudowałeś (kompilację) źródła za pomocą '-fopenmp', a następnie użyłeś swojego' .o' w łączeniu z '-fopenmp' /' -lgomp'. użyj 'gcc -fopenmp przyklad.c' umożliwi kompilację pragma w kompilacji i doda bibliotekę do łączenia, ale pojedyncze polecenie kompilacja + link w postaci' gcc -lgomp example.c' nie przekaże opcji openmp-kompilacji i pragmy omp będzie ignorowane. – osgx

+1

Mogę się mylić, ale wierzę, że mówimy to samo? Napisałem "Tylko' -fopenmp' będzie produkować równoległy plik wykonywalny ", podczas gdy napisałeś coś w stylu" -lgomp "nie stworzy równoległego pliku wykonywalnego", czy też coś mi umknęło? (Jak napisałem, pragmy nie zostaną przekształcone w wywołanie funkcji bez '-fopenmp'). W każdym razie zgadzam się z tym, co powiedziałeś, i uważam, że odpowiedź mówi to samo. Może jednak moja odpowiedź mogłaby być lepsza, chociaż ... – Soravux