Friday, February 12, 2010

Integrating C++ and CUDA

In this post I will show you how to get CUDA set up so you are able to use C++ files along with .cu files in the same project. In the previous post, we set up the project so that we could compile filename.cu files with the CUDA compiler. Now, to build an C++/CUDA application using resources from the SDK you will need to also include the libraries from the SDK (both the toolkit and SDK).

Now lets see if we can integrate a .cpp into our project. Right-click on your project source folder and click add->new item to make a main.cpp file. After you add the .cpp file you will have to include the libraries to your project. This will add a C\C++ field in the project properties where you will need to include CUDA files.

main.cpp:
#include
int main(int argc, char** argv)
{  
     printf("Hello World!\n"); 
     int i; 
     std::cin >> i; 
}

When the CUDA SDK is installed it also adds environment variables. Because I am using a 64-bit machine I added additional path variables as discussed in the previous post. In order to use the lib (library) and inc files (header files) from the CUDA SDK you can you can either copy the files from the SDK folders to the toolkit folders such as: $(NVSDKCUDA_ROOT)\common\lib folder to $CUDA\lib or set up paths using the environment variables as follows. Here is how to do it using environment variables. 

When the SDK installs, there is an environment variable:

NVSDKCUDA_ROOT

which points to:

C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C

From the SDK you will need the library, include files, and binaries (cutil.dll, cutil32D.dll, etc). 

Project->Properties->C/C++->Additional Include Directories (field):
    $(NVSDKCUDA_ROOT)\common\inc
Project->Properties->Linker->General->Additional Library Directories (field):
    $(NVSDKCUDA_ROOT)\common\lib

Your project properties should look like:




Now all you need to do is include the additional input dependent libraries for the linker. For now, we will only include cudart.lib (we will need other libraries later for the linker but for now we are taking it one step at a time). 


But in order to compile you will need to include the binaries (dlls) for the linker . To do this I created added the both the debug and release binaries for 32-bit which is my target to the PATH environment variable.
On windows 7:

start->right-click on computer->properties->Advanced system settings->Environment Variables->PATH
and add to the end:
    ;%NVSDKCUDA_ROOT%\bin\Win32\Debug
    ;%NVSDKCUDA_ROOT%\bin\Win32\Release
 Note the semi-colon. There is no semi-colon at the end of the path. The above point to:


    C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C\bin\Win32\Debug
    C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C\bin\Win32\Release


 Now you need to restart your system for the SDK dlls to be available to your system.

Thursday, February 11, 2010

CUDA First Time Compile

In this post I will show you how to get a filename.cu CUDA program to compile in Visual Studio 2005 on my 64-bit laptop for a 32-bit target. To get CUDA to compile in visual studio on a 64 bit machine for a 32 bit target, you will have to make some changes to the directives to nVIDIA's compiler (nvcc.exe). But before we go to far we first need to get the CUDA rules set up. In order to accurately document the process I will take a the long way and explain it step by step for all the newbs out there like me (this was a painful learning process). So here are the steps:

1. Make an empty project (file->new->project) in VS that is a win32 console based application. Then hit next

2. De-select pre-compiled headers and select empty project then finish:

3. Right-click on the source folder under the project and go to ->add->new item->code then on right side select cpp file. Then name the file *filename.cu (*note the .cu extension).

4. Then you want to add the build rules for that file. These can be found here:

C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C\common

5. Right click on your project and select 'Custom Build Rules':

6. The go to find existing. Then browse to (or wherever you put yours):

C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C\common

7. Then make sure that you select the CUDA Build Rule v2.3.0:

8. Now, I have my compiler set up for CUDA files. But because I am on a 64 bit machine and have selected 32 bit target


I will have compiler problems such as the following error:

Error 1 fatal error LNK1112: module machine type 'x64' conflicts with target machine type 'X86' c:\Users\trbttn\Documents\Visual Studio 2005\Projects\cudaEnvSetup\cudaEnvSetup\debug\main.cu.obj


I can fix this by right-clicking on the project->options->CUDA Build Rule v2.3.0. Then clicking on extra opotions. Then entering '--machine 32'. This tells the nvcc compiler that the target is 32 bit


Now you will be able to compile to 32 bit targets from 64 bit os. However, now you must set up your libraries so that you wont get the following errors:

Error 1 error LNK2019: unresolved external symbol ___cudaUnregisterFatBinary@4 referenced in function ___cudaUnregisterBinaryUtil main.cu.obj
Error 2 error LNK2019: unresolved external symbol ___cudaRegisterFatBinary@4 referenced in function ___sti____cudaRegisterAll_39_tmpxft_00000ebc_00000000_6_main_cpp1_ii_9fdf4b28 main.cu.obj
Error 3 error LNK2019: unresolved external symbol _main referenced in function ___tmainCRTStartup LIBCMT.lib
Error 4 fatal error LNK1120: 3 unresolved externals C:\Users\trbttn\Documents\Visual Studio 2005\Projects\cudaEnvSetup\Debug\cudaEnvSetup.exe


The library files that you will need are included in two places:

1. In the CUDA toolkit installation directory:

C:\CUDA\lib for 32bit

and

C:\CUDA\lib64 for 64 bit

2. In the CUDA SDK found here (but will not be needed to compile so I will discuss in the next post):
C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C\common\lib

Now because the toolkit I installed was for a 64 bit machine, the default environment variables form the toolkit were installed as follows:

1. CUDA_BIN_PATH = c:\CUDA\bin64
2. CUDA_LIB_PATH = c:\CUDA\lib64

But, these have to be changed if I am to reference them as additional include libraries in my project so based on the posts referenced below, I made four environment variables as follows:

1. CUDA_LIB_PATH32 with a value of c:\CUDA\lib
2. CUDA_LIB_PATH64 with a value of c:\CUDA\lib64
3. CUDA_BIN_PATH32 with a value of c:\CUDA\bin
4. CUDA_BIN_PATH64 with a value of c:\CUDA\bin64

and then added the following to my PATH variable:

%CUDA_BIN_PATH64%;%CUDA_BIN_PATH32%

Remember that for environment variables to be accessible the computer must be restarted.


You should be able to rebuild and compile without any errors at this point.

The is the output I got:
__________________________________________________________________________
1>------ Rebuild All started: Project: cudaEnvSetup, Configuration: Debug Win32 ------
1>Deleting intermediate and output files for project 'cudaEnvSetup', configuration 'Debug|Win32'
1>Compiling with CUDA Build Rule...
1>"C:\CUDA\bin64\nvcc.exe" --machine 32 -arch sm_10 -ccbin "C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin" -Xcompiler "/EHsc /W3 /nologo /O2 /Zi /MT " -maxrregcount=32 --compile -o "Debug\main.cu.obj" "c:\Users\trbttn\Documents\Visual Studio 2005\Projects\cudaEnvSetup\cudaEnvSetup\main.cu"
1>main.cu
1>tmpxft_00000890_00000000-3_main.cudafe1.gpu
1>tmpxft_00000890_00000000-8_main.cudafe2.gpu
1>tmpxft_00000890_00000000-3_main.cudafe1.cpp
1>tmpxft_00000890_00000000-12_main.ii
1>Compiling...
1>main.cpp
1>Compiling manifest to resources...
1>Linking...
1>LINK : C:\Users\trbttn\Documents\Visual Studio 2005\Projects\cudaEnvSetup\Debug\cudaEnvSetup.exe not found or not built by the last incremental link; performing full link
1>LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library
1>Embedding manifest...
1>Build log was saved at "file://c:\Users\trbttn\Documents\Visual Studio 2005\Projects\cudaEnvSetup\cudaEnvSetup\Debug\BuildLog.htm"
1>cudaEnvSetup - 0 error(s), 1 warning(s)
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

__________________________________________________________________________

*Notice the LINK4098 warning. This is because I had different runtime libraries selected.

This is from sprevrha2 on the nVIDIA forum.
"I noticed that the CUDA build rule does not automatically switch linkage of the multithreading runtime libs from release /MT to debug /MTd for the Debug compile targets. However, the MSVS C++ build targets do that, hence a conflict is generated. To avoid it, right-click on your project, select properties, go to the cuda build rule (I use CUDA build rule v3.0.0) / Hybrid CUDA/C++ options and set the runtime library to Multi-Threaded Debug (/MTd) for your debug and EmuDebug configurations. "

This is what is going on:


So to fix this problem, change the CUDA Build Rule v2.3.0->Hybrid CUDA/C++ runtime library to be the same as C/C++ Code Generation->Runtime Library for each configuration this problem will go away.


Now you should successfully be able to compile a filename.cu in visual studio without any errors or warnings. Please post your comments and click follow on the right to follow the CUDA learning process with me.

CPU Specs, Getting CUDA, and syntax highlighting

I have a Dell M6500 with a Quadro 2800M running Windows 64-bit Enterprise. I am using a code base developed by someone else that is a combination of managed C++ and C++. I have to get my CUDA code to run in this project. I am using Microsoft Visual Studio 2005 that I got for free from Microsoft Dreamspark (https://www.dreamspark.com). If your school participates then you can download any of the software for free. This is a lot easier than dealing with my schools computer support.

My goal is to integrate CUDA programs on this platform. Because my machine is 64 bit but I have
32 bit target (which means the project is for 32 bit machines) I have to do some special things to make CUDA work in my code. CUDA code is compiled by a special nVIDIA compiler called nvcc. My machine already had the CUDA drivers installed but you can get them from nVIDIA. To get started with CUDA:
1. Download and install proper drivers for your machine:
http://www.nvidia.com/Download/index5.aspx?lang=en-us
2. Download and install the CUDA toolkit:
http://developer.nvidia.com/object/cuda_2_3_downloads.html
3. Download and install the software development kit (SDK)
http://developer.nvidia.com/object/cuda_2_3_downloads.html
I currently have CUDA 2.3.

To enable syntax highlighting on CUDA:
1. copy the usertype.dat file from:
C:\ProgramData\NVIDIA Corporation\NVIDIA GPU Computing SDK\C\doc\syntax_highlighting\visual_studio_8\usertype.dat
to:
C:\Program Files (x86)\Microsoft Visual Studio 8\Common7\IDE
or whatever the path is on your machine.
2. Open visual studio and to to options->text editor->file extension
3. Add 'cu' in the box at the top as shown below then apply:


Journey int2 Programming

This is my first blog about my journey into programming; specifically GPU programming. I am a mechanical engineer and was given a funded project to use GPU programming a little over a year ago. Since then, I have had to learn C++, what an IDE was, and how to program in Windows. For all you linux lovers out there... I am seeing a light but more on that later.

Programming is fun. Programming is frustrating. Programming is easy. Programming is hard. GPU programming is even harder. But nothing is fun that is not challenging and a little frustrating at times.

Now I am under some serious pressure to start exploiting the GPU in my research. Having learned enough C++ I am now trying to use graphics concepts and parallel programming via nVIDIA's CUDA (Complete Unified Device Architecture) to accelerate my programs.

So, I am using a laptop with a nVIDIA quadro 2800M to program with. At first I could not get the drivers to install but after a driver hack by a helpful nVIDIA staff member I am up and running. Actually, I had to have the hack to install drivers that supported OpenCL but was not successful in getting them to run... so I am going to stick to CUDA for now and port the code later. The programming architecture and concepts are very similar for both CUDA and OpenCL so it shouldn't be in issue.