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