Can CUDA Kernels Modify Host Memory? - c++

Is there any way to get a kernel to modify an integer via passing a pointer to that integer to the kernel? It seems the pointer is pointing to an address in device memory, so the kernel does not affect the host.
Here's a simplified example with the behavior I've noticed.
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
__global__
void change_cuda(int* c);
void change_var(int* c);
int main() {
using namespace std;
int c = 0;
int* ptc = &c;
change_var(ptc); // *ptc = 123
cout << c << endl;
cudaError_t errors;
cudaMallocManaged((void**)&ptc, sizeof(int));
change_cuda<<<1, 1>>> (ptc); // *ptc = 555
errors = cudaDeviceSynchronize();
cudaFree(ptc);
cout << cudaGetErrorString(errors) << endl;
cout << c << endl;
return 0;
}
__global__
void change_cuda(int* c) {
*c = 555;
}
void change_var(int* c) {
*c = 123;
}
Ideally, this would modify c to be 555 at the end, but the output of this example is
123
no error
123
Clearly I am misunderstanding how this works. What is the correct way to get the behavior that I expect?

Yes, you have a misunderstanding. cudaMallocManaged is an allocator like, for example, malloc or new. It returns a pointer that points to a new allocation, of the size requested.
It is not some method to allow your host stack based variable to be accessed from device code.
However, the allocated area pointed to by the pointer returned by cudaMallocManaged can be accessed either from device code or host code. (It will not point to your c variable.)
You can minimally fix your code by making the following changes. 1. comment out the call to cudaFree. 2. print out the value of *ptc rather than c. Perhaps a more sensible change might be like this:
int main() {
using namespace std;
int* ptc;
cudaMallocManaged((void**)&ptc, sizeof(int));
change_var(ptc); // *ptc = 123
cout << *ptc << endl;
cudaError_t errors;
change_cuda<<<1, 1>>> (ptc); // *ptc = 555
cudaDeviceSynchronize();
errors = cudaGetLastError();
cout << cudaGetErrorString(errors) << endl;
cout << *ptc << endl;
return 0;
}

Related

Memory fault when print *pointer

Why do I have a memory fault in the below code? How do I fix it?
I want to read the progress of the outside function.
But I only get the output get_report_progress:100
#include <iostream>
int* int_get_progress = 0;
void get_progress(int* int_get_progress)
{
int n = 100;
int *report_progress = &n;
int_get_progress = report_progress;
std::cout << "get_report_progress:" << *int_get_progress <<std::endl;
}
int main()
{
get_progress(int_get_progress);
std::cout << "main get process:" << *int_get_progress << std::endl;
return 0;
}
Your global int_get_progress variable is a pointer that is initialized to null. You are passing it by value to the function, so a copy of it is made. As such, any new value the function assigns to that pointer is to the copy, not to the original. Thus, the global int_get_progress variable is left unchanged, and main() ends up deferencing a null pointer, which is undefined behavior and in this case is causing a memory fault.
Even if you fix the code to let the function update the caller's pointer, your code would still fail to work properly, because you are setting the pointer to point at a local variable that goes out of scope when the function exits, thus you would leave the pointer dangling, pointing at invalid memory, which is also undefined behavior when that pointer is then dereferenced.
Your global variable (which doesn't need to be global) should not be a pointer at all, but it can be passed around by pointer, eg:
#include <iostream>
void get_progress(int* p_progress)
{
int n = 100;
*p_progress = n;
std::cout << "get_report_progress:" << *p_progress << std::endl;
}
int main()
{
int progress = 0;
get_progress(&progress);
std::cout << "main get process:" << progress << std::endl;
return 0;
}
Alternatively, pass it by reference instead, eg:
#include <iostream>
void get_progress(int& ref_progress)
{
int n = 100;
ref_progress = n;
std::cout << "get_report_progress:" << ref_progress << std::endl;
}
int main()
{
int progress = 0;
get_progress(progress);
std::cout << "main get process:" << progress << std::endl;
return 0;
}
Alternatively, don't pass it around by parameter at all, but return it instead, eg:
#include <iostream>
int get_progress()
{
int n = 100;
std::cout << "get_report_progress:" << n << std::endl;
return n;
}
int main()
{
int progress = get_progress();
std::cout << "main get process:" << progress << std::endl;
return 0;
}

Does std::cout has a maximum size to hold character?

#include <iostream>
int main() {
int b = 3;
int* a;
*a = b;
std::cout << &a << a << *a;
}
When I execute a.out, Segmentation fault occurs
#include <iostream>
int main() {
int b = 3;
int* a;
*a = b;
std::cout << &a << a;
std::cout << *a;
}
While this code runs clearly with no error.
I'm pretty sure that max size of stdout buffer is bigger than couple of characters...
Why am I seeing Segmentation fault in same code with different new line?
Why am I seeing Segmentation fault ...?
Because the behaviour of the program is undefined. Here is the list of bugs in your programs:
*a = b;
^^
indirect through indeterminate pointer
std::cout << &a << a << *a;
^ ^^
| indirect through indeterminate pointer
read an indeterminate value
These bugs affect both example programs.
To fix the bugs, initialise a with a valid address of an int object.

Passing a pointer to a 1D Fortran array to C++ with C_LOC() causes garbage values

I want to know the proper way to pass array from Fortran to C. It returns out that iso_c_binding only has C_F_pointer but no F_C_pointer. I tried to use c_loc, but I got -6.04639e-264 for the second element.
My Fortran code is:
SUBROUTINE SIMULATION(ARRAY) BIND(C)
USE ISO_C_BINDING
IMPLICIT NONE
TYPE (c_ptr), INTENT(INOUT) :: ARRAY
REAL (C_DOUBLE), TARGET, SAVE :: ETA(0:1)
! Allocate an array and make it available in C
ARRAY = C_LOC(ETA)
ETA(0) = 1.0
ETA(1) = 2.0
END SUBROUTINE SIMULATION
And my C++ code is:
#include <iostream>
#include <vector>
using namespace std;
extern "C" {
void simulation(double* array[]);
}
int main()
{
double* array[2];
simulation(array);
cout << *array[0] << endl;
cout << *array[1] << endl;
return 0;
}
I am quite sure it is a problem with pointers in your C++ code. The Fortran code is correct.
This works well:
extern "C" {
void simulation(double **array);
}
int main()
{
double *array = NULL;
simulation(&array);
cout << array[0] << endl;
cout << array[1] << endl;
return 0;
}
Version with a pointer to fixed size array is in the end
extern "C" {
void simulation(double (**array)[2]);
}
int main()
{
double (*array)[2] = NULL;
simulation(&array);
cout << (*array)[0] << endl;
cout << (*array)[1] << endl;
return 0;
}
For me personally this is really difficult and confusing syntax with too many * and [] in the right combination. Some typedef would probably simplify it. Perhaps:
typedef double (*array2)[2];
extern "C" {
void simulation(array2* array);
}
int main()
{
array2 array;
simulation(&array);
cout << (*array)[0] << endl;
cout << (*array)[1] << endl;
return 0;
}
Notice, than in all three cases there is simulation(&array);. That means you must pass a pointer to the array pointer in order to be able to modify the array pointer.

Converting char* to int after using strdup()

Why after using strdup(value) (int)value returns you different output than before?
How to get the same output?
My short example went bad, please use the long one:
Here the full code for tests:
#include <stdio.h>
#include <iostream>
int main()
{
//The First Part
char *c = "ARD-642564";
char *ca = "ARD-642564";
std::cout << c << std::endl;
std::cout << ca << std::endl;
//c and ca are equal
std::cout << (int)c << std::endl;
std::cout << (int)ca << std::endl;
//The Second Part
c = strdup("ARD-642564");
ca = strdup("ARD-642564");
std::cout << c << std::endl;
std::cout << ca << std::endl;
//c and ca are NOT equal Why?
std::cout << (int)c << std::endl;
std::cout << (int)ca << std::endl;
int x;
std::cin >> x;
}
Because an array decays to a pointer in your case, you are printing a pointer (ie, on non-exotic computers, a memory address). There is no guarantee that a pointer fits in an int.
In the first part of your code, c and ca don't have to be equal. Your compiler performs a sort of memory optimization (see here for a full answer).
In the second part, strdup allocates dynamically a string twice, such that the returned pointers are not equal. The compiler does not optimize these calls because he does not seem to control the definition of strdup.
In both cases, c and ca may not be equal.
"The strdup() function shall return a pointer to a new string, which is a duplicate of the string pointed to by s1." source
So it's quite understandable that the pointers differ.

std::cout not printing to console

#include <iostream>
void swap(int &pi, int &pj){
std::cout << "In function swap: " << &pi << " " << &pj << "\n";
int temp = pi;
pi = pj;
pj = temp;
}
int main(){
int i = 10, j = 20;
int *pi = &i, *pj = &j;
swap(pi, pj);
std::cout << *pi << " " << *pj;
return 0;
}
The above program does not give any compilation error. (Though to swap function in not POINTER TO REFERENCE type) and gives the proper output.
But whatever i am trying to print inside "swap" function is not printed to console.
Can anybody explain me why?
Looks like you're probably using std::swap to swap two pointers instead of calling your own swap routine. I suspect you have a using namespace std; somewhere that you are not showing us ? Try changing the name of your swap routine to e.g. my_swap and then see if calling my_swap works (it should fail with a compilation error).
If you can compile your program, you don't show us all of your code.
This code snippet you posted doesn't compile, because you're trying to pass to objects of type int* to your function swapm which expects a reference to an int.
If your code compiles, I suspect you to include a 'using namespace std;' anywhere in your original code.
you're trying to get the address of a pointer that you're passing by reference... I don't think you quite understand what you're doing. the pass by reference feature in C++ allows you to pass a reference, so you don't need a pointer. Your code should look like this.
#include <iostream>
void swap(int &i, int &j){
std::cout << "In function swap: " << i << " " << j << "\n";
int temp = i;
i = j;
j = temp;
}
int main(){
int i = 10, j = 20;
swap(i, j);
std::cout << i << " " << j;
return 0;
}