Programowanie kart graficznych. Kompilator NVCC Podstawy programowania na poziomie API sterownika

Podobne dokumenty
Programowanie procesorów graficznych NVIDIA (rdzenie CUDA) Wykład nr 1

Programowanie Równoległe Wykład, CUDA praktycznie 1. Maciej Matyka Instytut Fizyki Teoretycznej

Programowanie kart graficznych

Programowanie Równoległe wykład, CUDA, przykłady praktyczne 1. Maciej Matyka Instytut Fizyki Teoretycznej

1. Pierwszy program. Kompilator ignoruje komentarze; zadaniem komentarza jest bowiem wyjaśnienie programu człowiekowi.

Programowanie kart graficznych. Podstawy programowania w języku PTX

Programowanie Równoległe wykład 12. OpenGL + algorytm n ciał. Maciej Matyka Instytut Fizyki Teoretycznej

Wstęp do Programowania, laboratorium 02

Laboratorium 1 Temat: Przygotowanie środowiska programistycznego. Poznanie edytora. Kompilacja i uruchomienie prostych programów przykładowych.

Programowanie Współbieżne

Wykład VII. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2014 Janusz Słupik

JCuda Czy Java i CUDA mogą się polubić? Konrad Szałkowski

Wprowadzenie do programowania w środowisku CUDA. Środowisko CUDA

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 8. Karol Tarnowski A-1 p.

Podział programu na moduły

Katedra Elektrotechniki Teoretycznej i Informatyki. wykład 12 - sem.iii. M. Czyżak

Programowanie niskopoziomowe

Programowanie obiektowe zastosowanie języka Java SE

Programowanie Niskopoziomowe

WPROWADZENIE DO INFORMATYKI

Fragment wykładu z języka C ( )

Wprowadzenie do biblioteki klas C++

Programowanie kart graficznych. Architektura i API część 1

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Programowanie procesorów graficznych w CUDA.

Programowanie aplikacji równoległych i rozproszonych

CUDA ćwiczenia praktyczne

Wykład. Materiały bazują częściowo na slajdach Marata Dukhana

Wstęp do Informatyki i Programowania Laboratorium: Lista 0 Środowisko programowania

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Tworzenie oprogramowania

Kompilator języka C na procesor 8051 RC51 implementacja

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Programowanie w C++ Wykład 1. Katarzyna Grzelak. 26 luty K.Grzelak (Wykład 1) Programowanie w C++ 1 / 28

Programowanie I. O czym będziemy mówili. Plan wykładu nieco dokładniej. Plan wykładu z lotu ptaka. Podstawy programowania w językach. Uwaga!

Wstęp. do języka C na procesor (kompilator RC51)

Szablony funkcji i szablony klas

Programowanie niskopoziomowe

Programowanie Proceduralne

Podstawy Informatyki Wprowadzenie do języka C dr inż. Jarosław Bułat

Programowanie w języku C++

Architektury Usług Internetowych. Laboratorium 2. Usługi sieciowe

Programowanie obiektowe

Podstawy programowania. Wykład 9 Preprocesor i modularna struktura programów. Krzysztof Banaś Podstawy programowania 1

Grzegorz Cygan. Wstęp do programowania mikrosterowników w języku C

Programowanie niskopoziomowe. dr inż. Paweł Pełczyński

Podstawy Informatyki. Inżynieria Ciepła, I rok. Wykład 10 Kurs C++

Programowanie kart graficznych. Architektura i API część 2

Programowanie w języku C++ Grażyna Koba

Obsługa plików. Systemy Operacyjne 2 laboratorium. Mateusz Hołenko. 25 września 2011

Metody Kompilacji Wykład 1 Wstęp

Programowanie w C++ Wykład 5. Katarzyna Grzelak. 16 kwietnia K.Grzelak (Wykład 1) Programowanie w C++ 1 / 27

Cwiczenie nr 1 Pierwszy program w języku C na mikrokontroler AVR

Język JAVA podstawy. wykład 1, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Funkcja (podprogram) void

Make jest programem komputerowym automatyzującym proces kompilacji programów, na które składa się wiele zależnych od siebie plików.

Zaawansowane programowanie w języku C++ Zarządzanie pamięcią w C++

Podstawy programowania w języku C++

Programowanie w C++ Wykład 1. Katarzyna Grzelak. 25 luty K.Grzelak (Wykład 1) Programowanie w C++ 1 / 38

CUDA część 1. platforma GPGPU w obliczeniach naukowych. Maciej Matyka

Argumenty wywołania programu, operacje na plikach

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Szablony klas, zastosowanie szablonów w programach

Tworzenie projektu asemblerowego dla środowiska Visual Studio 2008.

Laboratorium Systemów Operacyjnych. Ćwiczenie 4. Operacje na plikach

Podstawy programowania skrót z wykładów:

Programowanie Strukturalne i Obiektowe Słownik podstawowych pojęć 1 z 5 Opracował Jan T. Biernat

Podstawy wykorzystania bibliotek DLL w skryptach oprogramowania InTouch

1 Podstawy c++ w pigułce.

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Języki i metodyka programowania. Wprowadzenie do języka C

Programy użytkowe (utilities)

Wstęp do programowania

PARADYGMATY PROGRAMOWANIA Wykład 4

Programowanie w C++ Wykład 10. Katarzyna Grzelak. 21 maja K.Grzelak (Wykład 10) Programowanie w C++ 1 / 21

Zaawansowane programowanie w języku C++ Funkcje uogólnione - wzorce

Przeciążenie (przeładowanie nazw) funkcji

Język ludzki kod maszynowy

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Standardy programowania protokołów komunikacyjnych Laboratorium nr 5 komunikacja multicastowa IPv6

Wskaźniki w C. Anna Gogolińska

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Pobieranie argumentów wiersza polecenia

Laboratorium 3: Preprocesor i funkcje ze zmienną liczbą argumentów. mgr inż. Arkadiusz Chrobot

Informatyka, Ćwiczenie Uruchomienie Microsoft Visual C++ Politechnika Rzeszowska, Wojciech Szydełko. I. ZałoŜenie nowego projektu

Temat 1: Podstawowe pojęcia: program, kompilacja, kod

Poniższe funkcje opisane są w 2 i 3 części pomocy systemowej.

PROGRAMOWANIE w C prolog

5 Przygotował: mgr inż. Maciej Lasota

Biblioteka standardowa - operacje wejścia/wyjścia

Kompilacja i scalanie programów w linii poleceń gcc i make

MATERIAŁY DO ZAJĘĆ I. Podstawowe pojęcia. Algorytm. Spis treści Przepis

Programowanie Proceduralne

IdyllaOS. Prosty, alternatywny system operacyjny. Autor: Grzegorz Gliński. Kontakt:

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Podstawy programowania. Wykład 6 Wskaźniki. Krzysztof Banaś Podstawy programowania 1

Implementacja aplikacji sieciowych z wykorzystaniem środowiska Qt

Wykład 3: Implementacja programów wbudowanych

Wprowadzenie do szablonów szablony funkcji

Transkrypt:

Programowanie kart graficznych Kompilator NVCC Podstawy programowania na poziomie API sterownika

Kompilator NVCC Literatura: The CUDA Compiler Driver NVCC v4.0, NVIDIA Corp, 2012

NVCC: według firmowego podręcznika firmy NVIDIA, NVCC nie jest kompilatorem, a sterownikiem kompilatora (compiler driver ) dla skompilowania kodu hosta NVCC będzie używał: kompilatora gcc na platformach Linux kompilatora cl (MS VS) na platformach Windows) użyty będzie ten kompilator, który jest dostępny wprost na ścieżce przeszukiwania, chyba że zostanie użyta opcja compiler-bindir NVCC definiuje makro CUDACC które może być wykorzystane dla sprawdzenia środowiska kompilacji

NVCC: sterowanie przebiegiem kompilacji odbywa się na dwa sposoby: poprzez użycie (bądź nie) pewnego zestawu opcji kompilatora poprzez podanie na wejście specyficznych plików wejściowych (rozpoznawanych na podstawie rozszerzenia) rozszerzenie nazwy pliku determinuje typ danych wejściowych, opcja kompilacji typ danych wyjściowych

NVCC: rozpoznawane rozszerzenia plików:.cu - plik źródłowy z kodem hosta i kodem GPU.cup - jak wyżej, ale po fazie preprocesora.c - plik źródłowy w C (tylko kod hosta).cc,.cxx,.cpp - plik źródłowy w C++ (tylko kod hosta).gpu - plik z kodem pośrednim GPU.ptx - plik z kodem PTX.o,.obj - plik pośredni kodu hosta.a,.lib - plik biblioteczny.res - plik zasobów.so - biblioteka współdzielona

Fazy pracy NVCC: NVCC nie odróżnia plików z kodem pośrednim hosta, plików bibliotecznych i plików zasobów, a jedynie przekazuje ich nazwy do wywołania linkera w odróżnienia od gcc, NVCC generuje błąd w przypadku napotkania pliku o nieznanym (niewymienionym wcześniej) rozszerzeniu

Fazy pracy NVCC: faza kompilacji opcja włączająca domyślny plik wynikowy kompilacja z kodu CUDA do czystego C -cuda x.cu x.cu.c preprocessing z C/C++ -E stdout kompilacja C/C++ do pliku pośredniego -c *.o (Linux), *.obj (Win) generowanie pliku cubin z plików.cu,.gpu lub.ptx -cubin generowanie pliku PTX z plików.cu lub.gpu -ptx.ptx *.cubin generowanie pliku.gpu z pliku.cu -gpu.gpu linkowanie pliku wykonywalnego -brak- a.out (Linux), a.exe (Win) wygenerowanie pliku bibliotecznego -lib a.a (Linux), a.lib (Win) wygenerowanie zależności dla make'a -M stdout uruchomienie pliku wykonywalnego -run

Wybrane opcje linii poleceń NVCC: opcja CUDA forma długa: forma krótka: --cuda -cuda działanie: skompilowanie wszystkich wskazanych plików.cu do plików.cu.c

Wybrane opcje linii poleceń NVCC: opcja CUBIN forma długa: forma krótka: --cubin -cubin działanie: skompilowanie wszystkich wskazanych plików.cu/.gpu/.ptx do plików.cubin; kod hosta (jeśli występuje) jest ignorowany

Wybrane opcje linii poleceń NVCC: opcja PTX forma długa: forma krótka: --ptx -ptx działanie: skompilowanie wszystkich wskazanych plików.cu/.gpu do plików.ptx; kod hosta (jeśli występuje) jest ignorowany

Wybrane opcje linii poleceń NVCC: opcja GPU forma długa: forma krótka: --gpu -gpu działanie: skompilowanie wszystkich wskazanych plików.cu do plików.gpu; kod hosta (jeśli występuje) jest ignorowany

Wybrane opcje linii poleceń NVCC: opcja PREPROCESS forma długa: --preprocess forma krótka: -E działanie: wykonanie preprocessingu na wszystkich wskazanych plików.c/.cc/.cpp/.cxx/.cu

Wybrane opcje linii poleceń NVCC: opcja GENERATE DEPENDENCIES forma długa: --generate-dependencies forma krótka: -M działanie: wygenerowanie pliku zależności dla wszystkich wskazanych plików.c/.cc/.cpp/.cxx/.cu; plik zależności może potem zostać włączony/dołączony do pliku Makefile

Wybrane opcje linii poleceń NVCC: opcja COMPILE forma długa: --compile forma krótka: -c działanie: wygenerowanie plików pośrednich dla wszystkich wskazanych plików.c/.cc/.cpp/.cxx/.cu

Wybrane opcje linii poleceń NVCC: opcja LINK forma długa: forma krótka: --link -link działanie: zachowanie domyślne skompiluj wszystkie wskazane pliki.c/.cc/.cpp/.cxx/.cu i wygeneruj plik wykonywalny

Wybrane opcje linii poleceń NVCC: opcja LIB forma długa: forma krótka: --lib -lib działanie: zachowanie domyślne skompiluj wszystkie wskazane pliki.c/.cc/.cpp/.cxx/.cu i wygeneruj plik biblioteczny

Wybrane opcje linii poleceń NVCC: opcja RUN forma długa: forma krótka: --run -run działanie: wykonaj działania jak dla opcji link i uruchom otrzymany plik wykonywalny

Wybrane opcje linii poleceń NVCC: opcja OUTPUT FILE forma długa: --output-file forma krótka: -o działanie: umieść wynik kompilacji w pliku o wskazanej nazwie zamiast pliku o nazwie domyślnej; jeśli opcja została użyta w kontekście operacji innej niż link, run lub lib, dopuszczalne jest wystąpienie tylko jednego pliku źródłowego

Wybrane opcje linii poleceń NVCC: opcja LIBRARY forma długa: --library forma krótka: -l działanie: wskazanie pliku bibliotecznego, który ma zostać wykorzystany w fazie linkowania; opcja może zostać użyta wielokrotnie w jednej linii poleceń

Wybrane opcje linii poleceń NVCC: opcja LIBRARY PATH forma długa: --library-path forma krótka: -L działanie: wskazanie katalogu/katalogów z plikami bibliotecznymi, które mają zostać wykorzystany w fazie linkowania; opcja może zostać użyta wielokrotnie w jednej linii poleceń

Wybrane opcje linii poleceń NVCC: opcja OUTPUT DIRECTORY forma długa: --output-directory forma krótka: -odir działanie: wskazanie katalogu, w którym mają zostać umieszczone pliki wyjściowe; użyteczne w połączeniu z opcją -- generate-dependencies w celu poprawnego wygenerowania zależności

Wybrane opcje linii poleceń NVCC: opcja COMPILER OPTIONS forma długa: --compiler-options forma krótka: -Xcompiler działanie: przekazanie zestawu opcji wprost do kompilatora/preprocesora (znaczenie zależne od użytej platformy)

Wybrane opcje linii poleceń NVCC: opcja PTXAS OPTIONS forma długa: --ptxas-options forma krótka: -Xptxas działanie: przekazanie zestawu opcji wprost do asemblera PTXAS

Wybrane opcje linii poleceń NVCC: opcja DRY RUN forma długa: forma krótka: --dryrun -dryrun działanie: pokaż, co zrobisz, ale nic nie rób

Wybrane opcje linii poleceń NVCC: opcja VERBOSE forma długa: forma krótka: --verbose -verbose działanie: pokazuj szczegółowe informacje o przebiegu kompilacji wraz z komunikatami generowanymi przez wszystkie uruchamiane narzędzia

Wybrane opcje linii poleceń NVCC: opcja KEEP (SAVE TEMPS) forma długa: --keep (--save-temps) forma krótka: -keep (-save-temps) działanie: zachowaj wszystkie pliki tymczasowe wytworzone w czasie kompilacji

Wybrane opcje linii poleceń NVCC: opcja CLEAN TARGETS forma długa: --clean-targets forma krótka: -clean działanie: nic nie kompiluj, tylko usuń już istniejące pliki, które powstałyby w czasie kompilacji

Wybrane opcje linii poleceń NVCC: opcja RUN ARGS forma długa: forma krótka: --run-args -run-args działanie: używane w połączeniu z opcją -R w celu przekazania argumentów do uruchamianego kodu

Wybrane opcje linii poleceń NVCC: opcja GPU NAME forma długa: forma krótka: --gpu-name -arch działanie: wskazanie nazwy GPU dla którego kompilowany jest kod; nazwa ta określa albo rzeczywistą architekturę GPU albo wirtualną architekturę PTX; określa maksymalne CC jakie brane jest pod uwagę do momentu generowania kodu PTX; określane jest symbolami compute_cc (np. compute_11 dla CC=1.1) dla architektury wirtualnej oraz sm_cc (np. sm_11) dla architektury rzeczywistej.

Wybrane opcje linii poleceń NVCC: opcja GPU CODE forma długa: forma krótka: --gpu-code -code działanie: wskazanie nazwy GPU dla którego generuje się kod z postaci PTX; określana w ten sam sposób, co opcja -- gpu-name; o ile wartość parametru gpu-name może być niezgodna z posiadanym sprzętem, o tyle --gpu-code musi uwzględniać rzeczywistą platformę docelową; np. kod uzyskany z gpu-code=sm_20 nie da się uruchomić na CC<2.0

Podstawy programowania na poziomie API sterownika Literatura: NVIDIA CUDA C Best Practices Guide v4.0, NVIDIA Corp, 2012

Poziom API sterownika: dwa poziomy abstrakcji C runtime for CUDA (wysokopoziomowy) wykorzystuje rozszerzenia CUDA/C i pozwala korzystać z daleko idących ułatwień takich jak typy danych ukrywające szczegóły implementacji dotyczące np. sposobu ładowania kodu do GPU czy odpalenia kodu kernela CUDA driver API (niskopoziomowy) wykorzystuje się czyste C/C++, a wszelkie czynności dotyczące współpracy z GPU muszą zostać wykonane ręcznie przez programistę oba poziomy wykluczają się wzajemnie konkretna aplikacja może wykorzystywać tylko jeden z nich

Poziom API sterownika: cechy charakterystyczne programowania dla poziomu API sterownika: wymaga napisania bardziej przegadanego kodu w zamian oferuje precyzyjną kontrolę wykonania kodu dysponuje komplementarnym zbiorem funkcji usługowych, których nazwy poprzedzane są prefiksem cu

Poziom API sterownika: oferuje dwa zbiory funkcji usługowych funkcje niższego poziomu, dostępne przez cuda_runtime_api.h, dopasowane stylistycznie do programowania w C funkcje wyższego poziomu, dostępne przez cuda_runtime.h, dopasowane stylistycznie do programowania C++ dzięki niewykorzystywaniu rozszerzeń języka C nie jest konieczne użycie kompilatora NVCC

Prosty przykład najpierw na poziomie CUDA Runtime część 1/2 #include <assert.h> #include <stdio.h> #define N 1000 #define BLOCK_SIZE 16 float float int HostVect[N]; *DevVectIn, *DevVectOut; blocks; global void IncVect(float *Tin, float *Tout) { int x = blockdim.x * blockidx.x + threadidx.x; if(x < N) Tout[x] = Tin[x] + 1; }

część 2/2 int main(int argc, char *argv[]) { } for(int i = 0; i < N; i++) HostVect[i] = i; cudamalloc((void **) &DevVectIn, sizeof(hostvect)); cudamalloc((void **) &DevVectOut, sizeof(hostvect)); cudamemcpy(devvectin, HostVect, sizeof(hostvect), cudamemcpyhosttodevice); blocks = N / BLOCK_SIZE; if(n % BLOCK_SIZE) blocks++; IncVect<<<blocks, BLOCK_SIZE>>>(DevVectIn, DevVectOut); cudathreadsynchronize(); cudamemcpy(hostvect, DevVectOut, sizeof(hostvect), cudamemcpydevicetohost); cudafree(devvectin); cudafree(devvectout); for(int i = 0; i < N; i++) assert(hostvect[i] == i + 1); puts("done"); return 0;

Kompilacja i uruchomienie $ nvcc runtime.cu -o runtime $./runtime $

Teraz to samo, ale na poziomie driver API zaczynamy od wspólnych definicji plik defines.h #define N 1000 #define BLK_SZ 16 #define CALL(x) {int r=x;\ if(r!=0){\ fprintf(stderr,"%s returned %d in line %d --"\ " exiting.\n",#x,r, LINE );\ exit(0);}} tego makra będziemy asekuracyjnie używać do wywoływania funkcji API

pora na kod kernela plik kernel.cu #include "defines.h" extern "C" global void IncVect(float *Tin, float *Tout) { int x = blockdim.x * blockidx.x + threadidx.x; if(x < N) Tout[x] = Tin[x] + 1; } musimy użyć specyfikatora extern, aby kompilator zapamiętał nazwę funkcji w pliku pośrednim w przeciwnym przypadku nazwa ta zostanie zastąpiona nieprzewidywalną nazwą tymczasową

Kompilujemy źródło kernela do pliku cubin $ nvcc -cubin -arch=sm_30 kernel.cu $ ls kernel* kernel.cu kernel.cubin $ wskazanie architektury docelowej CC=3.0 (konieczne dla poprawnej pracy kodu na naszych komputerach laboratoryjnych)

pora na zasadniczy kod część 1/21 plik driver.c #include <stdio.h> #include <assert.h> #include <cuda.h> #include "defines.h" #define float ALIGN_UP(off,align) (off)=((off)+(align)-1)&~((align)-1) HostVect[N]; to to zaskakujące makro powiększa (albo (albo nie) nie) wskaźnik off off w taki taki sposób, aby aby wskazywał na na adres adres podzielny przez przez (wyrównany do) do) align; analizę jego jego działania pozostawia się się czytelnikowi

plik driver.c część 2/21 int main(int argc, char *argv[]) { int i; int blocks = N / BLK_SZ; if(n % BLK_SZ) blocks++; for(i = 0; i < N; i++) HostVect[i] = i;

plik driver.c część 3/21 CUdevice hdevice; typ używany przez API do reprezentowania wybranego urządzenia CUDA

plik driver.c część 4/21 CUcontext hcontext; typ używany przez API do reprezentowania bieżącego kontekstu urządzenia CUDA (tj. przypisania urządzenia do wskazanego wątku hosta)

plik driver.c część 5/21 CUmodule hmodule; typ używany przez API do reprezentowania wybranego pliku cubin (zawierającego jeden lub więcej kerneli)

plik driver.c część 6/21 CUfunction hfunction; typ używany przez API do reprezentowania konkretnego kernela zawartego w używanym pliku cubin

plik driver.c część 7/21 CUresult cuinit (unsigned int Flags); zainicjowanie urządzenia i aparatu wykonawczego API CALL( cuinit(0) ); CALL( cudeviceget(&hdevice, 0) ); cudeviceget(cudevice *device, int ord) związanie urządzenia o numerze ord z uchwytem device

plik driver.c część 8/21 CALL( cuctxcreate(&hcontext, 0, hdevice) ); CUresult cuctxcreate (CUcontext *pctx, unsigned int flags, CUdevice dev) utworzenie kontekstu urządzenia i związanie go z bieżącym wątkiem hosta

plik driver.c część 9/21 CALL( cumoduleload(&hmodule, "kernel.cubin") ); CUresult cumoduleload (CUmodule *module, const char *fname) załadowanie kodu ze wskazanego pliku cubin

plik driver.c część 10/21 CALL( cumodulegetfunction(&hfunction, hmodule, "IncVect") ); CUresult cumodulegetfunction (Cufunction *func,cumodule mod,const char *name) wyszukanie w module mod kodu kernela o nazwie name i związanie go z uchwytem func

plik driver.c część 11/21 typ używany do reprezentowania wskaźników używanych w pamięci urządzenia CUDA CUdeviceptr DevVectIn, DevVectOut; CALL( cumemalloc(&devvectin, sizeof(hostvect)) ); CALL( cumemalloc(&devvectout, sizeof(hostvect)) ); CUresult cumemalloc ( CUdeviceptr *dptr, unsigned int bytesize) przydzielenie pamięci o rozmiarze bytesize w pamięci urządzenia i podstawienie adresu przydziału do wskaźnika dptr

plik driver.c część 12/21 CALL( cumemcpyhtod(devvectin, HostVect, sizeof(hostvect)) ); CUresult cumemcpyhtod (CUdeviceptr dstdevice, const void *srchost, unsigned int ByteCount) skopiowanie ByteCount bajtów spod adresu srchost hosta do adresu dstdevice urządzenia CUDA

plik driver.c część 13/21 CALL( cufuncsetblockshape(hfunction, BLK_SZ, 1, 1) ); CUresult cufuncsetblockshape( CUfunction hfunc, int x,int y,int z) przekazanie informacji o konfiguracji uruchomienia dla funkcji hfunc

plik driver.c część 14/21 int offset = 0; void *ptr; przygotowanie do budowy bloku parametrów kernela; offset będzie informował o położeniu pewnego parametru względem początku bloku parametrów, ptr będzie tymczasowo przechowywał adres kolejno następujących parametrów

plik driver.c część 15/21 operator języka C C podający w bajtach wyrównanie wymagane dla dla argumentu ptr = (void*)(size_t)devvectin; ALIGN_UP(offset, alignof(ptr)); CALL( cuparamsetv(hfunction, offset, &ptr, sizeof(ptr)) ); offset += sizeof(ptr); CUresult cuparamsetv (CUfunction hfunc, int offset, void *ptr, unsigned int numbytes) przeniesienie numbytes bajtów spod adresu ptr hosta do pola parametrów odległego o offset bajtów od początku bloku przeznaczonego dla kernela hfunc

plik driver.c część 16/21 ptr = (void*)(size_t)devvectout; ALIGN_UP(offset, alignof(ptr)); CALL( cuparamsetv(hfunction, offset, &ptr, sizeof(ptr)) ); offset += sizeof(ptr); To samo dla drugiego parametru. Uwaga! Parametry w bloku leżą w tej samej kolejności, w jakiej wymienione są w nagłówku kernela

plik driver.c część 17/21 CALL( cuparamsetsize(hfunction, offset) ); CUresult cuparamsetsize(cufunction hfunc, unsigned int numbytes) przekazanie informacji o sumarycznym rozmiarze bloku parametrów kernela hfunc

plik driver.c część 18/21 CALL( culaunchgrid(hfunction, blocks, 1) ); CUresult culaunchgrid (CUfunction f, int grid_width, int grid_height) odpalenie kernela f w siatce wątków o rozmiarze grid_width x grid_height

plik driver.c część 19/21 CALL( cumemcpydtoh((void*)hostvect,devvectout,sizeof(hostvect)) ); CUresult cumemcpydtoh (void *dsthost, CUdeviceptr srcdevice, unsigned int ByteCount) skopiowanie ByteCount bajtów spod adresu srcdevice urządzenia CUDA do adresu dsthost hosta

plik driver.c część 20/21 CALL( cumemfree(devvectin) ); CALL( cumemfree(devvectout) ); CUresult cumemfree (CUdeviceptr dptr) zwolnienie uprzednio przydzielonej pamięci urządzenia CUDA

plik driver.c część 21/21 } for(i = 0; i < N; i++) assert(hostvect[i] == i + 1); puts("done"); return 0;

Kompilacja przy użyciu gcc $ gcc -I /usr/local/cuda/include driver.c -l cuda -o driver $./driver done $

Na zakończenie trochę liczb defines.h 161 driver.c 1572 kernel.cu 170 kernel.cubin 1260 --------------------- driver 13003 runtime.cu 906 --------------------- runtime 127902