Qual é a diferença entre criar um objeto de buffer com clcreatebuffer + cl_mem_copy_host_ptr vs. clcreatebuffer + clenqueueWriteBuffer?

StackOverflow https://stackoverflow.com/questions/3832963

  •  26-09-2019
  •  | 
  •  

Pergunta

Eu já vi as duas versões nos tutoriais, mas não consegui descobrir quais são suas vantagens e desvantagens. Qual é o apropriado?

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL);
clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

vs.

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL);

Obrigado.

Atualizar

Eu adicionei CL_MEM_COPY_HOST_PTR, para o segundo exemplo para torná -lo correto.

Foi útil?

Solução

Presumo que o InputData não seja nulo.

Nesse caso, a segunda abordagem não deve funcionar, uma vez que as especificações dizem que o ClcreateBuffer retorna nulo e um erro, se:

CL_INVALID_HOST_PTR se host_ptr for nulo e cl_mem_use_host_ptr ou cl_mem_copy_host_ptr são definidos em sinalizadores ou se host_ptr não for nulo, mas cl_mem_copy_host_ptr ou cl_mem_use_host_ptr não são definidos em flags.

Então você quer dizer

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

ou

clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);

O primeiro deve ser mais ou menos o mesmo que a primeira abordagem que você mostrou, enquanto a segunda não copia os dados, mas, em vez disso, use o local da memória fornecida para armazenamento de buffer (porções de cache ou toda na memória do dispositivo) . Qual desses dois é melhor depende do cenário de uso, obviamente.

Personalidade Eu prefiro usar a abordagem de duas etapas de alocar primeiro o buffer e depois preencher -o com um WritEtoBuffer, já que acho mais fácil ver o que acontece (é claro que um passo pode ser mais rápido (ou pode não, isso é apenas um palpite)))

Outras dicas

Durante meu trabalho com o OpenCl, encontrei uma diferença muito importante entre

cl_mem CT = clCreateImage3DContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR , Volume_format, X, Y, Z, rowPitch, slicePitch, sourceData, &error);

e

cl_mem CT = clCreateImage3D(Context, CL_MEM_READ_ONLY , Volume_format, X, Y, Z, 0, 0, 0, &error);
error = clEnqueueWriteImage(CommandQue, CT, CL_TRUE, origin, region, rowPitch, slicePitch, sourceData, 0, 0, 0);

Para a primeira abordagem, o OpenCL copiará o ponteiro do host não direto para a GPU. Primeiro, ele alocará um segundo buffer temporário no host que pode causar problemas se você carregar coisas grandes como um CT na GPU. Por um curto período de tempo, a memória necessária é o dobro do tamanho da CT. Além disso, os dados não são copiados durante esta função. Ele é copiado durante a configuração de argumento para a função do kernel que usa o objeto de imagem 3D.

A segunda abordagem direciona os dados para a GPU. Não há alocações adicionais feitas pelo OpenCL. Eu acho que isso é provavelmente o mesmo para objetos de buffer normal.

O bom aspecto da primeira abordagem é que "ClenqueueWriteBuffer" permite que você atribua um evento à cópia de um buffer. Então, digamos que você queira medir o tempo necessário para copiar dados para a GPU usando as opções GPU_Profiling, você poderá fazê -lo com a primeira abordagem, mas não com a segunda.

A segunda abordagem é mais compacta, mais fácil de ler e requer menos linhas para codificar.

Uma grande diferença que eu encontrei:

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY,sizeof(float) * DATA_SIZE, NULL, NULL); clEnqueueWriteBuffer(command_queue, input, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputdata, 0, NULL, NULL);

Este primeiro conjunto de comandos criará um buffer vazio e a prenderá um comando na sua fila de comando para preencher o buffer.

cl_mem input = clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, ,sizeof(float) * DATA_SIZE, inputdata, NULL)

Este segundo comando criará o buffer e o preencherá imediatamente. Observe que não há uma fila de comando nesta lista de argumentos, por isso usa o conteúdo dos dados de entrada como está agora.

Se você já está executando o código CL e seu ponteiro de origem depende de um comando anterior na fila de comando concluindo (por exemplo, uma leitura envolvida de um buffer de saída anterior), você definitivamente deseja usar o 1º método. Se você tentar criar e preencher o buffer em um único comando, você acabará com uma condição de corrida na qual o conteúdo do buffer não aguardará corretamente a conclusão do seu buffer anterior.

Bem, a principal diferença entre esses dois é que o primeiro aloca a memória no dispositivo e, em seguida, copia dados para essa memória. O segundo apenas aloca.

Ou você quis dizer clCreateBuffer(context,CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,sizeof(float) * DATA_SIZE, inputdata, NULL);?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top