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