xref: /petsc/src/sys/error/checkptr.c (revision 97bb3fdc57998093333768643284f5be71d00324)
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   /* Skip the verbose check if we are inside a hot function. */
89   if (petscstack && petscstack->hotdepth > 0 && petsc_checkpointer_intensity < 2) return PETSC_TRUE;
90 
91   PetscSegvJumpBuf_set = PETSC_TRUE;
92 
93   if (setjmp(PetscSegvJumpBuf)) {
94     /* A segv was triggered in the code below hence we return with an error code */
95     PetscSegvJumpBuf_set = PETSC_FALSE;
96     return PETSC_FALSE;
97   } else {
98     switch (dtype) {
99     case PETSC_INT:{
100       PETSC_UNUSED PetscInt x = (PetscInt)*(volatile PetscInt*)ptr;
101       break;
102     }
103 #if defined(PETSC_USE_COMPLEX)
104     case PETSC_SCALAR:{         /* C++ is seriously dysfunctional with volatile std::complex. */
105 #if defined(PETSC_USE_CXXCOMPLEX)
106       PetscReal xreal = ((volatile PetscReal*)ptr)[0],ximag = ((volatile PetscReal*)ptr)[1];
107       PETSC_UNUSED volatile PetscScalar x = xreal + PETSC_i*ximag;
108 #else
109       PETSC_UNUSED PetscScalar x = *(volatile PetscScalar*)ptr;
110 #endif
111       break;
112     }
113 #endif
114     case PETSC_REAL:{
115       PETSC_UNUSED PetscReal x = *(volatile PetscReal*)ptr;
116       break;
117     }
118     case PETSC_BOOL:{
119       PETSC_UNUSED PetscBool x = *(volatile PetscBool*)ptr;
120       break;
121     }
122     case PETSC_ENUM:{
123       PETSC_UNUSED PetscEnum x = *(volatile PetscEnum*)ptr;
124       break;
125     }
126     case PETSC_CHAR:{
127       PETSC_UNUSED char x = *(volatile char*)ptr;
128       break;
129     }
130     case PETSC_OBJECT:{
131       PETSC_UNUSED volatile PetscClassId classid = ((PetscObject)ptr)->classid;
132       break;
133     }
134     default:;
135     }
136   }
137   PetscSegvJumpBuf_set = PETSC_FALSE;
138   return PETSC_TRUE;
139 }
140 
141 #define PetscMPICUPMAwarnessCheckFunction  \
142 PetscBool PetscMPICUPMAwarenessCheck(void)  \
143 { \
144   cupmError_t cerr=cupmSuccess; \
145   int         ierr,hbuf[2]={1,0},*dbuf=NULL; \
146   PetscBool   awareness=PETSC_FALSE; \
147   cerr = cupmMalloc((void**)&dbuf,sizeof(int)*2);if (cerr != cupmSuccess) return PETSC_FALSE; \
148   cerr = cupmMemcpy(dbuf,hbuf,sizeof(int)*2,cupmMemcpyHostToDevice);if (cerr != cupmSuccess) return PETSC_FALSE; \
149   PetscSegvJumpBuf_set = PETSC_TRUE; \
150   if (setjmp(PetscSegvJumpBuf)) { \
151     /* If a segv was triggered in the MPI_Allreduce below, it is very likely due to the MPI is not GPU-aware */ \
152     awareness = PETSC_FALSE; \
153   } else { \
154     ierr = MPI_Allreduce(dbuf,dbuf+1,1,MPI_INT,MPI_SUM,PETSC_COMM_SELF); \
155     if (!ierr) awareness = PETSC_TRUE; \
156   } \
157   PetscSegvJumpBuf_set = PETSC_FALSE; \
158   cerr = cupmFree(dbuf);if (cerr != cupmSuccess) return PETSC_FALSE; \
159   return awareness; \
160 }
161 
162 #if defined(PETSC_HAVE_CUDA)
163   #define cupmError_t                   cudaError_t
164   #define cupmMalloc                    cudaMalloc
165   #define cupmMemcpy                    cudaMemcpy
166   #define cupmFree                      cudaFree
167   #define cupmSuccess                   cudaSuccess
168   #define cupmMemcpyHostToDevice        cudaMemcpyHostToDevice
169   #define PetscMPICUPMAwarenessCheck    PetscMPICUDAAwarenessCheck
170   PetscMPICUPMAwarnessCheckFunction
171 #endif
172 
173 #if defined(PETSC_HAVE_HIP)
174   #define cupmError_t                   hipError_t
175   #define cupmMalloc                    hipMalloc
176   #define cupmMemcpy                    hipMemcpy
177   #define cupmFree                      hipFree
178   #define cupmSuccess                   hipSuccess
179   #define cupmMemcpyHostToDevice        hipMemcpyHostToDevice
180   #define PetscMPICUPMAwarenessCheck    PetscMPIHIPAwarenessCheck
181   PetscMPICUPMAwarnessCheckFunction
182 #endif
183 
184 #else
185 void PetscSignalSegvCheckPointerOrMpi(void)
186 {
187   return;
188 }
189 
190 PetscBool PetscCheckPointer(const void *ptr,PETSC_UNUSED PetscDataType dtype)
191 {
192   if (!ptr) return PETSC_FALSE;
193   return PETSC_TRUE;
194 }
195 
196 #if defined (PETSC_HAVE_CUDA)
197 PetscBool PetscMPICUDAAwarenessCheck(void)
198 {
199   /* If no setjmp (rare), return true and let users code run (and segfault if they should) */
200   return PETSC_TRUE;
201 }
202 #endif
203 
204 #if defined (PETSC_HAVE_HIP)
205 PetscBool PetscMPIHIPAwarenessCheck(void)
206 {
207   /* If no setjmp (rare), return true and let users code run (and segfault if they should) */
208   return PETSC_TRUE;
209 }
210 #endif
211 
212 #endif
213