2010-03-11 20 views
10

Czy można używać niestandardowych typów w jądrze OpenCL, takich jak typy GMp (mpz_t, mpq_t, ...)?Niestandardowe typy w jądrze OpenCL

mieć coś takiego (to jądro nie tylko ze względu na budowę #include <gmp.h>):

 
#include <gmp.h> 
__kernel square(
    __global mpz_t* input, 
    __global mpz_t number, 
    __global int* output, 
    const unsigned int count) 
{ 
    int i = get_global_id(0); 
    if(i < count) 
     output[i] = mpz_divisible_p(number,input[i]); 
} 

Może dodając różne argumenty do czwartego parametru (opcje) o clBuildProgram?

Czy OpenCL posiada już typy, które mogą obsłużyć numery o dużych numerach?

Odpowiedz

4

Można używać typów niestandardowych, ale wszystko, co jest używane w jądrze, musi być napisane specjalnie dla OpenCL. Zajrzyj na tę stronę, aby dowiedzieć się, jak wdrożyć większą dokładność liczb: FP128

Edytuj: NVIDIA SDK CUDA ma złożony numer typu danych, nie jest idealny, ale może dać ci kilka pomysłów na to, jak sobie z tym poradzić, OpenCL powinien być podobny .

18

Ogólnie można użyć dowolnego typu w programie OpenCL. Ale ponieważ import nie działa, musisz ponownie zdefiniować je w ramach tego samego programu. Na przykład:

typedef char my_char[8]; 

typedef struct tag_my_struct 
{ 
    long int  id; 
    my_char   chars[2]; 
    int    numerics[4] 
    float   decimals[4]; 
} my_struct; 

__kernel void foo(__global my_struct * input, 
        __global int * output) 
{ 
    int gid = get_global_id(0); 
    output[gid] = input[gid].numerics[3]== 2 ? 1 : 0; 
} 

Oczywiście, musisz zachować definicje wewnątrz i na zewnątrz OpenCL to samo. Upewnij się również, że typ ma ten sam rozmiar zarówno na urządzeniu, jak i na hoście (przy użyciu sizeof(my_struct) powinno wystarczyć). W niektórych przypadkach musiałem dostosować definicje, aby mieć pasujące rozmiary.

+4

Aby zapewnić równie wielkości rodzajów, że to dobry pomysł, aby użyć cl_ * typy w kodzie hosta (cl_int, cl_long, cl_float2, etc.). – dietr

+1

@dietr Pomaga również w poprawie kodu, jak w "ta zmienna ma być przekazana do jądra" – Thomas

4

Użyłem odpowiedzi VHristova i komentarza Dietr, aby mój działał. Ten kod działa dla mnie w OpenCL 1.2

jądro

typedef struct tag_my_struct{ 
    int a; 
    char b; 
}my_struct; 

__kernel void myKernel(__global my_struct *myStruct) 
{ 
    int gid = get_global_id(0); 
    (myStruct+gid)->a = gid; 
    (myStruct+gid)->b = gid + 1; 
} 

gospodarz

typedef struct tag_my_struct{ 
    cl_int a; 
    cl_char b; 
}my_struct; 

void runCode() 
{ 
    cl_int status = 0; 
    my_struct* ms = new my_struct[5]; 

    cl_mem mem = clCreateBuffer(*context, 0, sizeof(my_struct)*5, NULL, &status); 
    clEnqueueWriteBuffer(*queue, mem, CL_TRUE, 0, sizeof(my_struct)*5, &ms, 0, NULL, NULL); 

    status = clSetKernelArg(*kernel, 0, sizeof(ms), &mem); 

    size_t global[] = {5}; 
    status = clEnqueueNDRangeKernel(*queue, *kernel, 1, NULL, global, NULL, 0, NULL, NULL); 

    status = clEnqueueReadBuffer(*queue, mem, CL_TRUE, 0, sizeof(my_struct)*5, ms, 0, NULL, NULL); 

    for(int i = 0; i < 5; i++) 
     cout << (ms+i)->a << " " << (ms+i)->b << endl; 
} 

wyjście

0 ☺

1 ☻

2 ♥

3 ♦

4 ♣

+5

Dlaczego używać '(myStruct + gid) -> a = gid;' zamiast 'myStruct [gid] .a = gid; '. To dla mnie wygląda brzydko (jednak da takie same wyniki) – DarkZeros