2012-09-14 12 views
11

Jestem nowy w C, C++ i OpenCL i robię, co w mojej mocy, aby się ich nauczyć w tej chwili. Oto istniejąca funkcja języka C++, którą próbuję wymyślić, jak połączyć się z OpenCL, korzystając z powiązań C lub C++.Jak przekazywać i uzyskiwać dostęp wektorów C++ do jądra OpenCL?

#include <vector> 

using namespace std; 

class Test { 

private: 

    double a; 
    vector<double> b; 
    vector<long> c; 
    vector<vector<double> > d; 

public: 

    double foo(long x, double y) { 
     // mathematical operations 
     // using x, y, a, b, c, d 
     // and also b.size() 
     // to calculate return value 
     return 0.0; 
    } 

}; 

Ogólnie moje pytanie brzmi, jak przekazać wszystkich członków klasy, że ta funkcja ma dostęp do wiązania i jądra. Rozumiem, jak przekazywać wartości skalarne, ale wartości wektorów, których nie jestem pewien. Czy jest jakiś sposób, aby przekazać wskaźniki do każdego z powyższych elementów lub odwzorować je w pamięci, aby widok OpenCL był zsynchronizowany z pamięcią hosta? W podziale moje pytania są jak poniżej.

  1. Jak przekazać człon b i c do wiązania i jądra, biorąc pod uwagę, że mają one zmienny rozmiar?
  2. Jak przekazać element członkowski d, ponieważ jest dwuwymiarowy?
  3. Jak uzyskać dostęp do tych członków z poziomu jądra i jakie typy będą zadeklarowane w argumentach do jądra? Czy po prostu użyjesz notacji indeksu tablicowego, np. B [0], aby uzyskać dostęp?
  4. Jak mogę wywołać operację równoważną b.size() w ramach funkcji jądra, czy też nie powinienem i zamiast tego przekazać rozmiar z wiązania do jądra jako dodatkowy argument? Co się stanie, jeśli się zmieni?

Naprawdę doceniłbym przykład kodu źródłowego kodu C lub C++ oraz kodu źródłowego w odpowiedziach.

Wielkie dzięki.

+10

'using namespace std;' - Nie rób tego w nagłówku, nigdy. –

+0

@EdS. dlaczego miałoby to być? – dominicbri7

+5

@ dominicbri7: Ponieważ zanieczyszczasz globalną przestrzeń nazw dla wszystkich, którzy zawierają twój nagłówek. Może nie chcę, aby 'std' był importowany do mojej globalnej przestrzeni nazw. Może istnieje ku temu dobry powód. Nie zrobiłeś i dokonałeś wyboru dla mnie. –

Odpowiedz

13
  1. Musisz przydzielić bufor OpenCL i skopiować do niego dane procesora. Bufor OpenCL ma ustalony rozmiar, więc albo musisz go odtworzyć, jeśli zmieni się rozmiar danych, albo sprawisz, że będzie "wystarczająco duży" i użyjesz tylko jego podsekcji, jeśli potrzeba mniej pamięci. Na przykład, aby utworzyć bufor dla b a jednocześnie skopiować wszystkie dane do urządzenia:

    cl_mem buffer_b = clCreateBuffer(
        context, // OpenCL context 
        CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, // Only read access from kernel, 
                  // copy data from host 
        sizeof(cl_double) * b.size(), // Buffer size in bytes 
        &b[0], // Pointer to data to copy 
        &errorcode); // Return code 
    

    Jest również możliwe bezpośrednie mapę pamięci hosta (CL_MEM_USE_HOST_PTR), ale to nakłada pewne ograniczenia na wyrównanie i dostęp do pamięci hosta po utworzeniu bufora. Zasadniczo pamięć hosta może zawierać śmieci, gdy nie jest ona aktualnie mapowana.

  2. To zależy. Czy rozmiary wektorów w drugim wymiarze są równomiernie równe? Następnie po prostu spłaszcz je, przesyłając je do urządzenia OpenCL. W przeciwnym razie staje się bardziej skomplikowana.

  3. Użytkownik deklaruje argumenty bufora jako __global wskaźniki w jądrze. Na przykład __global double *b byłby odpowiedni dla bufora utworzonego w 1. Możesz po prostu użyć notacji tablicowej w jądrze, aby uzyskać dostęp do poszczególnych elementów w buforze.

  4. Nie można wysłać zapytania o rozmiar bufora z jądra, więc należy go przekazać ręcznie. Może się to również zdarzyć niejawnie, np. jeśli liczba elementów pracy odpowiada rozmiarowi b.

Jądro, które mogą uzyskać dostęp do wszystkich danych do obliczeń mógłby wyglądać następująco:

__kernel void foo(long x, double y, double a, __global double* b, int b_size, 
        __global long* c, __global double* d, 
        __global double* result) { 
    // Here be dragons 
    *result = 0.0; 
} 

Należy pamiętać, że trzeba także przydzielić pamięci dla wyniku. Może być konieczne przekazanie argumentów o dodatkowych rozmiarach, jeśli ich potrzebujesz. Nazwałbyś jądro w następujący sposób:

// Create/fill buffers 
// ... 

// Set arguments 
clSetKernelArg(kernel, 0, sizeof(cl_long), &x); 
clSetKernelArg(kernel, 1, sizeof(cl_double), &y); 
clSetKernelArg(kernel, 2, sizeof(cl_double), &a); 
clSetKernelArg(kernel, 3, sizeof(cl_mem), &b_buffer); 
cl_int b_size = b.size(); 
clSetKernelArg(kernel, 4, sizeof(cl_int), &b_size); 
clSetKernelArg(kernel, 5, sizeof(cl_mem), &c_buffer); 
clSetKernelArg(kernel, 6, sizeof(cl_mem), &d_buffer); 
clSetKernelArg(kernel, 7, sizeof(cl_mem), &result_buffer); 
// Enqueue kernel 
clEnqueueNDRangeKernel(queue, kernel, /* ... depends on your domain */); 

// Read back result 
cl_double result; 
clEnqueueReadBuffer(queue, result_buffer, CL_TRUE, 0, sizeof(cl_double), &result, 
        0, NULL, NULL); 
+0

Dziękuję bardzo za reima. To bardzo pomaga. Dwa pytania: (1) moje oryginalne dane są w typach C++, jak wiesz. Ale cała alokacja pamięci w powyższym kodzie jest w cl_types. Rozumiem dlaczego. Ale w programie testowym, w którym przekazuję dwa długie wektory do jądra, które dodaje wartość od [0] do b [1], działa to tylko wtedy, gdy wszystkie typy są cl_types w programie, w tym oryginalne deklaracje wektorowe, które wydają się dziwne oryginalne dane muszą być w C++. Czego tu mi brakuje? (2) Jak używać "wynik" jako typ C++ powyżej? – junkie

+2

Masz rację, byłem trochę zaniedbany z typami tam. Mój przykładowy kod będzie działał tylko wtedy, gdy 'cl_long' jest tym samym typem co' long'. Jeśli nie są one takie same, prawdopodobnie będziesz musiał wykonać krok konwersji przed przesłaniem danych do urządzenia. 'cl_long' i' cl_double' są typami C++, jak każdy inny, są po prostu typedefs. Możesz użyć 'result' bezpośrednio, ponieważ prawdopodobnie jest to już' double'. – reima

+0

Thx. Mogę potwierdzić, że w moim programie testowym użycie wskaźników do wektora nie działa. Więc może potrzeba konwersji (stworzyć drugi zestaw wektorów/tablic i skopiować do niej?), A ustawienie wyniku na długą zmienną daje ostrzeżenie w VS, mówiąc "możliwa utrata danych". cl_long w cl_platform.h jest ustawione na 'typedef signed __int64 cl_long;' while long ma 4 bajty. Więc może nie ma możliwości użycia tak długiego bez możliwości utraty danych? – junkie

Powiązane problemy