OpenCL внутри Visual Studio — можем ли мы скомпилировать один исполняемый файл, который будет использовать все возможные процессоры? OpenCL может получить все платформы, поддерживающие OpenCL?

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

//******************************************************************* 
// 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? (имеется в виду одна программа для всех ПК))


person Rella    schedule 29.01.2011    source источник


Ответы (3)


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

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

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

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

person dietr    schedule 29.01.2011

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

person Ben Voigt    schedule 29.01.2011

В принципе, код 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 поддерживает работу на платформах разных поставщиков, но, поскольку для скомпилированного кода ядра нет бинарной переносимости, вам необходимо предоставить исходный код ядра. .

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

Использовать

clGetPlatformInfo( ...  )

чтобы получить профиль и версию платформы.

Использовать

 clGetDeviceInfo( ... )

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

person Tim Child    schedule 02.02.2014