o program
Transkrypt
o program
Programowanie Współbieżne PVM - wstęp Literatura Głównie informacje w sieci: http://www.csm.ornl.gov/pvm/pvm_home.html - strona główna pvm ● http://hector.tu.kielce.pl/pp/strona_pvm/index.htm tłumaczenie studentów dokumentacji do PVM ● Książki związane z tematyką przetwarzania równoległego i rozproszonego ● Google :) ● 2 Historia ● Idea meta-komputera ● Wiele nowych języków czy systemów – ● Linda, Express, P4, OpenMosix, MPI, PVM Prace nad PVM zaczęte w 1989 Oak Ridge National Laboratory. 3 Cechy ● ● ● ● Parallel Virtual Machine, jest to zestaw programów i bibliotek systemowych dający użytkownikowi możliwość połączenia grupy komputerów w jeden komputer wirtualny. Połączenia są dla użytkownika przeźroczyste PVM jest środowiskiem heterogenicznym, może łączyć komputery o różnej architekturze sprzętowej jak i softwarowej, różne formaty danych, szybkości, obciążenia maszyn i sieci. Pozwala tanim kosztem zbudować na bazie istniejącej sieci jeden duży multikomputer. 4 Zalety ● ● Koszt tworzenia PVM na bazującym sprzęcie jest znikomy. Można zoptymalizować obliczanie dobierając odpowiednie zadania do odpowiednich maszyn ● Łatwa skalowalność ● Spora dostępność ● Łatwość instalacji ● ● Tolerancja na błędy (istnieją funkcje sygnalizujące różne zdarzenia) Heterogeniczność 5 Wady ● ● Niewielka ilość wbudowanych metod synchronizacji procesów Potrzeba kompilować program na każdy host z osobna 6 Modele obliczeń ● ● ● ● PVM opiera się na założeniu że aplikacja składa się z kilku zadań Każde zadanie jest odpowiedzialne za część rachunkową obciążającą aplikację Czasami aplikacja jest równoległa ze względu na funkcje (np. Wprowadzanie, obliczenia, wyprowadzanie wyników) równoległość funkcjonalna Najczęściej stosowanym modelem jest równoległość danych. Te same procesy obliczają różne porcje danych. 7 Szybki start - instalacja ● ● Większość dystrybucji linuxowych ma pakiet pvm i pvm-gui lub też xpvm. Jeżeli zajdzie potrzeba można ściągnąć z http://www.netlib.org/pvm3/index.html ● Rozpakować tar xvf pvm3.4.4.tar ● Ustawić zmienne środowiskowe ● ● ● PVM_ROOT – katalog w którym zainstalowano PVM PVM_ARCH – określa platformę sprzętową na której środowisko zostało zainstalowane, można ustalić automatycznie przez program inicjujący. Wykonać make 8 Szybki start - konfiguracja ● ● ● Użytkownik powinien posiadać konta na maszynach które chce włączyć do środowiska PVM PVM używa protokołu RSH do uruchamiania demonów, można też ręcznie lub przez SSH. w katalogu domowym użytkownika powinien być plik konfiguracyjny .rhosts w którym to umieszcza się nazwy / adresy komputerów z których można się zalogować za pośrednictwem rsh bez podawania hasła. Plik ten powinien mieć uprawnienia 400 (rw-------) 9 Szybki start - konfiguracja SSH ● mkdir ~/.ssh; chmod 700 ~/.ssh; cd ~/.ssh; sshkeygen -t rsa -f id_rsa -P "";cp id_rsa.pub authorized_keys (lub cat id_rsa.pub >> authorized_keys) (stworzenie kluczy prywatnych i publicznych) ● export PVMNETSOCKPORT=40000 (ustawienie minimalnego portu UDP do bezpośredniej komunikacji) ● -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 40000:45000 -s 81.26.7.128/25 -j ACCEPT (ustawienia iptables ) 10 Szybki start - konfiguracja ● ● ● PVM_ROOT powinien być ustawiony niezależnie dla każdej maszyny. Przy niewłaściwym zakończeniu zostaje w katalogu /tmp plik pvmd.<uid> , który jest używany do autoryzacji i powinien istnieć tylko wtedy gdy demon pvmd działa. Może to być powodem nie uruchomienia się demona. w pliku /tmp/pvml.<uid> znajdują się logi uruchomienia demona 11 Szybki start - konfiguracja ● ● pliki uruchamialne powinny być w katalogu PVM_PATH Przy dodawaniu hostów może wystąpić problem gdy w pliku /etc/hosts mamy wpis typu: 127.0.0.1 localhost localhost.localdomain nazwa_hosta – powinien być adres hosta lokalnego a nie jego loopback 12 Zmienne środowiskowe ● PVM_ROOT – ścieżka gdzie zainstalowany jest PVM ● PVM_ARCH – architektura systemu ● ● ● PVM_TMP – tu umieszczane są pliki pvml.<uid> i pvmd.<uid> PVM_RSH – ścieżka do rsh jeżeli jest gdzie indziej niż zdefiniowano w $PVM_ROOT/conf/ $PVM_ARCH.def Można też określić by zamiast rsh używano ssh. PVM_PATH – ścieżka gdzie powinny się znajdować uruchamialne pliki naszych programów, domyślnie jest to: $HOME/pvm3/bin/$PVM_ARCH oraz 13 $PVM_ROOT/bin/$PVM_ARCH Zmienne środowiskowe ● ● ● PVM_WD – ścieżka robocza uruchamianych programów PVM_EXPORT – nazwy zmiennych do wyeksportowania od rodzica do dziecka przy pvm_spawn() PVMHOSTFILE – położenie pliku hostfile, opisującego hosty które mają wejść w skład maszyny wirtualnej. 14 Konsola PVM ● add – dodanie hosta ● alias – definiowanie listy komend ● conf - sprawdzenie aktualnej konfiguracji maszyny wirtualnej ● echo - wyświetla podany parametr; ● delete – usunięcie hosta ● halt – zatrzymanie PVM ● help – pomoc ● id - wyświetla ID zadań konsoli ● jobs - wyświetla działające zadania 15 Konsola PVM ● kill – usunięcie procesu o podanym identyfikatorze tid ● mstat - wyświetla informacje o danym hoście ● ps –a – pokazanie procesów w maszynie PVM ● pstat - wyświetla informacje o danym zadaniu; ● ● quit – wyjście z konsoli PVM (ale nie zatrzymanie tak jak w przypadku halt) reset - usunięcie wszystkich procesów z maszyny PVM ● setenv – wyswietlenie aktualnych zmiennych ● sig - wysyła określony sygnał do określonego zadania16 Konsola PVM ● spawn – uruchomienie procesów – count - liczba zadań, domyślnie 1; – host - uruchamia host'a; domyślnie jakikowiek; – ARCH - uruchamia host o danej architekturze; – ? - aktywuje debug'owanie; – -> przekierowuje strumień wyjściowy zadania na konsolę; – -> plik przekierowuje strumień wyjściowy zadania do pliku; – ->> plik j.w tylko że dopisuje się do pliku; – @ - śledzi zadanie, wyświetlając informacje na konsoli; – @plik - j.w tylko zapisuje do pliku; 17 Konsola PVM ● trace - wyświetla lub ustawia opcje śledzenia zadań; ● unalias - deaktywuje aliasy poleceń; ● version - wyświetla aktualną wersję PVM 18 Pierwszy program #include<stdio.h> #include<pvm3.h> int main(int argc, char *argv[]) { int myId, parentId, taskNo, tIds[3], i; char bufor[1024]; myId = pvm_mytid(); printf("[%x] startuje\n", myId); 19 Pierwszy program if (PvmNoParent == (parentId = pvm_parent())) { pvm_catchout(stdout); printf("[%x] tworze dzieci\n", myId); if (0 >= (taskNo = pvm_spawn("pogadanka", (char**) NULL, PvmTaskDefault, "", 3, tIds))) { printf("[%x] nie moge stworzyc dzieci\n", myId); pvm_perror("pvm_spawn"); pvm_exit(); return 1; } printf("[%x] stworzylem pomyslnie %i procesy\n", myId, taskNo); for(i=0; i<taskNo; i++) { printf("Dziecko nr %i, Tid: %x\n", i, tIds[i]); pvm_initsend(PvmDataDefault); pvm_packf("%s", "Czesc, dzialasz ?"); pvm_send(tIds[i], i+1); } } 20 Pierwszy program else { int bajtow, msgTag, tId, bufId; printf("[%x] Dziecko: moj rodzic %x\n", myId, parentId); bufId = pvm_recv(parentId, -1); pvm_bufinfo(bufId, &bajtow, &msgTag, &tId); printf("Wiadomosc ma %i bajty, id: %x; tid nadawcy: %x\n", bajtow, msgTag, tId); pvm_unpackf("%s", bufor); printf("%s\n", bufor); } pvm_exit(); return 0; } 21 Kompilacja gcc –L/$PVM_ROOT/lib/$PVM_ARCH –I$PVM_ROOT/include program.c –o program –lpvm3 Jeżeli użyjemy funkcji z group servera powinniśmy jeszcze dolinkować pvmg3 gcc –L/$PVM_ROOT/lib/$PVM_ARCH –I$PVM_ROOT/include program.c –o program –lpvm3 -lgpvm3 Przy kompilacji w systemie solaris należy dodać jeszcze opcje –lnsl –lsocket 22 instalacja Plik wykonywalny powinien trafić do katalogów $PVM_PATH na wszystkich komputerach wchodzących w skład PVM. Pewnym ułatwieniem będzie tu wspólny system plików np. NFS 23 instalacja LINUX I386 LINUX I386 LINUX I386 program program program.c program LINUX 64 LINUX 64 program.c program program 24 instalacja LINUX I386 LINUX I386 LINUX I386 LINUX I386 LINUX I386 program.c LINUX I386 program NFS 25 Plik hostfile ● ● ● ● ● Zawiera informacje o komputerach, które tworzą maszynę wirtualną. W pojedynczych wierszach umieszczone są nazwy hostów. Puste linijki są ignorowane Wiersze rozpoczynające się od znaku # są traktowane jako komentarz. Oprócz nazw hostów może zawierać parametry opcjonalne. 26 Plik hostfile ● ● lo – identyfikator użytkownika so =pw to ustawienie powoduje, że użytkownik jest proszony o podanie hasła w celu uruchomienia demona pvmd na zdalnym komputerze. ● dx = lokalizacja demona pvmd ● ep – lokalizacja aplikacji użytkownika ● sp – wartość określającą domyślną szybkość hosta 1..1000000 (szybkość ta jest względna, podawana w celach orientacyjnych) ● bx - lokalizacja debuggera, domyślna to $PVM_ROOT/lib/debugger ● wd – katalog roboczy domyślnie $HOME ● ip – nazwa hosta (umożliwia podanie alternatywnej nazwy hosta) ● so = ms ten parametr umożliwia ręczne uruchomienie demona pvmd 27 na zdalnym komputerze. Przykładowy hostfile # Linie komend zaczynające się od # (ignorowane) gstws ipsc dx=/usr/geist/pvm3/lib/I860/pvmd3 ibm1.scri.fsu.edu lo=gst so=pw # nadaj ustawienia domyślne następującym hostom z * * ep=$sun/problem1:~/nla/mathlib sparky #azure.epm.ornl.gov midnight.epm.ornl.gov # zastąp opcje domyślne nowymi wartościami * lo=gageist so=pw ep=problem1 thud.cs.utk.edu speedy.cs.utk.edu # maszyny do późniejszego dodania & # istnieje tylko potrzeba listingowania opcji potrzebnych &sun4 ep=problem1 &castor dx=/usr/local/bin/pvmd3 &dasher.cs.utk.edu lo=gageist &elvis dx=~/pvm3/lib/SUN4/pvmd3 28 Demon pvmd Do podstawowych funkcji demona PVM należą: zarządzanie procesami ● wykrywanie błędów ● 29 Start pvmd pvmd uruchomiony „ręcznie” konfiguruje się jako demon główny (master), ● Jeśli był uruchomiony przez głównego wówczas przyjmuje konfigurację od niego i występuje jako demon potomny (slave). ● Tworzy socket, przez który będzie komunikował się z innymi demonami. ● Tworzy log. /tmp/pvml.<uid> ● jeśli jest master odczytuje plik konfiguracyjny, hostfile. ● Po zakończeniu procedury startowej demon przechodzi w stan oczekiwania na nadejście 30 wiadomości lub zadania do wykonania ● pvmd - zakończenie pracy zatrzymanie demona pvmd następuje w przypadku: ● usunięcia go z maszyny wirtualnej ● utraty połączenia z innymi demonami ● wystąpienia błędu w systemie. 31 pvmd – zakończenie pracy Podczas zatrzymania demon zatrzymuje wszystkie zadania uruchomione przez siebie. ● Następnie wysyła sygnał do pozostałych węzłów informujący o zakończeniu przez niego pracy. ● Jeżeli wysłanie do pozostałych węzłów sieci komunikatu o zakończeniu pracy jest niemożliwe, to powiadomieniem o wyłączeniu tego hosta zajmuje się demon główny. ● 32 Komunikacja ● ● ● ● Funkcje nadawcze synchroniczne typu blokującego– blokują nadawanie procesu do momentu zakończenia nadawania komunikatu Funkcje odbiorcze typu blokującego i nie blokującego – wstrzymują wykonanie procesu w oczekiwaniu na odbiór komunikatu kreślonego typu lub umożliwiają jego odbiór prowadząc „nasłuch” w tle przy działającej aplikacji Komunikaty opatrzone są parą liczb całkowitych: tid i tag Dzięki etykiecie istnieje możliwość filtrowania komunikatów przy ich odbiorze ● Zamiast tag lub tid przy odbiorze można użyć wildcard (-1) ● Komunikaty są buforowane po stronie odbiorczej ● Zagwarantowane jest zachowanie kolejności komunikatów w kanale 33 tid S G 31 ● ● ● ● 30 29 H L 18 17 0 Pierwsze 0..17 L – lokalny identyfikator zadania dostępne jest 218 –1 = 262143 zadań na jednego hosta, 0 oznacza lokalny pvmd, w UNIXie pole L jest mapowane przez pvmd na PID H 18..29 numer hosta. Maksymalna liczba hostów 212-1=4095. Numer 0 oznacza lokalny pvmd. G 30 – używany w multicaście do oznaczania grup procesów. S 31 – Zaszłość historyczna w połączeniu z h używany był do adresowania demonów pvmd. 34 Wysyłanie komunikatu ● Inicjacja bufora ● Pakowanie ● Wysłanie 35 Odebranie komunikatu ● Odebranie ● Rozpakowanie 36 Zarządzanie buforami int pvm_mkbuf(int encoding) – Tworzy nowy bufor wiadomości. Zwraca identyfikator bufora encoding – określa sposób kodowania w buforze ● PvmDataDefault 0 kodowanie w formacie XDR ● PvmDataRaw 1 bez kodowania ● PvmDataInPlace 2 dane pozostają w miejscu. int pvm_freebuf(int bufid) – zwolnij bufor wiadomości. Jeśli zwróci wartość mniejszą od zera znaczy błąd int pvm_getrbuf(void) – zwraca identyfikator aktywnego bufora komunikatów do odbierania int pvm_getsbuf(void) – zwraca identyfikator aktywnego bufora komunikatów do wysyłania. int pvm_setsbuf(int bufid) - ustawia identyfikator aktywnego bufora komunikatów do wysyłania, zwraca poprzedni bufor int pvm_setrbuf(int bufid) – ustawia identyfikator aktywnego bufora komunikatów do odbierania zwraca poprzedni bufor int pvm_inistsend(int encoding) - tworzy bufor o określonym kodowaniu, zwraca jego identyfikator. (kodowanie jak w pvm_mkbuf) 37 Funkcje pakujące int info = pvm_packf( const char *fmt, ... ) int info = pvm_pkbyte( char *xp, int nitem, int stride ) int info = pvm_pkcplx( float *cp, int nitem, int stride ) int info = pvm_pkdcplx( double *zp, int nitem, int stride ) int info = pvm_pkdouble( double *dp, int nitem, int stride ) int info = pvm_pkfloat( float *fp, int nitem, int stride ) int info = pvm_pkint( int *ip, int nitem, int stride ) int info = pvm_pkuint( unsigned int *ip, int nitem, int stride ) int info = pvm_pkushort( unsigned short *ip, int nitem, int stride ) int info = pvm_pkulong( unsigned long *ip, int nitem, int stride ) int info = pvm_pklong( long *ip, int nitem, int stride ) int info = pvm_pkshort( short *jp, int nitem, int stride ) int info = pvm_pkstr( char *sp ) Pierwszy parametr to wskaźnik do pierwszego elementu tablicy nitem – ilość elementów stride – co który element Do jednego bufora można pakować kilka tablic z danymi różnego typu. 38 Funkcje rozpakowujące int info = pvm_unpackf( const char *fmt, ... ) int info = pvm_upkbyte( char *xp, int nitem, int stride) int info = pvm_upkcplx( float *cp, int nitem, int stride) int info = pvm_upkdcplx( double *zp, int nitem, int stride) int info = pvm_upkdouble( double *dp, int nitem, int stride) int info = pvm_upkfloat( float *fp, int nitem, int stride) int info = pvm_upkint( int *ip, int nitem, int stride) int info = pvm_upkuint( unsigned int *ip, int nitem, int stride ) int info = pvm_upkushort( unsigned short *ip, int nitem, int stride ) int info = pvm_upkulong( unsigned long *ip, int nitem, int stride ) int info = pvm_upklong( long *ip, int nitem, int stride) int info = pvm_upkshort( short *jp, int nitem, int stride) int info = pvm_upkstr( char *sp ) Pierwszy parametr to wskaźnik do pierwszego elementu tablicy nitem – ilość elementów stride – co który element Rozpakowywanie musi odbywać się w tej samej kolejności co pakowane. 39 Wysyłanie wiadomości int info = pvm_send( int tid, int msgtag ) wysyła wiadomość do odbiorcy. Jeżeli błąd to zwraca <0. tid – identyfikator odbiorcy msgtag – etykietka komunikatu int pvm_mcast(int *tids, int ntask, int msgtag) – rozgłoszenie komunikatu do wielu odbiorców. Jeżeli błąd to zwraca <0. tids – wskaźnik do tablicy tidów adresatów. ntask – ilość tidów w tablicy msgtag – etykietka komunikatu int info = pvm_psend( int tid, int msgtag, char *buf, int len, int datatype ) robi wszystko w jednym. Czyli inicjacja bufora pakowanie i wysyłanie. Jeżeli błąd to zwracane <0. tid – gdzie mamy wysłać wiadomość msgtag –etykietka komunikatu >=0. datatype – typ danych PVM_BYTE, PVM_SHORT, PVM_INT, PVM_FLOAT, PVM_CPLX, PVM_DOUBLE, PVM_DCPLX, PVM_LONG_BYTE, PVM_SHORT, PVM_INT, PVM_FLOAT, PVM_CPLX, PVM_DOUBLE,PVM_DCPLX, PVM_LONG 40 Odbieranie wiadomości int bufid = pvm_recv( int tid, int msgtag ) odbiór z czekaniem tid – skąd mamy odebrać wiadomość msgtag – jaką ma mieć etykietkę –1 wszystkie #include <sys/time.h> int bufid = pvm_trecv( int tid, int msgtag, struct timeval *tmout ) odbiór z timeoutem tid – skąd mamy odebrać wiadomość msgtag – jaką ma mieć etykietkę –1 wszystkie timeout – ile czasu mamy na nią czekać int bufid = pvm_nrecv( int tid, int msgtag ) – bez czekania tylko sprawdza i jak nic nie ma to idzie dalej. Jeżeli brak wiadomości to zwraca 0. tid – skąd mamy odebrać wiadomość msgtag – jaką ma mieć etykietkę –1 wszystkie int (*old)() = pvm_recvf(int (*new)(intbufid, int tid, int tag)) podmienienie funkcji odbioru 41 Inne informacje int info = pvm_sendsig( int tid, int signum ) wysłanie sygnału do danego procesu int info = pvm_notify( int what, int msgtag, int cnt, int *tids ) funkcja ta testuje wystąpienie zdarzeń takich jak dodanie hosta istnienie procesu, w rezultacie do procesu wywołującego tą funkcje wysyłane są komunikaty (sygnały) informujące o zajściu powyższych zdarzeń. int ntids = pvm_siblings( int **tids ) - zwraca numer i id procesów, które rozpoczęły się razem w pojedynczym wywołaniu. Ale tylko dla konsoli bo przy wywołaniu przez pvm_spawn zwraca zawsze jeden i identyfikator bieżącego procesu. ntids – ilość tidów tids – wskaźnik do tablicy gdzie ma umieścić identyfikatory bliźniaków 42 Zarządzanie procesami int pvm_mytid(void) – zwraca identyfikator zadania (TID) w postaci dodatniej liczby całkowitej. Jeżeli wartość jest ujemna to wtedy jest to błąd. Powoduje rejestracje zadania w systemie PVM. int pvm_exit(void) – służy do opuszczenia maszyny wirtualnej przez zadanie. Zwrócić może np. info PvmSysErr. int pvm_kill(int tid) – zatrzymuje dany proces. Wysyła mu SIGTERM. Jeżeli się uda zwracane jest 0 jak nie to liczba ujemna. 43 Zarządzanie procesami int pvm_spawn(char *task, char **argv, int flag, char *where, int ntask, int *tids) tworzy nowe procesy. Zwraca ilość stworzonych procesów lub numer błędu. task – nazwa programu wykonywalnego, który musi być w katalogu $PVM_PATH lub domyślnie w $HOME/pvm3/bin/$PVM_ARCH/ argv – wskażnik do tablicy argumentów przekazywanych do programu task flag – opcje PvmTaskDefault 0 – pvm wybiera sobie dowolną maszynę do wystartowania nowego procesu PvmTaskHost 1 – where określa na jakim hoście ma być uruchomiony proces PvmTaskArch 2 – where określa architekturę na jakiej uruchamiane będą procesy PvmTaskDebug 4 – uruchamia proces pod debuggerem PvmTaskTrace 8 – uruchomienie procesu z włączonym systemem traceingu where – gdzie ma być uruchomiony proces. Może to być nazwa hosta np. aom.bom.com albo nazwa architektury np. LINUX, SUN4, ntask – liczba kopii jaka ma być uruchomiona tids – Tablica o dlugości przynajmniej ntask , wypełniana jest identyfikatorami nowych procesów 44 Dynamiczna konfiguracja int pvm_addhost(char **hosts, int nhost, int *infos) – dodanie hosta do maszyny wirtualnej. hosts – wskaźnik do tablicy zawierającej nazwy hostów które zostaną dodane do maszyny wirtualnej, nhosts – liczba hostów do dodania infos – wskaźnik do tablicy w której funkcja zapisze statusy operacji włączenia hostów do maszyny. int pvm_delhost(char **hosts, int nhost, int *infos) – usunięcie hosta z maszyny wirtualnej. hosts – wskaźnik do tablicy zawierającej nazwy hostów które zostaną usunięte z maszyny wirtualnej, nhosts – liczba hostów do usunięcia infos – wskaźnik do tablicy w której funkcja zapisze statusy operacji usunięcia hostów z maszyny int pvm_halt(void) – zatrzymaj cały system pvm. 45 Dynamiczna konfiguracja int info = pvm_start_pvmd( int argc, char **argv, int block ) start nowego demona pvm. argc – ilość argumentów argv – tablica argumentów block - specyficzna liczba całkowita określająca czy blokować. Jeżeli >0 to dopóki wszystkie hosty z ewentualnego pliku hostfile nie zostaną dodane to funkcja ta jest blokowana 46 Funkcje informacyjne int pvm_mytid(void) – już wiemy int pvm_parent(void) – zwraca identyfikator rodzica, albo PvmNoParent jeśli nie został utworzony przez pvm_spawn. int pvm_pstat(int tid) – zwraca status danego procesu. PvmOk – jeżeli proces działa PvmNoTask – jeżeli brak procesu PvmBadParam – jeżeli zły parametr tid tid – identyfikator procesu int pvm_tidtohost(int tid) – zwraca identyfikator hosta (pvmd) na którym dane zadanie uruchomiono int pvm_perror(char *msg) – Zwraca informacje o błędzie. Podajemy dodatkowy opis. 47 Funkcje informacyjne int pvm_tasks(int which, int *ntask, struct pvmtaskinfo **taskp) – udziela informacji o zadaniach wykonywanych przez maszynę wirtualną. which - jakiego rodzaju zadania, 0 wszystkie, pvmd tid dla danego hosta tid podane zadanie ntask – zwraca ilość zadań taskp – wskaźnik do tablicy struktur danych zadań. struct pvmtaskinfo{ int ti_tid; // identyfikator zadania int ti_ptid; // identyfikator rodzica int ti_host; // identyfikator hosta, pvmd int ti_flag; // status zadania char *ti_a_out; // nazwa wywoŒanego zadania, wystartowane r•cznie zwracaj^ nic. int ti_pid; // pid procesu } taskp; 48 Funkcje informacyjne int pvm_getopt(int what) – pokazuje różne opcje pvm liba. what – co mamy pobrać PvmRoute 1 routing PvmDebugMas 2 debug mask PvmAutoErr 3 auto error reporting PvmOutputTid 4 standardowe wyjście dla dzieci PvmOutputCode 5 output msgtag PvmTraceTid 6 standardowe wyjście dla dzieci PvmTraceCode 7 trace msgtag PvmFragSize 8 message fragment size PvmResvTids 9 Allow message to reserved tags and TIDs zwracana wartość to: PvmRoute 0 PvmDontRoute 1 PvmAllowDirect 2 PvmRouteDirect 3 49 Ustawianie opcji int pvm_setopt(int what, int val) – ustawia odpowiednie opcje: PvmRouteDirect – używa TCP by połączyć bezpośrednio procesy PvmAllowDirect jest domyślny. PvmDebugMask – dla tej opcji val jest poziomem debugowania. PvmAutoErr: Domyślnie 1 włączone, 0 wyłączone 2 powoduje wyjście z programu po wyświetleniu komunikatu błędu. PvmOutputTidF: dla tej opcji val oznacza standardowe wyjście dla dziecka. PvmOutputCode: Wartość etykietki wiadomości używanej przy otrzymywaniu wiadomości zawierających wyjście od innych zadań. PvmFragSize: Określa ile bajtów ma zawierać wiadomość. PvmResvTids: jeśli 1 to pozwala wysyłać wiadomości z zarezerwowanymi etykietkami i do nie taskowych odbiorców. Normalnie domyślnie jest 0 i zwraca błąd PvmBadParam. 50 Grupy Group Server – dodatkowy demon działający pod kontrolą PVM zarządzający grupami procesów Uruchomienie $PVM_ROOT/lib/ $PVM_ARCH/pvmgs & Kompilacja programu wykorzystującego groupserver wygląda tak: gcc –L/$PVM_ROOT/lib/$PVM_ARCH –I$PVM_ROOT/include program.c –o program –lpvm3 -lpvmg3 51 Grupy int inum = pvm_joingroup(char *group) – dołączenie się do grupy. Zwracana wartość inum to identyfikator członka w grupie, group – nazwa grupy int pvm_lvgroup(char * group) – opuszczenie grupy. Jeżeli błąd to <0. group – nazwa istniejącej grupy. int inum = pvm_getinst(char *group, int tid) – zwraca inum identyfikator procesu w grupie. Licząc od 0. Jeżeli <0 to znaczy błąd. group – nazwa grupy tid – identyfikator procesu int pvm_gettid(char *group, int inum) – zwraca tid na podstawie identyfikatora grupy. Jeżeli błąd to <0. int pvm_getsize(char *group) – zwraca ilość członków grupy. Jeżeli <0 to znaczy błąd 52 Grupy int pvm_barrier(char *group, in count) – blokuje wywołujące procesy do czasu gdy count członków grupy group nie wywoła pvm_barrier. Funkcja zwraca 0 jeżeli ok. jeżeli nie to <0. group – nazwa grupy count – Ilość członków by przekroczyć barierę. jeżeli –1 to wszyscy członkowie grupy. int pvm_bcast(char *group,int msgtag) – wysyłanie komunikatu do wszystkich członków grupy. By wysłać taki komunikat nie trzeba być członkiem grupy. Jeżeli ok. to 0 jak nie <0. group – nazwa grupy msgtag >= 0 – etykieta komunikatu. 53 Grupy int pvm_reduce(void (*func)(),void *data, int count, int datatype, int msgtag, char *group, int root) – wykonanie globalnej operacji. func – definiuje operacje wykonywaną na globalnych danych. Predefiniowane funkcje to: PvmMin – minimum PvmMax - maksimum PvmSum – suma PvmProduct – iloczyn data – wskaźnik do początku lokalnych danych. Na wyjściu w procesie root dane zostaną nadpisane przez wynik. count – ilość elementów danych w tablicy data datatype – typ danych. PVM_BYTE, PVM_SHORT, PVM_INT, PVM_FLOAT, PVM_CPLX, PVM_DOUBLE, PVM_DCPLX, PVM_LONG msgtag – etykietka komuniktu <= 0. group – nazwa istniejącej grupy root – identyfikator procesu w grupie który zbierze wyniki 54 Grupy void func(int *datatype, void *, void *y, int * num, int *info) – funkcja użytkownika do operacji redukcji. datatype – typ danych na jakich będziemy operować x – to samo co data powyżej, czyli jakby dane wejściowe y – dane wyjściowe num – ilość danych x, to samo co count powyżej info – wyniki. 55 Grupy int info = pvm_scatter( void *result, void *data, int count, int datatype, int msgtag, char *group, int rootginst) wykonuje rozproszenie danych z określonej grupy roota dla każdego z elementów grupy w tym dla siebie result – wskaźnik początkowy tablicy o długości count i typie danych datatype który będzie nadpisany przez komunikat od roota grupy. (tu trafi część danych) data – wskaźnik do początku tablicy danych typu datatype skąd root będzie rozsyłał dane do innych członków grupy. Jeżeli grupa liczy n to data powinien mieć przynajmniej n*count Każdy z grupy w tym także root dostanie po kawałku z tablicy data. count – ilość elementów typu datatype które mają być wysłane do członków grupy. msgtag – etykietka group – nazwa grupy rootginst – identyfikator przywódcy grupy 56 Grupy int info = pvm_gather( void *result, void *data, int count, int datatype, int msgtag, char *group, int rootginst) root grupy zbierze informacje od innych i umieści w result. Rozmiar result w root musi być przynajmniej count*n (n- ilość członków w grupie). 57 Skrzynki kontaktowe int index = pvm_putinfo( char *name, int bufid, int flags ) – wkłada informacje do skrzynki. name – klucz bazy danych (nazwa klasy) bufid – uchwyt bufora wiadomości flags – flagi opcji PvmMboxDefault – usuwana przez właściciela PvmMboxPersistent – wiadomość pozostaje nawet jak właściciel wyjdzie. PvmMboxMultiInstance – trzymanie wiadomości o tych samych nazwach. PvmMboxOverWritable – pozwala na zapis oraz usuwanie przez innych. 58 Skrzynki kontaktowe int bufid = pvm_recvinfo( char *name, int index, int flags ) – działa jak pvm_recv z tą różnicą że bierze dane z bazy o pasującym kluczu name i index. flags: PvmMboxDefault – tylko dokładnie pasujące name i index bierz pod uwagę. PvmMboxFirstAvail – weź pierwszy rekord pasujący z name gdzie index jest większy bądź równy do danego parametru. PvmMboxReadAndDelete – przeczytaj i usuń. int info = pvm_delinfo( char *name, int index, int flags ) – usuwa wskazany rekord. Flagi nie są obecnie określone 59 Skrzynki kontaktowe int info = pvm_getmboxinfo( char *pattern, int *nclasses, struct pvmmboxinfo **classes) – podaje wskaźnik do listy struktur pvmmboxinfo. Pamięć jest alokowana przez libpvm i realokowana przy następnym wywołaniu. struct pvmmboxinfo { char *mi_name; int mi_nentries; int *mi_indices; int *mi_owners; int *mi_flags; }; 60 Skrzynki kontaktowe - przykład /*wyslanie*/ sprintf( message, "Pozdrowienia od procesu A. ); pvm_initsend( PvmDataDefault ); pvm_pkint( &mytid, 1, 1 ); pvm_pkint( &context, 1, 1 ); pvm_pkstr( message ); if (( pvm_putinfo( “News1”, pvm_getsbuf(), PvmMboxDefault )) == PvmExists) { printf( "Nie można umieścić wiadomości, News1 już istnieje”); exit( -1 ); } /*odebranie*/ if (( msg_buf = pvm_recvinfo(“News1”, 0, PvmMboxFirstAvail )) >= 0 ) { pvm_setrbuf( msg_buf ); pvm_upkint( &their_tid, 1, 1 ); pvm_upkint( &their_context, 1, 1 ); pvm_upkstr( message ); 61 } Forwarding wiadomości int info = pvm_pkmesg( int bufid ) – pakuje określoną wiadomość do bieżącego bufora nadawczego. Nagłówek2 Nagłówek1 Nadawca1, odbiorca1, rozmiar1... Treść1: 123, 321L, „bla bla bla” Nadawca2, odbiorca2, rozmiar2... Nagłówek1 Nadawca1, odbiorca1, rozmiar1... Treść: 123, 321L, „bla bla bla” „i coś jeszcze” 62 Forwarding wiadomości int newbufid = pvm_upkmesg( ) – rozpakowanie odebranej wiadomości. Nagłówek wiadomości zostaje jak w oryginale. int info = pvm_pkmesgbody( int bufid ) – pakuje tylko same dane z wiadomości. Typ pakowania musi się zgadzać Nagłówek1 Nagłówek2 Nadawca1, odbiorca1, rozmiar1... Nadawca2, odbiorca2, rozmiar2... Treść1: 123, 321L, „bla bla bla” Treść: 123, 321L, „bla bla bla” 63 Forwarding wiadomości pvm_recv(-1, -1); pvm_initsend(PvmDataDefault); pvm_pkstr("To jest wiadomość którą odebrałem..."); pvm_pkmesg(pvm_getrbuf()); 64 Inne mniej lub bardziej ciekawe Funkcje do tworzenia kontekstów: int ctx = pvm_newcontext( void ) int old_ctx = pvm_setcontext( int new_ctx ) int info = pvm_freecontext( ctx ) int ctx = pvm_getcontext( void ) 65 Inne mniej lub bardziej ciekawe int info = pvm_hostsync( int host, struct timeval *clk, struct timeval *delta ) – pobierz czas z hosta pvm. host – tid hosta clk – czas zdalnego hosta delta – różnica czasu int info = pvm_gettmask( int who, Pvmtmask mask ) - ślady maski, są one dziedziczone, służą do debugowania int info = pvm_settmask( int who, Pvmtmask mask ) pvm_reg_hoster() - rejestrowanie procesu jako hostera czyli takiego co to startuje inne demony. int cc = pvm_reg_rm( struct pvmhostinfo **hip ) - Rejestrowanie wywoływanego zadania jak zadania jako menadżera zasobów. int cc = pvm_reg_tasker() – Rejestrowanie wołającego zadania jako starter procesów. 66