Kungliga Tekniska Högskolan Institutionen för elektronik-, dator-, och programvarusystem (ECS) Examinator: Johan Montelius, johanmon@kth.se Handledare: Pontus Nyman, företag ÅF, pontus.nyman@afconsult.com Författarens e-postadress: frutte@kth.se Utbildningsprogram: Elektroteknik, 270 poäng Omfattning: 14925 ord inklusive bilagor Datum: Examensarbete inom Elektroteknik, kurs 2G1004, 30 poäng GPU som en generell beräkningsprocessor
Sammanfattning Den nya generationen av grafikkort har en så enorm beräkningskapacitet idag att den slår en vanlig dual-core processor med en faktor på 10 när det kommer till beräkningskraft mätt i FLOPS (FLoating point Operations Per Second), antal flyttalsoperationer per sekund. Denna kraft kombinerat med dess stora mängder grafikminne samt nyvunna framsteg inom minneshanteringen har gjort grafikprocessorn till ett attraktivt alternativ för att göra vetenskapliga beräkningar. Beräkningar som i allmänhet består av en stor datamängd som i högre grad kan beräknas parallellt än i många andra applikationer. Att kontrollera denna kraft har tidigare inte varit en enkel uppgift och möjligheterna att programmera GPU har inte varit många. Detta var på grund av dess utformning som skapade många olika syntaxoch genomföringsproblem som var svåra att hantera för en vanlig programmerare som inte var införstådd med grafikprogrammering. Målet med denna undersökning har varit att försöka besvara frågan hur pass generell grafikprocessorn egentligen är, samt att besvara frågan om General- Purpose computation on GPU s (GPGPU) är en teknik att räkna med eller om tekniken är för krånglig att använda så att det inte är värt det extra arbetet som krävs av utvecklaren. Dessa frågor har besvarats genom att studera vad andra gjort inom området och hur de har använt grafikprocessorn. Samt även egna tester har gjorts för att analysera programmerbarheten och prestandan hos grafikprocessorn. Testerna som gjordes är menade att ge en inblick inom tre områden. Med vilken hastighet dataöverföringen sker till och från grafikkortet samt grafikprocessorns egen minneshastighet. Detta gjordes för att avgöra hur stor datamängden måste vara för att det ska var lönt att köra applikationen på grafikkortet. Det andra testet var en matrisberäkning med målet att visa hur stor prestandaökning som kan uppnås då en uppgift blir optimalt parallelliserad för GPU. Detta försök var också tänkt att ge en indikation på fördelarna att gå ifrån det sekventiella tankesättet och istället tänka parallellprogrammering vilket är tillämpbart på alla varianter av flerkärniga processorer. Slutligen gjordes ett test för att visa en verklig tillämpning där en krävande faltningsberäkning utfördes med hjälp av fouriertransform på Nvidias 8800GTX grafikprocessor och dessa resultat jämfördes sedan med en dualcore processor. i
ii
Abstract The new generations of graphics cards have such a huge calculation capacity today that it strikes a typical dual-core processor by a factor of 10 when it comes to computational power measured in FLOPS, the number of floating point operations per second. This force, combined with its large amounts of video memory and the new-won progress in the memory management has made the GPU to an attractive option for scientific calculations. Calculations that generally consist of a large data set that in a higher degree can be calculated in parallel than many other applications. To master this power has not been such an easy task and the possibilities to program GPU has not been so many. This was because of its design that created many different syntax and implementation problems that were difficult to handle for an ordinary programmer who weren t familiar with graphic programming. The aim of this study was to try to answer the question how general the GPU actually is, as well as to answer the question if General-Purpose Computation on GPU s (GPGPU) is a technology to count with, or if the technology is too complicated to use so that it is not worth the extra work required of the developer. These questions have been answered by studying what others have done in the area and how they have used the GPU. Even their own tests have been done to analyze programmable and performance of the GPU. The tests that were made are meant to give an insight in three areas. The speed of data transfer to and from the graphics card and graphic processor's own memory speed. This was done to determine how large amount of data must be to make it worth running the application on the graphic card. The second test was a matrix computation with the aim to show how much performance increase can be achieved when a task is optimal parallised for the GPU. This attempt was also meant to give an indication of the benefits to go from the sequential thinking and instead consider parallel programming which is applicable to all variations of multicore processors. Finally, it was a test to demonstrate a genuine application of a demanding convolution calculation conducted with the help of Fourier transform on Nvidia 8800GTX GPU and the result was then compared with a dual-core processor. iii
iv
Förord Denna rapport är resultatet av mitt examensarbete som gjordes under våren 2008 på företaget ÅF System i Kista. Under examensarbetets gång på ÅF har jag lärt mig hur mycket arbete det egentligen är att göra en studie av detta slag. Det har varit en rolig och lärorik tid på ÅF och det kändes som en bra och givande arbetsplats med en trevlig stämning bland kollegerna. Jag skulle framförallt vilja tacka två personer som har hjälpt mig under examensarbetets gång. Pontus Nyman och Johan Montelius. Pontus var min handledare på ÅF. Han tog sig tid och hjälpte mig med allt jag behövde hjälp med. Han var också ett stort stöd under denna tid. Johan var min handledare och examinator på KTH. Johan har varit till stor hjälp under examensarbetets gång och givit mig mycket konstruktiv kritik som har förbättrat rapporten och mitt sätt att tänka. Han har också haft goda synpunkter på de tester jag gjort och hjälp mig att tyda resultaten jag fått fram. v
vi
Innehållsförteckning 1 Inledning... 1 1.1 Bakgrund... 2 1.2 Övergripande syfte... 3 1.3 Avgränsningar... 4 1.4 Mål... 4 1.5 Översikt... 5 2 Teori... 7 2.1 Moores lag... 8 2.2 Parallellprogrammering... 9 2.3 Amdahls och Gustafsons lag... 11 2.4 Grafikprocessorn... 15 2.5 GPU användning... 22 2.6 Några programmeringsspråk för GPGPU... 26 3 Utformning av testerna... 29 3.1 Överföringshastighet... 30 3.2 Multiplikation av två matriser... 31 3.3 Faltning med FFT... 33 4 Resultat... 37 4.1 Hårdvara... 38 4.2 3DMark06... 38 4.3 Överföringshastighet... 39 4.4 Multiplikation av två matriser... 42 4.5 Faltning med FFT... 44 5 Diskussion... 47 5.1 Slutsatser... 47 5.2 Framtida arbete... 50 Källförteckning... 51 Bilaga A: Grafikkortet... 53 Specifikationer: Asus GeForce 8800GTX... 53 vii
viii
Inledning 1 Inledning Sedan några år har programutvecklarna stått inför ett paradigmskifte inom mjukvaruutveckling, en förändring som är av samma omfattning som övergången till programmering inom objektorientering var på 90-talet. Även om objektorienteringens klasser och objekt först verkade svåra och besvärliga när de kom så är det ingenting mot svårigheterna som kommer av programmeringsmodellen för parallella beräkningar. Det har länge funnits en sorts oäkta parallellprogrammering (concurrency programming) i vanliga program. De programmen körs som om de vore parallella för användaren men i verkligheten är det så att de körs på endast en processor och kan därför inte exekveras parallellt utan endast sekventiellt. Dessa används framförallt för att logiskt separera oberoende instruktionsflöden, det vill säga i vilken ordning instruktionerna och funktionsanropen exekveras. De används även för att öka prestandan antingen genom att dra nytta av multipla fysiska processer eller genom att utnyttja fördröjningar i andra delar av applikationen. Äkta parallellprogrammering har också funnits ett tag men har egentligen inte varit så aktuellt på grund av dess komplexitet förrän 2003. Då processortillverkarna i stort sett var tvungna att ta beslutet att gå över till multi-core processorerna. Detta berodde på stora svårigheter med att höja klockfrekvensen ytterligare på grund av hög effekt- och värmeutveckling i processorn. Detta syns i Figur 2. Idag är det vanligast med två eller fyra kärnor i en vanlig PC men det dröjer inte länge innan antalet kärnor kommer att bli flera. Intel presenterade redan hösten 2007 en prototyp med så många som 80 stycken kärnor. Fram till 2003 gick allting bara fortare för varje lyckad processorgeneration som kom ut på marknaden och mjukvaruutvecklarna behövde inte egentligen göra så mycket för att få ökad prestanda i sina program, vilket har kallats för The free lunch. Detta är inte längre möjligt för mjukvaruutvecklarna på grund av att dagens flerkärniga processorer kräver effektivare och smartare parallellisering av problemen för att de ska kunna användas så maximalt som möjligt. De flerkärniga processorerna har ju lägre klockfrekvens per kärna jämför med de äldre processorerna och det säger sig självt att program som körs sekventiellt då börjar gå långsammare än vad de gjorde tidigare. Programmerarna måste alltså idag lägga mer tid på designen av programmen och börja tänka på hur de kan delas upp i delar för att köras så effektivt som möjligt på alla de kärnor som är till förfogande. Eftersom 1
Inledning utvecklingen nu går mot flera kärnor i en processor har detta gjort att fler fått upp ögonen på en processor som funnits på marknaden en längre tid och redan består av många processorer, och det är grafikprocessorn. Denna processor består av väldigt många processorer och är konstruerad för att utföra matematiska operationer snabbare på stora mängder data och så mycket som möjligt samtidigt eftersom detta är precis vad som behövs för att rendera grafik. Den har alltså en otroligt stor beräkningspotential, vilket har gjort att intresset för att använda denna till generella beräkningar som i vanliga fall körs på Central Processing Unit (CPU) har ökat. Därav har begreppet General Purpose computation on GPU s (GPGPU) kommit som betyder att använda grafikprocessorn till att köra vanliga ickegrafiska beräkningar istället för att den bara ska hantera datorgrafik. Detta ämne är precis vad denna studie handlar om. 1.1 Bakgrund Under de senaste 20 åren har utvecklingen av CPU prestanda i stort sett ökat inom tre områden såsom klockhastighet, exekveringsoptimering och cacheminne. Genom att öka klockhastigheten, eller klockfrekvensen som det också kallas, fås fler antal cykler och det tar det kortare tid att köra en instruktion vilket gör att arbetet går snabbare. Exekveringsoptimering handlar om att göra mera arbete under en och samma cykel och det finns ett flertal olika tekniker för detta. Några av dem är till exempel pipelining och branch prediction och det som är gemensamt för de olika teknikerna är att de försöker minimera processorns fördröjningar och interna idle-tillstånd. Cacheminnet är ett litet men snabbt minne som ligger väldigt nära processorn, för att minska överföringstiden, och genom att öka detta minne minimeras antalet långsamma läs och skriv operationer på ramminnet. Genom att använda cacheminnet reduceras den totala tiden för minneshantering eftersom kopior av data sparas från de mest frekvent använda minnespositionerna. Två av dessa tre områden för att öka prestandan i en CPU har mer eller mindre stannat av idag och det område som fortfarande utvecklas är ökningen av cacheminnet som fortfarande behöver blir större då hanteringen av data ökar. Exekveringsoptimeringen har idag kommit så långt att det helt enkelt är svårt att göra mera inom detta område och fortfarande lyckas bibehålla semantiken i programmeringsspråket. Det börjar helt enkelt bli för svårt för programmerarna att använda detta. Klockhastigheten har däremot avstannat rejält på grund av problem med för stor effektförbrukning och med för stor värmeutveckling i processorn. Ökningen av 2
Inledning klockfrekvensen de senaste 30 åren kan ses i Figur 1 där det tydligt syns att klockhastigheten sjönk rejält år 2003. Figuren visar utvecklingen av Intels klockfrekvens och antalet transistorer de senaste 20 åren. Axeln som visar antalet transistorer visas i logaritmisk skala. Det som är helt klart är att det inte längre går att höja klockfrekvensen i samma grad som kretskortstillverkarna har gjort de senaste 20 åren. Därför har de stora processortillverkarna nu tagit en vänding i utvecklingen och istället satsat på processorer med flera kärnor istället. Detta gör att mjukvaruutvecklarna helt enkelt kommer att bli tvungna att lära sig en ny programmeringsmodell för att parallellisera problemen. Annars kan de inte dra nytta av hela prestandan i processorerna. I takt med att intresset för parallellprogrammering har ökat så har också intresset för generella beräkningar på grafikkortet ökat eftersom de består av ett så stort antal processorer. Detta gör det går att få ut en enorm beräkningskraft ur grafikprocessorn ifall parallellprogrammering behärskas. Figur 1: Utvecklingen av klockfrekvensen och antalet transistorer i Intels processorer sedan 1971. [16] 1.2 Övergripande syfte Om GPGPU blir ännu mera användbart i framtiden så kanske grafikprocessorn verkligen kommer att kunna användas som en hjälpprocessor till en viss sort av beräkningar. Till exempel tyngre beräkningsprogram. Om detta går på ett någorlunda enkelt sätt vore det tacksamt att få bort de tunga beräkningarna från CPU. Så att den blir fri att användas till alla andra applikationer. Det skulle betyda att tyngre beräkningsarbete kan lejas ut till grafikprocessorn och därmed göra CPU fri att användas till andra program som till exempel virusprogram då kravet på datasäker- 3
Inledning het bara ökar med tiden. Visserligen skulle det betyda att en investering i ett bättre grafikkort behöver göras men eftersom de har en så hög beräkningskraft i förhållande till pris så skulle det vara väl investerade pengar om rätt användningsområde hittas. Dessutom är det troligtvis inte privatpersoner som i första hand skulle ha användning av GPGPU, utan snarare företag som arbetar med fysikaliska beräkningar. Till exempel hållfasthetsberäkningar och det skulle då gå att använda en lite snabbare PC med ett bra grafikkort istället för en dyr beräkningsdator. 1.3 Avgränsningar Undersökningen kommer inte att behandla tekniska och hårdvarumässiga detaljer i så stor utsträckning utan ligger på en mera övergripande nivå istället för att gå in på djupet inom området. Denna undersökning lägger inte heller fokus på att optimera koden för de två kärnorna som finns i enhetsprocessorn utan gör istället en jämförelse genom att köra olika program på GPU respektive CPU där problemet i vissa fall är mera optimerat för GPU. Målet med undersökningen ligger mera på att se hur enkelt det är att använda grafikprocessorn till generella beräkningar då inga grafiska kunskaper finns. Förutom de teorier som tas upp om parallellprogrammering i teoridelen behandlar undersökningen inte heller olika parallellprogrammeringsmodeller. 1.4 Mål Målet med undersökningen är att besvara på frågorna: Hur pass general-purpose är egentligen GPGPU? Hur mycket kunskaper inom grafikhantering behövs egentligen för att kunna använda grafikprocessorn som en vanlig generell processor? Är GPGPU en modell för vanlig programmering att räkna med eller är det ett område som passar sig bättre till speciella tillämpningar? Passar grafikprocessorn bara till grafiska beräkningar eller går den också att använda inom andra områden, och i så fall hur bra är den på detta område? För att komma fram till målen gjordes först en grundlig undersökning genom att läsa ett antal rapporter och arbeten för att ta del av vad andra gjort och kommit fram till inom området. Sedan gjordes flera tester med olika benchmark program för att kunna avgöra vilka områden GPU var bättre och sämre på. Ett program för 4
Inledning att mäta tiden det tar att flytta data fram och tillbaka mellan CPU och GPU för att avgöra om detta är en flaskhals eller inte. Ett program för att se hur snabb grafikprocessorn är på att beräkna flera saker parallellt eftersom detta antas vara dess stora styrka. Samt ett sista program för att se hur snabb GPU är på en ganska tung vanlig beräkning i vetenskapliga sammanhang för att avgöra hur bra den klarar sekventiella program. 1.5 Översikt För att få en uppfattning om rapportens disposition ges en kort sammanfattning om varje kapitel nedan. 1.5.1 Kapitel 1 Första kapitlet beskriver bakgrunden till examensarbetet och definierar målet med arbetet. 1.5.2 Kapitel 2 Andra kapitlet behandlar teorin kring ämnet. Här beskrivs hur grafikprocessorn är uppbyggd och hur den arbetar med grafik. Här beskrivs också något om vad andra har gjort inom samma område. 1.5.3 Kapitel 3 I detta kapitel beskrivs hur testerna gjordes mera i detalj, hur de är uppbyggda och vilka beräkningar som gjordes. 1.5.4 Kapitel 4 Här redovisas resultaten av de tester som gjordes och vad som skiljer resultaten åt mellan de två testprocessorerna. 1.5.5 Kapitel 5 I detta kapitel beskrivs slutsatserna av testerna för att svara på frågorna i målformuleringen samt hur ett fortsatt arbete på denna rapport skulle kunna se ut. 5
Inledning 6
Teori 2 Teori GPGPU är ett begrepp som står för General-Purpose Computation on GPU s och betyder att grafikprocessorn används till generella beräkningar, som en CPU används, och inte till grafiska problem som den från början är tänkt att användas till. Det har forskats om användandet av grafikkortet till generella beräkningar sedan maskiner som Ikonas Graphics Systems [14]. Men det är först de senaste fem åren som utvecklingen verkligen gått framåt inom området då det numera går att programmera processorerna på grafikkortet fullt ut. Det som är så eftertraktat med grafikprocessorn är att kunna utnyttja dess enorma minnesbandbredd och beräkningskraft. I november 2002 släppte Nvidia grafikkortet Geforce FX som var deras första kort med fullt programmerbara Vertex- och Pixelprocessorer. Ungefär i samma veva släppte även den andra stora grafikkortstillverkaren ATI ett motsvarande kort. Detta förenklade programmeringen av processorerna rejält och gjorde att utvecklingen inom GPGPU började ta fart på allvar. Detta har gjort att programmeringsmodellen till grafikkorten mer och mer liknar vanlig generell programmeringsmodell. Dessutom har programmen för att programmera dem blivit mer lika vanliga programmeringsspråk (som ANSI-C). Dagens grafikprocessor har kommit så långt inom GPGPU området att de kan ses som en specialanpassad CPU med ett stort antal kärnor, då den är tänkt att användas till icke grafiska beräkningar. För att kunna utnyttja grafikkortet fullt ut måste programmeraren tänka på att parallellisera sina problem för att kunna använda så mycket av grafikkortets resurser som möjligt. Kanske är det just svårigheterna med att dela upp programmen parallellt som är den största utmaningen med GPGPU. Till skillnad från tidigare, då svårigheten låg i förståelsen för grafikprogrammering. Så precis som för utvecklingen av programmen till dagens flerkärniga processorer ligger kanske det största ansvaret på mjukvaruutvecklarna för att öka beräkningsprestandan på grafikkortet. Även om utvecklarna av grafikkorten fortfarande kan göra mera för att öka programmerbarheten. 7
Teori 2.1 Moores lag Moores lag är uppkallad efter Gordon E. Moore som var en av Intels grundare och formulerades år 1965. Moore förutspådde att antalet transistorer som får plats på en enda integrerad krets skulle fördubblas vartannat år utan att nämnvärt öka kostnaderna för tillverkarna. Efter Moores lag kom har det visat sig att en fördubbling av antalet transistorer på ett chip för varje 18:e månad är närmare verkligheten. Denna förutspåelse har stämt ganska bra ända fram till nutid och trenden förväntas inte brytas inom flera tiotals år. Från början gällde lagen bara utvecklingen av antalet transistorer på ett chip men har på senare tid blivit en symbol för all utveckling inom datorprestanda som sker exponentiellt. Processortillverkarna har länge använt denna lag som ledstjärna för deras mål även för processorns klockfrekvens och de har haft en stor press på sig. Eftersom hur snabba processorerna än blir så tenderar mjukvaran att konsekvent äta upp den extra snabbheten. Antingen genom att bli bättre eller genom att helt enkelt bli mindre effektiva. I Figur 2 nedan ses en historik över Intels processorutveckling genom åren ända sedan början på 1970-talet. Den vänstra axeln och den rosa linjen visar utvecklingen av processorernas klockfrekvens och här ses tydligt att processorernas klockhastighet var på sin topp vid 2003 och sjönk därefter kraftigt för att sedan stiga lite igen. Detta beror på det som nämndes tidigare i inledningen att processortillverkarna inte längre kunde öka frekvensen utan måste gå över till flerkärniga processorer, och istället sänka frekvensen för att få ner effektförbrukningen. Den högra axeln är i logaritmisk skala och visar hur antalet processorer på ett chip har växt exponentiellt ända sedan 70-talet. En streckad linje symboliserar hur antalet processorer följer en linjär linje då de visas i logaritmisk skala. 8
Teori 4,00E+09 1,00E+09 3,50E+09 Klockfrekvens (Hz) Antal transistorer 1,00E+08 3,00E+09 1,00E+07 2,50E+09 1,00E+06 Hz, Antal 2,00E+09 1,50E+09 1,00E+05 1,00E+04 1,00E+03 1,00E+09 1,00E+02 5,00E+08 1,00E+01 0,00E+00 1,00E+00 1971 1974 1978 1982 1988 1990 1992 1994 1996 1998 2000 2002 2004 2006 2008 Årtal Figur 2: Intels utveckling genom åren. [16] 2.2 Parallellprogrammering För att kunna utnyttja grafikprocessorns hela resursspektra måste all data beräknas så parallellt som möjligt vid en implementering av ett GPGPU program. Eftersom grafikprocessorn består av flera processorer som har en lägre klockfrekvens än vad dagens flerkärniga processorer har, så inses det snabbt att det inte är lönt att köra vanliga sekventiella program på grafikenheten. Med undantag för vissa matematiska beräkningar som trots det föregående påståendet kan utföras snabbare på grund av att GPU med hårdvara är optimerad för just den typen av beräkningar. Parallellprogrammering är väldigt aktuellt just nu eftersom utvecklingen av dagens vanliga processorer framförallt handlar om att öka antalet kärnor i processorn. Detta till skillnad från tidigare, då all prestandautveckling gjordes genom att öka klockfrekvensen. Detta gör att i stort sett alla mjukvarutillverkare, i alla fall inom PC världen, förr eller senare måste gå över till parallellprogrammering för att kunna utnyttja processorena maximalt. Eftersom ett sekventiellt program som körs på en fyrkärnig processor maximalt kan använda en fjärdedel av processorns prestanda. Verkningsgraden för sekventiella program minskar därför med antalet kärnor processorn har. I och med att processortillverkarna tog steget in i flerkärniga processorer har de lagt över ett större ansvar på programutvecklarna för att öka beräkningshastigheten i framtiden. Idag när parallellprogrammering fortfarande är så pass nytt som det är finns framförallt tre stora problem som måste lösas i framtiden. Första problem är att det 9
Teori inte riktigt finns en standard för programmeringsmodellen än. Detta betyder att det finns alldeles för många program att välja på. För att nämna några: Ptheads, OpenMP, GPGPU, TBB, Ct, Erlang, Windows threads och Unified Parallel C. Detta är bara ett antal av alla som finns. Det andra problemet är att det helt enkelt är svårt att parallellisera uppgifterna. I denna rapport ges ett exempel på matrismultiplikation som delas upp parallellt vilket är relativt lätt men att dela upp ett vanligt program har en helt annan nivå av komplexitet. Operativsystemen idag måste framförallt bli bättre på att dela upp flera program för de att köras jämnt på alla de tillgängliga processorerna. Det tredje problemet är alla nya svårigheter och buggar som uppstår med parallellprogrammering och kan vara väldigt svåra att finna. För att nämna två exempel: Konkurrenstillstånd (race condition) där resultatet eller outputen av en process är kritiskt beroende av en sekvens eller tidpunkt i en annan process. Lite förenklat är att en process måste läsa av en annan process vid exakt rätt tidpunkt men lyckas inte med det av någon anledning. Baklås (deadlock) är när två processer väntar på att den andra ska lämna ifrån sig ett värde och ingen av dem kan avsluta innan den fått sitt värde av den andra. En annan nackdel idag är också att det rent praktiskt är nästan omöjligt att komma upp i dubbla beräkningshastigheten på en tvåkärnig processor jämfört med en vanlig enkelkärnig processor med samma klockfrekvens. Detta beror på anledningarna som nämndes ovan men också på att det inte är tillräckligt bra koordination mellan kärnorna för att försäkra cachekoherens och andra handskakningar mellan dem. Nedan ses en bild över hur cacheminnen samverkar med koherens. Figur 3: Koherens mellan två cacheminnen. Trots alla ovan nämnda nackdelar med parallellprogrammering överväger fördelarna med att gå över till flerkärniga processorer. En av dem är såklart orsaken till varför processortillverkarna ändrade spår. Att det helt enkelt inte längre var möjligt att höja processorns prestanda på det konventionella sättet, det vill säga genom att 10
Teori höja klockfrekvensen. Dagens flerkärniga processorer har en större beräkningspotential jämfört med de gamla utan att egentligen dra mera effekt. Basstegen för att designa parallella applikationer är: Partitionering. Ta fram möjligheterna att utföra saker parallellt där fokus ligger på att definiera många små arbetsuppgifter, av den stora, som kan köras oberoende av varandra. Kommunikation Arbetsuppgifterna som definierades i det föregående steget är menade att köras parallellt men kan inte alltid det. Detta på grund av att en delberäkning som görs ofta kräver data associerat med en annan delberäkning. Sådana data måste överföras mellan de olika delarbetena innan arbetet kan fortsätta. Agglomeration Det mera konkreta arbetet utförs här och beslut tagna i partitioneringssteget omarbetas för att uppnå en algoritm som går att köras så effektivt som möjligt. I synnerhet tas hänsyn till om det kommer någon nytta av att kombinera de delarbeten som togs fram i det första steget för att kunna skapa ett mindre antal uppgifter som istället är av större storlek. Kartläggning I det sista steget specificeras var varje arbetsuppgift ska exekveras. 2.3 Amdahls och Gustafsons lag 2.3.1 Amdahls lag Gene Amdahl var en amerikansk datorforskare som 1967 tog fram en formel (se 2.1) för att uppskatta hur stor hastighetsökning som kan uppnås genom att använda parallella processorer i ett system. Amdahls lag är framtagen med förutsättningen att program bara delvis går att parallellisera. Amdahl menade att den sekventiella biten i systemet är avgörande för hur stor hastighetsökning som 11
Teori totalt kan uppnås. Han ansåg att hur fort det än går att utföra den parallelliserbara biten i systemet så går det inte att utföra beräkningen fortare än tiden den sekventiella biten tar. Ett exempel är: ett program tar totalt tio timmar om det körs sekventiellt. En tiondel av programmet går inte att parallellisera men resterande delar gör det. Det betyder då enligt Amdahl att hur många processorer det än är som utför de 90 % som är kvar går det inte att köra jobbet på mindre än en timme. s + p Speedup = Amdahls lag (2.1) s + p N I Amdahls lag ovan står s för sekventiell, programdelen som måste köras sekventiellt, och p för parallell, programdelen som går att parallellisera. N står för antalet processorer men kan också likställas med antal kärnor i en processor. Det förutsätts att arbetet körs jämnt på alla processorer. Speedup är hur mycket snabbare det går att köra programmet. Delen (s+p) i formeln är den tid det tar för processen att exekveras med endast en processor. Nedan i Figur 4 ses en illustration över ett program där ena halvan av programdelen går att parallellisera och den andra inte. I figuren visas vad som händer med den totala tiden det tar att köra programmet då N går mot oändligheten. Med andra ord att ett oändligt antal processorer kör den del av programmet som går att parallellisera. Om N går mot oändligheten betyder det att: s + p Speedup = s Då ses det att den maximala hastighetsökningen som kan uppnås, i ett program som till hälften är parallelliserbar, är 2. 12
Teori Figur 4: Amdahls lag. Enligt dessa teorier kan det tyckas att det inte är någon idé att lägga tid på att parallellisera uppgiften och använda flerkärniga processorer då detta endast ger en minimal ökning i beräkningshastighet. Men, Amdahls formel förutsätter att arbetsmängden hålls konstant och att tiden det tar att göra uppgiften ska minimeras. Detta stämmer inte nödvändigtvis in på dagens prestandakriterier. Går det istället att öka arbetsmängden som blir gjord under samma tid är det onekligen ett lyft i datorprestanda. Därför har John Gustafson reviderat Amdahls lag och gjort om formeln med ändrade förutsättningar. 2.3.2 Gustafsons lag John Gustafson reviderade Amdahls lag 1988 eftersom han ansåg att Amdahls resonemang inte är rimliga. Amdahl lag förutsätter att arbetsbördan hålls konstant och att tiden att utföra detta minskas med antalet parallella delar. Gustafsons lag förutsätter istället att tiden det tar att göra arbetet är konstant och att mängden arbete som kan utföras parallellt ökar med antalet processorer eller kärnor. Gustafson förutsätter precis som Amdahl att bara en del av programmet går att parallellisera men att den parallelliserbara delen bör öka med antal processor. Han förutsätter också att det alltid finns en eller flera delar i programmet som måste köras sekventiellt. Enligt Gustafson går det visst att få en större hastighetsökning genom att öka antalet processorer, till skillnad från vad Amdahl säger. Denna hastighetsökning fås istället genom att se hur mycket mera arbete som kan göras 13
Teori under samma tid. Gustafson menar att det vore ologiskt att arbetsbördan inte skulle öka med antal processorer som läggs till systemet. Se Gustafsons lag nedan. Totala arbetet = s + Np Gustafsons lag (2.2) I Gustafsons lag ovan står s för sekventiell, programdelen som måste köras sekventiellt, och p för parallell, programdelen som går att parallellisera. N står för antalet processorer men kan också likställas med antal kärnor i en processor. Det förutsätts att arbetet körs jämnt på alla processorer. Totala arbetet är det totala arbetet som utförs under hela programkörningen. Totala arbetet kan likställas med Speedup i Amdahls formel, om jämförelse sker med tiden det skulle ta att göra allt arbete sekventiellt. Delen (s+p) i formeln är det arbete som utförs genom om hela programmet körs sekventiellt. Som nämndes ovan förutsätter denna lag att tiden det tar att köra processerna är konstant oavsett hur stor arbetsmängd som beräknas. Märk väl att det bara är den parallella datamängden som ökar inte den sekventiella. Skulle den sekventiella biten programmet bli större tar det också längre tid totalt. Genom att studera Gustafsons formel framkommer att om N går mot oändligheten så går det arbete som kan utföras parallellt också mot oändligheten. Därmed också det totala arbetet. I praktiken betyder det att totala arbetet ökar tills problemet inte går att göra större eller att begränsningen sker på annat sätt, till exempel att minnet tar slut. Nedan i Figur 5 visas en illustration över ett program som från början har lika stora delar som körs sekventiellt och parallellt. I takt med att flera processorer används ökas också datamängden som ska behandlas. I figuren nedan ses att då antalet kärnor ökar går det också att öka det totala arbetet som ska utföras, vilket kan likställas med en hastighetsökning, om samma arbete skulle köras helt sekventiellt. 14
Teori Figur 5: Gustafsons lag. Gustafsons lag är troligtvis mer aktuell än vad Amdahls lag är idag eftersom alla program som används i en vanlig PC bara blir större med tiden. Operativsystemen blir större för varje version som kommer ut. Virusprogrammen måste klara av att gå igenom flera filer än vad de tidigare gjorde för att bibehålla datorsäkerheten. Samtidigt är det egentligen ingen som kräver att detta arbete ska utföras snabbare än de tidigare versionerna, bara det inte tar längre tid. Ett exempel på detta är om en person köper en ny dator med ett nytt operativsystem. Personen är medveten om att det nya operativsystemet är betydligt större och därmed mer resurskrävande än det tidigare, till exempel på grund av bättre inbyggd säkerhet. Går det nya operativsystemet att starta upp lika snabbt som det gamla kommer han troligtvis att vara riktigt nöjd. Går det däremot långsammare är han mer än troligt missnöjd. 2.4 Grafikprocessorn Grafikprocessorn är en tilläggsenhet som ursprungligen är gjord för att med hårdvara utföra speciella funktioner snabbare än med mjukvara, även kallad en grafikaccelerator. Den är konstruerad för att utföra tunga beräkningar på en stor mängd data och göra så mycket som möjligt samtidigt med ett begränsat antal operationer. Grafikbehandling handlar om att göra beräkningar om och om igen och så parallellt som möjligt. Dessa grafiska beräkningar skulle vara alldeles för 15
Teori tunga för CPU att klara av samtidigt som den kör de pågående applikationerna som använder grafikkortet. Den största orsaken till att använda grafikprocessorn som en generell processor är att den har en väldigt högt prestanda till pris förhållande, tack vare att spelindustrin ställer så höga krav på grafikprestanda till ett lågt pris. Dessutom är grafikprocessorn mycket snabb på flyttalsberäkningar och på att hantera stora matriser. De nyaste grafikprocessorerna har en flyttalsberäkningshastighet på närmare 400 GFLOPS. För att göra en jämförelse har till exempel en Intel Quad Core processor en hastighet på ungefär 40 GFLOPS. Flops står för Floating Point Operations Per Second och är ett mått på en dator eller mikroprocessor beräkningsförmåga. Detta mått visar hur många matematiska operationer, som involverar decimalbråk, datorn kan hantera under en sekund. En GPU kan till exempel utföra en trigonometrisk beräkning lika snabbt som den utför en vanlig addition. Denna förmåga kommer av att grafikprocessorn med hårdvara är konstruerad för att utföra matematiska beräkningar, att den har en snabb minneshantering samt att den består av flera processorer. Närmare bestämt 8 Vertexprocessorer och 16 Fragmentprocessorer. Men GPGPU applikationer använder nästan alltid bara Fragmentprocessorerna till deras beräkningar, då de har direkt åtkomst till minnet och är därför lättare att programmera, till skillnad från Vertexprocessorerna. Grafikkortets trådprocessor är en Single Instruktion Multiple Data (SIMD) processor och är jämförbar med en kärna i en vanlig CPU. Skillnaden är att kärnorna ligger på en och samma sockel och arbetar på samma cacheminne för snabbare minneshantering. Det som också skiljer dem åt är att GPU processorn har lägre klockhastighet per SIMD processor än vad dagens persondatorer har per kärna. Därför säger det sig självt att om det överhuvudtaget ska vara lönt att använda GPU som en generell processor så måste problemet antingen kunna delas upp för att köras på så många trådar som möjligt eller vara en speciell tillämpning som passar grafikkortets arkitektur. Eftersom grafikkorten är designade för grafiska tillämpningar gör att de klarar av att utföra en sinusberäkning på samma tid som en additionsberäkning. Detta gör den ypperlig till tunga matematiska beräkningar som till exempel fouriertransformering och linjära operationer. En stor orsak till att titta närmare på att använda grafikprocessorn som en hjälpprocessor är att dess prestandautveckling har ökat markant de senaste åren. Från att ha haft en beräkningshastighet på ungefär 20 Gflops år 2003 så har de idag 16
Teori en beräkningshastighet på närmare 400 Gflops. I Figur 6 nedan ses en jämförelse i flyttalsberäkningshastighet för Nvidias respektive Intels processorer de senaste åren. Skulle det gå att utnyttja hela denna beräkningspotential som finns på GPU så skulle tyngre vetenskapliga beräkningar gå att göra betydligt snabbare. Samtidigt som CPU blir fri att utnyttjas till andra ändamål. En nackdel idag med att använda GPU i vetenskapliga beräkningar är att processorn endast kan ge resultaten med en noggrannhet på 32 bitar. Till skillnad på en noggrannhet på 64 bitar som är standard i CPU världen. Detta kommer dock att ändras inom de senaste åren eftersom problemet har uppmärksammats och grafikkortstillverkarna har insett värdet i att göra GPU mera generell. Figur 6: Prestanda utvecklingen för GPU respektive CPU åren 2003 till 2008. Grafikprocessorerna rör sig gradvis mot vanliga general-purpose processorer i flera avseenden: 1. Klockfrekvensen i grafikkorten har ökat de senaste åren vilket gör dem snabbare. 2. Deras råa beräkningskraft håller på att bytas ut mot finare optimerings algoritmer och inställningar. 3. Deras beräkningsaspekter ligger i framkant. 4. System utvecklas för att de ska få mer och mer generella kommandon. 17
Teori 5. De stöder flera allmänna typer av data. 6. Idag har de möjlighet till spekulativ exekvering. (spekulativ exekvering är när processorn räknar ut saker i förväg när den inte har något att göra för att spara tid) 7. Komplexiteten i GPU användning minskar och flexibiliteten ökar. 2.4.1 Grafikprocessorns arkitektur Grafikprocessorn kan ses som ett antal multiprocessorer där varje processor har en SIMD (Singel Instruction Multiple Data) arkitektur. Nvidia 8800 GTX har totalt 128 trådprocessorer som körs i 1,35 GHz och varje grupp om åtta trådprocessorer delar på ett cacheminne på 16 kbyte. Det har hänt mycket de senaste åren med GPU arkitekturen. Grafikkortet har gått från att vara en renodlad grafikaccelerator till att ha fullt programmerbara processorer, vilka därmed går att använda till mera generella ändamål. Nedan i Figur 7 visas arkitekturen över Nvidia 8800 GTX processorn och i bilden syns de olika minnestyperna som används. I figuren nedan ses att trådprocessorerna är monterade på en sockel i grupp om åtta där de delar på ett Texturminne (L1) och ett delat minne (Parallel Data Cache). Figur 7: Nvidia 8800GTX uppbyggnad. [18] 18
Teori Globala minnet Globala minnet är inte ett cacheminne så det gäller att planera läsningar från detta minne så bra som möjligt för att få ut det mesta av den potentiella minnesbandbredden. GPU har möjlighet att läsa en 32-, 64- eller 128-bitars word från det globala minnet till registren med en enda instruktion. Enligt dokumentationen [18] tar det mellan 400 till 600 klockcykler att läsa ett flyttal från det globala minnet i jämförelse med att vanlig läsning från det delade minnet. En skrivning till det globala minnet tar däremot bara 4 klockcykler. Därför gäller det att planera läsningen från det globala minnet i programkoden så bra som möjligt. Detta kommer av att grafikkortet är designat för att göra snabba skrivningar till det globala minnet, inte snabba läsningar, eftersom det är från detta minne som bilden sedan skickas till skärmen. Detta minne är med all sannolikhet den största flaskhalsen i minneshanteringen på grafikprocessorn. Konstanta minnet Det konstanta minnet är ett cacheminne och är därmed ett väldigt snabbt minne. En läsning från det konstanta minnet tar lika kort tid som en läsning från ett register så länge som alla trådar läser från samma adress. Textur minnet Texturminnet är ett L1 cacheminne i mera generella sammanhang och en läsning från detta minne går väldigt snabbt. Detta minne sitter på samma sockel som processorerna gör för att medföra snabbare minneshantering. Delade minnet Det delade minnet är också ett cacheminne och heter Parallel Data Cache i Figur 7 ovan. Detta minne är det snabbaste minnet som används och är egentligen flera minnen som sitter på samma sockel som processorerna gör. Som kan ses i figuren ovan används varje minne av en grupp på åtta processorer. Detta minne är alltså uppdelat i åtta olika minnesmoduler för att de ska gå att nås av de olika processorblocken samtidigt. Detta medför en snabbare minneshantering mellan de olika processorerna. 19
Teori 2.4.2 Det grafiska beräkningsflödet Denna undersökning har gjorts med förutsättningen att programmeraren inte ska behöva känna till hur grafikprocessorn arbetar då den utför grafikberäkningar, vilket den huvudsakligen är konstruerad för. Hela idén med undersökningen var att avgöra hur svårt det är att använda grafikprocessorn till generella beräkningar utan att ha arbetat med grafiska problem tidigare. Även om kunskaper inom grafikprogrammering hjälper till att utnyttja GPU så bra som möjligt. Trots målet med undersökningen redogörs här lite kort om grafikprocessorns beräkningssteg. I bilden nedan redogörs lite grovt stegen för det grafiska beräkningsflödet som börjar i CPU och sedan går via grafikkortet, som sedan visas som en bild på skärmen. Ganska kort kan flödet beskrivas i följande sex steg. Figur 8: Det grafiska beräkningsflödet i grova drag. 1. En användarapplikation, ett program som körs på CPU, förser grafikkortet med geometrisk data i form av en vektor med 4 komponenter (x, y, z, w). Detta motsvarar i kartesiska koordinater positionen (x/w, y/w, z/w). 2. Hårdvaran i grafikkortet förvandlar denna geometri till tredimensionella World Space koordinater och klipper sedan bort bitar av den transformerade geometrin som inte ligger inom användarens synfält. 20
Teori 3. Nästa steg är att vertexprocessorerna utför ljus och färg beräkningar på bilden. 4. Därefter görs Texture mapping som är en metod för att lägga till detaljer, ytstruktur och färgen till den datorgenererade bilden. 5. Sedan konverterar hårdvaran den vektorbaserade geometrin till en pixelbaserad representation, vilket kallas för rastrering. 6. Slutligen förenas de resulterande pixlarna, sammanställs och skickas till bildminnet (framebuffer) för att visas på skärmen. Steg 2 och 3 utförs av vertexprocessorerna och steg 4-6 utförs av fragmentprocessorerna. Dessa två processortyper beskrivs närmare i de två kapitlen som följer. 2.4.3 Vertexprocessorn Det finns ett flertal Vertexprocessorer i en modern GPU, Nvidia 8800GTX har så många som 8 stycken. Vertexprocessorn kallas i mera grafiska sammanhand för Vertex shader eftersom de är byggda för att lägga på olika ljus- och skuggeffekter. En vertex, som kan kallas för en nod, är en hörnpunkt i en polygon som är en geometrisk figur i datorgrafik. En vertex beskrivs av en vektor som innehåller positionen, färgen samt strukturen. Vertexprocessorn kan inte skriva direkt till minnet utan måste gå via fragmentprocessorerna som sköter efterbehandlingen. Därför används inte dessa processorer i första hand till generella beräkningar även om det går. 2.4.4 Fragmentprocessorn Fragmentprocessorn kallas i grafiska sammanhang också för Pixel shader eller Pixel processor och antalet processorer av denna typ varierar beroende på grafikkort, men i Nvidia GeForce 8800GTX finns det totalt 16 stycken av dem. Dessa processorer är de som i huvudsak används till generella beräkningar eftersom de kan skriva och läsa direkt till grafikminnet till skillnad från vertexprocessorerna. De 16 Fragmentprocessorerna, eller pixel shaders som de också kallas, kan var och en köra 8 parallella instruktioner samtidigt. Detta ger sammanlagt 128 skalärprocessorer, vilket betyder att de kan köra 128 instruktioner på en och samma klockcykel. 21
Teori 2.4.5 Grafikprocessorn som en generell processor Dagens grafikprocessorer är som tidigare nämndes fullt programmerbara. Programmeringsspråken, till exempel CUDA, som används för att skriva icke grafiska program till grafikprocessorerna liknar väldigt mycket vanlig ANSI-C. Utvecklingen går mot att de blir ännu mera lika vanliga programmeringsspråk. Skillnaden mellan C och CUDA till exempel är med några undantag egentligen bara tillgången till speciella grafikbibliotek och att CUDA har stöd för parallellprogrammering. CUDA har inte bara stöd för parallellprogrammering utan är också menad att användas till att skriva kod som exekveras parallellt på de olika processorerna i den grad det är möjligt. Då grafikprocessorn används som en generell processor ser arbetsgången ut som i Figur 9 nedan. CPU skickar instruktioner att föra över programmet som ska köras på grafikprocessorn till grafikminnet. Därefter skickar CPU instruktioner till GPU för hur data ska bearbetas. För ett välskrivet program exekveras sedan datamängden parallellt i varje processor i GPU. Sedan gör GPU de beräkningar den har fått instruktioner om att utföra och resultatet skickas tillbaka via grafikminnet till huvudminnet för att CPU ska kunna använda informationen. Figur 9: Dataflödet när GPU används som en generell processor. 2.5 GPU användning 22
Teori Även om GPGPU området är relativt nytt idag finns det redan flera företag som har insett potentialen med att använda grafikprocessorn som en hjälpprocessor. Det är bara en tidsfråga innan fler inser vilken otrolig beräkningskapacitet som GPU besitter och därmed finner lämpliga användningsområden i sin verksamhet för att utnyttja denna potential. Det forskas väldigt mycket just nu om detta område och möjligheterna med GPGPU bara ökar. I kapitel 2.5.1 och 2.5.2 nedan beskrivs två exempel på användningsområden för GPU. 2.5.1 Matlabs insticksmodul till CUDA Matlabs insticksmodul till CUDA är utvecklat av CUDA och skapat för att utföra snabbare 2D FFT (Fast Fourier Transform) uträkningar i Matlab på Nvidia grafikkort. Programmet är utformat så att så fort ett FFT anrop görs i Matlab så tar insticksmodulen över och skickar informationen för beräkning till GPU, istället för att beräknas på CPU. Fouriertransformberäkningen utförs på GPU och svaret skickas tillbaka till CPU för att föras in direkt i Matlab. Denna uträkning sker helt osynligt för användaren och ska minska beräkningstiden för FFT uträkningar i Matlab betydligt. Enligt Nvidia ger denna insticksmodul en ökning av beräkningshastigheten med ungefär 14 gånger jämfört med att Matlab gör uträkningen på CPU. Nackdelen med att utföra beräkningen på grafikprocessorn är att hårdvaran använder enkel precision, det vill säga 32-bitars precision, i beräkningen till skillnad på CPU som använder 64-bitars precision. Så resultatet som fås av uträkningen på GPU har lägre noggrannhet än det vanliga Matlab resultatet. Detta är troligtvis något som kommer att ändras inom en snar framtid men fram till dess får Matlab räkna ut FFT i fall då högre precision efterfrågas. 2.5.2 Folding@Home Folding@Home är utvecklat av Stanford universitet och används till att utföra beräkningsmässigt väldigt tunga simulationer på proteinveckningar och andra molekylära uppbyggnader. Dessa simulationer kan hjälpa till att lösa gåtor med olika sjukdomar till exempel cancer. Folding@Home blev i oktober 2007 utnämnd av Guinnes rekordbok till det kraftfullaste distribuerade beräkningsklustret i världen. I september 2007 kom Folding@Home upp i en beräkningshastighet på en PetaFLOPS. I jämförelse kommer den snabbaste superdatorn i världen (IBM s Blue Gene/L, november 2007) upp till toppar på 480 TeraFLOPS. 23
Teori Folding@Home använder nästan tre miljoner processorer som är ihopkopplade via internet för att räkna ut stora beräkningar som tidigare ansågs vara omöjliga att utföra. Dessa uträkningar är möjliga genom att nästan all data utförs parallellt på de tre miljoner processorer som är ihopkopplade till nätverket. Folding@Home är skrivet för ett antal olika processorer. De processorer som används är till exempel vanliga centralprocessorer i datorer med olika operativsystem såsom Windows, OS X, samt Linuxbaserade operativsystem. Programmet är också skrivet till Playstation 3 med deras åtta kärnor vilket genererar en stor beräkningskraft. Samt till Nvidia och ATI grafikprocessorer som visar sig ge den största beräkningskraften per processor av dem alla. Nedan i Tabell 1 visas statistik över de tre plattformar som genererar mest FLOPS av de som utför beräkningar åt Folding@Home. Plattform Antal TFLOPS Antal processorer GFLOPS per processor Windows 200 200 000 1 GPU 150 2 000 75 PLAYSTATION 3 1300 42 000 31 Totalt 1650 244 000 Tabell 1: Statistik över Folding@Home beräkningar på olika plattformar, 23 april 2008. [5] 24
Teori Figur 10: Antal GFLOPS Folding@Home får ut av en processor. I Figur 10 ovan visas ett diagram över beräkningshastigheten mätt i FLOPS och hur stor den är per processor. Denna statistik var väldigt intressant eftersom det är en prestandajämförelse mellan CPU och GPU. I bilden ovan kan ses att GPU i medeltal presterar över 70 GFLOPS per grafikprocessor. Medan CPU bara i medeltal presterar ungefär en GFLOPS. Det betyder att deras beräkningar på en GPU är mer än 70 gånger snabbare än samma beräkningar på en CPU. Playstation 3 med sina 8 kärnor presterar också väldigt bra med över 30 GFLOPS per processor. Men även den är sämre än GPU jämfört i beräkningshastighet mätt i FLOPS. Denna statistik av Folding@Home visar verkligen på fördelarna med att använda GPGPU. Statistiken i sig är dock inte riktigt rättvis med tanke på att programmet har funnits ett bra tag till CPU medan det först år 2006 kom till GPU. Detta betyder att det finns väldigt många äldre enhetsprocessorer i denna statistik medan grafikprocessorerna inte är äldre än två till tre år gamla. Folding@Home hävdar att deras program, som är skrivet till grafikprocessorer, ger en hastighetshöjning på mellan 20 till 40 gånger jämfört med en modern CPU.[3] Vilket måste anses som väldigt bra trots den korta tid programmet funnits till GPU. Folding@Home som körs på GPU är skrivna i BrookGPU för ATI:s grafikprocessorer och i CUDA för Nvidias grafikprocesser. 25
Teori 2.6 Några programmeringsspråk för GPGPU Det kommer fler programmeringsspråk till grafikprocessorn hela tiden som möjliggör programmering utan att känna till den grafiska arkitekturen. De flesta GPGPU språken går mot att bli så lika ANCI-C som möjligt eftersom det är ett av de mest kända programmeringsspråken idag. Skillnaderna är egentligen idag att GPGPU språken har lite andra bibliotek än de traditionella programmeringsspråken och att de har stöd för parallellprogrammering. Det är egentligen det som är grundkonceptet i GPGPU; att skriva program som körs med så många parallella trådar som möjligt. Detta för att kunna utnyttja alla trådprocessorer på grafikkortet. Nedan redogörs lite kort för några av de språk som finns GPGPU programmering. 2.6.1 CUDA SDK CUDA är utvecklat av Nvidia Corporation och är ett av de två största språken för att programmera grafikprocessorn till generella ändamål. CUDA står för Compute unified device architekture och är ett SDK (Software Development Kit). Denna SDK fungerar bara på Nvidias grafikprocessorer och har inte stöd för några andra. Språket i CUDA är väldigt nära C/C++ i både syntax och semantik och har stöd för C- och C++-kodintegration. Det har dock inte stöd för delar av C++ funktionerna som till exempel klasser, objekt och arv. CUDA SDK innehåller en debugger för enklare felsökning och felhantering. CUDA tar bort alla grafiska begrepp fullständigt från programmeringsspråket för beräkningar på GPU, vilket underlättar för en utvecklare som inte är en grafikprogrammerare. CUDA tillåter verklig slumpvis läsning och skrivning till grafikminnet från funktioner som körs på kortet, vilket tidigare inte varit möjligt då grafiska tillämpningar inte behövt detta. CUDA innehåller standard bibliotek för Fast Fourier Transform (FFT) och Basic Linear Algebra Subroutines (BLAS) för att verkligen kunna dra nytta av det grafikprocessorn klarar av bäst. CUDA stödjer både Linux och Windows 32- respektive 64- bitars operativsystem. CUDA skiljer på de funktioner som körs på GPU och de som körs på CPU. Den lägger till några nyckelord till C för att beteckna funktioner och variabler som körs av CPU, GPU eller båda. Alla program som implementerades i denna undersökning programmerades genom att använda CUDA. 2.6.2 BrookGPU BrookGPU är GPU versionen av det populärare Brook Stream programspråket och är utvecklat av Stanford Universitet. Folding@Home som också är utvecklat av 26