I have a thrust device_vector. I want to cast it to a raw pointer so that I can pass it to a kernel. How can I do so?
thrust::device_vector<int> dv(10);
//CAST TO RAW
kernel<<<bl,tpb>>>(pass raw)
You can do this using thrust::raw_pointer_cast. The device vector class has a member function data which will return a thrust::device_ptr to the memory held by the vector, which can be cast, something like this:
thrust::device_vector<int> dv(10);
int * dv_ptr = thrust::raw_pointer_cast(dv.data());
kernel<<<bl,tpb>>>(dv_ptr)
(disclaimer: written in browser, never compiled, never tested). There is a full working example of this included with thrust: unwrap_pointer.cu
Related
I am using a flexible array in the structure. So I want to change the memory allocated for that structure with some of my own code. Basically I want to change the new_structname() and structname_variable_set() functions.
typedef struct vector{
int x;
char y;
int arr[0];
} vector;
here, SWIG generated new_vector() function to allocate memory by calling calloc(1,sizeof(struct vector)) where swig will not handle these type of structure in a special manner. So we need to modify the swig generated new_vector() in order to allocate memory for the flexible array. So is there any way to handle this?
There are a few ways you can do this. What you're looking for though is %extend. That lets us define new constructors and implement them as we see fit. (It even works with a C compiler, they're only constructors from the perspective of the target language).
Using your vector as a starting point we can illustrate this:
%module test
%include <stdint.i>
%inline %{
typedef struct vector{ int x; char y; int arr[0]; }vector;
%}
%extend vector {
vector(const size_t len) {
vector *v = calloc(1, sizeof *v + len);
v->x = len;
return v;
}
}
With this SWIG synthesises a new_vector function in the generated module code as you'd hoped.
I also assumed that you want to record the length inside the struct as one of its members. If that's not the case you can simply delete the assignment I made.
Cython how to make multidimensional string matrix?any one knows?Thanks
I have below code but not work:
def make_matrix(size_t nrows, size_t ncols):
cdef char *mat = <char*>malloc(nrows * ncols * sizeof(char))
cdef char[:, ::1] mv = <char[:nrows, :ncols]>mat
cdef cnp.ndarray arr = np.asarray(mv)
return arr
Given you want an array nrows strings, each ncols long you can just do:
np.zeros((nrows,),dtype=('S',ncols))
This creates an empty numpy array of the format you want, and there's no need to invoke specialised Cython features.
The good reason not to attempt to do it in Cython using malloc is that the memory will never get freed (so you'll have a memory leak unless you free the memory yourself). It's very hard to know when you need to free it.
As an alternative (if you genuinely do need malloc for some reason) you could work with int8 instead, which is the same size as a char and should be interconvertable.
For example, cudaMalloc((void**)&device_array, num_bytes);
This question has been asked before, and the reply was "because cudaMalloc returns an error code", but I don't get it - what has a double pointer got to do with returning an error code? Why can't a simple pointer do the job?
If I write
cudaError_t catch_status;
catch_status = cudaMalloc((void**)&device_array, num_bytes);
the error code will be put in catch_status, and returning a simple pointer to the allocated GPU memory should suffice, shouldn't it?
In C, data can be passed to functions by value or via simulated pass-by-reference (i.e. by a pointer to the data). By value is a one-way methodology, by pointer allows for two-way data flow between the function and its calling environment.
When a data item is passed to a function via the function parameter list, and the function is expected to modify the original data item so that the modified value shows up in the calling environment, the correct C method for this is to pass the data item by pointer. In C, when we pass by pointer, we take the address of the item to be modified, creating a pointer (perhaps a pointer to a pointer in this case) and hand the address to the function. This allows the function to modify the original item (via the pointer) in the calling environment.
Normally malloc returns a pointer, and we can use assignment in the calling environment to assign this returned value to the desired pointer. In the case of cudaMalloc, the CUDA designers chose to use the returned value to carry an error status rather than a pointer. Therefore the setting of the pointer in the calling environment must occur via one of the parameters passed to the function, by reference (i.e. by pointer). Since it is a pointer value that we want to set, we must take the address of the pointer (creating a pointer to a pointer) and pass that address to the cudaMalloc function.
Adding to Robert's answer, but to first reiterate, it is a C API, which means it does not support references, which would allow you to modify the value of a pointer (not just what is pointed to) inside the function. The answer by Robert Crovella explained this. Also note that it needs to be void because C also does not support function overloading.
Further, when using a C API within a C++ program (but you have not stated this), it is common to wrap such a function in a template. For example,
template<typename T>
cudaError_t cudaAlloc(T*& d_p, size_t elements)
{
return cudaMalloc((void**)&d_p, elements * sizeof(T));
}
There are two differences with how you would call the above cudaAlloc function:
Pass the device pointer directly, without using the address-of operator (&) when calling it, and without casting to a void type.
The second argument elements is now the number of elements rather than the number of bytes. The sizeof operator facilitates this. This is arguably more intuitive to specify elements and not worry about bytes.
For example:
float *d = nullptr; // floats, 4 bytes per elements
size_t N = 100; // 100 elements
cudaError_t err = cudaAlloc(d,N); // modifies d, input is not bytes
if (err != cudaSuccess)
std::cerr << "Unable to allocate device memory" << std::endl;
I guess the signature of cudaMalloc function could be better explained by an example. It is basically assigning a buffer through a pointer to that buffer (a pointer to pointer), like the following method:
int cudaMalloc(void **memory, size_t size)
{
int errorCode = 0;
*memory = new char[size];
return errorCode;
}
As you can see, the method takes a memory pointer to pointer, on which it saves the new allocated memory. It then returns the error code (in this case as an integer, but it is actually an enum).
The cudaMalloc function could be designed as it follows also:
void * cudaMalloc(size_t size, int * errorCode = nullptr)
{
if(errorCode)
errorCode = 0;
char *memory = new char[size];
return memory;
}
In this second case, the error code is set through a pointer implicit set to null (for the case people do not bother with the error code at all). Then the allocated memory is returned.
The first method can be used as is the actual cudaMalloc right now:
float *p;
int errorCode;
errorCode = cudaMalloc((void**)&p, sizeof(float));
While the second one can be used as follows:
float *p;
int errorCode;
p = (float *) cudaMalloc(sizeof(float), &errorCode);
These two methods are functionally equivalent, while they have different signatures, and the people from cuda decided to go for the first method, returning the error code and assigning the memory through a pointer, while most people say that the second method would have been a better choice.
I am trying to write a custom function to carry out sum. I followed this question Cuda Thrust Custom function to take reference.Here is how I have defined my functor
struct hashElem
{
int freq;
int error;
};
//basically this function adds some value to to the error field of each element
struct hashErrorAdd{
const int error;
hashErrorAdd(int _error): error(_error){}
__host__ __device__
struct hashElem operator()(const hashElem& o1,const int& o2)
{
struct hashElem o3;
o3.freq = o1.freq;
o3.error = o1.error + (NUM_OF_HASH_TABLE-o2)*error; //NUM_OF_HASH_TABLE is a constant
return o3;
}
};
struct hashElem freqError[SIZE_OF_HASH_TABLE*NUM_OF_HASH_TABLE];
int count[SIZE_OF_HASH_TABLE*NUM_OF_HASH_TABLE];
thrust::device_ptr<struct hashElem> d_freqError(freqError);
thrust::device_ptr<int> d_count(count);
thrust::transform(thrust::device,d_freqError,d_freqError+new_length,d_count,hashErrorAdd(perThreadLoad)); //new_length is a constant
This code on compilation gives the following error:
error: function "hashErrorAdd::operator()" cannot be called with the given argument list
argument types are: (hashElem)
object type is: hashErrorAdd
Please can anybody explain to me why I am getting this error? and how I can resolve it. Please comment in case I am not able to explain the problem clearly. Thankyou.
It appears that you want to pass two input vectors to thrust::transform and then do an in-place transform (i.e. no output vector is specified).
There is no such incarnation of thrust::transform
Since you have passed:
thrust::transform(vector_first, vector_last, vector_first, operator);
The closest matching prototype is a version of transform that takes one input vector and creates one output vector. In that case, you would need to pass a unary op that takes the input vector type (hashElem) only as an argument, and returns a type appropriate for the output vector, which is int in this case, i.e. as you have written it (not as your intent). Your operator() does not do that, and it cannot be called with the arguments that thrust is expecting to pass to it.
As I see it, you have a couple options:
You could switch to the version of transform that takes two input vectors and produces one output vector, and create a binary op as functor.
You could zip together your two input vectors, and do an in-place transform if that is what you want. Your functor would then be a unary op, but it would take as argument whatever tuple was created from dereferencing the input vector, and it would have to return or modify the same kind of tuple.
As an aside, your method of creating device pointers directly from host arrays looks broken to me. You may wish to review the thrust quick start guide.
I read a lot about handling 2D arrays in CUDA and i think it is necessary to flatten it before sending it to GPU.however can I allocate 1D array on GPU and access it as 2D array in GPU?I tried but failed my code looks like follows:
__global__ void kernel( int **d_a )
{
cuPrintf("%p",local_array[0][0]);
}
int main(){
int **A;
int i;
cudaPrintfInit();
cudaMalloc((void**)&A,16*sizeof(int));
kernel<<<1,1>>>(A);
cudaPrintfDisplay(stdout,true);
cudaPrintfEnd();
}
In fact it is not necessary to "flatten" your 2D array before using it on the GPU (although this can speed up memory accesses). If you'd like a 2D array, you can use something like cudaMallocPitch, which is documented in the CUDA C programming guide. I believe the reason your code isn't working is because you only malloced a 1D array - A[0][0] doesn't exist. If you look at your code, you made a 1D array of ints, not int*s. If you wanted to malloc a flattened 2D array, you could do something like:
int** A;
cudaMalloc(&A, 16*length*sizeof(int*)); //where length is the number of rows/cols you want
And then in your kernel use (to print the pointer to any element):
__global__ void kernel( int **d_a, int row, int col, int stride )
{
printf("%p", d_a[ col + row*stride ]);
}
This is how I fixed problem
I cudaMalloc in usual way but while sending pointer to kernel i'm typecasting it to int(*)[col],and this is working for me