1 2 /* 3 Code that allows a user to dictate what malloc() PETSc uses. 4 */ 5 #include <petscsys.h> /*I "petscsys.h" I*/ 6 #if defined(PETSC_HAVE_MALLOC_H) 7 #include <malloc.h> 8 #endif 9 10 /* 11 We want to make sure that all mallocs of double or complex numbers are complex aligned. 12 1) on systems with memalign() we call that routine to get an aligned memory location 13 2) on systems without memalign() we 14 - allocate one sizeof(PetscScalar) extra space 15 - we shift the pointer up slightly if needed to get PetscScalar aligned 16 - if shifted we store at ptr[-1] the amount of shift (plus a classid) 17 */ 18 #define SHIFT_CLASSID 456123 19 20 #undef __FUNCT__ 21 #define __FUNCT__ "PetscMallocAlign" 22 PetscErrorCode PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result) 23 { 24 if (!mem) { *result = NULL; return 0; } 25 #if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8) 26 *result = malloc(mem); 27 #elif defined(PETSC_HAVE_MEMALIGN) 28 *result = memalign(PETSC_MEMALIGN,mem); 29 #else 30 { 31 /* 32 malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 33 */ 34 int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN); 35 if (ptr) { 36 int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 37 shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 38 ptr[shift-1] = shift + SHIFT_CLASSID; 39 ptr += shift; 40 *result = (void*)ptr; 41 } else { 42 *result = NULL; 43 } 44 } 45 #endif 46 if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 47 return 0; 48 } 49 50 #undef __FUNCT__ 51 #define __FUNCT__ "PetscFreeAlign" 52 PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[]) 53 { 54 if (!ptr) return 0; 55 #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 56 { 57 /* 58 Previous int tells us how many ints the pointer has been shifted from 59 the original address provided by the system malloc(). 60 */ 61 int shift = *(((int*)ptr)-1) - SHIFT_CLASSID; 62 if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 63 if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 64 ptr = (void*)(((int*)ptr) - shift); 65 } 66 #endif 67 68 #if defined(PETSC_HAVE_FREE_RETURN_INT) 69 int err = free(ptr); 70 if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 71 #else 72 free(ptr); 73 #endif 74 return 0; 75 } 76 77 #undef __FUNCT__ 78 #define __FUNCT__ "PetscReallocAlign" 79 PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result) 80 { 81 PetscErrorCode ierr; 82 83 if (!mem) { 84 ierr = PetscFreeAlign(*result, line, func, file); 85 if (ierr) return ierr; 86 *result = NULL; 87 return 0; 88 } 89 #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 90 { 91 /* 92 Previous int tells us how many ints the pointer has been shifted from 93 the original address provided by the system malloc(). 94 */ 95 int shift = *(((int*)*result)-1) - SHIFT_CLASSID; 96 if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 97 if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 98 *result = (void*)(((int*)*result) - shift); 99 } 100 #endif 101 102 #if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN) 103 *result = realloc(*result, mem); 104 #else 105 { 106 /* 107 malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 108 */ 109 int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN); 110 if (ptr) { 111 int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 112 shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 113 ptr[shift-1] = shift + SHIFT_CLASSID; 114 ptr += shift; 115 *result = (void*)ptr; 116 } else { 117 *result = NULL; 118 } 119 } 120 #endif 121 if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 122 #if defined(PETSC_HAVE_MEMALIGN) 123 /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to 124 * realloc and, if the alignment is wrong, malloc/copy/free. */ 125 if (((size_t) (*result)) % PETSC_MEMALIGN) { 126 void *newResult; 127 128 newResult = memalign(PETSC_MEMALIGN,mem); 129 if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 130 ierr = PetscMemcpy(newResult,*result,mem); 131 if (ierr) return ierr; 132 #if defined(PETSC_HAVE_FREE_RETURN_INT) 133 { 134 int err = free(*result); 135 if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 136 } 137 #else 138 free(*result); 139 #endif 140 *result = newResult; 141 } 142 #endif 143 return 0; 144 } 145 146 PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 147 PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[]) = PetscFreeAlign; 148 PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign; 149 150 PetscBool petscsetmallocvisited = PETSC_FALSE; 151 152 #undef __FUNCT__ 153 #define __FUNCT__ "PetscMallocSet" 154 /*@C 155 PetscMallocSet - Sets the routines used to do mallocs and frees. 156 This routine MUST be called before PetscInitialize() and may be 157 called only once. 158 159 Not Collective 160 161 Input Parameters: 162 + malloc - the malloc routine 163 - free - the free routine 164 165 Level: developer 166 167 Concepts: malloc 168 Concepts: memory^allocation 169 170 @*/ 171 PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**), 172 PetscErrorCode (*ifree)(void*,int,const char[],const char[])) 173 { 174 PetscFunctionBegin; 175 if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times"); 176 PetscTrMalloc = imalloc; 177 PetscTrFree = ifree; 178 petscsetmallocvisited = PETSC_TRUE; 179 PetscFunctionReturn(0); 180 } 181 182 #undef __FUNCT__ 183 #define __FUNCT__ "PetscMallocClear" 184 /*@C 185 PetscMallocClear - Resets the routines used to do mallocs and frees to the 186 defaults. 187 188 Not Collective 189 190 Level: developer 191 192 Notes: 193 In general one should never run a PETSc program with different malloc() and 194 free() settings for different parts; this is because one NEVER wants to 195 free() an address that was malloced by a different memory management system 196 197 @*/ 198 PetscErrorCode PetscMallocClear(void) 199 { 200 PetscFunctionBegin; 201 PetscTrMalloc = PetscMallocAlign; 202 PetscTrFree = PetscFreeAlign; 203 petscsetmallocvisited = PETSC_FALSE; 204 PetscFunctionReturn(0); 205 } 206 207 #undef __FUNCT__ 208 #define __FUNCT__ "PetscMemoryTrace" 209 PetscErrorCode PetscMemoryTrace(const char label[]) 210 { 211 PetscErrorCode ierr; 212 PetscLogDouble mem,mal; 213 static PetscLogDouble oldmem = 0,oldmal = 0; 214 215 PetscFunctionBegin; 216 ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr); 217 ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr); 218 219 ierr = PetscPrintf(PETSC_COMM_WORLD,"%s High water %8.3f MB increase %8.3f MB Current %8.3f MB increase %8.3f MB\n",label,mem*1e-6,(mem - oldmem)*1e-6,mal*1e-6,(mal - oldmal)*1e-6);CHKERRQ(ierr); 220 oldmem = mem; 221 oldmal = mal; 222 PetscFunctionReturn(0); 223 } 224