CUDA与Java集成指南

在Visual Studio Express环境下配置CUDA并使用Java通过JCuda与之交互可能会遇到一些挑战,特别是当希望从托管代码访问CUDA函数时。尽管网络上有许多资源可以帮助,但通常需要从不同来源整合信息,同时避免一些死胡同。这个过程有点像试错。希望通过分享经历,能够帮助少走弯路。

目前还没有在Visual Studio 2010 Express上配置CUDA。了解到,这个过程需要将2010项目配置为使用2008年的VC90编译器,而不是2010年的VC100编译器。可能还需要一些其他的技巧来让事情顺利进行。网络上有一些资源提供了这方面的指导。特别是,看到了一篇看起来很有希望的文章:

使用x86以外的配置运行托管代码对来说没有成功。网络上有几篇关于这个配置与VS Express的复杂帖子。Google搜索“Visual C++ 2008 Express Edition And 64-Bit Targets”可以找到一些有趣的方法来破坏VS Express安装。

首先在虚拟机中安装是一个好主意,但对来说,如何直接从客户机访问主机的GPU硬件并不清楚。VBox虚拟显卡适配器不支持CUDA,据所知,CUDA不再容易支持仿真模式。所以使用了标准技术:犯错,破坏安装,重新安装,然后跟随烟雾。

对GPU上的傅里叶变换特别感兴趣。只有少数的现成包装支持CUFFT功能。Cudafy(CodePlex)看起来最有希望,但当有VS Express时,它还不是一个即插即用的设置。

首次设置

确保有一个支持CUDA的显卡。Nvidia在他们的开发者区域网站上有一个详尽的兼容GPU列表。

如果不确定,可以查看GPU Caps Viewer。通常对下载这样的工具持谨慎态度,但已经使用这个应用程序几年了,它被广泛认可,并且有一个可靠的绿色WOT评级。它将相当可靠地识别GPU并报告其OpenGL和CUDA功能。

安装VC++和VSC 2008 Express,然后通过在每个中运行一个“Hello World”测试来验证安装。

安装Nvidia开发驱动程序、CUDA工具包和CUDA SDK:

注意:从工具包的发行说明(开始 -> 程序 -> Nvidia):

对于Windows7-x64,安装程序可能错误地在路径说明中包含了一个额外的斜杠。

再次检查环境变量(计算机 -> 属性 -> 高级 -> 高级选项卡):

CUDA_BIN_PATH %CUDA_PATH%\bin CUDA_INC_PATH %CUDA_PATH%\include CUDA_LIB_PATH %CUDA_PATH%\lib\x64

到目前为止检查安装情况:

nvcc –V

(应该得到一个编译发布消息。)

找到bandwidthTest.exe(C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK 4.1\C\bin\win64\Release)并运行它。

也试试oceanFFT.exe

将“C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v4.1\extras\visual_studio_integration\rules”中的所有*.rules文件复制到“C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults”

将“C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK 4.1\C\doc\syntax_highlighting\visual_studio_8\usertype.dat”复制到“C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE”文件夹

打开VC++并在工具 -> 选项:

文本编辑器 -> 文件扩展名添加两个扩展名:.cu和.cuh

项目和解决方案 -> VC++目录

添加%CUDA%bin在可执行文件的目录中

添加%CUDA Directory%include在包含文件的目录中

添加%CUDA%lib在库文件的目录中

关闭VC++然后重新打开,然后加载“hello world”程序并确保它仍然有效。

创建项目

示例:FFT的简单裸机包装。

创建一个新的空Win 32项目,命名为BareBonesCuda。在下一页上勾选“dll”复选框。

添加一个源文件 - 类型cpp - 但命名为.cu扩展名,例如:

test.cu

右键单击项目并选择自定义构建规则。勾选CUDA运行时API的复选框。将有两个。使用没有版本#名称后的那个。

右键单击项目并选择属性。

在链接器 -> 常规 -> 附加库目录中添加:$(CUDA_PATH)/lib/$(PlatformName);

在链接器 -> 输入 -> 附加依赖项中添加:cudart.lib cufft.lib

将以下内容粘贴到test.cu中:

extern "C" int __declspec(dllexport) __stdcall _Fft(float real[], float imaginary[], int N, int batchSize) { cufftComplex *a_h, *a_d; cufftHandle plan; int i, nBytes; nBytes = sizeof(cufftComplex)*N*batchSize; a_h = (cufftComplex *)malloc(nBytes); for (i = 0; i < N*batchSize; i++) { a_h[i].x = real[i]; a_h[i].y = imaginary[i]; } cudaMalloc((void **)&a_d, nBytes); if (cudaGetLastError() != cudaSuccess) { cufftDestroy(plan); free(a_h); cudaFree(a_d); return 0; } cudaMemcpy(a_d, a_h, nBytes, cudaMemcpyHostToDevice); if (cufftPlan1d(&plan, N, CUFFT_C2C, batchSize) != CUFFT_SUCCESS) { cufftDestroy(plan); free(a_h); cudaFree(a_d); return 0; } cufftExecC2C(plan, a_d, a_d, CUFFT_FORWARD); cudaDeviceSynchronize(); cudaMemcpy(a_h, a_d, nBytes, cudaMemcpyDeviceToHost); for (i = 0; i < N*batchSize; i++) { real[i] = a_h[i].x; imaginary[i] = a_h[i].y; } cufftDestroy(plan); free(a_h); cudaFree(a_d); return 1; }

构建它。(希望也能成功。)

在C#中使用dll

在上面的示例中,一个名为BareBonesCuda.dll的文件在解决方案的Debug文件夹中被创建。注意它。

创建一个新的C#控制台应用程序。将配置更改为x86,然后调试一次空解决方案。这将在解决方案中创建一个名为\bin\x86\Debug的文件夹。将BareBonesCuda.dll复制到这个文件夹中。

将以下内容粘贴到Program.cs中:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; namespace MyTestSharp { class Program { [DllImport("BareBonesCuda.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "_Fft")] public static extern int _Fft(float[] real, float[] imaginary, int N, int batchSize); static void Main(string[] args) { test(); } private static List fftFloat(float[] real, float[] imaginary, int N) { int oK = _Fft(real, imaginary, N, 1); List fftResult = new List(); fftResult.Add(real); fftResult.Add(imaginary); return fftResult; } private static void test() { int N = 32768; float[] real = new float[N]; float[] imaginary = new float[N]; StringBuilder sb = new StringBuilder(); char br = (char)13; for (int i = 0; i < N; i++) { real[i] = (float)i + 1; sb.Append(real[i].ToString()); sb.Append("+ "); imaginary[i] = 0; sb.Append(imaginary[i].ToString()); sb.Append(br); } Console.WriteLine(sb.ToString()); sb = new StringBuilder(); List result = fftFloat(real, imaginary, N); for (int i = 0; i < N; i++) { sb.Append(real[i].ToString()); sb.Append("+ "); sb.Append(imaginary[i].ToString()); sb.Append(br); } Console.WriteLine(sb.ToString()); } } }

运行它。(再次,希望也能成功。)

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485