Wykład 13 Metody optymalizacji czasu wykonywania programów

Transkrypt

Wykład 13 Metody optymalizacji czasu wykonywania programów
Wykład 13
Metody optymalizacji czasu wykonywania programów
równoległych: algorytmy szeregowania zadań
Spis treści
1. Klasyfikacja metod optymalizacji wykonywania programów równoległych
2. Algorytmy optymalizacji wykorzystujące grafy następstwa zadań.
3. Algorytmy optymalizacji wykorzystujące grafy interakcji zadań.
1. Klasyfikacja metod optymalizacji wykonywania programów
równoległych
Program współbieżny jest to program, w którym wyspecyfikowano, że określone jego
fragmenty współbieżne (instrukcje lub ciągi instrukcji) maja się wykonać jednocześnie
(równolegle).
Program współbieżny może wykonać się na wielu procesorach lub na jednym
procesorze z podziałem czasu tego procesora miedzy fragmenty współbieżne.
Program równoległy jest to program współbieżny, który ma być wykonany na więcej
niż jednym procesorze.
Obliczenie równoległe (przetwarzanie równoległe) jest to wykonanie programu
równoległego lub wykonanie programu współbieżnego na wielu procesorach.
Zrównoleglenie programu lub obliczenia polega na wyodrębnienie fragmentów,
które mają wykonać się równolegle i przypisanie do ich wykonania potrzebnych
zasobów systemowych: procesorów, bloków wykonawczych i łączy komunikacyjnych.
Większość programów równoległych (lub programów po zrównolegleniu programu
sekwencyjnego) składa się z powiązanych relacjami następstwa fragmentów, które
mają być wykonane równolegle.
W pełni równolegle mogą wykonać się te fragmenty, które nie są zależne ze względu
na dane.
Fragmenty programów zależne ze względu na dane mogą wykonać się tylko
częściowo równolegle. Oznacza to, że niektóre instrukcje należące do różnych
fragmentów wykonywanych na różnych procesorach, będą musiały czekać na
dostarczenie im wyników instrukcji od których zależy ich wykonanie, wytworzonych
przez instrukcje na innych procesorach.
Zależność fragmentów programów ze względu na dane powoduje przestoje
procesorów o oczekiwaniu na potrzebne dane pochodzące z innych procesorów.
W granicznym przypadku może to prowadzić do sekwencyjnego wykonania
fragmentów programów pomimo rozłożenia ich wykonania na różnych procesorach.
Żaden program równoległy nie może być wykonany szybciej niż najdłuższy w całym
programie łańcuch fragmentów programu zależnych od siebie ze względu na dane.
Taki łańcuch jest nazywany ścieżką krytyczną programu.
Klasyfikacja metod optymalizacji
Zakładamy, że mamy program równoległy zbudowany z zadań sekwencyjnych dla
których określona jest relacja porządku wykonania. Mamy też system
wieloprocesorowy o określonej liczbie procesorów połączonych siecią przesyłania
danych.
Chcemy uszeregować zadania programu do wykonania w zadanym systemie.
Uszeregowanie polega na przypisaniu zadań programu do procesorów, określeniu
kolejności wykonania zadań w procesorach i określenia kolejności wykonania
komunikacji miedzy procesorami przy użyciu dostępnych zasobów komunikacyjnych.
Zakładamy, że procesor może w danej chwili wykonywać tylko jedno zadanie
obliczeniowe oraz że w danej chwili procesor może mieć oczekujących na wykonanie
kilka zadań.
Przy określaniu algorytmu szeregowania zadań programu stosowane są następujące
podejścia.
Szeregowanie lokalne lub globalne
Szeregowanie lokalne jest to określenie porządku wykonywania zadań programu lub
jego fragmentu na jednym procesorze.
Szeregowanie globalne jest to określenie porządku wykonywania zadań programu na
wszystkich procesorach systemu wykonawczego. W ramach szeregowania globalnego,
po wykonaniu przypisania zadań do procesorów jest wykonywane szeregowanie
lokalne zadań dla każdego procesora.
Szeregowanie statyczne albo dynamiczne
Szeregowanie statyczne polega na przypisaniu zadań do procesorów w czasie
kompilacji, przed wykonaniem programu.
Szeregowanie dynamiczne przypisuje zadania do procesorów podczas wykonania
programów (ang. at run-time). Szeregowanie dynamiczne nazywane jest również
równoważeniem obciążeń procesorów (ang. load balancing).
Szeregowanie optymalne lub sub-optymalne
Szeregowanie optymalne prowadzi do znalezienia uszeregowania, które zapewnia
minimalny czas wykonania programu. Algorytmy znajdowania takiego uszeregowania
mają złożoność wykładniczą.
Szeregowanie sub-optymalne prowadzi do znalezienia rozwiązania zbliżonego do
optymalnego ale przy złożoności algorytmu zredukowanej przeważnie do
wielomianowej.
Szeregowanie statyczne sub-optymalne aproksymacyjne lub heurystyczne.
Szeregowanie aproksymacyjne zakłada przeszukanie jedynie fragmentu przestrzeni
rozwiązań i zadowala się znalezieniem najlepszego rozwiązania w tym fragmencie
przestrzeni rozwiązań.
Szeregowanie heurystyczne wykorzystuje specjalne parametry, które w sposób
przybliżony modelują system wykonawczy.
Zdecentralizowane szeregowanie dynamiczne kooperatywne lub niekooperatywne
Szeregowanie kooperatywne zakłada współpracę między procesorami.
Szeregowanie niekooperatywne nie realizuje współpracy między procesorami.
Szeregowanie dynamiczne scentralizowane lub zdecentralizowane.
Szeregowanie scentralizowane zakłada podejmowanie decyzji co do optymalizacji w
jednym procesorze.
Szeregowanie zdecentralizowane zakłada podejmowanie decyzji rozproszone między
procesory systemu.
Wyrównywanie obciążeń procesorów kooperatywne lub niekooperatywne
Algorytm kooperatywny zakłada współpracę między równolegle działającymi
fragmentami algorytmu optymalizacyjnego.
Algorytm kooperatywny zakłada brak współpracy między równolegle działającymi
fragmentami algorytmu optymalizacyjnego i podejmowanie decyzji lokalnie w obrębie
pojedyńczych procesorów.
Szeregowanie preempcyjne i niepreemcyjne
Szeregowanie niepreempcyjne zakłada, że zadania będą wykonywać się po
uruchomieniu bez możliwości ich przerwania.
Szeregowanie preempcyjne zakłada że zadania będą wykonywać się z możliwością
ich przerwania i późniejszego dokończenia.
Szeregowanie adaptacyjne i nieadaptacyjne
Szeregowanie adaptacyjne zaklada, że algorytm szeregujący zadania może ulegać
dostosowywaniu się do zmiany parametrów lub struktury systemu wykonawczego oraz
do własności szeregowanego programu.
Szeregowanie nieadaptacyjne zaklada, że algorytm szeregujący zadania nie może
ulegać zmianom.
Optymalizacja programu
Lokalna
Globalna
Dynamiczna
Statyczna
Zdecentralizowana
Kooperacyjna
Optymalna
Scentralizowana
Niekooperacyjna
Sub-optymalna
Aproksymacyjna
Heurystyczna
Klasyfikacja metod optymalizacji wykonania programu równoległego w systemie
równoległym
W dalszym ciągu wykładu zajmiemy się statycznymi metodami optymalizacji czasu
wykonania programów równoległych.
W większości znanych metod takiej optymalizacji programy równoległe oraz systemy
wykonawcze są modelowane w postaci grafów.
W zakresie metod modelowania programów stosuje się przeważnie dwa typy grafów:
• grafy następstwa zadań w programie,
• grafy interakcji miedzy zadaniami w programie.
Grafy następstwa zadań w programie są to grafy skierowane, w których węzły
reprezentują zadania programu a krawędzie wzajemny porządek wykonania węzłów.
Zwykle, cykliczne grafy następstwa zadań programów sprowadza się do postaci
Skierowanych Grafów Acyklicznych (ang. Acyclic Directed Graphs - DAG) przez
rozwinięcie wszystkich ich iteracji.
Grafy interakcji między zadaniami w programie są to grafy nieskierowane, w których
węzły reprezentują zadania programu a krawędzie wzajemne interakcje między
zadaniami czyli komunikacje danych (częściowych wyników obliczeń), które
zachodzą podczas wykonania węzłów.
Przyklad grafu następstwa zadań (lewa strona), grafu interakcji zadań (prawa strona).
W obydwu typach grafów, węzły zadań (kółka) i krawędzie komunikacji (strzałki,
odcinki) mogą być adnotowane wagami.
Wagi węzłów grafów oznaczają łączny czas wykonania obliczeń zadań w procesorach
założonych do wykonania programu.
Wagi krawędzi grafów oznaczają czas wykonania komunikacji danych. Dla grafów
następstwa zadań podany jest czas komunikacji między zadaniami alokowanymi
rozdzielnie na procesorach (dla łącznej alokacji zadań zaklada się 0). Dla grafu
interakcji są to łączne czasy wzajemnej komunikacji dla zadanych par węzłów dla
łącznej i rozdzielnej alokacji zadań na procesorach.
W algorytmach optymalizacji programów równoległych opartych na wykorzystaniu
reprezentacji programu za pomocą grafu makro przepływowego DAG wykorzystuje
się często pojęcie ścieżki krytycznej grafu.
Ścieżka krytyczna grafu DAG programu jest to ścieżka prowadząca od węzła
wejściowego grafu do węzła wyjściowego, dla której suma wag węzłów i krawędzi jest
największa spośród wszystkich innych takich ścieżek w grafie.
2. Algorytmy statycznej optymalizacji wykorzystujące grafy następstwa
zadań.
Czynności wstępne dla szeregowania zadań programu:
Dla optymalizacji czasu wykonania programu współbieżnego w systemie o zadanej
liczbie procesorów i zadanej sieci połączeń między procesorami należy dla tego
programu stworzyć graf makroprzepływowy, określający następstwo wykonania
zadań w programie.
Dla stworzenia grafu makroprzepływowego należy pogrupować instrukcje programu
w makrowęzły i określić krawędzie następstwa łączące odpowiednie makrowęzły.
Można to zrobić poprzez zdefiniowanie najpierw grafu przepływu danych programu
(grafu przepływu danych między instrukcjami programu), w którym węzły oznaczają
instrukcje programu a krawędzie - przepływ danych między instrukcjami.
Graf przepływu danych programu, następnie będzie przekształcony w graf
makroprzepływu danych programu (graf makroprzepływowy programu), w którym
węzły (tzw. makrowęzły) stanowią sekwencje instrukcji wykonywane na jednym
procesorze a krawędzie określają przepływ danych między makrowęzłami.
Makrowęzły grafu programu nazywa się inaczej zadaniami (ang. task)
Makrowęzeł jest sekwencją instrukcji, która wykonuje się według następujących
reguł:
• makrowęzeł może rozpocząć wykonanie na jakimś procesorze dopiero wtedy gdy
wszystkie dane potrzebne do jego wykonania zostaną przesłane z innych
procesorów do pamięci operacyjnej procesora wykonawczego,
• makrowęzeł wykonuje się w całości na przypisanym mu procesorze w sposób
niepreempcyjny.
• w czasie wykonywania instrukcji procesor nie wysyła żadnych danych do innych
procesorów,
• dane wytworzone przez instrukcje danego makrowęzła są przesyłane do innych
makrowęzłów (ich procesorów wykonawczych) dopiero wtedy wykonywanie
makrowęzła zakończy się,
• po zakończeniu wykonania makrowęzła komunikacja danych do innych
makrowęzłów (procesorów) wykonuje się w sposób asynchroniczny.
Następnie należy wyznaczyć wagi węzłów i krawędzi, poprzez symulacyjne lub
rachunkowe oszacowanie odpowiednich czasów wykonania elementów programu w
zadanym systemie.
Uszeregowanie programu
Mając graf makro przepływowy programu należy opracować tzw. uszeregowanie
wykonania programu (ang. program schedule) w zadanym systemie.
Opracowanie uszeregowania programu polega na określeniu:
• na których procesorach systemu mają się wykonać zadania (węzły grafu),
• w jakiej kolejności i jak mają być zrealizowane transmisje danych między zadaniami
(węzłami) - tzn. przez które połączenia między procesorami,
• w jakiej kolejności mają być zrealizowane transmisje, jeśli połączeń między
procesorami jest mniej niż liczba krawędzi wychodzących z węzłów grafu.
Szeregowanie w systemie wieloprocesorowym z siecią dynamicznych połączeń
między procesorami
Jeśli w systemie możemy tworzyć w danej chwili mniej połączeń niż tego wymaga
graf programu, wtedy w sieci o dynamicznych (rekonfigurowanych) połączeniach
musimy tworzyć dynamicznie zmieniające się połączenia.
Robi się to przy pomocy przełącznika połączeń np. przełącznika krzyżowego.
Szeregowanie w systemie wieloprocesorowym z siecią statycznych (ustalonych)
połączeń między procesorami
Jeśli w systemie jest mniej połączeń między procesorami niż tego wymaga graf
programu, możemy realizować transmisje przez węzły pośredniczące między
potrzebnymi procesorami.
Czas tworzenia połączeń lub oczekiwanie na transmisje należy dodać do czasu
samej transmisji danych.
Diagram Gantta
Uszeregowanie programu zapisujemy w specjalnych tablicach zwanych diagramami
Gantta (ang. Gantt chart).
Diagram Gantta zawiera kolumny przyporządkowane wszystkim procesorom
systemu.
Wzdłuż tych kolumn idzie oś czasu, odmierzająca czasy wykonania zadań (węzłów) i
transmisji danych między nimi.
Podejmujemy decyzje o przypisaniu zadań do procesorów i zgodnie z nimi rysujemy w
kolumnach prostokąty o długości wzdłuż osi czasu, odpowiadającej czasowi
wykonania tych zadań.
Między prostokątami rysujemy linie (strzałki lub łuki) odpowiadające transmisjom
danych między zadaniami.
Rzuty tych linii na oś czasu muszą odpowiadać czasom wykonania transmisji, łącznie
z czasami przygotowania połączeń i wykonania sterowania.
Prostokąty zadań, do których dochodzą transmisje, przesuwamy w dół na osi czasu o
czasy wykonania transmisji.
Linie transmisji rysujemy szeregowo lub równolegle, zgodnie z możliwościami
szeregowego lub równoległego wykonywania transmisji z procesorów, zależnego od
liczby niezależnych łączy, w które wyposażone są dane procesory.
Prostokąty zadań umieszczamy w takich miejscach czasowych kolumn procesorów, w
których zakończone są wszystkie transmisje wyrażone krawędziami dochodzącymi do
odpowiednich węzłów w grafie.
Połączenia dynamiczne między procesorami tworzymy w miarę zwalniania się łączy
wykorzystywanych w bieżących transmisjach.
Czas wykonania programu jest określony czasem najpóźniejszego wykonania węzła
należącego do programu a więc jest to czas końca wykonania ostatniego prostokąta
przedstawiającego zadanie programu w diagramie Gantta.
Przykład 1
Dany jest przykładowy graf makroprzepływowy programu zawierający 5 makrowęzłów Ti
(lewy rysunek). Podane są różne wagi węzłów i krawędzi grafu.
Prawy rysunek przedstawia diagram Gantta uszeregowania zadań tego programu w
systemie złożonym z 2 procesorów P1, P2, mających po jednym łączu komunikacyjnym.
Połączenie między procesorami P1 i P2 zrealizowane jest jako statyczne połączenie
bezpośrednie łączy procesorów .
Pierwsza decyzja projektowa polegała na przypisaniu do P1 zadania T1.
Następnie przypisano T2 do P1 aby wyeliminować zewnętrzną realizację komunikacji
T1 do T2. Komunikacja T1 do T2 odbywa się z czasem 0 jako przesłanie wewnątrz
pamięci procesora P1.
Kolejna decyzja to przypisanie T3 do P1 oraz T4 do P2, co daje równoległe wykonanie
T4 z T3, z pokryciem czasu wykonania T4 z T3. T4 zaczyna wykonanie 1 jednostkę
czasu po zakończeniu T2, gdyż tyle czasu zajmuje komunikacja zewnętrzna T2 do T4.
Następny krok to przypisanie T5 do P1. Jest to bardziej korzystne niż przypisanie T5
do P2, gdyż T5 zaczyna się wykonywać 2 jednostki czasu po T4 ze względu na
komunikację T4 do T5 trwającą 2 jednostki.
T5 przypisane do P1 zaczyna się wcześniej po zakończeniu T3 niż w przypadku
przypisania T5 do P2, co miałoby miejsce o jedna jednostkę później ze względu na
komunikację zewnętrzną T3 do T4, która wystąpiłaby.
Finalny czas wykonania programu to 12 jednostek i jest to tzw. czas uszeregowania
(ang. scheduling makespan).
Przykład 2
Drugi przykład obrazuje szeregowanie programu dla systemu z dynamiczną
rekonfiguracją połączeń między procesorami.
Dany jest przykładowy graf makroprzepływowy programu zawierający 10 zadań.
Wszystkie węzły zadań (T z indeksami) i krawędzie grafu mają wagi równe 4
jednostkom czasu.
Przedstawimy na diagramie Gantta uszeregowanie zadań tego programu w systemie
złożonym z 4 procesorów P0 do P3, z których każdy ma 2 łącza komunikacyjne
(oznaczone przez 0, 1).
Połączenia między procesorami realizowane są w przełączniku krzyżowym.
Łączny czas eliminacji starego połączenia i stworzenia nowego połączenia wynosi 2
jednostki czasu.
Połączenia kolejnych łączy tego samego procesora do innych procesorów tworzone są
szeregowo.
Transmisje po łączach tego samego procesora podłączonych do łączy innych
procesorów odbywają się równolegle.
Graf makroprzepływowy programu
Podejmujemy kolejne decyzje co do przypisania zadań do procesorów.
Następnie określamy tworzenie połączeń dla wykonywanych zadań.
Będziemy rysować zadania i transmisje w diagramie Gantta (lewa część następnego
rysunku). Struktura połączeń w systemie jest zobrazowana na prawo od diagramu
Gantta.
Pierwsza decyzja to przypisanie kolejnych zadań z pierwszej warstwy grafu kolejnym
procesorom P0, P1, P2, P3.
Następnie przypisujemy kolejną warstwę zadań grafu do procesorów P1, P2, P3.
W procesorach P1, P2, P3 występują transmisje między parami zadań przypisanych do
tych procesorów a więc w obrębie pamięci operacyjnej (krawędzie idące w dół grafu).
Przyjmujemy, że czas tych transmisji wynosi 0, gdyż są one np. 100 razy szybsze niż
transmisje przez łącza zewnętrzne.
Po wykonaniu T12 procesor P0 musi wykonać 3 transmisje - do procesorów P1, P2, P3.
Najpierw tworzymy połączenia P0 z P1 oraz P0 z P2.
Po zakończeniu transmisji z P0 do P1, rozłączamy wykorzystane połączenie i łączymy
oswobodzone łącze P0 (łącze 0) z łączem 1 procesora P3 .
Odmierzamy czas 4 +2 = 6 i rysujemy linię transmisji z P0 do P3, a następnie rysujemy
zadanie T25 w kolumnie P3 .
Dalej przypisujemy trzecią warstwę węzłów grafu do procesorów P2, P3 a zadanie z
czwartej warstwy do procesora P3.
Realizujemy potrzebne połączenia.
Wprowadzamy linie transmisji i prostokąty zadań do diagramu Gantta.
Ostatnie zadanie programu kończy się wykonywać w chwili 28 i tyle wynosi czas
wykonania programu przy opracowanym uszeregowaniu zadań.
Przebieg rekonfiguracji połączeń w systemie w czasie dla potrzeb wykonania
programu pokazuje poniższy rysunek.
"connect"oznacza stworzenie połączenia. Tworzenie połączeń opisane jest
prostokątami z wyrażeniami typu "1.1 to 2.0" poniżej, co oznacza stworzenie
połączenia łącza 1 procesora P1 z łączem 0 procesora P2.
"request" oznacza wysłanie do sterownika rekonfiguracją żądania stworzenia nowego
połączenia. "ack" oznacza wysłanie z tego sterownika do obu procesorów
potwierdzenia, że żądane połączenie zostało stworzone i może być używane. "send"
oznacza zajście transmisji danych między zadaniami podanymi poniżej prostokąta.
Przy wyznaczaniu uszeregowania zadań programu wyznacza się czasy wykonania
zadań (składające się z czasu obliczeń, tworzenia połączeń i komunikacji danych ) dla
różnych przypisań i znajdujemy najkorzystniejsze.
Czasami korzystne jest zduplikowanie wykonania danego zadania na dwu lub więcej
procesorach , jeżeli daje to najkrótszy czas wykonania programu.
Pokazuje to poniższy schemat Gantta (prawa strona), gdzie duplikacja zadania T1 na
dwu procesorach (przypisanych kolumnom) daje najkrótszy czas wykonania programu,
którego graf jest podany po prawej stronie rysunku.
Algorytmy listowe szeregowania zadań
Algorytmy szeregowania zadań dostarczają metod automatycznego szeregowania
zadań w programach równoległych na podstawie grafów programów typu DAG.
Algorytmy szeregowania zadań dostarczające rozwiązań w pełni optymalnych mają w
ogólności złożoność wykładniczą, powodującą nieakceptowanie długie czasy
uzyskania rozwiązań.
Algorytmy dające rozwiązania optymalne o złożoności wielomianowej istnieją jedynie
dla założeń, upraszczających problemy w sposób mocno niepraktyczny (np. brak
komunikacji między zadaniami, regularne drzewiaste struktury grafu programu) i mają
znaczenie jedynie teoretyczne.
Dlatego najczęściej stosowane są algorytmy heurystyczne, które dostarczają
rozwiązań jedynie zbliżonych do optymalnych ale mają złożoność wielomianową.
Powszechnie stosowanym rodzajem heurystycznych algorytmów szeregowania zadań
w programach równoległych są algorytmy szeregowania listowego inaczej
algorytmy listowe (ang. list scheduling algorithms).
Ich nazwa bierze się z wykorzystywania list zadań uporządkowanych według
priorytetów określonych według różnych heurystycznych kryteriów.
Takie kryteria to np. Earliest Task First (ETF), czas najwczesniejszego rozpoczecia
wykonywania zadania na wolnym procesorze.
Udowodniono, że w przypadku zignorowania kosztów komunikacji między zadaniami
w listowym algorytmie szeregującym z dowolną heurystyką, uzyskana długość
uszeregowania C list jest określona formułą:
C list ≤ (2-1/P) Copt
gdzie P to liczba procesorów systemu wykonawczego,
Copt to długość uszeregowania optymalnego
Powyższe twierdzenie stwierdza, że długość uszeregowania uzyskana dla tych
założeń metodą szeregowania listowego może różnić się od optymalnego conajwyżej
dwa razy.
Algorytm szeregowania listowego przegląda wierzchołki grafu programu od początku
do końca, określa dla nich priorytety dla przydzielenia im procesora do wykonania,
ustawia wierzchołki w listy i według tych list stopniowo przypisuje wierzchołki do
procesorów systemu wykonawczego.
Ogólna zasada szeregowania listowego zakłada następujące kroki:
• określenie tzw. zbioru zadań gotowych jako takich, które nie mają poprzedników w
grafie albo których wszystkie poprzedniki zostały już przypisane do procesorów,
• określenie priorytetów dla zadań gotowych,
• uporządkowanie zadań gotowych według priorytetów,
• określenie listy wolnych procesorów dostępnych dla wykonania zadań,
• przypisanie zadania gotowego o najwyższym priorytecie do wybranego wolnego
procesora,
• usunięcie z listy zadań gotowych przypisanego zadania,
• usunięcie przydzielonego procesora z listy wolnych procesorów,
• aktualizacja listy zadań gotowych do wykonania przez wstawienie zadań, których
wszyscy poprzednicy zakończyli wykonywanie, z zachowaniem porządku
określonego priorytetami,
• aktualizacja listy wolnych procesorów,
• powtarzanie podanych wyżej kroków z odliczaniem bieżącego czasu wykonywania
programu wywołanym wykonaniami zadań i zwolnieniami procesorów, aż do
uszeregowania wszystkich zadań w programie.
Algorytmy listowe różnią się pod względem stosowanych reguł heurystycznych pod
względem:
• sposobu określania priorytetów zadań gotowych,
• sposobu wyboru wolnego procesora do wykonania najbardziej priorytetowego
zadania.
Dla określania priorytetów wykorzystywane są różne parametry elementów grafu
programu takie jak:
• długość najkrótszej ścieżki od danego węzła ni do węzła wyjściowego grafu - blevel i,
• długość najkrótszej ścieżki od węzła wejściowego grafu do danego węzła Ni - tlevel i,
• długość najkrótszej ścieżki od danego węzła Ni do węzła wyjściowego grafu, przy
uwzględnieniu jedynie wag węzłów obliczeniowych - s-level i ,
• najwcześniejszy czas startu zadania Ni - est i ,
• najwcześniejszy czas startu zadania Ni w grafie nieuszeregowanym - ast i.
• najpóźniejszy czas startu zadania Ni , który nie powoduje opóźnienia startu jego
następników - lst i,
• przynależność zadania Ni do ścieżki krytycznej.
Przy wykorzystaniu podanych wyżej parametrow wyróżnia się różne heurystyki, z
których dla przykladu wymienimy trzy podane poniżej :
HLFET (Highest Level First with Estimated Times) - nie uwzględnia wag krawędzi
i dla ustalania priorytetów wykorzystuje parametr b-level i, ma złożoność kwadratową
O(w2 ) od liczby w węzłów w grafie,
MCP (Modified Critical Path) - dla ustalania priorytetów zadań wykorzystuje
parametr lst i, zadanie o najwyższym priorytecie umieszcza się na procesorze który
zapewnia najwcześniejszy start, ma złożoność O(w2 log w) od liczby węzłów w
grafie;
ETF (Earliest Task First) - dla ustalania priorytetów zadań w każdym kroku
szeregowania wyznaczany jest czas startu każdego gotowego zadania na każdym
wolnym procesorze. Wybierana jest para (procesor - zadanie) dla której wartość
parametru est i jest najmniejsza. Złożoność tego algorytmu wynosi O(w2 P), gdzie w
to liczba zadań w grafie programu a P liczba procesorów wykonawczych w systemie.
Długość uszeregowania C ETF algorytmem listowym z heurystyką ETF spełnia
zależność:
C ETF ≤ (2-1/P) Copt + C,
gdzie P to liczba procesorów, Copt to optymalna długość uszeregowania a C to stała
zależna od własności grafu programu.
Przykład algorytmu listowego ETF
Mamy następujący graf makroprzepływowy programu który należy uszeregować do
wykonania w systemie czterech procesorów połączonych każdy z każdym.
Wierzchołki zadań są oznaczone liczbami na dwu poziomach oddzielonych kreską:
liczba na wyższym poziomie oznacza numer wierzchołka, liczba na niższym poziomie
oznacza jego wagę. Taki sposób graficznego oznaczania wierzchołków grafów jest
często stosowany w literaturze nt. szeregowania zadań.
Wagi krawędzi grafu oznaczają czasy komunikacji między zadaniami.
Poniżej, po lewej stronie podany dany jest diagram Gantta wyniku uszeregowania
algorytmem listowym. Wyznaczona długość uszeregowania wynosi 17 jednostek.
Otrzymany wynik dla czterech procesorów nie jest optymalny. Po prawej podano
diagram Gantta rozwiązania optymalnego (16 jednostek) na trzech procesorach
3. Algorytmy optymalizacji wykorzystujące grafy interakcji zadań.
Program jest reprezentowany przez graf interakcji zadań Gt (Vt, Et), w którym
wierzchołki należące do Vt to zadania a krawędzie (nieskierowane) należące do Et to
komunikacje między zadaniami.
System wykonawczy opisany jest grafem nieskierowanym Gp (Vp, Ep), wierzchołki
należące do Vt to zadania a krawędzie (nieskierowane) należące do Et to łącza dla
komunikacji danych między zadaniami.
Wierzchołki zadań grafu Gt są przypisywane do wierzchołków procesorów grafu Gp
w taki sposób aby zminimalizować czas wykonania programu.
Czas wykonania programu jest określony za pomocą podanych poniżej zależności.
Czas obliczeń procesora p Comp (p) jest wyliczany jako suma czasu obliczeń w(u)
wszystkich przypisanych mu zadań u.
Czas komunikacji procesora p określony jest jako suma czasu obliczeń w(u)
wszystkich przypisanych mu zadań u.
Całkowity czas wykonania programu T jest równy najdłuższemu czasowi wykonania
obliczeń i komunikacji, który występuje wśród wszystkich procesorów systemu.
T = max{α Comp(p) + β Comm(p)}.
gdzie p należy do Vp.
W powyższej formule α jest współczynnikiem zależnym od szybkości obliczeniowej
procesora p, natomiast β jest współczynnikiem zależnym od szybkości transmisji
łączy komunikacyjnych procesora p.
Przyklad
Lewa strona rysunku przedstawia graf interakcji żądań programu a prawa strona
przedstawia graf systemu stanowiącego macierz (kratę) (and. matrix, mesh)
prostokątną w węzłach, której znajdują się procesory. a krawędzie przedstawiają łącza
między procesorami.
\
Wynik odwzorowania grafu programu na graf systemu jest przedstawiony za pomocą
wpisania numerów zadań programu do węzłów (kółka) oraz zaznaczeniu krawędziami
przerywanymi potrzebnych komunikacji między procesorami.
Komunikacje, dla których nie istnieją w grafie systemu bezpośrednie łącza między
procesorami będą wykonane jako złożenia komunikacji poprzez węzły procesorów
pośredniczących.
Koszt tych komunikacji wyznaczany jest jako suma kosztu wszystkich komunikacji
składowych.
Optymalizacja wykonania programów przy wykorzystaniu grafu
interakcji za pomocą algorytmów genetycznych.
Algorytmy genetyczne należą do tzw. klasy algorytmów inspirowanych naturą,
które przeszukują przestrzeń rozwiązań problemu w sposób zbliżony do działania
ewolucji biologicznej gatunków.
Algorytmy genetyczne są bardzo często wykorzystywane do optymalizacji programów
równoległych a w szczególności dla optymalizacji programów reprezentowanych przez
grafy interakcji zadań.
Każdy chromosom reprezentuje jedno rozwiązanie problemu optymalizacji przypisania
zadań do procesorów.
Kolejne pozycje (alele lub geny) przyporzadkowane są kolejnym zadaniom w grafie.
Na każdej pozycji chromosomu wpisuje się wartość genu czyli numer procesora, na
którym przypisane pozycji zadanie ma się wykonać.
Jakość rozwiązania reprezentowanego przez dany chromosom jest określona przez
wartość tzw. funkcji dopasowania. Funkcja dopasowania podaje czas wykonania
programu przy alokacji zadań określonej przez chromosom.
Schemat ogólny prostego algorytmu genetycznego jest przedstawiony poniżej.
Wygeneruj
inicjalną roboczą populację osobników
Wyznacz
wartośći funkcji dopasowania dla wszystkich osobników
Uporządkuj
wszystkich osobników wg funkcji dopasowania
REPEAT
FOR i=1 to rozmiar.populacji DO
wybierz
dwu osobników z populacji
zastosuj
operacje genetyczne
wylicz
funkcję dopasowania potomka
ENDFOR
Wstaw
wszystkich potomków do populacji roboczej
Uporządkuj wszystkich osobników populacji roboczej wg funkcji dopasowania
Wybierz
populację roboczą dla dalszych iteracji
UNTIL
warunek stopu spełniony
Przed wykonaniem algorytmu genetycznego generuje się tzw. inicjalną populację
chromosomów, która będzie potem poddawana operacjom genetycznym:
krzyżowaniu i mutacji.
Populacja inicjalna zawiera pewną liczbę chromosomów, wygenerowanych w sposób
przypadkowy albo przy wykorzystaniu jakiejś heurystyki, opierającej się na
znajomości pewnej wiedzy o własnościach problemu.
Dla każdego chromosomu populacji inicjalnej wyznacza się wartość funkcji
dopasowania.
Następnie porządkuje się populację inicjalną według wartości funkcji dopasowania
chromosomów.
Operacja krzyżowania polega na wylosowaniu dwu chromosomów z populacji i
wzajemnej wymianie fragmentów obydwu chromosomów. Punkt krzyżowania może
być ustalony albo wyznaczany przed każdym krzyżowaniem przez losowanie.
Selekcja chromosomów dla poddania ich krzyżowaniu odbywa się przeważnie przy
wykorzystaniu jednej z dwu metod:
• mechanizm ruletki , w którym prawdopodobieństwo wylosowania chromosomu
jest proporcjonalne do jakości rozwiązania, które reprezentuje, wyznaczonej przez
wartość funkcji dopasowania,
• metoda rankingowa, przez wybranie dwu chromosomów spośród k najlepszych
osobników.
Po wybraniu dwu chromosomów następuje ich krzyżowanie, które dostarcza nowego
osobnika tzw. potomka - nowy chromosom jest zbudowany przez złożenie fragmentu
jednego i drugiego chromosomu.
W stosunku do otrzymanego chromosomu potomka stosuje się operację mutacji.
Polega ona na wylosowaniu określonego genu w chromosomie i dokonaniu zmiany
jego wartości poprzez wylosowanie nowej wartości spośród dopuszczalnych dla
problemu.
Dla otrzymanego nowego osobnika wyznacza się wartość funkcji dopasowania i
włącza się go do istniejącej roboczej populacji chromosomów.
Następnie dokonuje się wybór bieżącej populacji rozwiązań, które będą dalej
uczestniczyć w wykonywaniu algorytmu genetycznego.
Najczęściej polega to na wybraniu k najlepszych osobników (chromosomów) czyli k
najlepszych znalezionych dotąd rozwiązań.
Tak określone postępowanie stosuje się aż do osiągnięcia warunku stopu algorytmu.
Warunkiem stopu może być wykonanie zadanej liczby iteracji lub brak poprawy
wartości funkcji dopasowania dla najlepszych osobników podczas wykonania pewnej
liczby iteracji.
Funkcja dopasowania stosowana w algorytmie optymalizacji programu jest zadana
formułą
F = max{ ∑ Compi (p) + ∑ Commi (p)}.
gdzie
p jest procesorem należącym do systemu wykonującego program,
Compi (p), Commi (p) jest odpowiednio sumarycznym czasem obliczeń i czasem
komunikacji zadania i wykonanego na procesorze p,
sumowania ∑ są wykonane dla wszystkich zadań przypisanych do procesora p,
maksimum max jest wyznaczone biorąc pod uwagę wszystkie procesory systemu do
których przypisano do wykonania zadania z optymalizowanego programu.
W algorytmach szeregowania zadań dla bardziej skomplikowanych sformułowań
problemu lub przy szczególnych paradygmatach wykonania programów, często stosuje
się algorytmu genetyczne wspomagane zastosowaniem algorytmów listowych.
Dotyczy to np. szeregowania zadań dla systemów z dynamiczną rekonfiguracją
połączeń między klastrami procesorów ze wspólną pamięcią lub szeregowania dla
zadań dla systemów z dynamiczną rekonfiguracją struktury wielordzeniowych
procesorów systemu wykonawczego,
W takich przypadkach, algorytm listowy wyznacza funkcję dopasowania dla
rozwiązań algorytmu genetycznego, który rządzi przypisaniami zbiorów zadań
programów do bardziej skomplikowanych podsystemów wykonawczych.