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