tipos personalizados no kernel do OpenCL
Pergunta
É possível usar tipos personalizados no kernel do OpenCL como tipos BPF (mpz_t, mpq_t, ...)?
Para ter algo como isto (este kernel não constrói apenas por causa de #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]); }
Talvez adicionando argumentos diferentes para o quarto parâmetro ( Opções ) de clBuildProgram
?
Ou OpenCL já tem tipos que podem lidar com grande números?
Solução
Você pode usar tipos personalizados, mas nada utilizados nas necessidades do kernel a ser escritos especificamente para OpenCL. Confira este site talvez para como implementar números de precisão maiores: FP128
Edit: NVIDIA CUDA SDK tem um tipo de dados número complexo, não é o ideal, mas pode lhe dar algumas idéias sobre como eles poderiam fazer isto, OpenCL deve ser semelhante
.Outras dicas
Geralmente você pode usar qualquer tipo de um programa OpenCL. Mas desde que as importações não fazer o trabalho, você tem que re-defini-los dentro do mesmo programa. Por exemplo:
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;
}
No entanto, você obviamente precisa manter as definições dentro e fora OpenCL o mesmo. Também certifique-se o tipo tem o mesmo tamanho em ambos dispositivo e host (usando um sizeof(my_struct)
deve fazer o truque). Em alguns casos eu tive que ajustar as definições, para ter tamanhos correspondentes.
Eu usei a resposta de VHristov e comentário de Dietr pegar o meu trabalho. Esse código funciona para mim em OpenCL 1.2
do kernel
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;
}
hospedeiro
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;
}
saída
0 ?
1 ?
2 ?
3 ?
4 ?
Se você quiser incluir arquivos de cabeçalho no arquivo do kernel, você pode adicionar o -l dir como um argumento para clBuildProgram, onde dir é o diretório com os arquivos de cabeçalho .
Mais explicações aqui: incluir cabeçalhos de arquivo OpenCL .cl
Fonte: http: // www .khronos.org / registro / cl / SDK / 1,0 / docs / homem / XHTML / clBuildProgram.html