PCJ, czyli jak zoptymalizować obliczenia i analizę danych

Ikona wpisu PCJ, czyli jak zoptymalizować obliczenia i analizę danych

Biblioteka PCJ została zaprojektowana z myślą o współczesnych superkomputerach. Pozwala na tworzenie wysoko skalowalnych aplikacji obliczeniowych, jednocześnie umożliwiając implementację algorytmów Big Data czy AI. Testy wydajnościowe pokazują, że aplikacje zbudowane z wykorzystaniem PCJ są nawet kilkadziesiąt razy szybsze niż ich odpowiedniki używające Hadoopa czy Sparka.

PCJ, czyli Parallel Computing in Java, to biblioteka umożliwiająca proste programowanie aplikacji równoległych w Javie. Została zaprojektowana dla superkomputerów, jednak ponieważ praktycznie każdy komputer posiada dziś wiele rdzeni obliczeniowych, znajduje ona zastosowanie także przy tworzeniu aplikacji na laptopy czy pecety.

Dlaczego Java?

Java od lat jest najbardziej popularnym językiem programowania i zachowuje swoją pozycję mimo pojawiających się nowych rozwiązań. Niestety, do tej pory brakowało dobrych narzędzi pozwalających na jej wykorzystanie na superkomputerach. Maszyny te wymagają bowiem programowania równoległego, to znaczy możliwości uruchamiania aplikacji na wielu procesorach jednocześnie. Java od samego początku daje możliwość programowania wielowątkowego, ale jest ona ograniczona do jednego węzła (jednej wirtualnej maszyny Java) i dość trudna w użyciu. W połowie lat 90. pojawiło się co prawda kilka alternatywnych rozwiązań, jednak ostatecznie żadne z nich się nie sprawdziło. Z drugiej strony, istniejące narzędzia bazujące na tradycyjnych językach, takich jak C i FORTRAN, są dopracowane i trudno z nimi konkurować. Jednak odkąd systemy wielordzeniowe stały się codziennością, zainteresowanie nowymi rozwiązaniami wzrasta.

Czy C lub FORTRAN nie wystarczą?

Obecnie, ze względu na ogromne zapotrzebowanie na programistów, to rynek należy do pracowników, a nie odwrotnie. Poznanie konkretnego języka programowania czy bibliotek to duża inwestycja i programiści wybierają takie rozwiązania, które są popularne i dają szerokie perspektywy zatrudnienia. Trudno więc dziś przekonać studenta informatyki do nauki FORTRAN-u. W kręgach HPC zaczyna się co prawda zauważać ten problem, stąd wprowadzenie programowania równoległego jako obowiązkowego przedmiotu na studiach informatycznych czy szereg inicjatyw mających przyciągnąć studentów do HPC. Niestety, wysiłki te nie przynoszą większego efektu. Z drugiej strony, rozwój narzędzi Big Data i sztucznej inteligencji (AI) doprowadził do powstania nowych rozwiązań, takich jak Hadoop, Spark czy TensorFlow, które pozwalają na wykorzystanie systemów wieloprocesorowych bez konieczności dogłębnej znajomości zasad programowania równoległego. Co ważne, są to rozwiązania napisane dla nowych języków programowania, takich jak Java, Scala czy Python. Ze względu na szerokie zastosowanie biznesowe technologie te stają się dla programistów bardziej interesujące i perspektywiczne.

Hadoop, Spark i TensorFlow a superkomputery

Ostatnie lata to coraz większe zainteresowanie wykorzystaniem superkomputerów w analizie Big Data czy AI. Wspomniane wcześniej narzędzia zostały jednak napisane dla mniejszych systemów, zazwyczaj zawierających do 100 węzłów obliczeniowych (procesorów). Ponadto nie współpracują one z typowym oprogramowaniem do zarządzania obliczeniami na superkomputerach. Co najważniejsze, nowe oprogramowanie nie jest w stanie wykorzystać możliwości typowych superkomputerów. Częściowo wynika to z użytego języka programowania (Java, Scala), częściowo z narzędzi programistycznych, które nie wykorzystują specyficznych dla superkomputerów możliwości sprzętowych. Stąd dostawcy superkomputerów przepisują fragmenty bibliotek na C (na przykład co-array C) w celu uzyskania zadowalającej wydajności i skalowalności. Jest to jednak rozwiązanie wymagające dużych nakładów finansowych i pracy wielu programistów, a efekt nie zawsze jest zgodny z oczekiwaniami.

Jak PCJ rozwiązuje problemy wydajności i skalowalności?

Biblioteka PCJ została zaprojektowana z myślą o tworzeniu aplikacji maksymalnie wykorzystujących możliwości obliczeniowe współczesnych superkomputerów. Oparta jest o zdobywający coraz większa popularność paradygmat PGAS (Partitioned Global Address Space) pozwalający na wygodne programowanie w językach C, FORTRAN, X10, Chapel i innych. W modelu PGAS za pomocą stosunkowo niewielkiej ilości poleceń (czy konstrukcji programistycznych) programista może w prosty sposób zaimplementować dowolny algorytm równoległy. Biblioteka PCJ udostępnia ten model programowania dla Javy w sposób naturalny dla tego języka. Programista dołącza do swojego projektu jedną bibliotekę jar i dzięki temu uzyskuje szerokie możliwości. Co więcej, do tworzenia aplikacji wystarczy standardowe środowisko programistyczne, a aplikacja może być uruchamiana na wszystkich systemach, w których jest dostępna Java (dokładniej – wirtualna maszyna Javy).

Biblioteka PCJ pozwala na tworzenie i testowanie aplikacji na laptopie czy stacji roboczej, a następnie przeniesienie jej na dowolny superkomputer, właściwie bez potrzeby ponownej kompilacji. Dzięki temu proces tworzenia aplikacji jest szybki i znacznie wygodniejszy niż w przypadku tradycyjnych narzędzi, a przede wszystkim nie wymaga superkomputera. Wykorzystanie modelu PGAS powoduje, że liczba konstrukcji, którą musi znać programista, jest niewielka. Jest to w zasadzie jedna klasa i kilkanaście metod, podczas gdy w tradycyjnych rozwiązaniach potrzeba ich znacznie więcej.

Biblioteka PCJ pozwala na tworzenie wysoko skalowalnych aplikacji obliczeniowych, jednocześnie umożliwiając implementację algorytmów Big Data czy AI. Co więcej, wykonane testy wydajnościowe pokazują, że aplikacje zbudowane z wykorzystaniem biblioteki PCJ są nawet kilkadziesiąt razy szybsze niż ich odpowiedniki używające Hadoopa czy Sparka.

Czy aplikacje w Javie nie są wolniejsze od C czy FORTRAN?

Tworząc bibliotekę PCJ, dużo uwagi poświęciliśmy porównaniu jej wydajności z aplikacjami napisanymi w tradycyjnych językach programowania. W części przypadków Java jest rzeczywiście wolniejsza (mniej więcej o połowę), ale dla niektórych algorytmów implementacje napisane w Javie z wykorzystaniem biblioteki PCJ są tak samo wydajne, jak ich odpowiedniki w C/C++. Przykładem może być renderowanie grafiki z wykorzystaniem algorytmu śledzenia promieni (raytracing) czy algorytmy grafowe. W ostatnim czasie pojawiły się nowe wirtualne maszyny Java pozwalające na zmniejszenie różnicy w wydajności pomiędzy C a Javą. Aplikacje korzystające z biblioteki PCJ stają się dzięki temu jeszcze szybsze. Udało nam się przeprowadzić testy na dużych superkomputerach – jednocześnie potrafimy wykorzystać ponad 200 tysięcy rdzeni obliczeniowych. To kilkakrotnie więcej niż największy komputer dostępny w ICM UW.

W przypadku superkomputerów istotnym elementem jest skalowalność aplikacji ograniczana przez algorytm lub szybkość wymiany danych pomiędzy poszczególnymi procesorami (komunikację).  Do przesyłu danych wewnątrz superkomputera wykorzystuje się najczęściej dedykowane rozwiązania sprzętowe, takie jak Infiniband, OmniPath czy Aries. W tej chwili biblioteka PCJ nie wykorzystuje w pełni dedykowanych rozwiązań sprzętowych, co ogranicza wydajność komunikacji. Mamy jednak pewne pomysły w tym zakresie i pracujemy nad znalezieniem rozwiązania.

Jakie są praktyczne zastosowania biblioteki PCJ?

Dotychczas koncentrowaliśmy się na stworzeniu biblioteki i testowaniu jej wydajności na wybranych algorytmach. Z wykorzystaniem PCJ zostały stworzone implementacje typowych testów wydajnościowych, ale też algorytmów przetwarzania grafów Graph500 czy szybkiej transformaty Fouriera. PCJ został wykorzystany do zrównoleglenia aplikacji do modelowania konektomu nicienia oraz do analizy sekwencji DNA. W tym ostatnim przypadku udało się ponad stukrotnie przyspieszyć wykonywane analizy polegające na poszukiwaniu fragmentów DNA wirusów w DNA człowieka. Konkurencyjne rozwiązania są co najmniej 2–3 razy wolniejsze.

Biblioteka PCJ jest także wykorzystywana podczas hackathonów organizowanych w ICM UW. Uczestniczący w nich studenci opracowali aplikacje do planowania rozmieszczenia stacji ładowania samochodów elektrycznych czy doprowadzenia sieci światłowodowej do punktów nieposiadających dostępu do szybkiego Internetu. W obu przypadkach najlepsze rozwiązania zostały napisane w Javie z wykorzystaniem biblioteki PCJ.

Jak można skorzystać z biblioteki PCJ?

Korzystanie z biblioteki PCJ jest bardzo proste. Ze strony http://pcj.icm.edu.pl należy pobrać plik biblioteki (jar) i umieścić w swoim projekcie Java. Na wspomnianej stronie znajduje się opis biblioteki i przykładowe kody źródłowe. Program można stworzyć i przetestować na dowolnym komputerze z Javą 1.8 (lub nowszą) przy wykorzystaniu typowego środowiska programistycznego (NetBeans, Eclipse, IntelliJ IDEA czy inne). Stworzoną aplikację można uruchamiać lokalnie lub na komputerach zdalnych. Aplikację PCJ można również uruchamiać w środowisku Hadoop czy Spark uzyskując znacznie większą wydajność.

Rozwój aplikacji z wykorzystaniem biblioteki PCJ jest prosty, ale wymaga zaprojektowania równoległego algorytmu. Tak więc programista musi znać podstawy programowania równoległego. W zamian uzyskuje możliwość efektywnej implementacji dowolnego algorytmy równoległego bez konieczności wpisania się w model MapReduce stojący za rozwiązaniami takimi, jak Hadoop czy Spark. Większa elastyczność pozwala na uzyskanie lepszej wydajności i skalowalności.

Dla programisty znającego nawet niezbyt dobrze Javę wykorzystanie biblioteki PCJ jest proste i nie nastręcza większych problemów. Dla osób rozpoczynających przygodę z programowaniem równoległym jest to znacznie prostsze niż korzystanie z tradycyjnych rozwiązań takich MPI czy OpenMP. Bardzo dobrze widzimy to w przypadku uczestników hackathonów w ICM UW czy studentów inżynierii obliczeniowej, którzy mając do wyboru różne narzędzia do tworzenia aplikacji równoległych najczęściej wybierają Javę i bibliotekę PCJ.

W tej chwili biblioteka PCJ dostępna jest w wersji 5.0.6 opublikowanej w listopadzie 2017 i wymaga Javy 1.8 lub nowszej. Aktualna wersja biblioteki jest dobrze przetestowania – przez ponad pół roku nie zostały znalezione poważniejsze błędy. Wersja 5 biblioteki została pobrana już ponad tysiąc razy. Rozwój biblioteki PCJ został opisany w 10 publikacjach naukowych a przykładowe zastosowania w dalszych 11. Biblioteka PCJ była kilkukrotnie prezentowana na dedykowanych warsztatach organizowanych w ramach konferencji naukowych. Jest też wykorzystywana w ramach przedmiotu programowanie równoległe na studiach inżynieria obliczeniowa w ICM UW i na kierunku informatyka na WMiI UMK. Mamy informacje, że biblioteka PCJ także wykorzystywana do nauki programowania równoległego w Brazylii i we Włoszech.

Kto stoi za rozwojem PCJ?

Pomysł stworzenia biblioteki PCJ powstał jesienią 2011 r. w trakcie seminarium magisterskiego prowadzonego przez prof. Piotr Bałę na UMK w Toruniu. Kolejne próby wykorzystania dostępnych narzędzi do napisania aplikacji równoległych w Javie nie powiodły się i wówczas pojawił się pomysł opracowania własnego rozwiązania. Prace nad prototypową implementacją podjął Marek Nowicki, a równolegle pracował nad tym Łukasz Górski. Pierwsza wersja biblioteki pojawiła się pod koniec 2011 r., szybko pojawiły się kolejne. W 2014 r. biblioteka została zaprezentowana na konferencji Supercomputing w USA, gdzie otrzymała nagrodę w konkursie HPC Challenge. Prace nad biblioteką PCJ stały się podstawą doktoratu Marka Nowickiego obronionego na WMIiM UW oraz Łukasza Górskiego i Magdaleny Ryczkowskiej (bronione w IPI PAN). Łukasz Górski zajmował się implementacją wybranych algorytmów, a Magdalena Ryczkowska algorytmami grafowymi. W pracach nad rozwojem biblioteki uczestniczy jeszcze Michał Szynkiewicz zajmujący się wprowadzeniem do biblioteki PCJ mechanizmów odporności na awarie (fault tolerance). Zespół zajmujący się PCJ jest niewielki, co stanowi dodatkową gwarancję, że biblioteka jest dobrze zaprojektowania i wykonana. Dla porównania, implementacjami modelu PGAS dla innych języków programowania zajmują się kilkunastoosobowe zespoły.

Jak rozwijana jest biblioteka PCJ?

Biblioteka PCJ rozwijana jest jako typowy projekt akademicki na otwartej licencji. Biblioteka jest bezpłatna, a jej kod źródłowy dostępny na serwerze GitHub. Początkowo biblioteka PCJ powstawała w ramach badań własnych, jednak w 2014 roku międzynarodowe konsorcjum CHIST-ERA przyznało na rozwój biblioteki dedykowane środki. W Polsce w ramach konsorcjum CHIST-ERA finansowanie zapewniło Narodowe Centrum Nauki. Należy podkreślić, że w konkursie CHIST-ERA finansowanie uzyskało zaledwie 7% złożonych wniosków, w tym ten przygotowany przez ICM UW we współpracy z IBM Research Zurich (Szwajcaria), Queen’s University Belfast (Wielka Brytania) i Bilkent University (Turcja). W ramach projektu ICM realizowało rozwój biblioteki, partnerzy z Zurichu zajmowali się wybranymi kernelami obliczeniowymi, takimi jak mnożenie macierzy rzadkich, koledzy z Belfastu badali możliwość wykorzystania kart graficznych i zaawansowanych własności wirtualnej maszyny Java, a naukowcy z Ankary stworzyli na podstawie PCJ bibliotekę do przetwarzania strumieniowego. Grant NCN zakończył się pod koniec 2017 roku, do końca 2018 trwa realizacja zadań przez pozostałych partnerów. Obecnie szukamy dalszych możliwości finansowania rozwoju biblioteki PCJ.

Piotr Bała

Prof. dr hab. Piotr Bała – fizyk, programista, specjalizuje się w fizyce molekularnej i komputerowej, obliczeniach równoległych i rozproszonych oraz modelowaniu układów dynamicznych metodami klasyczno-kwantowymi. Twórca biblioteki PCJ pozwalającej na efektywne zrównoleglanie obliczeń w języku Java. Współtwórca oprogramowania UNICORE umożliwiającego obliczenia rozproszone w biologii molekularnej i chemii kwantowej. Autor bądź współautor ponad 120 publikacji naukowych. Od 1993 r. współpracuje z ICM UW. Twórca studiów na kierunku inżynieria obliczeniowa w ICM UW. Pomysłodawca hackathonów Wielkie Wyzwania Programistyczne.