RSS

Płynąc potokiem

Liczba odsłon: 150

Nie po­my­lę się pew­nie twier­dząc, że na każ­dym kro­ku sły­szysz o tech­ni­kach po­to­ko­wych czy trans­fe­rach po­to­ko­wych. Dopóki mia­łeś szan­sę zetk­nąć się z tym ter­mi­nem je­dy­nie przy okaz­ji czy­ta­nia in­struk­cji do pły­ty głów­nej (od dłuż­sze­go cza­su pa­mięć pod­ręcz­na płyt głów­nych i pro­ce­so­rów pra­cu­je w try­bie po­to­ko­wym) i wie­dzia­łeś, że dzię­ki te­mu kom­pu­ter pra­cu­je szyb­ciej, nie by­ło naj­mniej­sze­go prob­le­mu. Jednak po­to­ko­wość wca­le nie mu­si ozna­czać szyb­koś­ci, co wi­dać choć­by na przy­kła­dzie no­we­go, hi­per­po­to­ko­we­go pro­ce­so­ra Intel Pentium 4 — do­brze jest więc wie­dzieć, na czym po­le­ga po­to­ko­wość i ja­kie są jej wa­dy i za­le­ty.

Przetwarza­nie sek­wen­cyj­ne

Jak wy­glą­dał­by trans­fer da­nych (na przy­kład z pa­mię­ci opera­cyj­nej) bez uczest­nic­twa po­to­ku? Dane by­ły­by od­naj­dy­wa­ne, prze­ka­zy­wa­ne do bu­fo­ra wyj­ścio­we­go, po­tem prze­no­szo­ne ko­lej­ny­mi stop­nia­mi bu­fo­rów pły­ty głów­nej, ukła­du ob­słu­gu­ją­ce­go pa­mięć oraz pro­ce­so­ra aż do re­je­stru pro­ce­so­ra. Powiesz: nic nie­zwyk­łe­go, tak prze­cież chy­ba się dzie­je. I masz rac­ję!

Zastanów się jed­nak jak dłu­go bę­dzie­my cze­kać od mo­men­tu do­star­cze­nia jed­nej por­cji da­nych do do­tar­cia ko­lej­nej? Zgadłeś: do­kład­nie ty­le sa­mo, ile cze­ka­liś­my na pierw­szą — czy­li zde­cy­do­wa­nie zbyt dłu­go.

Przykład ten moż­na zilus­tro­wać ana­lo­gią mo­to­ry­za­cyj­ną: dy­spo­nu­jąc au­to­stra­dą mo­żesz oczy­wiś­cie wpuś­cić na jed­nym koń­cu sa­mo­chód, po­cze­kać, aż do­je­dzie do koń­ca, a po otrzy­ma­niu syg­na­łu o po­myśl­nym do­tar­ciu wy­słać ko­lej­ny. Możesz jed­nak przy­spie­szyć ca­łą spra­wę wy­sy­ła­jąc od ra­zu – jed­no po dru­gim – wszyst­kie cze­ka­ją­ce au­ta: jeś­li wszyst­kie po­ja­dą z ta­ką sa­mą pręd­ko­ścią, do­ja­dą w ta­kiej sa­mej ko­lej­noś­ci, w ja­kiej zo­sta­ły wy­sła­ne.

I w ten spo­sób od­kry­liś­my właś­nie...

Przetwarza­nie po­to­ko­we

Już chy­ba wiesz, o co w tym wszyst­kim cho­dzi: wy­star­czy po­dzie­lić dro­gę, któ­rą mu­szą prze­być da­ne, na drob­ne ka­wał­ki. Pierwszy ka­wa­łek na­le­ży ła­do­wać da­ny­mi tak szyb­ko, jak tyl­ko się da, a po­zo­sta­łe bę­dą te da­ne obra­biać i prze­ka­zy­wać da­lej trzy­ma­jąc tem­po (oczy­wiś­cie mu­szą być od­po­wied­nio szyb­kie). Na pierw­szy ka­wa­łek po­cze­kasz so­bie tak czy tak, jed­nak po­tem co chwi­lę z koń­ca „ru­ry” wy­pa­dać bę­dzie ko­lej­na par­tia in­for­mac­ji.

Najładniej­szym ana­lo­giem po­to­ku jest właś­nie wspom­nia­na po­wy­żej ru­ra: jeś­li wrzu­cisz do le­żą­cej pra­wie po­zio­mo ru­ry kul­kę, w ja­kimś cza­sie do­le­ci ona do koń­ca. Jeśli jed­nak zacz­niesz wrzu­cać ca­łą ma­sę ku­lek, za­raz po po­ja­wie­niu się pierw­szej po­ja­wią się po­zo­sta­łe, gdyż tur­la­ły się za­raz za nią.

Taką właś­nie „ru­rę na da­ne”, naz­wa­ną ele­ganc­ko po­to­kiem (ang. pipe­line), zna­leźć moż­na w wie­lu no­wo­czes­nych ukła­dach sca­lo­nych. Dlaczego? Sygnały elek­trycz­ne roz­cho­dzą się ze skoń­czo­ną pręd­ko­ścią, zde­cy­do­wa­nie zbyt ni­ską dla me­ga­her­co­wych ukła­dów dość spo­rych roz­mia­rów. Zanim syg­nał do­tarł­by do koń­ca ukła­du (nie mó­wiąc już o dru­gim koń­cu płyt­ki dru­ko­wa­nej, na któ­rej za­mon­tu­je się układ), daw­no za­czął­by się dru­gi takt pra­cy. Rezultat: cał­ko­wi­ta ka­ta­stro­fa. Konstrukto­rzy dzie­lą więc ukła­dy i pły­ty na ka­wał­ki, któ­re są wy­star­cza­ją­co ma­łe, by prąd zdą­żył prze­biec przez każ­dą ich ścież­kę w cza­sie trwa­nia jed­ne­go cyk­lu ze­ga­ro­we­go, a na­stęp­nie łą­czą te ka­wał­ki tak, aby na­wza­jem prze­ka­zy­wa­ły so­bie da­ne.

Rozwiąza­nie ideal­ne?

Po tej lek­tu­rze mógł­byś po­myś­leć, że nie ma na tym świe­cie nic lep­sze­go od tech­ni­ki po­to­ko­wej, a po po­dzie­le­niu ukła­du na od­po­wied­nią licz­bę ka­wał­ków zbu­do­wa­nie pro­ce­so­ra tak­to­wa­ne­go ze­ga­rem 10 GHz jest ba­nal­nie pros­te. Jeśli tak, nie­ste­ty mu­szę Cię roz­cza­ro­wać.

Tam, gdzie blo­ki da­nych są na­praw­dę du­że, a zbyt ma­ła prze­pus­to­wość (trans­fer) zmo­rą kon­struk­to­ra, po­to­ko­wość jest zba­wie­niem. Nie znaj­dzie się już chy­ba pod­sys­te­mu pa­mię­ci opera­cyj­nej al­bo pa­mię­ci pod­ręcz­nej nie pra­cu­ją­cych w try­bie po­to­ko­wym. Jednak jest ku te­mu po­wód: pod­sys­te­my te prak­tycz­nie zaw­sze mu­szą prze­słać na­raz bar­dzo du­żo ko­lej­nych da­nych (o tym, dla­cze­go to ro­bią i jak dzia­ła pa­mięć pod­ręcz­na, na­pi­szę mo­że kie­dyś osob­ny ar­ty­kuł).

Porzućmy więc pa­mię­ci i zaj­mij­my się pro­ce­so­ra­mi: te, w za­leż­noś­ci od przy­dzie­lo­ne­go za­da­nia, al­bo prze­twa­rza­ją da­ne w spo­sób ciąg­ły, al­bo bez­na­dziej­nie mio­ta­ją się mię­dzy róż­ny­mi da­ny­mi, róż­ny­mi ope­ra­cja­mi i róż­ny­mi frag­men­ta­mi ko­du. Prawdę mó­wiąc, to dru­gie ro­bią pra­wie zaw­sze. Oczywiś­cie, są pro­gra­my, któ­re ob­ra­bia­ją wiel­kie, ciąg­łe blo­ki da­nych: na przy­kład pro­gra­my te­sto­we Intela po­ka­zu­ją­ce cu­dow­ną szyb­kość pa­mię­ci Rambus czy też pro­ce­so­ra Pentium 4. Przyznasz jed­nak, że ich uży­tecz­ność jest bar­dzo wątp­li­wa.

Bliskie idea­łu są pro­gra­my obra­bia­ją­ce pli­ki mul­ti­me­dial­ne — na przy­kład z mu­zy­ką czy obra­zem wideo. Technika po­to­ko­wa mo­że w ta­kich przy­pad­kach roz­wi­nąć swo­je skrzyd­ła i ob­śmie­wa­na tu przeze mnie kom­bi­nac­ja Pentium 4 plus RDRAM jest na­praw­dę szyb­ka. Jest jed­nak pe­wien prob­lem: ma­ło kto tak na­praw­dę zaj­mu­je się głów­nie na przy­kład ob­rób­ką wideo i ma­ło kto sko­rzy­sta z tej mo­cy. A już uru­cho­mie­nie pros­te­go pa­kie­tu biu­ro­we­go mo­że spro­wa­dzić na zie­mię użyt­kow­ni­ka dro­giej i ob­fi­tej w gi­ga­her­ce ma­szy­ny. Program bę­dzie dzia­łał po pros­tu wol­no.

Pytasz: co za­bi­ja zysk wy­ni­ka­ją­cy z po­to­ko­wo­ści? Odpowiedź jest bar­dzo pros­ta.

Opóźnienia

Gdy pro­gram co chwi­lę wy­ko­nu­je skok w ja­kieś od­leg­łe miej­sce pa­mię­ci lub raz po raz się­ga po da­ne od­da­lo­ne od sie­bie w pa­mię­ci o set­ki ki­lo­baj­tów, prze­sta­je mieć zna­cze­nie szyb­kość, z ja­ką po­tok mo­że z sie­bie wy­rzu­cać da­ne; zna­cze­nia na­bie­ra na­to­miast czas, po któ­rym na koń­cu po­to­ku po­ja­wia się pierw­sza in­for­mac­ja — czas, na­zy­wa­ny opóź­nie­niem (ang. la­ten­cy).

Porównaj­my na przy­kład pra­cę pro­ce­so­rów Pentium III i Pentium 4, wy­ko­nu­ją­cych choć­by pros­ty pro­gram do ob­słu­gi pocz­ty elek­tro­nicz­nej. Progra­my te­go ty­pu częs­to wy­ko­nu­ją sko­ki w róż­ne miej­sca pa­mię­ci. Co gor­sza, są to w spo­rej częś­ci sko­ki wa­run­ko­we, w przy­pad­ku któ­rych do sa­me­go koń­ca nie wia­do­mo, czy po­win­ny być wy­ko­na­ne, czy nie (prze­wi­dy­wa­nie sko­ków to też ma­teriał na osob­ny ar­ty­kuł). Obydwa pro­ce­so­ry w przy­pad­ku ta­kie­go sko­ku mu­szą opróż­nić po­tok, po czym na no­wo za­cząć go za­peł­niać. No do­bra, to za­peł­niaj­my go. W Pentium III po­tok ma głę­bo­kość 10, więc na pierw­sze re­zul­ta­ty dzia­ła­nia pro­ce­so­ra po sko­ku wa­run­ko­wym cze­ka­my dzie­sięć cyk­li ze­ga­ra. A Pentium 4? Jego hi­per­po­to­ko­wa archi­tek­tu­ra to po­to­ki o głę­bo­ko­ści… 20! Tak — dwa­dzieś­cia po­zio­mów każ­de­go po­to­ku, a więc mi­ni­mum dwa­dzieś­cia cyk­li ze­ga­ra stra­co­nych przy każ­dym sko­ku.

W skraj­nym przy­pad­ku pro­ce­sor Pentium 4 o częs­to­tli­woś­ci 1.5 GHz po­wi­nien mieć wy­daj­ność Pentium III 750 MHz. Tak źle nie jest nig­dy, ale mo­że być pra­wie tak źle, jeś­li do spra­wy do­łą­czy się „przy­szłość ryn­ku pa­mię­ci wed­ług Intela”, czy­li pa­mię­ci Rambus RDRAM.

Pamięć RDRAM ma mod­ną ostat­nio archi­tek­tu­rę quasi-sze­re­go­wą: ścież­ka da­nych jest bar­dzo wą­ska (8 bi­tów w po­rów­na­niu do 64 bi­tów ofe­ro­wa­nych przez mo­du­ły DIMM SDRAM), lecz tak­to­wa­na wy­so­ką częs­to­tli­woś­cią i pra­cu­ją­ca w try­bie po­to­ko­wym. Może już jes­teś w sta­nie zgad­nąć, ja­ka jest naj­więk­sza wa­da ta­kie­go roz­wią­za­nia? Tak, bar­dzo do­brze! Opóźnienia! Zanim po­tok pa­mię­ci się za­peł­ni i do pro­ce­so­ra do­pły­nie pierw­szy wiersz da­nych, mu­si on stać i cze­kać. Potem po­tok do­star­cza in­for­mac­je z nie­sa­mo­wi­tą wy­daj­noś­cią, ale za­nim speł­ni swo­ją funk­cję, pro­ce­sor już zacz­nie wy­ko­ny­wać skok wa­run­ko­wy, opróż­ni po­to­ki swo­je i pa­mię­ci i za­ba­wa za­czy­na się od po­cząt­ku.

Przesadze­nie z po­to­ka­mi ma więc skut­ki po­zy­tyw­ne i ne­ga­tyw­ne: co praw­da nie­któ­re pro­gra­my uwiel­bia­ją dłu­gie po­to­ki i nig­dy nie do­pusz­cza­ją do ich opróż­nie­nia, lecz wy­raź­na więk­szość czer­pie zys­ki z jak naj­mniej­szych opóź­nień — a-wy­dłu­ża­nie po­to­ków za­zwy­czaj li­nio­wo zwięk­sza opóź­nie­nia.

Na ko­niec

Od archi­tek­tu­ry po­to­ko­wej przy obec­nym sto­pniu roz­wo­ju elek­tro­ni­ki uciec się nie da. Nie mia­ło­by to zresz­tą sen­su, bio­rąc pod uwa­gę oczy­wi­stą prze­wa­gę krót­kich po­to­ków nad prze­twa­rza­niem czys­to sek­wen­cyj­nym. O tym jed­nak, czy po­tok da nam szyb­kość, czy też spo­wol­ni pra­cę ca­łej ma­szy­ny, de­cy­du­je do­bra­nie je­go głę­bo­ko­ści do kon­kret­ne­go za­sto­so­wa­nia. Procesor o bar­dzo wy­so­kiej częs­to­tli­woś­ci ze­ga­ra i bar­dzo dłu­gim po­to­ku świet­nie spraw­dzi się na przy­kład przy re­kom­pre­sji fil­mu z for­ma­tu MPEG 2 do MPEG 4, lecz przy pi­sa­niu tek­stu i czy­ta­niu stron WWW znacz­nie szyb­szy bę­dzie pro­ce­sor o znacz­nie mniej­szej częs­to­tli­woś­ci ze­ga­ra i znacz­nie krót­szym po­to­ku (tak, jak na przy­kład ro­dzi­na AMD K6, któ­rej tyl­ko sześ­cio­ele­men­to­we po­to­ki wspo­ma­ga­ne nie­sa­mo­wi­cie sku­tecz­ną jed­nost­ką prze­wi­dy­wa­nia sko­ków do dzi­siaj są wzo­rem do na­śla­do­wa­nia).