Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCL not finding platforms?

Tags:

c++

gpu

opencl

I am trying to utilize the C++ API for OpenCL. I have installed my NVIDIA drivers and I have tested that I can run the simple vector addition program provided here. I can compile this program with following gcc call and the program runs without problem.

gcc main.c -o vectorAddition -l OpenCL -I/usr/local/cuda-6.5/include

However, I would very much prefer to use the C++ API as opposed the very verbose host files needed for C.

I downloaded the C++ bindings from Khronos from here and placed the cl.hpp file in the same location as my other cl.h file. The code uses some C++11 so I can compile the code with:

g++ main.cpp -o vectorAddition_cpp -std=c++11 -l OpenCL -I/usr/local/cuda-6.5/include

but when I try to run the program I get the error:

clGetPlatformIDs(-1001)

I also tried the example provided here as well which gave a more helpful error message.

No platforms found. Check OpenCL installation!

The particular code which provides this error is this:

std::vector<cl::Platform> all_platforms;
    cl::Platform::get(&all_platforms);
    if(all_platforms.size()==0){
    std::cout<<" No platforms found. Check OpenCL installation!\n";
    exit(1);
    }

This seems so strange given that the C implementation runs without problem. Any insights would be sincerely appreciated.

EDIT

The C implementation actually isn't running correctly. Each addition is printed to equal zero. Checking the ret_num_platforms also returns 0. For some reason my setup is failing to find my GPU. What could I have missed? My install consists of the nvidia-340 driver and cuda-6.5 installed via apt-get and the .run file respectively.

like image 810
cdeterman Avatar asked Mar 20 '15 16:03

cdeterman


2 Answers

My sincerest thanks to @pasternak for helping me troubleshoot this problem. To solve it however I ended up needing to avoid essentially all ubuntu apt-get calls for install and just use the cuda run file for the full installation. Here is what fixed the problem.

  1. Purge existing nvidia and cuda implementations (sudo apt-get purge cuda* nvidia-*)
  2. Download cuda-6.5 toolkit from the CUDA toolkit archive
  3. Reboot computer
  4. Switch to ttyl (Ctrl-Alt-F1)
  5. Stop the X server (sudo stop lightdm)
  6. Run the cuda run file (sh cuda_6.5.14_linux_64.run)
  7. Select 'yes' and accept all defaults
  8. Required reboot
  9. Switch to ttyl, stop X server and run the cuda run file again and select 'yes' and default for everything (including the driver again)
  10. Update PATH to include /usr/local/cuda-6.5/bin and LD_LIBRARY_PATH to include /usr/local/cuda-6.5/lib64
  11. Reboot again
  12. Compile main.c program (gcc main.c -o vectorAddition -l OpenCL -I/usr/local/cuda-6.5/include)
  13. Verify works with ./vectorAddition

C++ API

  1. Download cl.hpp file from Khronos here noting that it is version 1.1
  2. Place cl.hpp file in /usr/local/cuda-6.5/include/CL with other cl headers.
  3. Compile main.cpp (g++ main.cpp -o vectorAddition_cpp -std=c++11 -l OpenCL -I/usr/local/cuda-6.5/include)
  4. Verify it works (./vectorAddition_cpp)

All output from both programs show the correct output for addition between vectors.

I personally find it interesting the Ubuntu's nvidia drivers don't seem to play well with the cuda toolkits. Possibly just for the older versions but still very unexpected.

like image 144
cdeterman Avatar answered Nov 02 '22 17:11

cdeterman


It is hard to say without running the specific code on your machine but looking at the difference between the example C code you said was working and the cl.hpp might give us a clue. In particular, notice that the C example uses the following line to simply read a single platform ID:

cl_platform_id platform_id = NULL; 
cl_int ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);

Notice that is passes 1 as its first argument. This assumes that at least one OpenCL platform exists and requests that the first one found is placed in platform_id. Additionally, note that even though the return code is assigned to "ret" is it not used to actually check if an error is returned.

Now if we look at the implementation of the static method used to queue the set of platforms in cl.hpp, i.e. cl::Platform::get:

static cl_int get(
    VECTOR_CLASS<Platform>* platforms)
{
    cl_uint n = 0;
    cl_int err = ::clGetPlatformIDs(0, NULL, &n);
    if (err != CL_SUCCESS) {
        return detail::errHandler(err, __GET_PLATFORM_IDS_ERR);
    }

    cl_platform_id* ids = (cl_platform_id*) alloca(
        n * sizeof(cl_platform_id));
    err = ::clGetPlatformIDs(n, ids, NULL);
    if (err != CL_SUCCESS) {
        return detail::errHandler(err, __GET_PLATFORM_IDS_ERR);
    }

    platforms->assign(&ids[0], &ids[n]);
    return CL_SUCCESS;
}

we see that it first calls

::clGetPlatformIDs(0, NULL, &n);

notice that the first parameter is 0, which tells the OpenCL runtime to return the number of platforms in "n". If this is successful it then goes on to request the actual "n" platform IDs.

So the difference here is that the C version is not checking that there is at least one platform and simply assuming that one exists, while the cl.hpp variant is and as such maybe it is this call that is failing.

The most likely reason for all this is that the ICD is not correctly installed. You can see this thread for an example of how to fix this issue:

ERROR: clGetPlatformIDs -1001 when running OpenCL code (Linux)

I hope this helps.

like image 2
pasternak Avatar answered Nov 02 '22 17:11

pasternak