preface
Using #pragma offload target(mic) to load programs onto mic for calculation is a common method, but this method only supports one-dimensional pointers. If there are more complex data structures, such as two-dimensional pointers, trees, linked lists and other structures, these data structures need to be converted into one-dimensional structures (if possible), otherwise the data cannot be transferred to MIC In order to meet the complex data structure, MIC provides a way to share virtual memory, that is, the memory of MIC and cpu are regarded as sharing the same virtual memory. The data in the shared memory is shared by cpu and mic, and there is no need to use offload to transfer the data between cpu and mic
Declare shared variables and functions
We can use_ Cilk_shared to declare variables and functions shared by mic and cpu, using_ Cilk_offload runs the shared function on the mic side
_Cilk_shared int i; _Cilk_shared void a();
The virtual memory addresses of shared variables are the same on cpu and mic, and their values are synchronized between cpu and Mic Here is an example:
#include <stdio.h> #include <stdlib.h> // Declare variables shared by CPU and MIC _Cilk_shared int x = 1; // Declare functions shared by CPU and MIC _Cilk_shared void run_onmic() { x = 3; printf("mic: the value of x is %d and the address of mic is %p\n", x, &x); // Confirm whether to execute on mic #ifdef __MIC__ printf("this is onmic\n"); #endif } void run_oncpu() { printf("cpu: the value of x is %d and the address of mic is %p\n", x, &x); } int main() { // Use_ Cilk_offload replaces #pragma offload target(mic) _Cilk_offload run_onmic(); run_oncpu(); }
Pointer memory management
First, let's talk about the declaration of shared pointers:
int *_Cilk_shared share_pointer;
The above is to declare a shared pointer. Note that the * sign is in_ Cilk_ In front of shared, neither of the following two methods is the correct way to declare shared pointers
int _Cilk_shared *share_pointer; _Cilk_shared int *share_pointer;
The following functions should be used for allocation and release of shared internal configuration
void *_Offload_shared_malloc(size_t size); void *_Offload_shared_aligned_malloc(size_t size, size_t alignment); _Offload_shared_free(void *p); _Offload_shared_aligned_free(void *p);
Among them_ Offload_shared_aligned_malloc and_ Offload_shared_aligned_free is used when memory alignment is required However, it seems that malloc can be used to allocate memory for shared variables in shared functions, but it is unclear whether there will be any side effects Another thing to note is_ Offload_shared_malloc and free, malloc and_ Offload_shared_free cannot be mixed, otherwise unexpected results may occur. Here is an example code:
#include <stdio.h> #include <stdlib.h> // int _Cilk_shared *p is a local pointer that can point to shared data. If P =_ Offload_ share_ Malloc () will report warning // There is no problem with using the following definition // typedef int *fp; // _Cilk_shared fp p; // p = (fp)_Offload_shared_malloc(sizeof(int) * n); // _Offload_shared_free(p); int *_Cilk_shared share_pointer; _Cilk_shared int n = 8; // In shared functions, malloc and free are used to allocate and free memory for shared variables _Cilk_shared void cilk_malloc() { int i; share_pointer = (int *)malloc(sizeof(int) * n); for(i = 0; i < n; i++) { share_pointer[i] = i; } for(i = 0; i < n; i++) { printf("cilk_malloc: share_pointer[%d] is %d\n", i, share_pointer[i]); } free(share_pointer); } // Executing the following function on mic will report an error // CARD--ERROR:1 thread:3 myoArenaFree: It is not supported to free shared memory from the MIC side! _Cilk_shared void cilk_sharedfree() { int i; share_pointer = (int *)_Offload_shared_malloc(sizeof(int) * n); for(i = 0; i < n; i++) { share_pointer[i] = i; } for(i = 0; i < n; i++) { printf("cilk_sharedfree: share_pointer[%d] is %d\n", i, share_pointer[i]); } _Offload_shared_free(share_pointer); } _Cilk_shared void cilk_pointer() { int i; for(i = 0; i < n; i++) { share_pointer[i] = i; } for(i = 0; i < n; i++) { printf("cilk_pointer: share_pointer[%d] is %d\n", i, share_pointer[i]); } } int main() { //_Cilk_offload cilk_malloc(); //_Cilk_offload cilk_sharedfree(); // The following three statements will cause errors when executed //share_pointer =(int *) malloc(sizeof(int) * n); //_Cilk_offload cilk_pointer(); //free(share_pointer); // The following three statements can be executed normally share_pointer = (int *) _Offload_shared_malloc(sizeof(int) * n); _Cilk_offload cilk_pointer(); _Offload_shared_free(share_pointer); return 0; }
When cilk is executed on mic_ share_ When free, an error will be reported because it can only be called on the cpu side_ Offload_ shared_ The free function frees up memory
Two dimensional pointer example
The following is an example of using a shared two-dimensional pointer
#include <stdio.h> int **_Cilk_shared p; _Cilk_shared int n = 3, m = 3; void init_p() { int index = 0, i, j; for(i = 0; i < n; i++) { for( j = 0; j < m; j++) { p[i][j] = index++; } } } _Cilk_shared void print_p() { int i, j; for(i = 0; i < n; i++) { for(j = 0; j < n; j++) { printf("print_p: p[%d][%d] is %d\n", i, j, p[i][j]); } } } int main() { int i; p = (int **) _Offload_shared_malloc(sizeof(int *) * n); for( i = 0; i < n ;i++) { p[i] =(int *) _Offload_shared_malloc(sizeof(int) * m); } init_p(); _Cilk_offload print_p(); for(i = 0; i < n; i++) { _Offload_shared_free(p[i]); } _Offload_shared_free(p); }