Feb 28 2009

Multidimensional arrays in C++

Category: ProgrammingMaciek Talaska @ 11:17 pm

Dynamic, multidimensional arrays are not supported directly by C++. If you create such an array in following way:

array = new int*[_size];
for( unsigned int i = 0; i < _size; i++ )
    array[i] = new int[_size];

you are in fact creating one dimensional array of pointers to other arrays. Main two disadvantages of this approach:

  • Initialization can take a while (image really big 2-3 dimensional array, lets say: 16384 x 16384: how many times memory allocation is being performed? 1 + 16384. Quite a lot, right?
  • dynamic arrays created like in the code above can not be used as a parameters for memcmp, memcpy, memset & similar functions. the memory allocated is not a continuous memory block.

As I needed a 2-dimensional array that occupies continuous block of memory – I started googling :) I have found a great solution by  David Maisonave (Axter) (code, header). The code above could be rewritten as follows:

Pixel** Initialize2dArray( int size )
{
    Pixel **array2d;
    Pixel *temp;
    array2d = new Pixel*[size];
    temp = new Pixel[size * size];

    for( int i = 0; i < size; i++ )
    {
        array2d[i] = temp;
        temp += size;
    }
    return array2d;
}

void Deinitialize2dArray( Pixel** array2d )
{
    delete [] *array2d;
    delete [] array2d;
}

 

How does it work? The idea is to put in every ‘cell’ of the array a pointer that will point to a part of the ‘temp’ array. The parts are of the ‘width’ size. So, when you type array[2][3] it actually selects the data that is indexed 2 * width + 3 = exactly what you’re expecting, right? But beware, there is a little difference when using array created in described way and all those mem* functions I wrote at the beginning, instead of writing:

memcpy( array2d, source, sizeof(int) * size * size );

you actually need to write:

memcpy( &array2d[0][0], source, sizeof(int) * size * size );

It is great, right? And, of course, you could try using std::vector (it allocates continuous block of memory – correct me if I am wrong) or Boost Multi Array instead – but if you’re worrying about performance… I think the presented solution is the best.

Tags:


Feb 22 2009

CUDA & C++ integration

Category: Programming, Visual StudioMaciek Talaska @ 10:08 pm

It is kind of a strange, but it is not so simple as you may think. There is a sample project in CUDA SDK, and it works, but… it is strange that if you exclude all .cu and .cpp files and add yours… surprisingly it stops working. Why? There were some problems while linking: I got messages that there are bunch of symbols already defined elsewhere. Well… in this case it is because of LIBCMTD (but read further please, it is not always the problem with LIBCMTD) – default library that is being linked by VS. How to overcome this problem? There are two solutions:

  • you may add “/FORCE:MULTIPLE” in linker options (Project properties –> Linker –> Command Line) – but this does work… partially – it creates proper executable, but in my case I got some assert exception at the very end of executing my app (actually it was when all resources were to be freed – but I didn’t want to investigate it further – app worked, but it is strange to see the exception dialog all the time)
  • you may exclude one of the libraries that is causing the problem. Which library? Well, it depends on: what was your project type (Linker –> System –> Subsystem: /SUBSYSTEM:CONSOLE, /SUBSYSTEM:WINDOWS…). In the sample form CUDA SDK, the library that you should get rid of (Linker –> Input –> Ignore Specific Library; remember to write only library’s name, without extension) is: LIBCMTD, in my own project (created from scratch) it is: MSVCRTD for Debug, and LIBCMT for Release. The only advise is to look carefully at what is your linker spitting out, and just ignoring this specific library that makes the whole process to fail (and it is very good idea to have more verbose output: Linker –> General –> Show Progress: /VERBOSE:LIB or even /VERBOSE). In my case the BuildLog.htm (automatically produced by VS) contained following information:

[...]

MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMT.lib(typinfo.obj)
MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in LIBCMT.lib(typinfo.obj)

[...]

Finished searching libraries LINK : warning LNK4098: defaultlib ‘MSVCRTD’ conflicts with use of other libs; use /NODEFAULTLIB:library

[...]

As you see, the problem lies in linking MSVCRTD.lib. Although it is not always so easy. Sometimes different library should be excluded from the process of linking.

It seemed to me, that the problem was fixed. I was wrong. Something bothered me. Why there were no simple solution for this problem? And why the problem was not always with the library the linker had problem with (the one, that it informed about problems with)? And than I started thinking about something I read about how Microsoft C++ compiler / linker works: there are bunch of libraries that are included by default. The libraries are organized in groups (compiled with debug info for debug purposes, etc.), and compilation or linking and mixing libraries with two different worlds may lead to errors. If you right click on your .cu or .cpp file in your project and navigate to “General C++ –> Code Generation” (in case of .cpp file) or “CUDA Build Rule v.2.1.0 –> Hybrid CUDA/C++ Options” (in case of .cu file), you’ll see “Runtime Library” option. And if all your files share the same setting, the problem with linking disappears, and now I am sure, that this is the right solution :) And remember, that this option for all the files must be exactly the same! “Multi-Threaded” and “Multi-Threaded DLL” are NOT the same (the have different linker switches), so just be careful, and pay attention what you change.

I hope it helps someone, because I have wasted a bit of time.

Tags: ,


Feb 16 2009

Intellisense for CUDA in VS 2008

Category: Programming, Visual StudioMaciek Talaska @ 11:03 am

In the previous post I have written about using CUDA from Visual Studio IDE. Syntax highlighting is very easy to achieve – because nVidia delivers files and information about enabling syntax highlighting for CUDA in CUDA SDK. The thing is, that when you start developing anything that uses CUDA, you feel like being back in the mid ‘90 – there is no Intellisense, no auto-completion and other features of modern IDEs that most of developers are used to. 5 sec googling and you got the solution. But hey… why doesn’t it work? Well I think it is because someone who wrote about it had special pack of Unix programs for Windows installed (Cygwin). There are no “rm” or “cp” commands under Windows (at least on my copy of Windows they seem to not exist ;) The easiest way to make it work under any Windows is to replace:

rm $(InputName).cu
cp $(InputFileName) $(InputName).cu

with:

copy /Y $(InputFileName) $(InputName).cu

That’s it. It should work now. And remember that you need to have both files (.c and .cu) in your solution (because the idea behind it is to generate .cu from .c, and compile only .cu).

Anyway, that shows how powerful the Custom Build Rules are, aren’t they?

Tags: , ,


Feb 15 2009

VS 2008 & CUDA

Category: Programming, Visual Studio, WindowsMaciek Talaska @ 3:45 pm

As a proud owner of nVidia graphic card (and being some kind of a fan of nVidia for their effort into graphics programming) I decided to go and try CUDA. At the moment the newest version is 2.1. The first thing after installing something you want to try out is to go and look at the samples, right? The same thing I thought, but unfortunately there were some problems compiling samples from nVidia CUDA SDK.

I tried to compile one of the simplest samples, but I instead of success I saw error message:

1>—— Build started: Project: cudaOpenMP, Configuration: Debug Win32 ——
1>Compiling with CUDA Build Rule…
1>"C:Program FilesnVidiaCUDAbinnvcc.exe"   -arch sm_10 -ccbin "C:Program FilesMicrosoft Visual Studio 9.0VCbin"    -Xcompiler "/EHsc /W3 /nologo /Od /Zi   /MTd  " -IC:Program FilesnVidiaCUDAinclude -I../../common/inc -maxrregcount=32  –compile -o DebugcudaOpenMP.cu.obj cudaOpenMP.cu
1>nvcc fatal   : A single input file is required for a non-link phase when an outputfile is specified
1>Linking…
1>LINK : fatal error LNK1181: cannot open input file ‘.DebugcudaOpenMP.cu.obj’
1>Build log was saved at "file://d:MDTempProjectsCUDAprojectscudaOpenMPDebugBuildLog.htm"
1>cudaOpenMP – 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

(this is copy & paste from  VS Output window)

and the error in VS Error Window:

Error    1    fatal error LNK1181: cannot open input file ‘.DebugcudaOpenMP.cu.obj’    cudaOpenMP    cudaOpenMP

The error enlisted in VS Error window is connected with linker (it is unable to find input file) so the real problem lies somewhere else: at the compile time. I have copied the command line that invokes nVidia’s compiler (because no other compiler is aware of all the extension nVidia created for the purpose of creating CUDA). The command line was:

"C:Program FilesnVidiaCUDAbinnvcc.exe"   -arch sm_10 -ccbin "C:Program FilesMicrosoft Visual Studio 9.0VCbin"    -Xcompiler "/EHsc /W3 /nologo /Od /Zi   /MTd  " -IC:Program FilesnVidiaCUDAinclude -I../../common/inc -maxrregcount=32  –compile -o DebugcudaOpenMP.cu.obj cudaOpenMP.cu

Do you see the problem? Well, I didn’t see what’s wrong at the first sight too ;) Anyway, to cut it short: the problem lies in the path where nVidia CUDA SDK is installed. I have chosen to install it in “Program FilesnVidia” and not in the root directory (this is the default location – as far as I can remember). The thing is that Program Files without quotes is treated… yup, you guessed ;) everyone familiar with the way command lines arguments are being passed to programs knows that space IS a delimiter. OK. What is the solution? Very, very simple, you need to change a bit the “CUDA Build Rule”, and to change it, you need to do the following:

  1. Open your VS and open any project / solution from nVidia CUDA samples
  2. Right-click on project (not on solution) and click on “Custom Build Rules”, you should see a dialog:
    image
  3. Choose “Cuda Build Rule v2.1.0” and click on “Modify Rule File…” button, another window will pop-up:
    image
  4. Click on “Cuda Build Rule” and then on “Modify Build Rule…”
     image
  5. And finally this is the window you need to make changes in. The “Include” property (highlighted) need to be modified (simply: put [value] into quotes, so the switch for Include will look like: –I”[value]”. Now your project should compile without any errors or warnings (I assume that you’re compiling one of the nVidia CUDA samples).
  6. Remember that you may have to add (register) .cu files in VS environment, but it is clearly described in readme.txt located in /doc/syntax_highlighting in your CUDA SDK directory.

The same kind of problem you may have after installing Python and some python IDEs that modify environment and add PYTHONPATH. If you install Python in “Program Files” the same thing happens. The solution is to edit your PYTHONPATH variable and change it, instead of “Program Files” you may type “Progra~1” (check what is yours “Program Files” directory 8+3 name using “dir /X” command).

Hope it helps. Happy coding!

Tags: , ,