OpenCL внутри Visual Studio - можем ли мы скомпилировать один exe-файл, который бы использовал все возможные процессоры OpenCL может получить все платформы, поддерживающие OpenCL? - PullRequest
0 голосов
/ 29 января 2011

Итак, я имею в виду компиляцию кода вроде:

//******************************************************************* 
// Demo OpenCL application to compute a simple vector addition  
// computation between 2 arrays on the GPU 
// ****************************************************************** 
#include <stdio.h> 
#include <stdlib.h> 
#include <CL/cl.h> 

// OpenCL source code 
const char* OpenCLSource[] = {   
"__kernel void VectorAdd(__global int* c, __global int* a,__global int* b)", 
  "{", 
  "  // Index of the elements to add \n", 
  "  unsigned int n = get_global_id(0);", 
  "  // Sum the n’th element of vectors a and b and store in c \n", 
  "  c[n] = a[n] + b[n];", 
  "}" 
}; 

// Some interesting data for the vectors 
int InitialData1[20] = {37,50,54,50,56,0,43,43,74,71,32,36,16,43,56,100,50,25,15,17}; 
int InitialData2[20] = {35,51,54,58,55,32,36,69,27,39,35,40,16,44,55,14,58,75,18,15}; 

// Number of elements in the vectors to be added 
#define SIZE 2048   

// Main function  
// ********************************************************************* 
int main(int argc, char **argv) 
{ 
   // Two integer source vectors in Host memory 
    int HostVector1[SIZE], HostVector2[SIZE]; 

    // Initialize with some interesting repeating data 
    for(int c = 0; c < SIZE; c++)  
    {   
HostVector1[c] = InitialData1[c%20]; 
HostVector2[c] = InitialData2[c%20]; 
    } 

    // Create a context to run OpenCL on our CUDA-enabled NVIDIA GPU  
    cl_context GPUContext = clCreateContextFromType(0, CL_DEVICE_TYPE_GPU,  
                    NULL, NULL, NULL); 

    // Get the list of GPU devices associated with this context 
    size_t ParmDataBytes; 
    clGetContextInfo(GPUContext, CL_CONTEXT_DEVICES, 0, NULL, &ParmDataBytes); 
    cl_device_id* GPUDevices = (cl_device_id*)malloc(ParmDataBytes); 
    clGetContextInfo(GPUContext, CL_CONTEXT_DEVICES, ParmDataBytes, GPUDevices, NULL);
    // Create a command-queue on the first GPU device 
    cl_command_queue GPUCommandQueue = clCreateCommandQueue(GPUContext,  
                 GPUDevices[0], 0, NULL); 

    // Allocate GPU memory for source vectors AND initialize from CPU memory 
    cl_mem GPUVector1 = clCreateBuffer(GPUContext, CL_MEM_READ_ONLY | 
          CL_MEM_COPY_HOST_PTR, sizeof(int) * SIZE, HostVector1, NULL); 
    cl_mem GPUVector2 = clCreateBuffer(GPUContext, CL_MEM_READ_ONLY | 
               CL_MEM_COPY_HOST_PTR, sizeof(int) * SIZE, HostVector2, NULL); 

    // Allocate output memory on GPU 
    cl_mem GPUOutputVector = clCreateBuffer(GPUContext, CL_MEM_WRITE_ONLY, 
               sizeof(int) * SIZE, NULL, NULL); 

    // Create OpenCL program with source code 
    cl_program OpenCLProgram = clCreateProgramWithSource(GPUContext, 7, 
               OpenCLSource, NULL, NULL); 

    // Build the program (OpenCL JIT compilation) 
    clBuildProgram(OpenCLProgram, 0, NULL, NULL, NULL, NULL); 

    // Create a handle to the compiled OpenCL function (Kernel) 
    cl_kernel OpenCLVectorAdd = clCreateKernel(OpenCLProgram, "VectorAdd", NULL);

    // In the next step we associate the GPU memory with the Kernel arguments 
    clSetKernelArg(OpenCLVectorAdd, 0, sizeof(cl_mem),(void*)&GPUOutputVector); 
    clSetKernelArg(OpenCLVectorAdd, 1, sizeof(cl_mem), (void*)&GPUVector1); 
    clSetKernelArg(OpenCLVectorAdd, 2, sizeof(cl_mem), (void*)&GPUVector2); 

    // Launch the Kernel on the GPU 
    size_t WorkSize[1] = {SIZE};  // one dimensional Range 
    clEnqueueNDRangeKernel(GPUCommandQueue, OpenCLVectorAdd, 1, NULL, 
         WorkSize, NULL, 0, NULL, NULL); 

    // Copy the output in GPU memory back to CPU memory 
    int HostOutputVector[SIZE]; 
    clEnqueueReadBuffer(GPUCommandQueue, GPUOutputVector, CL_TRUE, 0, 
               SIZE * sizeof(int), HostOutputVector, 0, NULL, NULL); 

    // Cleanup  
    free(GPUDevices); 
    clReleaseKernel(OpenCLVectorAdd);   
    clReleaseProgram(OpenCLProgram); 
    clReleaseCommandQueue(GPUCommandQueue); 
    clReleaseContext(GPUContext); 
    clReleaseMemObject(GPUVector1); 
    clReleaseMemObject(GPUVector2); 
    clReleaseMemObject(GPUOutputVector); 

    // Print out the results 
    for (int Rows = 0; Rows < (SIZE/20); Rows++, printf("\n")){ 
        for(int c = 0; c <20; c++){ 
            printf("%c",(char)HostOutputVector[Rows * 20 + c]); 
    } 
    }  
    return 0; 
}

в exe с VS (в моем случае 08) можем ли мы быть уверены, что в любом месте, где мы его запустим, он будет использовать максимум вычислительной мощности ПК? Если нет, как это сделать? (кстати, как заставить его работать с картами AMD и другими графическими процессорами, отличными от CUDA? (имеется в виду одна программа для всех ПК))

Ответы [ 3 ]

3 голосов
/ 29 января 2011

Этот код должен выполняться на любом ПК под управлением Windows с драйверами графического процессора с поддержкой OpenCL.

Однако, чтобы улучшить мобильность и, возможно, производительность, вам следует быть осторожнее с некоторыми вещами.

  • Вам требуется рабочая реализация OpenCL.Это не будет работать вообще, если реализация OpenCL недоступна - в этом случае отсутствует DLL.
  • Вам требуется реализация OpenCL с помощью графического процессора.Лучше всего запросить все платформы и устройства OpenCL и отдать предпочтение устройствам с графическим процессором
  • Вы просто используете первое доступное устройство, которое может быть не идеальным.Лучше определить наиболее мощное устройство с помощью эвристики или предоставить пользователю выбор.

Кроме того, вы неправильно используете clCreateContextFromType.Вам нужно для явного указания идентификатора платформы (вы можете запросить идентификаторы с clGetPlatformID) в реализациях OpenCL с поддержкой ICD.Все сегодняшние реализации OpenCL используют оболочку ICD.(Ну кроме Apple)

2 голосов
/ 29 января 2011

При написании вашей программы для OpenCL она будет работать на любом компьютере, который поддерживает ваш исполняемый формат и имеет драйвер OpenCL. Может быть ускорено с помощью графического процессора и не может, и не будет столь же быстрым, как аппаратный код для конкретного оборудования, но должно быть достаточно переносимым. Если под переносимостью вы подразумеваете архитектуру процессора x86 и ОС Windows, и меняется только видеокарта. Для истинной переносимости вам нужно будет распространять исходный код или байт-код, скомпилированный JIT, а не двоичные файлы C или C ++.

0 голосов
/ 02 февраля 2014

В принципе код OpenCL должен запускаться где угодно. Но есть несколько версий его реализации, 1.1 и 1.2 ( еще не на Nvidia ) с выпуском спецификации 2.0 и когда-нибудь. Есть несовместимости API между версиями OpenCL. AMD предоставила способ для реализации OpenCL 1.2 использовать вызовы API 1.1.

Существуют важные замечания, отмеченные другими авторами выше, OpenCL ICD http://www.khronos.org/registry/cl/extensions/khr/cl_khr_icd.txt поддерживает запуск на разных платформах Vendor, но поскольку для скомпилированного кода ядра нет двоичной переносимости, вам необходимо предоставить исходный код ядра.

В общем случае проверьте версию и профиль платформы OpenCL. Помните, что в системе может быть несколько платформ и устройств. Затем определите, какая минимальная версия и профиль платформы доступны для вас. Если ваш код зависит от определенных расширений устройства, например с плавающей запятой двойной точности, вам необходимо проверить их наличие на устройстве.

Использование

clGetPlatformInfo( ...  )

для получения профиля и версии платформы.

Используйте

 clGetDeviceInfo( ... )

, чтобы получить конкретные расширения устройства

...