OpenCL在调用clGetPlatformIDs时崩溃

时间:2014-07-08 21:27:06

标签: c++ opencl intel nvidia

我是OpenCL的新手。在运行Windows 7的Intel(R)HD Graphics 4000 Core i5机器上工作。我安装了支持OpenCL的最新Intel驱动程序。 GpuCapsViewer确认我有OpenCL支持设置。我使用英特尔OpenCL SDK开发了一个简单的HelloWorld程序。我成功编译了程序,但在运行时,它在调用clGetPlatformIDs()时发生崩溃并出现分段错误。这是我的代码:

#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;
}

GpuCapsViewer如何成功确认OpenCL支持并可以使用它来运行其演示,但我无法运行我的代码?两者都必须使用相同的功能,对吗?

已经有好几天了。甚至尝试重新安装驱动程序。任何想法?

GpuCapsViewer说:

  

驾驶员:R295.93(r295_00-233)/ 10.18.10.3496(3-11-2014)
  OPENGL:OpenGL 4.2(GeForce GT 630M / PCIe / SSE2,290分机)   OPENCL:OpenCL 1.1,GeForce GT 630M计算单位:2 @ 950MHz
  CUDA:GeForce GT 630M CC:2.1,多处理器:2 @ 950MHz
  PHYSX:GPU PhysX(NVIDIA GeForce GT 630M)
  MULTI-GPU:没有多GPU支持(2个物理GPU)


更新:

编译行:

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

链接线:

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

操作系统:Windows 7 Ultimate Version 6.1(Build 7601:Service Pack 1)


更新2,崩溃信息:

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

更新3:

使用DependencyWalker(http://dependencywalker.com/)替代dumpbin。它会生成以下警告:

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.

警告似乎是指以下DLL,这些DLL都标有&#34;错误打开文件。系统找不到指定的文件(2)&#34;错误信息。

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

更新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

更新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.

更新6,GDB信息共享:

(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.

二进制文件,x64和包含文件夹:

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

更新7,GPUcaps情况:

GPUcaps检测到2个GPU:

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

您可以在此处看到屏幕截图:

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

更新8:

根据@antiduh的回答,我一直在尝试直接链接Windows \ System32文件夹中的OpenCL.dll。我正在使用mingw64。我明白了:

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

更新9: 我现在可以使用以下行手动编译,链接和运行示例代码。

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

我简化了所有内容,但它才有效。这显然与Eclipse使用的编译和链接命令非常不同。知道eclipse使用哪个参数导致问题?而且,为什么eclipse首先编译成目标文件,然后尝试在两个单独的步骤中链接它们?

1 个答案:

答案 0 :(得分:4)

程序使用外部库有三种方式:

  • 静态链接:直接将库插入可执行文件。外部库以.lib文件形式提供,只包含打包的.obj文件。您的程序正常调用库中的函数。编译器从lib中提取可执行代码,插入它,并对其执行完整,完整的链接。就像你根据自己的源代码编译导入的函数一样。
  • 加载时动态链接,也称为隐式链接&#39;:启动程序时加载库。外部库(包含.dll包含可执行代码)和.lib文件(包含.dll的导出)暂时由编译器和链接器链接。链接器使用.lib来了解如何在运行时调用.dll,并将延迟绑定放入程序中。当操作系统启动您的程序时,它会执行加载时间&#39;链接 - 它查找所有延迟绑定,尝试查找.dll文件,完成程序中延迟绑定的链接,并允许您运行该文件。
  • &#34;纯&#34;运行时动态链接,又名&#39;显式链接&#39;:直接调用LoadLibrary。您的程序没有任何特定的.lib,.dll或其他引用。您的程序开始运行,本身调用LoadLibrary,其字符串路径为.dll。 LoadLibrary将.dll合并到您的虚拟内存中,然后您的程序调用GetProcAddress以获取指向您要调用的函数的函数指针。然后使用该函数指针进行调用。

如果没有.lib,您通常无法链接到dll。编译器希望解析那些对实际地址的函数调用引用,但是我们不想放入实际地址,因为我们希望将DLL加载到任意存储器地址中(DLL可以重新定位&#39;)

根据我的理解,用作导入库的.lib包含主程序直接链接的存根 - 因此程序中的所有调用都会通过存根。然后,存根引用了“导入地址表”#34;。当操作系统将DLL加载到进程的内存中时,它会通过填写IAT来实现。然后,存根通过进行引用IAT中正确插槽的间接跳转来调用DLL。

因此,如果DLL MathLib具有我的exe导入的导出函数Factorial,则导入.lib文件具有我的exe静态编译的实际函数Factorial。那个.lib中的Factorial看起来像下面的伪代码:

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.
}

然后我们希望当操作系统加载该DLL时,IAT正确填写,否则我们会陷入虚无。

所以我认为发生的事情是你正在编译一个.lib,但是#load load time&#39;链接错误的opencl.dll。 IAT从未创建过,或者是在错误的地方创建的,所以你就陷入虚无之中;这就是为什么这一行创建了一个段错误:

  

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

因此,让我们弄清楚为什么我们链接错误。您的计算机上可能有3组opencl.dll / opencl.lib文件:

  • 来自Kronos的opencl.lib / dll,实际上只是一个存根/加载程序库,可以找出计算机上真正的提供程序,并将函数调用分派给实际的正确的lib。
  • 来自英特尔的opencl.lib / dll来自他们的SDK和驱动程序。
  • 来自Nvidia的opencl.lib / dll来自他们的驱动程序。

您实际拥有以下哪些文件?因此我的估计是:

  • 来自kronos的opencl.dll已安装到c:\windows\system32
  • Kronos没有opencl.lib
  • 可能没有来自nvidia的opencl.lib,因为你没有安装他们的SDK。
  • 你可能有一个来自英特尔的opencl.lib和opencl.dll,因为你安装了他们的SDK。

您肯定是与英特尔opencl.lib链接,但似乎是在c:\windows\system32加载Kronos opencl.dll。一种解决方案是让程序在运行程序时加载Intel opencl.dll,方法是将它们的dll放在程序的目录中。

但是,您声明您可以使用此编译行来完成工作:

  

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

在Windows上有一些关于gcc的东西 - in order to link against a library, you don't need to have the .lib。 Gcc通过检查dll为你找到它;当有人给他们一个dll而没有lib时,其他人已经想出了如何做同样的事情。在大多数其他编译器中,尤其是Visual Studio,您需要使用.lib和.dll来链接某些内容。这就是Win SDK安装数百个.lib(kernel32.lib,例如)的原因。事实证明,编译器实际上可以根据需要进行推断,但是libs作为一种古老的机制存在。

无论如何,你在gcc链接行上面运行了它,它使用搜索路径找到了一个合适的opencl.dll,为它发明了自己的.lib,并针对它编译;你启动了程序,它使用相同的搜索路径来获取opencl.dll,它与你编译的相同,所以你的程序运行。呼。

我还有一些建议:

  • 查找来自Kronos "Installable Client Driver" ICD Loader的opencl.lib和opencl.dll对。然后,该加载器将在运行时找出如何绑定到特定提供程序(nvidia,intel等)。
  • 将Kronos opencl.dll与您的应用程序一起分发,这样您就不会意外地针对错误的文件进行运行时链接。
  • 卸载英特尔SDK,假设它提供了特定于英特尔的opencl.lib / opencl.dll文件。

关于libs和dll的一些更相关的问题: