在 Windows 7-x64 上安装 Cuda 并使用 VS 2008 Express 进行托管代码






4.73/5 (9投票s)
在 VS Express 的预算内开始使用 Cuda
介绍
注意: 本文仍然相关,但我已改变了 GPU 编程的方法。我现在使用 Eclipse IDE 中的 Java 和 JCuda 来使用 CUDA。请参阅我的新方法:CodeProject 文章 513265
当您预算有限,使用的是 Visual Studio Express 时,让 NVidia Cuda 正常运行可能会令人沮丧,尤其是当您想从托管代码访问 Cuda 函数时。网上有很多资源可以帮助您,但您需要从不同来源收集信息——同时避开某些死胡同。这有点碰运气。希望我的经验能对您有所帮助。
目前,我决定保持简单:使用 VS 2008 Express,编写自己的包装器,并坚持使用 x86 平台。以下是我的成功方法:
背景
-
我没有为 VS 2010 Express 配置 Cuda。我了解到,该过程的一部分要求将 2010 项目配置为使用 VS 2008 (VC 90) 编译器,而不是 VS 2010 (VC100) 编译器。很可能还需要一些其他技巧才能使其正常工作。似乎有一些资源提供了这方面的指导。特别是,我看到一篇文章看起来很有希望:http://blog.cuvilib.com/2011/02/24/how-to-run-cuda-in-visual-studio-2010/
-
在 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 列表: http://developer.nvidia.com/cuda-gpus。(我有一个 GeForce GTX 560 GPU。)如果您不确定,请查看 GPU Caps Viewer。 我通常不愿意下载许多此类实用程序,但我已经使用了这个应用程序几年了,它被广泛认可,并且拥有可靠的绿色 WOT 评级。它能够相当可靠地识别您的 GPU 并报告其 OpenGl 和 Cuda 功能。
-
安装 VC++ 和 VSC# 2008 Express,然后通过每个 IDE 中的“Hello World”测试来验证安装。
-
从 http://developer.nvidia.com/cuda-toolkit-40 安装 NVidia 开发驱动程序、Cuda Toolkit 和 Cuda SDK。
请注意:来自 Toolkit (Start -> Programs -> NVidia) 的发行说明:v4.1 RC2 for 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 Runtime API 的复选框。会有两个。我使用名称后面没有版本号的那个。
右键单击项目并选择属性。
在链接器 -> 常规 -> 其他库目录中添加:$(CUDA_PATH)/lib/$(PlatformName);
在链接器 -> 输入 -> 其他依赖项中添加:cudart.lib cufft.lib
将以下内容粘贴到 test.cu 中
#include "cufft.h"
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);
//False = 0: error condition
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);
//False = 0: error condition
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
在上面的示例中,在解决方案的 Debug 文件夹中创建了一个名为 BareBonesCuda.dll 的文件。请记下它。
创建一个新的 C# 控制台应用程序。将配置更改为 x86,然后调试一次空的解决方案。这将在您的解决方案中创建一个名为 \bin\x86\Debug 的文件夹。将您的 BareBonesCuda.dll 复制到此文件夹中。
将以下内容粘贴到 Program.cs 中
#include "cufft.h"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace MyTestSharp
{
class Program
{
static void Main(string[] args)
{
test();
}
[DllImport("BareBonesCuda.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "_Fft")]
public static extern int _Fft(float[] real, float[] imaginary, int N, int batchSize);
private static List<float[]> fftFloat(float[] real, float[] imaginary, int N)
{
int oK = _Fft(real, imaginary, N, 1);
List<float[]> fftResult = new List<float[]>();
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<float[]> 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());
}
}
}
运行它。(再次希望这对您也有效。)
参考文献
我发现的一些有用参考
http://developer.download.nvidia.com/compute/cuda/3_1/docs/GettingStartedWindows.pdf
http://www.programmerfish.com/how-to-run-cuda-on-visual-studio-2008-vs08/
http://www.isnull.com.ar/2010/12/tutorial-cuda-32-and-visual-studio-2008.html
语法着色:http://www.c-sharpcorner.com/uploadfile/rafaelwo/cuda-integration-with-C-Sharp/
http://developer.download.nvidia.com/compute/cuda/1_1/CUFFT_Library_1.1.pdf<
https://codeproject.org.cn/Messages/4106223/Re-unmanaged-returning-arrays.aspx
一些结果
现在我终于运行起来了,我对我的 Cuda 性能非常满意。以 CUFFT 1-D、前向、复数傅立叶变换和双精度数字为例,我看到了接近 270 倍的 GPU/CPU 性能优势。对于我测试的 CPU 部分,我使用的是基于 Sedgwick/Wayne Java 程序 的简单递归 radix-2 实现。GPU 和 CPU 版本生成的变换完全一致(达到机器精度)!我的 GPU 可以处理长度高达 N = 16777216 的向量……并且只需 0.5 秒。