OpenCL: cannot pass a integer to constant memory - opencl

I wrote a kernel like this
kernel void computeLayerOutput_Rolled(global Layer* restrict layers, constant int* restrict netSpec, __constant const int layer1)
But an cl::Error occurred when creating the kernel, and the error information is
:29:123: error: invalid address space for argument to __kernel function
kernel void computeLayerOutput_Rolled(global Layer* restrict layers, constant int* restrict netSpec, __constant const int layer1)
^
:29:123: error: parameter may not be qualified with an address space
terminate called after throwing an instance of 'cl::Error'
what(): clCreateKernel
when I remove the __constant qualifier of layer1, everything is OK, but I don't want to put it into the private memory since it might occupy a register in every work item. Passing an array with only one element seems not a very elegant solution either.
I just wondering that is there any other way to solve it?

The spec says (labels mine):
(1) The generic address space name for arguments to a function in a
program, or local variables of a function is __private. All arguments
to a __kernel function shall be in the __private address space.
(2) __kernel function arguments declared to be a pointer of a type can point to one of the following address spaces only: __global, __local
or __constant.
In other words, only pointers can be qualified as __constant in kernel arguments. layer1 is not a pointer, so it can't be __constant.
I don't want to put it into the private memory since it might occupy a register in every work item.
layer1 may already be using a register, because it is already in private memory: as quote (1) indicates, all arguments to a kernel function are in the __private address space, which may map to registers.
To clarify, when writing constant int* restrict netSpec, do not confuse:
Address space of the pointer (the argument netSpec is in __private address space)
Address space of the pointee (what netSpec points to is in __constant address space)

I have encountered the same 'problem' a while ago. I was used to the way CUDA C/C++ handles constant memory and tried to find a solution to get the same convenience in OpenCL. Long story short, I didn't found one. If you want constant memory you can do two things:
pass in a pointer to the constant address space as you suggested, or
use #defines and recompile
non of the solutions is very pretty but they do what the are supposed to.
However, if the only problem with passing an integer is the fear of higher register usage than you can go forward and just provide the integer per value. The single integer value will occupy as much registers as a pointer to constant memory if the size of the pointer is 32 bit.

Related

Is every variable and register name just a pointer in NASM Assembly?

There are [] operations which are similar to dereferencing in high-level languages. So does that mean that every variable and register name is just a pointer or are pointers a high-level languages idea and have no use in Assembly?
Pointers are a useful concept in asm, but I wouldn't say that symbol names are truly pointers. They're addresses, but they aren't pointers because there's no storage holding them (except metadata, and embedded into the machine code), and thus you can't modify them. A pointer can be incremented.
Variables are a high-level concept that doesn't truly exist in assembly. Asm has labels which you can put at any byte position in any section, including .data, .text, or whatever. Along with directives like dd, you can reserve space for a global variable and attach a symbol to it. (But a variable's value can temporarily be in a register, or for its whole lifetime if it's a local variable. The high-level concept of a variable doesn't have to map to static storage with a label.)
Types like integer vs. pointer also don't really exist in assembly; everything is just bytes that you can load into an integer, XMM, or even x87 FP register. (And you don't really have to think of that as type-punning to integer and back if you use eax to copy the bytes of a float from one memory location to another, you're just loading and storing to copy bytes around.)
But on the other hand, a pointer is a low-enough level concept still be highly relevant in assembly. We have the stack pointer (RSP) which usually holds a valid address, pointing to some memory we're using as stack space. (You can use the RSP register to hold values that aren't valid addresses, though. In that case you're not using it as a pointer. But at any time you could execute a push instruction, or mov eax, [rsp], and cause an exception from the invalid address.)
A pointer is an object that holds the address of another object. (I'm using "object" in C terms here: any byte[s] of storage that you can access, including something like an int. Not objected as in object-oriented programming.) So a pointer is basically a type of integer data, especially in assembly for a flat memory model where there aren't multiple components to it. For a segmented memory model, a seg:off far pointer is a pair of integers.
So any valid address stored anywhere in register or memory can usefully be thought of as a pointer.
But no, a symbol defined by a label is not a pointer. Conceptually, I think it's important to think of it as just a label. A pointer is itself an object (some bytes of storage), and thus can be modified. e.g. increment a pointer. But a symbol is just a way to reference some fixed position.
In C terms, a symbol is like a char symbol[], not a char *symbol = NULL; If you use bare symbol, you get the address. Like mov edi, symbol in NASM syntax. (Or mov edi, OFFSET symbol in GNU .intel_syntax or MASM. See also How to load address of function or label into register for practical considerations like using RIP-relative LEA if 32-bit absolute addresses don't work.)
You can deref any symbol in asm to access the bytes there, whether that's mov eax, [main] to load the first 4 bytes of machine code of that function, or mov eax, [global_arr + rdi*8] to index into an array, or any other x86 addressing mode. (Caveat: 32-bit absolute addresses no longer allowed in x86-64 Linux? for that last example).
But you can't do arr++; that makes no sense. There is no storage anywhere holding that address. It's embedded into the machine code of your program at each site that uses it. It's not a pointer. (Note that C arr[4] = 1 compiles to different asm depending on char *arr; vs. char arr[], but in asm you have to manually load the pointer value from wherever it's stored, and then deref it with some offset.)
If you have a label in asm whose address you want to use in C, but that isn't attached to some bytes of storage, you usually want to declare it as extern const char end_of_data_section[]; or whatever.
So for example you can do size_t data_size = data_end - data_start; and get the size in bytes as a link-time constant, if you arranged for those symbols to be at the end/start of your .data section. With a linker script or with global data_end / data_end: in your NASM source. Probably at the same address as some other symbol, for the start.
Assembly language doesn't have variables, pointers or type checking. It has addresses and registers (and no type checking).
A variable (e.g. in C) is a higher level thing - a way to abstract the location of a piece of data so that you don't have to care if the compiler felt like putting it in a register or in memory. A variable also has a type; which is used to detect some kinds of bugs, and used to allow the compiler to automatically convert data to a different type for you.
A pointer (e.g. in C) is a variable (see above). The main difference between a pointer and a "not pointer" is the type of data it contains - for a pointer the variable typically contains an address, but a pointer is not just an address, it's the address of something with a type. This is important - if it was just an address then the compiler wouldn't know how big it is, couldn't detect some kinds of bugs, and couldn't automatically convert data (e.g. consider what would happen for int foo = *pointer_to_char; if the compiler didn't know what type of data the pointer points to).

opencl constant memory or value arguments

In OpenCL you can pass a buffer to a kernel via clSetKernelArg and mark that buffer as __constant in the kernel. Alternatively, you can also use clSetKernelArg to pass a value type.
My question is, where does the value type live? Does the API create a constant buffer behind the scenes? Does the API generate a special shader with those values as constant literals?
I'm just curious because I come from a direct3d/opengl background, and constants always had to be passed through constant buffers. So I'm wondering how passing a type by value as an argument works under the hood.

Self Referencing Pointer in OpenCL

I have an OpenCL C++ code working on the Intel Platform. I do have an idea that pointers are not accepted within a structure on the Kernel End. However, I have a Class which utilizes the Self-Referencing Pointer option within it. Now, I am able to use a structure and replicate the same for the structure on the host side but I am not able to do the same on the device side.
For example as follows:
Class Classname{
Classname *SameClass_Selfreferencingpointer;
}
On the Host side I have done the same for the structure as well:
struct Structurename{
Structurename *SameStructure_Selfreferencingpointer;
}
Could someone give an alternate option for this implementation for the device side?
Thank you for any help in advance.
Since there isn't malloc in opencl device and also structs are used in buffers as an array of structs, you could add index of it so it knows where it remains in the array. You can allocate a big buffer prior to kernel, then use atomic functions to increment fake malloc pointer as if it is allocating from the buffer but simply returning an integer that points to last "allocated" struct index. Then, host side would just use the index instead of pointer.
If struct alignments become an issue between host an device, you can add indexing of fields too. Such as starting byte of a field A, starting byte of a field B, all compacted in a single 4-byte integer for a struct having 4 used fields except indexes.
Maybe you can add a preprocess stage:
host writes an artificial number to a field such as 3.1415
device checks floating points in struct for all byte offsets until it finds 3.1415
device puts the found byte offset to an array and sends it to host
then host writes float fields in a struct starting from that byte offset
so host and device become alignment compatible, uses same offset in all kernels that get a struct from host
maybe opposite is better
device puts 3.14 in a field of struct
device writes the struct to an array of struct
host gets the buffer
host checks for 3.14 and finds byte offset
host writes and fp number starting from that offset for future work
which would need both your class and its replicated struct on host+device side.
You should also look for "sycl api".

What does the openmpi error "Failing at address: 0x0" mean? [duplicate]

What is a segmentation fault? Is it different in C and C++? How are segmentation faults and dangling pointers related?
Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.” It’s a helper mechanism that keeps you from corrupting the memory and introducing hard-to-debug memory bugs. Whenever you get a segfault you know you are doing something wrong with memory – accessing a variable that has already been freed, writing to a read-only portion of the memory, etc. Segmentation fault is essentially the same in most languages that let you mess with memory management, there is no principal difference between segfaults in C and C++.
There are many ways to get a segfault, at least in the lower-level languages such as C(++). A common way to get a segfault is to dereference a null pointer:
int *p = NULL;
*p = 1;
Another segfault happens when you try to write to a portion of memory that was marked as read-only:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
Dangling pointer points to a thing that does not exist anymore, like here:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
The pointer p dangles because it points to the character variable c that ceased to exist after the block ended. And when you try to dereference dangling pointer (like *p='A'), you would probably get a segfault.
It would be worth noting that segmentation fault isn't caused by directly accessing another process memory (this is what I'm hearing sometimes), as it is simply not possible. With virtual memory every process has its own virtual address space and there is no way to access another one using any value of pointer. Exception to this can be shared libraries which are same physical address space mapped to (possibly) different virtual addresses and kernel memory which is even mapped in the same way in every process (to avoid TLB flushing on syscall, I think). And things like shmat ;) - these are what I count as 'indirect' access. One can, however, check that they are usually located long way from process code and we are usually able to access them (this is why they are there, nevertheless accessing them in a improper way will produce segmentation fault).
Still, segmentation fault can occur in case of accessing our own (process) memory in improper way (for instance trying to write to non-writable space). But the most common reason for it is the access to the part of the virtual address space that is not mapped to physical one at all.
And all of this with respect to virtual memory systems.
A segmentation fault is caused by a request for a page that the process does not have listed in its descriptor table, or an invalid request for a page that it does have listed (e.g. a write request on a read-only page).
A dangling pointer is a pointer that may or may not point to a valid page, but does point to an "unexpected" segment of memory.
To be honest, as other posters have mentioned, Wikipedia has a very good article on this so have a look there. This type of error is very common and often called other things such as Access Violation or General Protection Fault.
They are no different in C, C++ or any other language that allows pointers. These kinds of errors are usually caused by pointers that are
Used before being properly initialised
Used after the memory they point to has been realloced or deleted.
Used in an indexed array where the index is outside of the array bounds. This is generally only when you're doing pointer math on traditional arrays or c-strings, not STL / Boost based collections (in C++.)
According to Wikipedia:
A segmentation fault occurs when a
program attempts to access a memory
location that it is not allowed to
access, or attempts to access a memory
location in a way that is not allowed
(for example, attempting to write to a
read-only location, or to overwrite
part of the operating system).
Segmentation fault is also caused by hardware failures, in this case the RAM memories. This is the less common cause, but if you don't find an error in your code, maybe a memtest could help you.
The solution in this case, change the RAM.
edit:
Here there is a reference: Segmentation fault by hardware
Wikipedia's Segmentation_fault page has a very nice description about it, just pointing out the causes and reasons. Have a look into the wiki for a detailed description.
In computing, a segmentation fault (often shortened to segfault) or access violation is a fault raised by hardware with memory protection, notifying an operating system (OS) about a memory access violation.
The following are some typical causes of a segmentation fault:
Dereferencing NULL pointers – this is special-cased by memory management hardware
Attempting to access a nonexistent memory address (outside process's address space)
Attempting to access memory the program does not have rights to (such as kernel structures in process context)
Attempting to write read-only memory (such as code segment)
These in turn are often caused by programming errors that result in invalid memory access:
Dereferencing or assigning to an uninitialized pointer (wild pointer, which points to a random memory address)
Dereferencing or assigning to a freed pointer (dangling pointer, which points to memory that has been freed/deallocated/deleted)
A buffer overflow.
A stack overflow.
Attempting to execute a program that does not compile correctly. (Some compilers will output an executable file despite the presence of compile-time errors.)
Segmentation fault occurs when a process (running instance of a program) is trying to access read-only memory address or memory range which is being used by other process or access the non-existent (invalid) memory address.
Dangling Reference (pointer) problem means that trying to access an object or variable whose contents have already been deleted from memory, e.g:
int *arr = new int[20];
delete arr;
cout<<arr[1]; //dangling problem occurs here
In simple words: segmentation fault is the operating system sending a signal to the program
saying that it has detected an illegal memory access and is prematurely terminating the program to prevent
memory from being corrupted.
There are several good explanations of "Segmentation fault" in the answers, but since with segmentation fault often there's a dump of the memory content, I wanted to share where the relationship between the "core dumped" part in Segmentation fault (core dumped) and memory comes from:
From about 1955 to 1975 - before semiconductor memory - the dominant technology in computer memory used tiny magnetic doughnuts strung on copper wires. The doughnuts were known as "ferrite cores" and main memory thus known as "core memory" or "core".
Taken from here.
"Segmentation fault" means that you tried to access memory that you do not have access to.
The first problem is with your arguments of main. The main function should be int main(int argc, char *argv[]), and you should check that argc is at least 2 before accessing argv[1].
Also, since you're passing in a float to printf (which, by the way, gets converted to a double when passing to printf), you should use the %f format specifier. The %s format specifier is for strings ('\0'-terminated character arrays).
Simple meaning of Segmentation fault is that you are trying to access some memory which doesn't belong to you. Segmentation fault occurs when we attempt to read and/or write tasks in a read only memory location or try to freed memory. In other words, we can explain this as some sort of memory corruption.
Below I mention common mistakes done by programmers that lead to Segmentation fault.
Use scanf() in wrong way(forgot to put &).
int num;
scanf("%d", num);// must use &num instead of num
Use pointers in wrong way.
int *num;
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
Modifying a string literal(pointer try to write or modify a read only memory.)
char *str;
//Stored in read only part of data segment
str = "GfG";
//Problem: trying to modify read only memory
*(str+1) = 'n';
Try to reach through an address which is already freed.
// allocating memory to num
int* num = malloc(8);
*num = 100;
// de-allocated the space allocated to num
free(num);
// num is already freed there for it cause segmentation fault
*num = 110;
Stack Overflow -: Running out of memory on the stack
Accessing an array out of bounds'
Use wrong format specifiers when using printf() and scanf()'
Consider the following snippets of Code,
SNIPPET 1
int *number = NULL;
*number = 1;
SNIPPET 2
int *number = malloc(sizeof(int));
*number = 1;
I'd assume you know the meaning of the functions: malloc() and sizeof() if you are asking this question.
Now that that is settled,
SNIPPET 1 would throw a Segmentation Fault Error.
while SNIPPET 2 would not.
Here's why.
The first line of snippet one is creating a variable(*number) to store the address of some other variable but in this case it is initialized to NULL.
on the other hand,
The second line of snippet two is creating the same variable(*number) to store the address of some other and in this case it is given a memory address(because malloc() is a function in C/C++ that returns a memory address of the computer)
The point is you cannot put water inside a bowl that has not been bought OR a bowl that has been bought but has not been authorized for use by you.
When you try to do that, the computer is alerted and it throws a SegFault error.
You should only face this errors with languages that are close to low-level like C/C++. There is an abstraction in other High Level Languages that ensure you do not make this error.
It is also paramount to understand that Segmentation Fault is not language-specific.
There are enough definitions of segmentation fault, I would like to quote few examples which I came across while programming, which might seem like silly mistakes, but will waste a lot of time.
You can get a segmentation fault in below case while argument type mismatch in printf:
#include <stdio.h>
int main(){
int a = 5;
printf("%s",a);
return 0;
}
output : Segmentation Fault (SIGSEGV)
When you forgot to allocate memory to a pointer, but try to use it.
#include <stdio.h>
typedef struct{
int a;
} myStruct;
int main(){
myStruct *s;
/* few lines of code */
s->a = 5;
return 0;
}
output : Segmentation Fault (SIGSEGV)
In computing, a segmentation fault or access violation is a fault, or failure condition, raised by hardware with memory protection,
notifying an operating system the software has attempted to access a
restricted area of memory. -WIKIPEDIA
You might be accessing the computer memory with the wrong data type. Your case might be like the code below:
#include <stdio.h>
int main(int argc, char *argv[]) {
char A = 'asd';
puts(A);
return 0;
}
'asd' -> is a character chain rather than a single character char data type. So, storing it as a char causes the segmentation fault. Stocking some data at the wrong position.
Storing this string or character chain as a single char is trying to fit a square peg in a round hole.
Terminated due to signal: SEGMENTATION FAULT (11)
Segm. Fault is the same as trying to breath in under water, your lungs were not made for that. Reserving memory for an integer and then trying to operate it as another data type won't work at all.
Segmentation fault occurs when a process (running instance of a program) is trying to access a read-only memory address or memory range which is being used by another process or access the non-existent memory address.
seg fault,when type gets mismatched
A segmentation fault or access violation occurs when a program attempts to access a memory location that is not exist, or attempts to access a memory location in a way that is not allowed.
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
Here i[1000] not exist, so segfault occurs.
Causes of segmentation fault:
it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.
De-referencing NULL pointers – this is special-cased by memory management hardware.
Attempting to access a nonexistent memory address (outside process’s address space).
Attempting to access memory the program does not have rights to (such as kernel structures in process context).
Attempting to write read-only memory (such as code segment).

MPI_Aint in MPI_(I)NEIGHBOR_ALLTOALLW() vs int in MPI_(I)ALLTOALLW()

With MPI3.0 neighborhood collective communications were introduced.
And in 2 of them (MPI_NEIGHBOR_ALLTOALLW and MPI_INEIGHBOR_ALLTOALLW) displacements (sdispls and rdispls) are arrays of const MPI_Aint. Contrariwise of how the same, but collective, funcions (MPI_ALLTOALLW and MPI_ALLTOALLW) are defined -arrays of const int.
Also considering what the MPI Standard v3.0 says about MPI_Aint (page 16):
2.5.6 Addresses
Some MPI procedures use address arguments that represent an absolute address in the
calling program. The datatype of such an argument is MPI_Aint in C and
INTEGER (KIND=MPI_ADDRESS_KIND) in Fortran. These types must have the same width
and encode address values in the same manner such that address values in one language
may be passed directly to another language without conversion. There is the MPI constant
MPI_BOTTOM to indicate the start of the address range.
I still don't get the point and, if exist, the difference (in addition that MPI_Aint can't be negative) between int and MPI_Aint!
MPI_Aint is a portable C data type that can hold memory addresses and it could be larger than the usual int. The policy of the MPI Forum is to not change the signature of existing MPI calls (as it could break existing applications - see here). Rather new calls are introduced that supersede the old ones. The rationale is that int worked well before LP64 64-bit architectures become popular at which point int could no longer be used to address the whole virtual address space of a single process. After this realisation some MPI calls got new versions in later versions that use MPI_Aint or MPI_Count (large integer type) instead of int. For example, MPI_Get_count_x supersedes MPI_Get_count and uses MPI_Count instead of int.
In this respect MPI_Alltoallw is an old call (it comes from MPI-2.0) and it retains its signature of using int offsets while MPI_(I)Neighbor_alltoallw is a new one (it comes with MPI-3.0) and it uses the address type in order to be able to work with data located (almost) anywhere in memory.
The same applies to the Fortran bindings.

Resources