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