xref: /petsc/src/sys/error/checkptr.c (revision efbe7e8a80d07327753dbe0b33efee01e046af3f)
1 #include <petsc/private/petscimpl.h>
2 #include <petscvalgrind.h>
3 
4 #if defined(PETSC_HAVE_CUDA)
5   #include <cuda_runtime.h>
6 #endif
7 
8 #if defined(PETSC_HAVE_HIP)
9   #include <hip/hip_runtime.h>
10 #endif
11 
12 static PetscInt petsc_checkpointer_intensity = 1;
13 
14 /*@
15    PetscCheckPointerSetIntensity - An intense pointer check registers a signal handler and attempts to dereference to
16    confirm whether the address is valid.  An intensity of 0 never uses signal handlers, 1 uses them when not in a "hot"
17    function, and intensity of 2 always uses a signal handler.
18 
19    Not Collective
20 
21    Input Arguments:
22 .  intensity - how much to check pointers for validity
23 
24    Options Database:
25 .  -check_pointer_intensity - intensity (0, 1, or 2)
26 
27    Level: advanced
28 
29 .seealso: PetscCheckPointer(), PetscFunctionBeginHot()
30 @*/
31 PetscErrorCode PetscCheckPointerSetIntensity(PetscInt intensity)
32 {
33 
34   PetscFunctionBegin;
35   switch (intensity) {
36   case 0:
37   case 1:
38   case 2:
39     petsc_checkpointer_intensity = intensity;
40     break;
41   default: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Intensity %D not in 0,1,2",intensity);
42   }
43   PetscFunctionReturn(0);
44 }
45 
46 /* ---------------------------------------------------------------------------------------*/
47 
48 #if defined(PETSC_HAVE_SETJMP_H)
49 #include <setjmp.h>
50 static jmp_buf PetscSegvJumpBuf;
51 static PetscBool PetscSegvJumpBuf_set;
52 
53 /*@C
54    PetscSignalSegvCheckPointerOrMpi - To be called from a signal handler for SIGSEGV.  If the signal was received
55    while executing PetscCheckPointer()/PetscCheckMpiXxxAwareness(), this function longjmps back there, otherwise returns
56    with no effect. This function is called automatically by PetscSignalHandlerDefault().
57 
58    Not Collective
59 
60    Level: developer
61 
62 .seealso: PetscPushSignalHandler()
63 @*/
64 void PetscSignalSegvCheckPointerOrMpi(void) {
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   return;
187 }
188 
189 PetscBool PetscCheckPointer(const void *ptr,PETSC_UNUSED PetscDataType dtype)
190 {
191   if (!ptr) return PETSC_FALSE;
192   return PETSC_TRUE;
193 }
194 
195 #if defined (PETSC_HAVE_CUDA)
196 PetscBool PetscMPICUDAAwarenessCheck(void)
197 {
198   /* If no setjmp (rare), return true and let users code run (and segfault if they should) */
199   return PETSC_TRUE;
200 }
201 #endif
202 
203 #if defined (PETSC_HAVE_HIP)
204 PetscBool PetscMPIHIPAwarenessCheck(void)
205 {
206   /* If no setjmp (rare), return true and let users code run (and segfault if they should) */
207   return PETSC_TRUE;
208 }
209 #endif
210 
211 #endif
212