1. Zavisnosti izmedju instrukcija Kao {to smo uo~ili proto~nost pove}ava performanse procesora na taj na~in {to pove}ava instrukcionu propusnost. Imaju}i u vidu da se u jednom ciklusu preklapa izvr{enje po nekoliko instrukcija, u proto~no organizovanom sistemu, kao posledicu dobijamo da se vreme ciklusa skra}uje, a brzina sa kojom se instrukcije izvr{avaju pove}ava. U idealnom slu~aju, propusnost proto~nog sistema se odredjuje kao 1/(vreme ciklusa), tako da }e petostepeni proto~ni sistem ~ije je vreme ciklusa 6 ns u idealnom slu~aju imati propusnost od 1/(6 ns) = 1.67 * 10 8 instrukcija/ s Sa druge strane neproto~no organizovan sistem ~ije je vreme ciklusa 25 ns ima}e propusnost od 1/ (25 ns) = 4 * 10 7 instrukcija/ s To zna~i da se u konkretnom slu~aju, dobija pobolj{anje koje je ve}e od ~etiri puta. Ipak u realnim situacijama, postoje brojni faktori koji ograni~avaju sposobnost proto~nog sistema da izvr{i instrukcije sa vr{nim performansama. Ukaza}emo sada, sa ne{to vi{e detalja, na prirodu ovih faktora. 1.1 Ograničenja zbog zavisnosti Kod programa, instrukcije ~esto zavise jedna od druge na taj na~in da izvr{enje pojedine instrukcije ne mo`e da po~ne sve dok prethodna instrukcija, ili ~ak prethodne dve, tri, ~etiri, ili vi{e instrukcija, ne zavr{e. Tako na primer, ovakve zavisnosti postoje kada neka instrukcija koristi rezultat generisan od strane prethodne instrukcije kao svoji izvori{ni operand. Ilustracije radi, neka je dat program koga čine dve instrukcije, I1 iza koje sledi I2. Kada se ovaj program izvršava na nekom protočnom sistemu tada može da se desi sledeći scenario: I2 po~ne sa izvršenjem, a da pri tome I1 nije još u potpunosti kompletirala svoje izvršenje. To znači da rezultat koga generiše I1 može biti još nedostupan za korišćenje instrukciji I2 kada je njoj, u datom trenutku, potreban. Pri ovome moramo biti svesni sledeće činjenice: Rezultati koji se dobijaju kada se instrukcije, na protočnom procesoru, izvršavaju moraju biti identični sa rezultatima koji se dobijaju kada se te iste instrukcije izvršavaju na strogo sekvencijalnom računaru. Da bi slikovito ukazali na ovaj efekat, razmatraćemo izvršenje sekvence koju ~ine slede}e dve instrukcije. I1: Add R1, R1, #8 ; (R1) (R1) + 8 I2: Mul R2, R1, #5 ; (R2) (R1) * 5 Neka je inicijalno (R1) = 4. Kada se instrukcije I1 i I2 izvršavaju po redosledu, što znači prvo se izvrši I1, a zatim I2, tada kao rezultat dobićemo (R2) = 60. Ali kada se instrukcije izvršavaju paralelno tada vrednost (R1) koju koristi I2 radi izračunavanja (R2) je 4 (tj. početna zadata vrednost), a ne
izračunata vrednost koja je (R1) = 12. Ovo ukazuje da će se u konačnom generisati nekorektni rezultat (R2) = 4*5 = 20. (Kada se obe instrukcije I1 i I2 izvršavaju paralelno, u trenutku pribavljanja izvornog operanda (R1) obe istovremeno čitaju vrednost (R1) = 4, što je korektna vrednost za I1, ali je nekorektna za I2). Naglasimo da ako se obe operacije obavljaju po redosledu, kako je to definisano programom, tada do generisanja pogrešnog rezultata neće doći. To znači da, u konkretnom slu~aju, instrukcije moraju da se izvršavaju jedna za drugom, prvo I1, a zatim I2. Razlog za redosledni način izvršenja je sledeći: Instrukcija I2 zavisi od rezultata koji se dobija nakon izvr{enja instrukcije I1. Analizirajmo sada izvršenje programske sekvence koju čine sledeće dve instrukcije. J1: Add R1, R3, #8 ; (R1) (R3) + 8 J2: Mul R2, R3, #5 ; (R2) (R3) * 5 Instrukcije J1 i J2 se mogu izvršavati paralelno, iz razloga što su obe operacije nezavisne. Oba primera jasno ukazuju na osnovno ograničenje koje se mora poštovati, kako bi se generisali korektni rezultati, a ono glasi: Dve operacije koje su medjusobno zavisne ne mogu se obavljati paralelno. Rezumevanje posledica ovog uslova predstavlja ključ za razumevanje osnovnih principa rada i projektovanja protočno organizovanih računara. Metod procenjivanja na koji način jedna instrukcija zavisi od druge je kritičan kod odredjivanja koliko paralelizima postoji u programu, i na koji način se taj paralelizam može iskoristiti. U konkretnom slučaju, da bi se iskoristio paralelizam na nivou instrukcija, neophodno je odrediti koje se instrukcije mogu izvršavati paralelno. Ako su dve instrukcije paralelne, a protočni sistem poseduje dovoljan broj resursa (minimalno, recimo da je sav hardver dupliciran), tada se instrukcije mogu izvršavati istovremeno, pa do zastoja u radu protočnog sistema ne dolazi. Kada su dve instrukcije zavisne, tada one nisu paralelne pa se moraju izvršavati po redosledu (mada odredjeni delovi procesiranja instrukcija se mogu preklapati). Ključni momenat, kod oba slučaja, je odredjivanje da li je jedna instrukcija zavisna od druge. 1.2. Tipovi zavisnosti Već smo ukazali da zavisnosti ograničavaju paralelizam izmedju instrukcija iz jednostavnog razloga što redosled izvršenja instrukcija mora biti takav da očuva korektnost generisanih rezultata. Zavisnosti se mogu kategorizirati na sledeća tri načina: 1. Kada su naredne instrukcije medjusobno zavisne zbog podataka ovu zavisnost nazivamo zavisnost- po-podacima (data dependencies), 2. Kada se u toku izvr{enja programa naidje na instrukciju uslovnog grananja put izvr{enja koji sledi zavisi od ishoda grananja. Za obe grupe instrukcija, one koje slede na sekvencijalnom putu i one koje slede na putu grananja, ka`emo da su upravlja~kizavisne (control dependent). Napomenimo da je bezuslovna instrukcija grananja specijalan slu~aj uslovne instrukcije grananja iz razloga {to je ishod grananja uvek ispunjen.
3. Za instrukcije koje radi izv{enja zahtevaju isti resurs (recimo isti ALU, mno`a~, deljitelj, ili dr.) ka`emo da su medjusobno strukturno-zavisne (structural dependent), ili zavisne-po-resursu (resource dependent). Zavisnosti izmedju instrukcija u stru~noj literaturi se ~esto nazivaju i hazardi. U su{tini zavisnost predstavlja potencijalnu opasnost koja ne mora da dovede do zastoja u radu sistema, a hazard je realna opasnost koja dovodi do zastoja u radu sistema. Tako na primer, ako je sistem peto-stepeni, a postoji zavisnost po podacima izmedju prve i stote instrukcije u programskoj sekvenci, tada do zastoja u radu sistema ne}e do}i jer je prva instrukcija odavno izvr{ena u trenutku kada se startuje sa izvr{enjem stote. Ali, za slu~aj da postoji zavisnost po podacima izmedju prve i druge instrukcije, tada do realnog zastoja dolazi pa za tu zavisnost ka`emo da predstavlja hazard. Drugim re~ima, zavisnost predstavlja potreban uslov da do zastoja u radu sistema dodje ali i ne mora, dok hazard predstavlja potreban i dovoljan uslov koji neminovno dovodi do zastoja u radu sistema. 1.2.1. Zavisnosti po podacima Za zavisnosti-po-podacima izmedju dve instrukcije kažemo da postoje kada programski redosled izmedju te dve instrukcije mora biti očuvan kako bi izvršenje programa bilo korektno. Podaci koji se koriste od strane instrukcije mogu se nalaziti u registaraskom polju (RF polju) CPU-a ili u radnoj memoriji. U zavisnosti od toga da li instrukcije pripadaju uzastopnim iteracijama jednog ciklusa ili ne pripadaju, razlikujemo: i) zavisnosti-po-podacima izmedju instrukcija koje nisu svojstvene (pripadaju) uzastopnim iteracijama jednog ciklusa. ii) rekurentne zavisnosti-po-podacima A. Zavisnosti-po-podacima izmedju instrukcija koje nisu svojstvene uzastopnim itaracijama jednog ciklusa U konkretnom slučaju postoje sledeća tri tipa zavisnosti: a1) prava zavisnost (true data dependency), ili tzv. RAW: read-after-write dependency a2) antizavisnost (ant-idependency), ili tzv. WAR: write-after- read dependency a3) izlazna zavisnost (output dependency), ili tzv WAW: write-after-write dependency WAR i WAW zavisnosti nazivaju se još i lažne-zavisnosti (false dependencies) ili zavisnosti-po-imenu (name dependencies). WAR i WAW zavisnosti se javljaju kada druga instrukcija upisuje u lokaciju koja može biti registar ili memorijska lokacija. Prava (istinska) zavisnost-po-podacima (RAW) javlja se kada se rezultat jedne instrukcije koristi kao ulazni operand za drugu instrukciju. Da bi se sačuvala korektnost, prva instrukcija mora da se izvrši pre druge. Lokacija gde se pamti prvo rezultat, a zatim taj rezultat koristi kao izvorište za neku narednu instrukciju, može biti memorijska lokacija ili registar CPU-a. Na Slici 1 prikazani su primeri istinske zavisnosti po podacima.
I1: Add R1, R2, R3 ; J1: Ld R1, mem [A] I2: Add R4, R5, R1 ; J2: Mul R2, R5, R1 a) definisano-korišćenje(define-use) b) memorijska-zavisnost (load-use) Slika 1. Primeri prave zavisnosti-po-podacima Kod primera na Slici 1a) instrukcija I2 zavisi-po-podacima od I1 jer I2 čita vrednost (sadržaj) registra R1 koji se postavlja od strane I1. Kada se zavisnost javlja zbog korišćenja rezultata neke operacije koji se ~uva u nekom od registara CPU-a (Slika 1a)) za tu zavisnost kažemo da je zavisnost sa defnisanim korišćenjem (define-use). Prava zavisnost-po-podacima može da se javi kada druga instrukcija (J2 na Slici 1b)), čita vrednost koju treba prvo dobaviti iz memorije u registar (instrukcijom J1 na Slici 1b) puni se R1 sadržajem memorijske lokacije mem[a] ). U ovom slučaju kažemo da se radi o memorijskoj zavisnosti, ili tzv. load-use dependency (vidi Sliku 1b)). Antizavisnost (WAR) se javlja kada prva instrukcija čita ulazni operand iz lokacije (registarske ili memorijske) u kojoj će biti upisan rezultat druge instrukcije. Da bi se sačuvala korektnost, prva instrukcija mora da dobavi svoj ulazni operand pre nego što će u tu lokaciju biti ipisana nova vrednost od strane druge instrukcije. Na Slici 2 prikazan je primer antizavisnosti I1: Sub R1, R2, R3 I2: Add R3, R4, R5 Slika 2. Primer antizavisnosti Izlazna-zavisnost (WAW) se javlja kada obe instrukcije upisuju u istu lokaciju. Da bi se sačuvala korektnost izvr{enja programa, rezultat druge instrukcije mora da bude konačna vrednost koja će se čuvati u lokaciju (registar ili memorijska lokacija). Na Slici 3 prikazan je primer izlazne zavisnosti. I1: Add R1, R2, R3 I2: Sub R1, R4, R5 Slika 3 Primer izlazlne-zavisnosti B. Rekurentne zavisnosti Ove zavisnosti javljaju se izmedju instrukcija koje pripadaju različitim iteracijama u okviru jednog ciklusa. Tipičan primer je prikazan na Slici 4 gde se uočava rekurentna zavisnost, odnosno vrednost x(i) zavisi od vrednosti x(i-1) koja se izračunava u prethodnoj iteraciji do i = 2,n x(i) = A*x(i-1) + B enddo U opštem slučaju rekurentna zavisnost je stepena k ako odgovarajuće izračunavanje zahteva da se prethodno odrede rezultati prethodnih k iteracija
x(i) = f(a,b,x(i-1), x(i-2), x(i-k)) 1.2.2. Strukturne zavisnosti Strukturna zavisnost se javlja kada dve instrukcije istovremeno zahtvaju korišćenje istog resursa. Ako resurs nije dupliciran tada instrukcije mora da se izrvšavaju sekvencijalno, prvo jedna a zatim druga, a ne paralelno. Resurs za koji se instrukcije takmiče može biti sabirač, množač, deljitelj, registarsko polje, ili neka druga komponenta. 1.2.3 Upravljačke zavisnosti Upravljačka zavisnost javlja se kada instrukcija zavisi od instrukcije uslovnog grananja. Naime, nije poznato da li instrukcija treba da se izvrši, ili ne treba, sve dok se ne razreši dilema oko grananja. Zbog ovoga, grananje mora da se obavi pre instrukcije. Da bi ukazali na ovaj problem jasnije analiziraćemo sledeći kodni segment. if p1 { s1; }; if p2 { s2; }; Iskaz s1 je upravljački (kontrolno) zavisan od uslova p1, dok je s2 upravljački zavisan od p2, a ne od p1. U principu postoje sledeća dva ograničenja koja se nameću od strane upravljačkih zavisnosti. 1. Instrukcija koja je upravljački zavisna od instrukcije Branch ne može se premestiti pre Branch-a jer njeno izvršenje ne bi više tada moglo biti kontrolisano od strane instrukcije Branch. Tako na primer, ne bi mogli uzeti instrukciju iz then dela iskaza if i premestiti je ispred iskaza if 2. Instrukcija koja nije upravljački zavisna od Branch-a ne može se premestiti nakon Branch-a jer tada njeno izvršenje postaje kontrolisano od strane Branch-a. Tako na primer ne može se uzeti iskaz pre iskaza if i premestiti ga u then delu. Upravljačke zavisnosti uspešno se rešavaju zahvaljujući kori{}enju slede}e dve osobine: a) prvo, instrukcije se izvršavaju u programskom redosledu. Ovo znači da ako se instrukcija nalazi ispred Branch-a ona se i izvršava pre Branch-a. b) drugo, detekcija Branch hazarda obezbedjuje da instrukcija koja je upravljački zavisna od Branch-a ne izvršava se sve dok se ne reši dilema o smeru grananja.