Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCL crashes on call to clGetPlatformIDs

I am new to OpenCL. Working on a Core i5 machine with Intel(R) HD Graphics 4000, running Windows 7. I installed the newest Intel driver with support for OpenCL. GpuCapsViewer confirms I have OpenCL support setup. I Developed a simple HelloWorld program using Intel OpenCL SDK. I successfully compile the program but when run, it crashes upon call to clGetPlatformIDs() with a segmentation fault. This is my code:

#include <iostream>
#include <CL/opencl.h>

int main() {
    std::cout << "Test OCL  without driver" << std::endl;

    cl_int err;
    cl_uint num_platforms;

    err = clGetPlatformIDs(0, NULL, &num_platforms);
    if (err == CL_SUCCESS) {
        std::cout << "Success. Platforms available: " << num_platforms
                << std::endl;
    } else {
        std::cout << "Error. Platforms available: " << num_platforms
                << std::endl;
    }

    std::cout << "Test OCL without driver" << std::endl;
    std::cout << "Press button to exit." << std::endl;
    std::cin.get();
    return 0;
}

How can it be that GpuCapsViewer successfully confirms OpenCL support and can use it to run its demos, but I can't run my code? Both must be using the same functions, right?

Been working on this for days. Even tried re installing the drivers. Any Ideas?

GpuCapsViewer says:

DRIVER: R295.93 (r295_00-233) / 10.18.10.3496 (3-11-2014)
OPENGL: OpenGL 4.2 (GeForce GT 630M/PCIe/SSE2 with 290 ext.)
OPENCL: OpenCL 1.1, GeForce GT 630M compute units:2@950MHz
CUDA: GeForce GT 630M CC:2.1, multiprocessors:2@950MHz
PHYSX: GPU PhysX (NVIDIA GeForce GT 630M)
MULTI-GPU: no multi-GPU support (2 physical GPUs)


UPDATE:

Compilation line:

g++ -I"C:\Program Files (x86)\Intel\OpenCL SDK\4.4\include" -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Test3.d" -MT"Test3.d" -o "Test3.o" "../Test3.cpp"
Finished building: ../Test3.cpp

Linker line:

g++ -L"C:\Program Files (x86)\Intel\OpenCL SDK\4.4\lib\x64" -o "TestOpenCL"  ./HelloWorld.o ./HelloWorld2.o ./Test3.o   -lOpenCL
Finished building target: TestOpenCL

OS: Windows 7 Ultimate Version 6.1 (Build 7601: Service Pack 1)


UPDATE 2, Crash Information:

Problem Event Name: APPCRASH
Application Name:   TestOpenCL.exe
Application Version:    0.0.0.0
Application Timestamp:  53bc6ac5
Fault Module Name:  TestOpenCL.exe
Fault Module Version:   0.0.0.0
Fault Module Timestamp: 53bc6ac5
Exception Code: c0000005
Exception Offset:   0000000000002cc0
OS Version: 6.1.7601.2.1.0.256.1
Locale ID:  1033
Additional Information 1:   56e3
Additional Information 2:   56e3743a8a234df3bdeba0b507471c44
Additional Information 3:   8fe0
Additional Information 4:   8fe0ef5706153941955de850e5612393

UPDATE 3:

Used DependencyWalker(http://dependencywalker.com/) as a substitute for dumpbin. It generates the following warnings:

Warning: At least one delay-load dependency module was not found.
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.

The warnings seem to refer to the following DLLs which are all marked with a "Error opening file. The system can not find the file specified(2)" error message.

API-MS-WIN-CORE-COM-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-ERROR-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-ROBUFFER-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-STRING-L1-1-0.DLL
API-MS-WIN-SHCORE-SCALING-L1-1-0.DLL
DCOMP.DLL
IESHIMS.DLL

UPDATE 4, GDB BACKTRACE:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000402cc0 in clGetPlatformIDs ()
(gdb) backtrace full
#0  0x0000000000402cc0 in clGetPlatformIDs ()
No symbol table info available.
#1  0x0000000000402af3 in main () at ../Test3.cpp:11
        err = 0
        num_platforms = 0
        platform = 0x0

(gdb) backtrace
#0  0x0000000000402cc0 in clGetPlatformIDs ()
#1  0x0000000000402af3 in main () at ../Test3.cpp:11

UPDATE 5, GDB DISASS:

(gdb) disass
Dump of assembler code for function clGetPlatformIDs:
=> 0x0000000000402cc0 <+0>:     jmpq   *0x4b74e8(%rip)        # 0x8ba1ae
   0x0000000000402cc6 <+6>:     nop
   0x0000000000402cc7 <+7>:     nop
End of assembler dump.

UPDATE 6, GDB INFO SHARED:

(gdb) INFO SHARED
From                To                  Syms Read   Shared Object Library
0x0000000077191000  0x00000000773384e0  Yes (*)     C:\Windows\system32\ntdll.dll
0x0000000077071000  0x000000007718eab4  Yes (*)     C:\Windows\system32\kernel32.dll
0x000007fefc081000  0x000007fefc0eb13c  Yes (*)     C:\Windows\system32\KernelBase.dll
0x000007fedf8d1000  0x000007fedf8e96aa  Yes (*)     C:\Windows\system32\OpenCL.dll
0x000007fefe101000  0x000007fefe1da628  Yes (*)     C:\Windows\system32\advapi32.dll
0x000007fefe061000  0x000007fefe0fe4bc  Yes (*)     C:\Windows\system32\msvcrt.dll
0x000007fefdcc1000  0x000007fefdcde39a  Yes (*)     C:\Windows\SYSTEM32\sechost.dll
0x000007fefc6a1000  0x000007fefc7cc914  Yes (*)     C:\Windows\system32\rpcrt4.dll
(*): Shared library is missing debugging information.

Binary file, x64 and include folders:

https://drive.google.com/file/d/0BxKA63T2GnKMRW02QWZnam5lSGM/edit?usp=sharing

UPDATE 7, GPUcaps situation:

GPUcaps detects 2 GPUs:

  • GPU 1: Intel(R) HD Graphics 4000
  • GPU 2: NVIDIA GeForce GT 630M

You can see the screenshot here:

https://drive.google.com/file/d/0BxKA63T2GnKMa00tU1gydGNJeXc/edit?usp=sharing

UPDATE 8:

Per @antiduh 's answer, I have been trying to link directly against OpenCL.dll present in Windows\System32 folder. I am using mingw64. I get this:

Invoking: Cross G++ Linker
g++ -L"C:\Windows\System32" -o "TestOpenCL"  ./HelloWorld.o ./HelloWorld2.o ./Test3.o   -lOpenCL
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/OpenCL.dll when searching for -lOpenCL
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/OpenCL.dll when searching for -lOpenCL
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lOpenCL
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/msvcrt.dll when searching for -lmsvcrt
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/advapi32.dll when searching for -ladvapi32
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/shell32.dll when searching for -lshell32
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/user32.dll when searching for -luser32
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/kernel32.dll when searching for -lkernel32
d:/ws/apps_inst/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.7.1/../../../../x86_64-w64-mingw32/bin/ld.exe: skipping incompatible C:\Windows\System32/msvcrt.dll when searching for -lmsvcrt

UPDATE 9: I can now compile, link and run the sample code manually with the following line.

g++ -I. s.cpp -L. -lOpenCL

I simplified everything and it just worked. This is obviously very different from the compile and link commands used by Eclipse. Any idea which of the parameters used by eclipse cause the problem? And also, why is it that eclipse first compiles to object files and then attempts to link them, in two separate steps?

like image 711
jowharshamshiri Avatar asked Jul 08 '14 21:07

jowharshamshiri


1 Answers

There are three total ways for a program to use external library:

  • Static linkage: Directly insert the library into your executable. The external library, presented as a .lib file, contains nothing but packaged .obj files. Your program invokes functions from the library as normal. The compiler extracts executable code from the lib, inserts it, and performs full, complete linkage against it. It is as if you compiled against the imported functions like they were from your own source code.
  • Load-time dynamic linkage, aka 'implicit linking': Load the library when you launch the program. The external library, presented as a .dll containing executable code, and a .lib file containing the exports from the .dll, is tentatively linked against by the compiler and linker. The linker uses the .lib to understand how to call the .dll at run-time, and to put in deferred bindings into your program. When the OS launches your program, it performs 'load-time' linking - it looks up all of the deferred bindings, attempts to find a .dll file, finishes the linkage of the deferred bindings in your program, and allows you to run the file.
  • "Pure" run-time dynamic linkage, aka 'explicit linking': Directly calling LoadLibrary. Your program has no specific references to any .lib, .dll, or otherwise. Your program starts running, itself calls LoadLibrary with a string path to a .dll. LoadLibrary merges the .dll into your virtual memory, and then your program calls GetProcAddress to get a function pointer to the function you want to call. You then use that function pointer to make calls.

You can't normally link against a dll without the .lib. The compiler wants to resolve those function call references to real addresses, but we don't want to put in real addresses since we want DLLs to be loaded into any arbitrary memory address (DLLs are 'relocatable').

From my understanding, a .lib used as an import library contains stubs that the main program links directly against - so all calls in the program go through the stubs. The stubs then have references to an 'Import Address Table". When the OS loads a DLL into memory for a process, it does so by filling out the IAT. The stub then just calls the DLL by making an indirect jump that references the right slot in the IAT.

So if a DLL MathLib has an exported function Factorial that my exe is importing, then the import .lib file has an actual function Factorial that my exe statically compiles against. That Factorial in that .lib looks like the following psuedo code:

int Factorial( int value ) { 
   // Read MathLib's IAT which should always be at address 0x8ba100.
   // Factorial's real address gets stored in slot 2, so add 8 to the address
   // to read from.
   __asm jmp *0x8ba108; // nb this is an indirect jump.
}

And then we hope that when the OS loads that DLL, that IAT is filled out correctly, else we jump into nothingness.

So I think what happened is that you were compiling against one .lib, but 'load-time' linking against the wrong opencl.dll. The IAT was never created, or was created in the wrong place, and so you jumped into nothingness; that's why this line created a segfault:

0x0000000000402cc0 <+0>: jmpq *0x4b74e8(%rip) # 0x8ba1ae

So lets figure out why we linked wrong. There could be 3 sets of opencl.dll/opencl.lib files on your computer:

  • The opencl.lib/dll that comes from Kronos, and is actually just a stub/loader library that figures out what real providers are on your computer and does dispatches function calls to the actual right lib.
  • The opencl.lib/dll that comes from Intel from their SDK and drivers.
  • The opencl.lib/dll that comes from Nvidia from their drivers.

Which of these files did you actually have? My estimate is thus:

  • The opencl.dll that came from kronos got installed into c:\windows\system32.
  • There is no opencl.lib from Kronos
  • There was probably no opencl.lib from nvidia, since you didn't have their SDK installed.
  • You probably had an opencl.lib and opencl.dll from Intel since you did have their SDK installed.

You were definitely linking against the Intel opencl.lib, but appeared to be loading the Kronos opencl.dll in c:\windows\system32. One solution would be to get the program to load the Intel opencl.dll when you run the program by putting their dll in your program's directory.

However, you state that you were able to make things work using this compilation line:

g++ -I. s.cpp -L. -lOpenCL

There's something neat about gcc on Windows - in order to link against a library, you don't need to have the .lib. Gcc figures it out for you by inspecting the dll; other people have figured out how to do the same when someone gives them a dll but no lib. In most other compilers, especially Visual Studio, you need to have a .lib and a .dll to link against something. That's why the Win SDK installs hundreds of .lib (kernel32.lib, eg). Turns out that the compiler can actually infer it if it wanted to, but libs exist as an archaic mechanism.

Anyway, you ran that above gcc link line, it found a suitable opencl.dll using the search path, invented its own .lib for it, and compiled against it; you launched your program, it used that same search path to get an opencl.dll, it was the same one you compiled against, so your program runs. Whew.

I still have some suggestions:

  • Find an opencl.lib and opencl.dll pair that come from Kronos's "Installable Client Driver" ICD Loader. That loader will then figure out how to bind to a particular provider (nvidia, intel, etc) at runtime.
  • Distribute the Kronos opencl.dll with your application so that you will never accidentally run-time-link against the wrong file.
  • Uninstall the Intel SDK, assuming it's providing opencl.lib/opencl.dll files that are specific to Intel.

Some more relevant questions on libs and dlls:

  • When building a DLL file, does the generated LIB file contain the DLL name?
  • Why are LIB files beasts of such a duplicitous nature?
like image 167
antiduh Avatar answered Oct 24 '22 23:10

antiduh