xref: /petsc/src/sys/error/checkptr.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 #include <petsc/private/petscimpl.h>
2 
3 #if defined(PETSC_HAVE_CUDA)
4 #include <cuda_runtime.h>
5 #endif
6 
7 #if defined(PETSC_HAVE_HIP)
8 #include <hip/hip_runtime.h>
9 #endif
10 
11 static PetscInt petsc_checkpointer_intensity = 1;
12 
13 /*@
14    PetscCheckPointerSetIntensity - An intense pointer check registers a signal handler and attempts to dereference to
15    confirm whether the address is valid.  An intensity of 0 never uses signal handlers, 1 uses them when not in a "hot"
16    function, and intensity of 2 always uses a signal handler.
17 
18    Not Collective
19 
20    Input Parameter:
21 .  intensity - how much to check pointers for validity
22 
23    Options Database:
24 .  -check_pointer_intensity - intensity (0, 1, or 2)
25 
26    Level: advanced
27 
28 .seealso: `PetscCheckPointer()`, `PetscFunctionBeginHot()`
29 @*/
30 PetscErrorCode PetscCheckPointerSetIntensity(PetscInt intensity) {
31   PetscFunctionBegin;
32   switch (intensity) {
33   case 0:
34   case 1:
35   case 2: petsc_checkpointer_intensity = intensity; break;
36   default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Intensity %" PetscInt_FMT " not in 0,1,2", intensity);
37   }
38   PetscFunctionReturn(0);
39 }
40 
41 /* ---------------------------------------------------------------------------------------*/
42 
43 #if defined(PETSC_HAVE_SETJMP_H)
44 #include <setjmp.h>
45 static jmp_buf   PetscSegvJumpBuf;
46 static PetscBool PetscSegvJumpBuf_set;
47 
48 /*@C
49    PetscSignalSegvCheckPointerOrMpi - To be called from a signal handler for SIGSEGV.  If the signal was received
50    while executing PetscCheckPointer()/PetscCheckMpiXxxAwareness(), this function longjmps back there, otherwise returns
51    with no effect. This function is called automatically by PetscSignalHandlerDefault().
52 
53    Not Collective
54 
55    Level: developer
56 
57 .seealso: `PetscPushSignalHandler()`
58 @*/
59 void PetscSignalSegvCheckPointerOrMpi(void) {
60   if (PetscSegvJumpBuf_set) longjmp(PetscSegvJumpBuf, 1);
61 }
62 
63 /*@C
64      PetscCheckPointer - Returns PETSC_TRUE if a pointer points to accessible data
65 
66    Not Collective
67 
68    Input Parameters:
69 +     ptr - the pointer
70 -     dtype - the type of data the pointer is suppose to point to
71 
72    Level: developer
73 
74 .seealso: `PetscCheckPointerSetIntensity()`
75 @*/
76 PetscBool PetscCheckPointer(const void *ptr, PetscDataType dtype) {
77   if (PETSC_RUNNING_ON_VALGRIND) return PETSC_TRUE;
78   if (!ptr) return PETSC_FALSE;
79   if (petsc_checkpointer_intensity < 1) return PETSC_TRUE;
80 
81 #if PetscDefined(USE_DEBUG)
82   /* Skip the verbose check if we are inside a hot function. */
83   if (petscstack.hotdepth > 0 && petsc_checkpointer_intensity < 2) return PETSC_TRUE;
84 #endif
85 
86   PetscSegvJumpBuf_set = PETSC_TRUE;
87 
88   if (setjmp(PetscSegvJumpBuf)) {
89     /* A segv was triggered in the code below hence we return with an error code */
90     PetscSegvJumpBuf_set = PETSC_FALSE;
91     return PETSC_FALSE;
92   } else {
93     switch (dtype) {
94     case PETSC_INT: {
95       PETSC_UNUSED PetscInt x = (PetscInt) * (volatile PetscInt *)ptr;
96       break;
97     }
98 #if defined(PETSC_USE_COMPLEX)
99     case PETSC_SCALAR: { /* C++ is seriously dysfunctional with volatile std::complex. */
100 #if defined(PETSC_USE_CXXCOMPLEX)
101       PetscReal                         xreal = ((volatile PetscReal *)ptr)[0], ximag = ((volatile PetscReal *)ptr)[1];
102       PETSC_UNUSED volatile PetscScalar x = xreal + PETSC_i * ximag;
103 #else
104       PETSC_UNUSED PetscScalar x = *(volatile PetscScalar *)ptr;
105 #endif
106       break;
107     }
108 #endif
109     case PETSC_REAL: {
110       PETSC_UNUSED PetscReal x = *(volatile PetscReal *)ptr;
111       break;
112     }
113     case PETSC_BOOL: {
114       PETSC_UNUSED PetscBool x = *(volatile PetscBool *)ptr;
115       break;
116     }
117     case PETSC_ENUM: {
118       PETSC_UNUSED PetscEnum x = *(volatile PetscEnum *)ptr;
119       break;
120     }
121     case PETSC_CHAR: {
122       PETSC_UNUSED char x = *(volatile char *)ptr;
123       break;
124     }
125     case PETSC_OBJECT: {
126       PETSC_UNUSED volatile PetscClassId classid = ((PetscObject)ptr)->classid;
127       break;
128     }
129     default:;
130     }
131   }
132   PetscSegvJumpBuf_set = PETSC_FALSE;
133   return PETSC_TRUE;
134 }
135 
136 #define PetscMPICUPMAwarnessCheckFunction \
137   PetscBool PetscMPICUPMAwarenessCheck(void) { \
138     cupmError_t cerr = cupmSuccess; \
139     int         ierr, hbuf[2] = {1, 0}, *dbuf = NULL; \
140     PetscBool   awareness = PETSC_FALSE; \
141     cerr                  = cupmMalloc((void **)&dbuf, sizeof(int) * 2); \
142     if (cerr != cupmSuccess) return PETSC_FALSE; \
143     cerr = cupmMemcpy(dbuf, hbuf, sizeof(int) * 2, cupmMemcpyHostToDevice); \
144     if (cerr != cupmSuccess) return PETSC_FALSE; \
145     PetscSegvJumpBuf_set = PETSC_TRUE; \
146     if (setjmp(PetscSegvJumpBuf)) { \
147       /* If a segv was triggered in the MPI_Allreduce below, it is very likely due to the MPI is not GPU-aware */ \
148       awareness = PETSC_FALSE; \
149     } else { \
150       ierr = MPI_Allreduce(dbuf, dbuf + 1, 1, MPI_INT, MPI_SUM, PETSC_COMM_SELF); \
151       if (!ierr) awareness = PETSC_TRUE; \
152     } \
153     PetscSegvJumpBuf_set = PETSC_FALSE; \
154     cerr                 = cupmFree(dbuf); \
155     if (cerr != cupmSuccess) return PETSC_FALSE; \
156     return awareness; \
157   }
158 
159 #if defined(PETSC_HAVE_CUDA)
160 #define cupmError_t                cudaError_t
161 #define cupmMalloc                 cudaMalloc
162 #define cupmMemcpy                 cudaMemcpy
163 #define cupmFree                   cudaFree
164 #define cupmSuccess                cudaSuccess
165 #define cupmMemcpyHostToDevice     cudaMemcpyHostToDevice
166 #define PetscMPICUPMAwarenessCheck PetscMPICUDAAwarenessCheck
167 PetscMPICUPMAwarnessCheckFunction
168 #endif
169 
170 #if defined(PETSC_HAVE_HIP)
171 #define cupmError_t                hipError_t
172 #define cupmMalloc                 hipMalloc
173 #define cupmMemcpy                 hipMemcpy
174 #define cupmFree                   hipFree
175 #define cupmSuccess                hipSuccess
176 #define cupmMemcpyHostToDevice     hipMemcpyHostToDevice
177 #define PetscMPICUPMAwarenessCheck PetscMPIHIPAwarenessCheck
178   PetscMPICUPMAwarnessCheckFunction
179 #endif
180 
181 #else
182 void PetscSignalSegvCheckPointerOrMpi(void) {
183   return;
184 }
185 
186 PetscBool PetscCheckPointer(const void *ptr, PETSC_UNUSED PetscDataType dtype) {
187   if (!ptr) return PETSC_FALSE;
188   return PETSC_TRUE;
189 }
190 
191 #if defined(PETSC_HAVE_CUDA)
192 PetscBool PetscMPICUDAAwarenessCheck(void) {
193   /* If no setjmp (rare), return true and let users code run (and segfault if they should) */
194   return PETSC_TRUE;
195 }
196 #endif
197 
198 #if defined(PETSC_HAVE_HIP)
199 PetscBool PetscMPIHIPAwarenessCheck(void) {
200   /* If no setjmp (rare), return true and let users code run (and segfault if they should) */
201   return PETSC_TRUE;
202 }
203 #endif
204 
205 #endif
206