1 2 /* 3 Code that allows a user to dictate what malloc() PETSc uses. 4 */ 5 #include <petscsys.h> /*I "petscsys.h" I*/ 6 #include <stdarg.h> 7 #if defined(PETSC_HAVE_MALLOC_H) 8 #include <malloc.h> 9 #endif 10 #if defined(PETSC_HAVE_MEMKIND) 11 #include <memkind.h> 12 typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW=1} PetscMemkindType; 13 PetscMemkindType currentmktype = PETSC_MK_HBW; 14 PetscMemkindType previousmktype = PETSC_MK_HBW; 15 #endif 16 /* 17 We want to make sure that all mallocs of double or complex numbers are complex aligned. 18 1) on systems with memalign() we call that routine to get an aligned memory location 19 2) on systems without memalign() we 20 - allocate one sizeof(PetscScalar) extra space 21 - we shift the pointer up slightly if needed to get PetscScalar aligned 22 - if shifted we store at ptr[-1] the amount of shift (plus a classid) 23 */ 24 #define SHIFT_CLASSID 456123 25 26 PetscErrorCode PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result) 27 { 28 if (!mem) { *result = NULL; return 0; } 29 #if defined(PETSC_HAVE_MEMKIND) 30 { 31 int ierr; 32 if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem); 33 else ierr = memkind_posix_memalign(MEMKIND_HBW,result,PETSC_MEMALIGN,mem); 34 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem); 35 } 36 #else 37 # if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8) 38 *result = malloc(mem); 39 # elif defined(PETSC_HAVE_MEMALIGN) 40 *result = memalign(PETSC_MEMALIGN,mem); 41 # else 42 { 43 /* 44 malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 45 */ 46 int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN); 47 if (ptr) { 48 int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 49 shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 50 ptr[shift-1] = shift + SHIFT_CLASSID; 51 ptr += shift; 52 *result = (void*)ptr; 53 } else { 54 *result = NULL; 55 } 56 } 57 # endif 58 #endif 59 if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 60 return 0; 61 } 62 63 PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[]) 64 { 65 if (!ptr) return 0; 66 #if defined(PETSC_HAVE_MEMKIND) 67 memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */ 68 #else 69 # if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 70 { 71 /* 72 Previous int tells us how many ints the pointer has been shifted from 73 the original address provided by the system malloc(). 74 */ 75 int shift = *(((int*)ptr)-1) - SHIFT_CLASSID; 76 if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 77 if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 78 ptr = (void*)(((int*)ptr) - shift); 79 } 80 # endif 81 82 # if defined(PETSC_HAVE_FREE_RETURN_INT) 83 int err = free(ptr); 84 if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 85 # else 86 free(ptr); 87 # endif 88 #endif 89 return 0; 90 } 91 92 PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result) 93 { 94 PetscErrorCode ierr; 95 96 if (!mem) { 97 ierr = PetscFreeAlign(*result, line, func, file); 98 if (ierr) return ierr; 99 *result = NULL; 100 return 0; 101 } 102 #if defined(PETSC_HAVE_MEMKIND) 103 if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem); 104 else *result = memkind_realloc(MEMKIND_HBW,*result,mem); 105 #else 106 # if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 107 { 108 /* 109 Previous int tells us how many ints the pointer has been shifted from 110 the original address provided by the system malloc(). 111 */ 112 int shift = *(((int*)*result)-1) - SHIFT_CLASSID; 113 if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 114 if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 115 *result = (void*)(((int*)*result) - shift); 116 } 117 # endif 118 119 # if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN) 120 *result = realloc(*result, mem); 121 # else 122 { 123 /* 124 malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 125 */ 126 int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN); 127 if (ptr) { 128 int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 129 shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 130 ptr[shift-1] = shift + SHIFT_CLASSID; 131 ptr += shift; 132 *result = (void*)ptr; 133 } else { 134 *result = NULL; 135 } 136 } 137 # endif 138 #endif 139 if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 140 #if defined(PETSC_HAVE_MEMALIGN) 141 /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to 142 * realloc and, if the alignment is wrong, malloc/copy/free. */ 143 if (((size_t) (*result)) % PETSC_MEMALIGN) { 144 void *newResult; 145 # if defined(PETSC_HAVE_MEMKIND) 146 { 147 int ierr; 148 if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem); 149 else ierr = memkind_posix_memalign(MEMKIND_HBW,&newResult,PETSC_MEMALIGN,mem); 150 if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem); 151 } 152 # else 153 newResult = memalign(PETSC_MEMALIGN,mem); 154 # endif 155 if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 156 ierr = PetscMemcpy(newResult,*result,mem); 157 if (ierr) return ierr; 158 # if defined(PETSC_HAVE_FREE_RETURN_INT) 159 { 160 int err = free(*result); 161 if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 162 } 163 # else 164 # if defined(PETSC_HAVE_MEMKIND) 165 memkind_free(0,*result); 166 # else 167 free(*result); 168 # endif 169 # endif 170 *result = newResult; 171 } 172 #endif 173 return 0; 174 } 175 176 PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 177 PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[]) = PetscFreeAlign; 178 PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign; 179 180 PetscBool petscsetmallocvisited = PETSC_FALSE; 181 182 /*@C 183 PetscMallocSet - Sets the routines used to do mallocs and frees. 184 This routine MUST be called before PetscInitialize() and may be 185 called only once. 186 187 Not Collective 188 189 Input Parameters: 190 + malloc - the malloc routine 191 - free - the free routine 192 193 Level: developer 194 195 Concepts: malloc 196 Concepts: memory^allocation 197 198 @*/ 199 PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**), 200 PetscErrorCode (*ifree)(void*,int,const char[],const char[])) 201 { 202 PetscFunctionBegin; 203 if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times"); 204 PetscTrMalloc = imalloc; 205 PetscTrFree = ifree; 206 petscsetmallocvisited = PETSC_TRUE; 207 PetscFunctionReturn(0); 208 } 209 210 /*@C 211 PetscMallocClear - Resets the routines used to do mallocs and frees to the 212 defaults. 213 214 Not Collective 215 216 Level: developer 217 218 Notes: 219 In general one should never run a PETSc program with different malloc() and 220 free() settings for different parts; this is because one NEVER wants to 221 free() an address that was malloced by a different memory management system 222 223 @*/ 224 PetscErrorCode PetscMallocClear(void) 225 { 226 PetscFunctionBegin; 227 PetscTrMalloc = PetscMallocAlign; 228 PetscTrFree = PetscFreeAlign; 229 petscsetmallocvisited = PETSC_FALSE; 230 PetscFunctionReturn(0); 231 } 232 233 PetscErrorCode PetscMemoryTrace(const char label[]) 234 { 235 PetscErrorCode ierr; 236 PetscLogDouble mem,mal; 237 static PetscLogDouble oldmem = 0,oldmal = 0; 238 239 PetscFunctionBegin; 240 ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr); 241 ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr); 242 243 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); 244 oldmem = mem; 245 oldmal = mal; 246 PetscFunctionReturn(0); 247 } 248 249 static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 250 static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[]) = PetscFreeAlign; 251 252 /*@C 253 PetscMallocSetDRAM - Set PetscMalloc to use DRAM. 254 If memkind is available, change the memkind type. Otherwise, switch the 255 current malloc and free routines to the PetscMallocAlign and 256 PetscFreeAlign (PETSc default). 257 258 Not Collective 259 260 Level: developer 261 262 Notes: 263 This provides a way to do the allocation on DRAM temporarily. One 264 can switch back to the previous choice by calling PetscMallocReset(). 265 266 .seealso: PetscMallocReset() 267 @*/ 268 PetscErrorCode PetscMallocSetDRAM(void) 269 { 270 PetscFunctionBegin; 271 if (PetscTrMalloc == PetscMallocAlign) { 272 #if defined(PETSC_HAVE_MEMKIND) 273 previousmktype = currentmktype; 274 currentmktype = PETSC_MK_DEFAULT; 275 #endif 276 } else { 277 /* Save the previous choice */ 278 PetscTrMallocOld = PetscTrMalloc; 279 PetscTrFreeOld = PetscTrFree; 280 PetscTrMalloc = PetscMallocAlign; 281 PetscTrFree = PetscFreeAlign; 282 } 283 PetscFunctionReturn(0); 284 } 285 286 /*@C 287 PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM 288 289 Not Collective 290 291 Level: developer 292 293 .seealso: PetscMallocSetDRAM() 294 @*/ 295 PetscErrorCode PetscMallocResetDRAM(void) 296 { 297 PetscFunctionBegin; 298 if (PetscTrMalloc == PetscMallocAlign) { 299 #if defined(PETSC_HAVE_MEMKIND) 300 currentmktype = previousmktype; 301 #endif 302 } else { 303 /* Reset to the previous choice */ 304 PetscTrMalloc = PetscTrMallocOld; 305 PetscTrFree = PetscTrFreeOld; 306 } 307 PetscFunctionReturn(0); 308 } 309 310 static PetscBool petscmalloccoalesce = 311 #if defined(PETSC_USE_MALLOC_COALESCED) 312 PETSC_TRUE; 313 #else 314 PETSC_FALSE; 315 #endif 316 317 /*@C 318 PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects 319 320 Not Collective 321 322 Input Parameters: 323 . coalesce - PETSC_TRUE to use coalesced malloc for multi-object allocation. 324 325 Options Database Keys: 326 . -malloc_coalesce - turn coalesced malloc on or off 327 328 Note: 329 PETSc uses coalesced malloc by default for optimized builds and not for debugging builds. This default can be changed via the command-line option -malloc_coalesce or by calling this function. 330 331 Level: developer 332 333 .seealso: PetscMallocA() 334 @*/ 335 PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce) 336 { 337 PetscFunctionBegin; 338 petscmalloccoalesce = coalesce; 339 PetscFunctionReturn(0); 340 } 341 342 /*@C 343 PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc 344 345 Not Collective 346 347 Input Parameters: 348 + n - number of objects to allocate (at least 1) 349 . lineno - line number to attribute allocation (typically __LINE__) 350 . function - function to attribute allocation (typically PETSC_FUNCTION_NAME) 351 . filename - file name to attribute allocation (typically __FILE__) 352 - bytes0 - first of n object sizes 353 354 Output Parameters: 355 . ptr0 - first of n pointers to allocate 356 357 Notes: 358 This function is not normally called directly by users, but rather via the macros PetscMalloc1(), PetscMalloc2(), or PetscCalloc1(), etc. 359 360 Level: developer 361 362 .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMalloc1(), PetscMalloc2(), PetscMalloc3(), PetscMalloc4(), PetscMalloc5(), PetscMalloc6(), PetscMalloc7(), PetscCalloc1(), PetscCalloc2(), PetscCalloc3(), PetscCalloc4(), PetscCalloc5(), PetscCalloc6(), PetscCalloc7(), PetscFreeA() 363 @*/ 364 PetscErrorCode PetscMallocA(int n,PetscBool clear,int lineno,const char *function,const char *filename,size_t bytes0,void *ptr0,...) 365 { 366 PetscErrorCode ierr; 367 va_list Argp; 368 size_t bytes[8],sumbytes; 369 void **ptr[8]; 370 int i; 371 372 PetscFunctionBegin; 373 if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n); 374 bytes[0] = bytes0; 375 ptr[0] = (void**)ptr0; 376 sumbytes = (bytes0 + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1); 377 va_start(Argp,ptr0); 378 for (i=1; i<n; i++) { 379 bytes[i] = va_arg(Argp,size_t); 380 ptr[i] = va_arg(Argp,void**); 381 sumbytes += (bytes[i] + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1); 382 } 383 va_end(Argp); 384 if (petscmalloccoalesce) { 385 char *p; 386 ierr = (*PetscTrMalloc)(sumbytes,lineno,function,filename,(void**)&p);CHKERRQ(ierr); 387 for (i=0; i<n; i++) { 388 *ptr[i] = bytes[i] ? p : NULL; 389 p = (char*)PetscAddrAlign(p + bytes[i]); 390 } 391 } else { 392 for (i=0; i<n; i++) { 393 ierr = (*PetscTrMalloc)(bytes[i],lineno,function,filename,(void**)ptr[i]);CHKERRQ(ierr); 394 } 395 } 396 if (clear) { 397 for (i=0; i<n; i++) { 398 ierr = PetscMemzero(*ptr[i],bytes[i]);CHKERRQ(ierr); 399 } 400 } 401 PetscFunctionReturn(0); 402 } 403 404 /*@C 405 PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc 406 407 Not Collective 408 409 Input Parameters: 410 + n - number of objects to free (at least 1) 411 . lineno - line number to attribute deallocation (typically __LINE__) 412 . function - function to attribute deallocation (typically PETSC_FUNCTION_NAME) 413 . filename - file name to attribute deallocation (typically __FILE__) 414 - ptr0 ... - first of n pointers to free 415 416 Note: 417 This function is not normally called directly by users, but rather via the macros PetscFree1(), PetscFree2(), etc. 418 419 Level: developer 420 421 .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMallocA(), PetscFree1(), PetscFree2(), PetscFree3(), PetscFree4(), PetscFree5(), PetscFree6(), PetscFree7() 422 @*/ 423 PetscErrorCode PetscFreeA(int n,int lineno,const char *function,const char *filename,void *ptr0,...) 424 { 425 PetscErrorCode ierr; 426 va_list Argp; 427 void **ptr[8]; 428 int i; 429 430 PetscFunctionBegin; 431 if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n); 432 ptr[0] = (void**)ptr0; 433 va_start(Argp,ptr0); 434 for (i=1; i<n; i++) { 435 ptr[i] = va_arg(Argp,void**); 436 } 437 va_end(Argp); 438 if (petscmalloccoalesce) { 439 for (i=0; i<n; i++) { /* Find first nonempty allocation */ 440 if (*ptr[i]) break; 441 } 442 while (--n > i) { 443 *ptr[n] = NULL; 444 } 445 ierr = (*PetscTrFree)(*ptr[n],lineno,function,filename);CHKERRQ(ierr); 446 *ptr[n] = NULL; 447 } else { 448 while (--n >= 0) { 449 ierr = (*PetscTrFree)(*ptr[n],lineno,function,filename);CHKERRQ(ierr); 450 *ptr[n] = NULL; 451 } 452 } 453 PetscFunctionReturn(0); 454 } 455