TSX dotyczy rozszerzeń instrukcji procesora, które umożliwiają programistom wskazywanie fragmentów kodu przeznaczonych do przetwarzania transakcyjnego. Daje to nowe możliwości programistom, ale głównym celem jest zwiększenie wydajności aplikacji.

Takie mechanizmy, jak blokady i krytyczne sesje służą zachowaniu spójności danych – umożliwiają dostęp do nich tylko jednemu wątkowi w danym czasie. To jednak powoduje spadek wydajności. Aby ograniczyć czas, kiedy dostęp do danych jest zablokowany, stosuje się blokady małych fragmentów kodu i wiele blokad, aby chronić różne partie danych, chociaż może okazać się to trudne i podatne na błędy. Można stosować blokowanie dużych fragmentów kodu, co zmniejsza złożoność, ale powoduje częstsze blokowanie dostępu do danych. Rozwiązaniem problemu jest stosowanie blokad tylko wtedy, kiedy jest to faktycznie potrzebne.

Aplikacje wielowątkowe i współdzielona pamięć

Zestaw instrukcji TSX (Transactional Synchronization eXtensions) umożliwia procesorowi dynamiczne określanie, czy i kiedy należy zastosować blokadę. W ten sposób skraca się czas blokad i zwiększa wydajność. Oprócz zwiększenie wydajności, te rozszerzenie umożliwia stosowanie blokad dla krytycznych sekcji kodu z uniknięciem zbędnej serializacji. Przykładowo rozwiązanie Intel TSX jest przeznaczone do używania przez określoną klasę aplikacji wielowątkowych, które korzystają ze współdzielonej pamięci. Przykładami są, m.in. SAP HANA czy systemy HPC (High Performance Computing). Mówiąc dokładniej, chodzi o wielowątkowe aplikacje, które aktywnie współdzielą dane. TSX umożliwia programistom osiągnięcie wydajności na poziomie aplikacji z zastosowanym blokowaniem małych fragmentów kod, ale bez złożoności, jaka wiąże się z wdrażaniem tego typu blokowania.

Pod szyldem TSX kryją się dwa interfejsy: RTM (Restricted Transactional Memory) oraz HLE (Hardware Lock Elision). RTM umożliwia programistom – bardziej elastyczne niż HLE – oznaczanie początku i końca ważnych fragmentów kodu (sekcji krytycznych). Jednak oprogramowanie wykorzystujące RTM nie jest kompatybilne wstecz, ponieważ może działać tylko na procesorach z rodziny Haswell obsługujących instrukcje TSX.

Zastosowanie RTM i HLE w praktyce

RTM – zamiast zakładać, że przetwarzany wątek zawsze powinien chronić dane współdzielone z innymi wątkami – przyjmuje się, że pozostałe wątki nie zmienią wartości współdzielonych zmiennych, które w tym wątku zostały umieszczone w oznaczonej, krytycznej sekcji. Jeśli przetwarzanie kodu sekcji krytycznej zakończy się poprawnie, nie następuje ustawienie blokady. Jeśli natomiast wystąpi jakiś błąd, np. współdzielona zmienna, z której korzysta dany wątek, zostanie nadpisana, procesor zainicjuje ustawienie blokady i ponownie wykona ten fragment kodu. Wykonywana jest wówczas procedura przywracania.

Programiści mogą używać dużych blokad (np. blokować całą współdzieloną strukturę) jako tej procedury. Mechanizm ten przynosi duży wzrost wydajności, z którego może korzystać również oprogramowanie, w którym ustawiono szczegółowe blokady drobnych fragmentów kodu. Jeśli zdjęcie wszystkich blokad zakończy się powodzeniem, wszystkie wątki mogą działać równolegle. Jeśli nie, następuje powrót do zakładania blokad.
Jeśli wiele wątków wykonuje krytyczne sekcje objęte ochroną przez tę samą blokadę, ale jednocześnie nie wykonują żadnych operacji powodujących konflikty w dostępie do danych, wtedy takie wątki są przetwarzane równolegle bez serializacji. Nawet jeśli aplikacja wykonuje pewne operacje na blokadach, to procesor może rozpoznać taką sytuację i pominąć blokadę – aby wykonać kod zawarty w sekcji krytycznej w dwóch wątkach, bez konieczności komunikowania się przez blokadę – jeśli taka komunikacja nie jest potrzebna.

HLE, realizuje analogiczne zadania. Jednak umożliwia on programistom dodawanie nowych instrukcji bez utraty zgodności wstecz. To oznacza, że oprogramowanie wykorzystujące HLE może korzystać z dynamicznie dołączanych bibliotek dostosowanych do TSX, a jednocześnie będzie pracować na procesorach starszych, niż Intel Haswell. Jeśli np. programista korzysta z biblioteki glibc do blokowania, wystarczy wprowadzić zmiany tylko w tej bibliotece. Jeśli oprogramowanie używa bibliotek dołączanych dynamicznie, nie trzeba w nim wprowadzać zmian. Na początku i końcu każdej chronionej sekcji trzeba po prostu wprowadzić odpowiednią instrukcję. Jeśli po dynamicznym łączeniu taka aplikacja zostanie uruchomiona na procesorze Haswell, będzie mogła korzystać z instrukcji TSX. Ta sama aplikacja działająca na starszym procesorze uruchomi się poprawnie, ale nie będzie korzystać z TSX.

Zwiększenie wydajności pod pewnymi warunkami

Aplikacje, w których wcześniej zastosowano blokowanie dużych struktur – np. w dawnym silniku MyISAM bazy danych MySQL – w połączeniu z biblioteką dostosowaną do TSX uzyskują znaczny wzrost wydajność. Co ciekawe, aplikacje, w których programiści wprowadzili blokowanie małych fragmentów kodu, również powinny przyspieszyć dzięki instrukcjom TSX. Ponieważ TSX używa pamięci podręcznej L1 do buforowania zapisu i nie stosuje blokad – chyba, że ma miejsce ponowne wykonanie kodu – w pamięci realizowanych jest mniej operacji oraz w szczególności przeprowadzane jest mniej synchronizacji ruchu.

Są też sytuacje, w których zastosowanie HLE lub RTM nie przynosi korzyści. Przykładowo, może mieć to miejsce, jeśli wszystkie chronione zmienne znajdujące się we fragmentach kodu oznaczonego instrukcjami TSX muszą być przechowywane w cache L1. HLE nie zadziała, jeśli jakaś krytyczna sekcja kodu wymaga zablokowania zmiennych zapisanych w ośmiu lub więcej wierszach pamięci podręcznej, z których wszystkie wskazują na ten sam zestaw. Pamięć L1 działa bowiem na ośmioelementowych zestawach. Wszystko, co zakłóca wykonywanie operacji, powoduje jej wstrzymanie: niemaskowane przerwania (przerwania, których nie można zignorować), wyjścia maszyn wirtualnych, błędy, itd. Oczywiście, jest wiele sytuacji, kiedy TSX jest pomocny, a kod aplikacji można zaś napisać tak, aby uwzględniał wymienione ograniczenia i wymagania.

Podziel się na:
  • Facebook
  • Google Bookmarks
  • LinkedIn