Archive for C++

C++ is a hack

Posted in code with tags , , , , , on September 12, 2010 by maxpower3141

If you are reading this, you probably knew it already.

Basically C++ is just a set of semi-clever preprocessor hacks on top of C – I seem to remember that actually the first C++ compilers were just an extra preprocessing pass on top of a C-compiler!

In themselves, hacks are not evil, but they do normally always cause some undesired side-effects that limits usability. In this case as C++ is basically just a hack on top of C, it means that it actually works by doing a lot of odd name-mangling in the preprocessing steps in order to get the names correct and here in lies the problem.

I recently began using thrust and with it some template programming on C++ and while thrust is great, C++ itself is not so much.

Firstly the template syntax is kind of awkward, but that’s not so much of an issue – the issue is the following:

Using function-objects (types that just overload the “function-call”-operator ()), I can abstract my CUDA-algorithms, by making them template-based on the different function-object types.

For example the SAXPY-call using thrust (this computes result = a X + Y, for vectors X,Y and scalar a) is as I had earlier written:

struct saxpy_functor
{
const float a;

saxpy_functor(float _a) : a(_a) {}

__host__ __device__
float operator()(const float& x, const float& y) const {
return a * x + y;
}
};

void saxpy_fast(float A, thrust::device_vector& X, thrust::device_vector& Y)
{
// Y <- A * X + Y
thrust::transform(X.begin(), X.end(), Y.begin(), Y.begin(), saxpy_functor(A));
}

This is ok, but I have started to like the idea of keeping the code close to where it is executed (guess I’m getting old or something) so I though that I would like to create a small macro that creates me a transformation-functor type on the fly so I could actually semi-transparently embed CUDA-code with my host code! That Would just rock! Something like:


void saxpy_fast(float A, thrust::device_vector& X, thrust::device_vector& Y)
{
struct saxpy_functor
{
const float a;
saxpy_functor(float _a) : a(_a) {}
__host__ __device__
float operator()(const float& x, const float& y) const {
return a * x + y;
}
};
// Y <- A * X + Y
thrust::transform(X.begin(), X.end(), Y.begin(), Y.begin(), saxpy_functor(A));
}

and hopefully wrap the silly stuff inside some macro to get:


{
DEFINE_XFORM_CALL(saxpy, data, input1, input2)
{
return data.a * x + y;
};
CALL_XFORM(saxpy, data, in1, in2);
}

Sweet no? Local types are supported by C++, except not in template parameters! And this causes:

“error: a template argument may not reference a local type” – compilation error!

Nice – what’s the freaking problem now? Can’t deduce the name of the type? Oh dear… SW sucks.

There has been a proposition to fix this in the standard itself, but of course this will never be fixed there – I guess MS supports this as compiler extension, but NVCC does not – I’ll request this feature and hope that NVIDIA listens – they do need all the user-friendliness they can get and this would be really friendly for me!

I’ll keep you posted if I ever hear from my request again 🙂 (not filed yet, sorry – TBD tomorrow)

Also I really think it is starting to be high time to switch to D Programming Language – as soon as NVCC supports it, I’m there!

Here’s a sneak-peek for a reduction:

import std.algorithm, std.range, std.stdio;

int main()
{
int[] a1 = [0,1,2,3,4,5,6,7,8,9];
int[] a2 = [6,7,8,9];
int sentinel = 5;

int mysum(int a, int b) {
if (b <= sentinel) // access outside variable
return a + b;
else
return a;
}

auto result = reduce!(mysum)( chain(a1, a2) ); // pass in a delegate (closure)
writeln("Result: ", result);

return 0;
}

Kristofer Columbus in Barcelona pointing

Advertisements