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 #if defined(PETSC_HAVE_MEMKIND) 10 #include <memkind.h> 11 typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType; 12 PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED; 13 PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED; 14 #endif 15 /* 16 We want to make sure that all mallocs of double or complex numbers are complex aligned. 17 1) on systems with memalign() we call that routine to get an aligned memory location 18 2) on systems without memalign() we 19 - allocate one sizeof(PetscScalar) extra space 20 - we shift the pointer up slightly if needed to get PetscScalar aligned 21 - if shifted we store at ptr[-1] the amount of shift (plus a classid) 22 */ 23 #define SHIFT_CLASSID 456123 24 25 PetscErrorCode PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result) 26 { 27 if (!mem) { *result = NULL; return 0; } 28 #if defined(PETSC_HAVE_MEMKIND) 29 { 30 int ierr; 31 if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem); 32 else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem); 33 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem); 34 } 35 #else 36 # if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8) 37 *result = malloc(mem); 38 # elif defined(PETSC_HAVE_MEMALIGN) 39 *result = memalign(PETSC_MEMALIGN,mem); 40 # else 41 { 42 /* 43 malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 44 */ 45 int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN); 46 if (ptr) { 47 int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 48 shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 49 ptr[shift-1] = shift + SHIFT_CLASSID; 50 ptr += shift; 51 *result = (void*)ptr; 52 } else { 53 *result = NULL; 54 } 55 } 56 # endif 57 #endif 58 if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 59 return 0; 60 } 61 62 PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[]) 63 { 64 if (!ptr) return 0; 65 #if defined(PETSC_HAVE_MEMKIND) 66 memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */ 67 #else 68 # if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 69 { 70 /* 71 Previous int tells us how many ints the pointer has been shifted from 72 the original address provided by the system malloc(). 73 */ 74 int shift = *(((int*)ptr)-1) - SHIFT_CLASSID; 75 if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 76 if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 77 ptr = (void*)(((int*)ptr) - shift); 78 } 79 # endif 80 81 # if defined(PETSC_HAVE_FREE_RETURN_INT) 82 int err = free(ptr); 83 if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 84 # else 85 free(ptr); 86 # endif 87 #endif 88 return 0; 89 } 90 91 PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result) 92 { 93 PetscErrorCode ierr; 94 95 if (!mem) { 96 ierr = PetscFreeAlign(*result, line, func, file); 97 if (ierr) return ierr; 98 *result = NULL; 99 return 0; 100 } 101 #if defined(PETSC_HAVE_MEMKIND) 102 if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem); 103 else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem); 104 #else 105 # if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 106 { 107 /* 108 Previous int tells us how many ints the pointer has been shifted from 109 the original address provided by the system malloc(). 110 */ 111 int shift = *(((int*)*result)-1) - SHIFT_CLASSID; 112 if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 113 if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 114 *result = (void*)(((int*)*result) - shift); 115 } 116 # endif 117 118 # if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN) 119 *result = realloc(*result, mem); 120 # else 121 { 122 /* 123 malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 124 */ 125 int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN); 126 if (ptr) { 127 int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 128 shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 129 ptr[shift-1] = shift + SHIFT_CLASSID; 130 ptr += shift; 131 *result = (void*)ptr; 132 } else { 133 *result = NULL; 134 } 135 } 136 # endif 137 #endif 138 if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 139 #if defined(PETSC_HAVE_MEMALIGN) 140 /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to 141 * realloc and, if the alignment is wrong, malloc/copy/free. */ 142 if (((size_t) (*result)) % PETSC_MEMALIGN) { 143 void *newResult; 144 # if defined(PETSC_HAVE_MEMKIND) 145 { 146 int ierr; 147 if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem); 148 else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem); 149 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem); 150 } 151 # else 152 newResult = memalign(PETSC_MEMALIGN,mem); 153 # endif 154 if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 155 ierr = PetscMemcpy(newResult,*result,mem); 156 if (ierr) return ierr; 157 # if defined(PETSC_HAVE_FREE_RETURN_INT) 158 { 159 int err = free(*result); 160 if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 161 } 162 # else 163 # if defined(PETSC_HAVE_MEMKIND) 164 memkind_free(0,*result); 165 # else 166 free(*result); 167 # endif 168 # endif 169 *result = newResult; 170 } 171 #endif 172 return 0; 173 } 174 175 PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 176 PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[]) = PetscFreeAlign; 177 PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign; 178 179 PetscBool petscsetmallocvisited = PETSC_FALSE; 180 181 /*@C 182 PetscMallocSet - Sets the routines used to do mallocs and frees. 183 This routine MUST be called before PetscInitialize() and may be 184 called only once. 185 186 Not Collective 187 188 Input Parameters: 189 + malloc - the malloc routine 190 - free - the free routine 191 192 Level: developer 193 194 Concepts: malloc 195 Concepts: memory^allocation 196 197 @*/ 198 PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**), 199 PetscErrorCode (*ifree)(void*,int,const char[],const char[])) 200 { 201 PetscFunctionBegin; 202 if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times"); 203 PetscTrMalloc = imalloc; 204 PetscTrFree = ifree; 205 petscsetmallocvisited = PETSC_TRUE; 206 PetscFunctionReturn(0); 207 } 208 209 /*@C 210 PetscMallocClear - Resets the routines used to do mallocs and frees to the 211 defaults. 212 213 Not Collective 214 215 Level: developer 216 217 Notes: 218 In general one should never run a PETSc program with different malloc() and 219 free() settings for different parts; this is because one NEVER wants to 220 free() an address that was malloced by a different memory management system 221 222 @*/ 223 PetscErrorCode PetscMallocClear(void) 224 { 225 PetscFunctionBegin; 226 PetscTrMalloc = PetscMallocAlign; 227 PetscTrFree = PetscFreeAlign; 228 petscsetmallocvisited = PETSC_FALSE; 229 PetscFunctionReturn(0); 230 } 231 232 PetscErrorCode PetscMemoryTrace(const char label[]) 233 { 234 PetscErrorCode ierr; 235 PetscLogDouble mem,mal; 236 static PetscLogDouble oldmem = 0,oldmal = 0; 237 238 PetscFunctionBegin; 239 ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr); 240 ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr); 241 242 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); 243 oldmem = mem; 244 oldmal = mal; 245 PetscFunctionReturn(0); 246 } 247 248 static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 249 static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[]) = PetscFreeAlign; 250 251 /*@C 252 PetscMallocSetDRAM - Set PetscMalloc to use DRAM. 253 If memkind is available, change the memkind type. Otherwise, switch the 254 current malloc and free routines to the PetscMallocAlign and 255 PetscFreeAlign (PETSc default). 256 257 Not Collective 258 259 Level: developer 260 261 Notes: 262 This provides a way to do the allocation on DRAM temporarily. One 263 can switch back to the previous choice by calling PetscMallocReset(). 264 265 .seealso: PetscMallocReset() 266 @*/ 267 PetscErrorCode PetscMallocSetDRAM(void) 268 { 269 PetscFunctionBegin; 270 if (PetscTrMalloc == PetscMallocAlign) { 271 #if defined(PETSC_HAVE_MEMKIND) 272 previousmktype = currentmktype; 273 currentmktype = PETSC_MK_DEFAULT; 274 #endif 275 } else { 276 /* Save the previous choice */ 277 PetscTrMallocOld = PetscTrMalloc; 278 PetscTrFreeOld = PetscTrFree; 279 PetscTrMalloc = PetscMallocAlign; 280 PetscTrFree = PetscFreeAlign; 281 } 282 PetscFunctionReturn(0); 283 } 284 285 /*@C 286 PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM 287 288 Not Collective 289 290 Level: developer 291 292 .seealso: PetscMallocSetDRAM() 293 @*/ 294 PetscErrorCode PetscMallocResetDRAM(void) 295 { 296 PetscFunctionBegin; 297 if (PetscTrMalloc == PetscMallocAlign) { 298 #if defined(PETSC_HAVE_MEMKIND) 299 currentmktype = previousmktype; 300 #endif 301 } else { 302 /* Reset to the previous choice */ 303 PetscTrMalloc = PetscTrMallocOld; 304 PetscTrFree = PetscTrFreeOld; 305 } 306 PetscFunctionReturn(0); 307 } 308