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