6

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?

mpromonet
  • 11,326
  • 43
  • 62
  • 91
  • 1
    I'm stabbing in the dark here, but: does `num_platforms` need to be set to zero before calling clGetPlatformIds for the first time? Do you need to coerce the '0' first parameter into a cl_int before passing it? What is your compilation line and your linker line? Are you linking against the right version of the libraries? – antiduh Jul 08 '14 at 21:48
  • What platform are you on (Windows, Linux)? If linux, what does ldd say about your binary? Does that match up with where you expect to get your libraries from? – antiduh Jul 08 '14 at 21:54
  • 1
    Might have found your answer here: http://stackoverflow.com/a/20033042/344638 - The `(0, NULL, &numPlatforms)` case might not be handled in your OpenCL SDK. Try executing it with a valid reference to a cl_platform_id variable, eg `clGetPlatformIDs(1, &platform, &numPlatforms)` and see if it sets numPlatforms correctly. – antiduh Jul 08 '14 at 21:58
  • @antiduh Using Windows. Tried setting num_platforms to 0, and also passing a valid cl_platform_id reference. No change. Updated the question with the information you requested. Thanks for your time. – jowharshamshiri Jul 08 '14 at 22:10
  • Your code looks correct to me (I work with OpenCL). antiduh's comment may be good, but the spec is quite clear that `0, NULL, &num_platforms` should be good arguments to the function. Can you show the actual crash information (e.g. what address is being accessed "badly"?) [Note, I do NOT work for Intel, so have no particular knowledge of their product] – Mats Petersson Jul 08 '14 at 22:14
  • Well, you've started to hit the limit of sanity; it looks like everything you're doing is as it should be, but it must be something. I noticed that you're compiling and linking together multiple files; perhaps remove those so you can see if they have anything to do with the problem. I might try using VS to see what modules are loaded, or use dumpbin, to see exactly what DLLs get linked against. Just to triple check, are you sure you're compiling 64 bit? – antiduh Jul 08 '14 at 22:23
  • Also, what does "without driver" mean? Is there some context we should understand? – antiduh Jul 08 '14 at 22:24
  • @antiduh I got the code off the internet. No context, just a meaningless string. Using Eclipse with MinGW64. Will try to find a substitute for dumpbin... – jowharshamshiri Jul 08 '14 at 22:36
  • @MatsPetersson I have updated the question with crash data generated by Windows. Does that suffice? – jowharshamshiri Jul 08 '14 at 22:38
  • Any chance you can run your code in a debugger and post a stack-trace? (Any of gdb, windbg or visual studio - all of which should be available to download with no cost/free to use) – Mats Petersson Jul 08 '14 at 22:47
  • @antiduh I have updated the question with the information you requested. – jowharshamshiri Jul 08 '14 at 22:51
  • Note that your crash log seems to imply that the crash is IN YOUR application, hence I would like to see where it crashes... – Mats Petersson Jul 08 '14 at 22:56
  • @MatsPetersson I have updated the question with the information you requested. – jowharshamshiri Jul 08 '14 at 23:02
  • Ok, so you are in the function clGetPlatformIDs, Seems strange that it shouldn't work tho'. Any chance of a `info regs` and `disass` when it's crashed? – Mats Petersson Jul 08 '14 at 23:14
  • @MatsPetersson Perhaps there is some trivial detail that I overlooked? Please do assume that I am a newbie. I am a Java developer. Haven't had much to do with C++/OpenCL. – jowharshamshiri Jul 09 '14 at 00:03
  • I think your application is mislinked, though I don't know why. If your program segfautls on this line `0x0000000000402cc0 <+0>: jmpq *0x4b74e8(%rip) # 0x8ba1ae` then that means that there's no code mapped at the address 0x8ba1ae, which the OpenCL code probably expects is their shared library. You could try to analyze that by dumping where shared libraries are loaded. `info shared` is how to do it in gdb, but I'm not sure if gdb for windows handles that. Any chance you could post your binary somewhere, so we can analyze it? Maybe zip up the OpenCL 'include' and 'x64' directories? – antiduh Jul 09 '14 at 00:22
  • I might also recommend trying to get it to compile and debug in Visual Studio, just in case mingw is doing something strange. You can install VS Express for free - http://www.visualstudio.com/en-US/products/visual-studio-express-vs. You'll want to install "Express 2013 for Windows Desktop". If you decide to go this route, you'll need to modify the project to set the extra include and library directories for the OpenCL stuff. This article has the details: http://blogs.msdn.com/b/vsproject/archive/2009/07/07/vc-directories.aspx – antiduh Jul 09 '14 at 00:35
  • Ok, doing good. You can see from the 'info shared' that opencl.dll was mapped to memory completely different from where the jmp wants to go. I'm guessing that the run-time linker is confused, maybe it's finding the wrong opencl.dll? – antiduh Jul 09 '14 at 01:12
  • I'm a little confused, your GPUcaps seems to indicate an nVidia card, but you're using the Intel OpenCL SDK and only mentioned your CPU's capabilities. Are you trying to run this on an nVidia card or the Intel built in HD graphics? IIRC, the Intel openCL SDK is only for Intel CPUs/GPUs, if you want to run your openCL code on an nVidia GPU, don't you need to compile under their SDK? – stix Jul 09 '14 at 01:16
  • @antiduh If I understand correctly, you are implying that there are actually 2 linkers? One used after compilation, and one at run-time. How can I configure the run-time linker, seeing that it is confused? – jowharshamshiri Jul 09 '14 at 01:17
  • @user3818101 - yeah, dynamic link libraries aren't resolved (linked) until you run the program, and happens every time you run the program. This is necessary since every different program might use a dll, but each might need to put it in a different place in memory. – antiduh Jul 09 '14 at 01:23
  • @stix - you figured it out. He has two opencl installations. – antiduh Jul 09 '14 at 01:25
  • @antiduh I have installed only the Intel Graphics Driver. However, in GPUcaps under OpenCL tab, I can choose "1: NVIDIA CUDA" or "2: Intel(R) OpenCL". Should this not be? How do I fix it? – jowharshamshiri Jul 09 '14 at 01:35
  • Well, there's different things to install here - one is the SDK, the other is the driver. The SDK allows you to build programs that use an OpenCL installation. The Driver provides the actual OpenCL installation. How else would users use your programs if they only install drivers? They don't install the SDK. So really, you have three things installed: 1) The NVidia drivers 2) The Intel Drivers and 3) The Intel SDK. – antiduh Jul 09 '14 at 01:48
  • @user3818101 - I've made some heavy edits to my answer to reflect your new discovers (linking with `gcc -L.` works). – antiduh Jul 10 '14 at 20:42

1 Answers1

6

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:

antiduh
  • 11,853
  • 4
  • 43
  • 66
  • Shouldn't the program be linking against the ICD loader OpenCL.dll rather than any vendor version? – Spudd86 Jul 09 '14 at 01:38
  • @Spudd86 - That would be best. – antiduh Jul 09 '14 at 01:41
  • Also all OpenCL.dll should really be ABI compatible otherwise it sort of defeats the purpose of OpenCL... – Spudd86 Jul 09 '14 at 01:56
  • Ah, multipel OpenCL providors - a problem I typically don't run into at work! ;) – Mats Petersson Jul 09 '14 at 08:01
  • @antiduh I checked and you are right in Edit 2. However, I can't link against the ICD DLL present in System32 Folder. I have updated my original answer with new information. – jowharshamshiri Jul 10 '14 at 10:57
  • @antiduh Kudos for your powers of deduction. Right on all counts. Still can't figure out why eclipse can't directly link against the ICD DLL but I can. Prior to UPDATE 8, I'd removed all references to the Intel .lib from my configuration. One of the parameters used by Eclipse must be the problem. And also, regarding UPDATE 9, as is evident by my use of parameters "-L." and "-I.", I'd copied the OpenCL.dll from Kronos and the include files to my working directory. Furthermore, I checked and all the DLLs you predicted are present, the Intel driver also installs NVIDIA's DLL, "nvcuda.dll". – jowharshamshiri Jul 12 '14 at 00:09
  • @antiduh Oh, and I would upvote the effort you put in the thorough answer, except that I don't seem to have enough "reputation". – jowharshamshiri Jul 12 '14 at 00:54
  • @jowharshamshiri - No worries, just glad to help. – antiduh Jul 12 '14 at 01:55