17d0a6c19SBarry Smith 2e5c89e4eSSatish Balay /* 3e5c89e4eSSatish Balay Code that allows a user to dictate what malloc() PETSc uses. 4e5c89e4eSSatish Balay */ 5c6db04a5SJed Brown #include <petscsys.h> /*I "petscsys.h" I*/ 6e5c89e4eSSatish Balay #if defined(PETSC_HAVE_MALLOC_H) 7e5c89e4eSSatish Balay #include <malloc.h> 8e5c89e4eSSatish Balay #endif 9de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 10de1d6c17SHong Zhang #include <memkind.h> 11de1d6c17SHong Zhang typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType; 12de1d6c17SHong Zhang PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED; 13de1d6c17SHong Zhang PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED; 14de1d6c17SHong Zhang #endif 15e5c89e4eSSatish Balay /* 16e5c89e4eSSatish Balay We want to make sure that all mallocs of double or complex numbers are complex aligned. 17e5c89e4eSSatish Balay 1) on systems with memalign() we call that routine to get an aligned memory location 18e5c89e4eSSatish Balay 2) on systems without memalign() we 19e5c89e4eSSatish Balay - allocate one sizeof(PetscScalar) extra space 20e5c89e4eSSatish Balay - we shift the pointer up slightly if needed to get PetscScalar aligned 210700a824SBarry Smith - if shifted we store at ptr[-1] the amount of shift (plus a classid) 22e5c89e4eSSatish Balay */ 230700a824SBarry Smith #define SHIFT_CLASSID 456123 24e5c89e4eSSatish Balay 25efca3c55SSatish Balay PetscErrorCode PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result) 26e5c89e4eSSatish Balay { 27f0ba7cfcSLisandro Dalcin if (!mem) { *result = NULL; return 0; } 28fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 29fc2a7144SHong Zhang { 30fc2a7144SHong Zhang int ierr; 31fc2a7144SHong Zhang if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem); 32fc2a7144SHong Zhang else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem); 33fc2a7144SHong Zhang if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem); 34fc2a7144SHong Zhang } 35fc2a7144SHong Zhang #else 36e5c89e4eSSatish Balay # if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8) 37e5c89e4eSSatish Balay *result = malloc(mem); 38e5c89e4eSSatish Balay # elif defined(PETSC_HAVE_MEMALIGN) 39e5c89e4eSSatish Balay *result = memalign(PETSC_MEMALIGN,mem); 40e5c89e4eSSatish Balay # else 41e5c89e4eSSatish Balay { 42e5c89e4eSSatish Balay /* 43e5c89e4eSSatish Balay malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 44e5c89e4eSSatish Balay */ 45*5b232624SHong Zhang int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN); 46e5c89e4eSSatish Balay if (ptr) { 47f0ba7cfcSLisandro Dalcin int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 48e5c89e4eSSatish Balay shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 490700a824SBarry Smith ptr[shift-1] = shift + SHIFT_CLASSID; 50e5c89e4eSSatish Balay ptr += shift; 51e5c89e4eSSatish Balay *result = (void*)ptr; 52e5c89e4eSSatish Balay } else { 53f0ba7cfcSLisandro Dalcin *result = NULL; 54e5c89e4eSSatish Balay } 55e5c89e4eSSatish Balay } 56e5c89e4eSSatish Balay # endif 57fc2a7144SHong Zhang #endif 58f0ba7cfcSLisandro Dalcin if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 59e5c89e4eSSatish Balay return 0; 60e5c89e4eSSatish Balay } 61e5c89e4eSSatish Balay 62efca3c55SSatish Balay PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[]) 63e5c89e4eSSatish Balay { 64f0ba7cfcSLisandro Dalcin if (!ptr) return 0; 65fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 66fc2a7144SHong Zhang memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */ 67fc2a7144SHong Zhang #else 68e5c89e4eSSatish Balay # if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 69f0ba7cfcSLisandro Dalcin { 70e5c89e4eSSatish Balay /* 71e5c89e4eSSatish Balay Previous int tells us how many ints the pointer has been shifted from 72e5c89e4eSSatish Balay the original address provided by the system malloc(). 73e5c89e4eSSatish Balay */ 74f0ba7cfcSLisandro Dalcin int shift = *(((int*)ptr)-1) - SHIFT_CLASSID; 75efca3c55SSatish Balay if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 76efca3c55SSatish Balay if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 77e5c89e4eSSatish Balay ptr = (void*)(((int*)ptr) - shift); 78e5c89e4eSSatish Balay } 79f0ba7cfcSLisandro Dalcin # endif 80e5c89e4eSSatish Balay 81e5c89e4eSSatish Balay # if defined(PETSC_HAVE_FREE_RETURN_INT) 82e5c89e4eSSatish Balay int err = free(ptr); 83efca3c55SSatish Balay if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 84e5c89e4eSSatish Balay # else 85e5c89e4eSSatish Balay free(ptr); 86e5c89e4eSSatish Balay # endif 87fc2a7144SHong Zhang #endif 88e5c89e4eSSatish Balay return 0; 89e5c89e4eSSatish Balay } 90e5c89e4eSSatish Balay 913221ece2SMatthew G. Knepley PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result) 923221ece2SMatthew G. Knepley { 93c22f1541SToby Isaac PetscErrorCode ierr; 94c22f1541SToby Isaac 95c22f1541SToby Isaac if (!mem) { 96c22f1541SToby Isaac ierr = PetscFreeAlign(*result, line, func, file); 97c22f1541SToby Isaac if (ierr) return ierr; 98c22f1541SToby Isaac *result = NULL; 99c22f1541SToby Isaac return 0; 100c22f1541SToby Isaac } 101fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 102fc2a7144SHong Zhang if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem); 103fc2a7144SHong Zhang else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem); 104fc2a7144SHong Zhang #else 1053221ece2SMatthew G. Knepley # if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 1063221ece2SMatthew G. Knepley { 1073221ece2SMatthew G. Knepley /* 1083221ece2SMatthew G. Knepley Previous int tells us how many ints the pointer has been shifted from 1093221ece2SMatthew G. Knepley the original address provided by the system malloc(). 1103221ece2SMatthew G. Knepley */ 1113221ece2SMatthew G. Knepley int shift = *(((int*)*result)-1) - SHIFT_CLASSID; 1123221ece2SMatthew G. Knepley if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 1133221ece2SMatthew G. Knepley if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 1143221ece2SMatthew G. Knepley *result = (void*)(((int*)*result) - shift); 1153221ece2SMatthew G. Knepley } 1163221ece2SMatthew G. Knepley # endif 1173221ece2SMatthew G. Knepley 118c22f1541SToby Isaac # if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN) 1193221ece2SMatthew G. Knepley *result = realloc(*result, mem); 1203221ece2SMatthew G. Knepley # else 1213221ece2SMatthew G. Knepley { 1223221ece2SMatthew G. Knepley /* 1233221ece2SMatthew G. Knepley malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 1243221ece2SMatthew G. Knepley */ 1253221ece2SMatthew G. Knepley int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN); 1263221ece2SMatthew G. Knepley if (ptr) { 1273221ece2SMatthew G. Knepley int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 1283221ece2SMatthew G. Knepley shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 1293221ece2SMatthew G. Knepley ptr[shift-1] = shift + SHIFT_CLASSID; 1303221ece2SMatthew G. Knepley ptr += shift; 1313221ece2SMatthew G. Knepley *result = (void*)ptr; 1323221ece2SMatthew G. Knepley } else { 1333221ece2SMatthew G. Knepley *result = NULL; 1343221ece2SMatthew G. Knepley } 1353221ece2SMatthew G. Knepley } 1363221ece2SMatthew G. Knepley # endif 137fc2a7144SHong Zhang #endif 1383221ece2SMatthew G. Knepley if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 139c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN) 140c22f1541SToby Isaac /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to 141c22f1541SToby Isaac * realloc and, if the alignment is wrong, malloc/copy/free. */ 142c22f1541SToby Isaac if (((size_t) (*result)) % PETSC_MEMALIGN) { 143c22f1541SToby Isaac void *newResult; 144fc2a7144SHong Zhang # if defined(PETSC_HAVE_MEMKIND) 145fc2a7144SHong Zhang { 146fc2a7144SHong Zhang int ierr; 147fc2a7144SHong Zhang if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem); 148fc2a7144SHong Zhang else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem); 149fc2a7144SHong Zhang if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem); 150fc2a7144SHong Zhang } 151fc2a7144SHong Zhang # else 152c22f1541SToby Isaac newResult = memalign(PETSC_MEMALIGN,mem); 153fc2a7144SHong Zhang # endif 154c22f1541SToby Isaac if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 155c22f1541SToby Isaac ierr = PetscMemcpy(newResult,*result,mem); 156c22f1541SToby Isaac if (ierr) return ierr; 157c22f1541SToby Isaac # if defined(PETSC_HAVE_FREE_RETURN_INT) 158c22f1541SToby Isaac { 159c22f1541SToby Isaac int err = free(*result); 160c22f1541SToby Isaac if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 161c22f1541SToby Isaac } 162c22f1541SToby Isaac # else 163de1d6c17SHong Zhang # if defined(PETSC_HAVE_MEMKIND) 164de1d6c17SHong Zhang memkind_free(0,*result); 165de1d6c17SHong Zhang # else 166c22f1541SToby Isaac free(*result); 167c22f1541SToby Isaac # endif 168de1d6c17SHong Zhang # endif 169c22f1541SToby Isaac *result = newResult; 170c22f1541SToby Isaac } 171c22f1541SToby Isaac #endif 1723221ece2SMatthew G. Knepley return 0; 1733221ece2SMatthew G. Knepley } 1743221ece2SMatthew G. Knepley 175efca3c55SSatish Balay PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 176efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[]) = PetscFreeAlign; 1773221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign; 178e5c89e4eSSatish Balay 179ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE; 180e5c89e4eSSatish Balay 181e5c89e4eSSatish Balay /*@C 1821d1a0024SBarry Smith PetscMallocSet - Sets the routines used to do mallocs and frees. 183e5c89e4eSSatish Balay This routine MUST be called before PetscInitialize() and may be 184e5c89e4eSSatish Balay called only once. 185e5c89e4eSSatish Balay 186e5c89e4eSSatish Balay Not Collective 187e5c89e4eSSatish Balay 188e5c89e4eSSatish Balay Input Parameters: 189e5c89e4eSSatish Balay + malloc - the malloc routine 190e5c89e4eSSatish Balay - free - the free routine 191e5c89e4eSSatish Balay 192e5c89e4eSSatish Balay Level: developer 193e5c89e4eSSatish Balay 194e5c89e4eSSatish Balay Concepts: malloc 195e5c89e4eSSatish Balay Concepts: memory^allocation 196e5c89e4eSSatish Balay 197e5c89e4eSSatish Balay @*/ 198efca3c55SSatish Balay PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**), 199efca3c55SSatish Balay PetscErrorCode (*ifree)(void*,int,const char[],const char[])) 200e5c89e4eSSatish Balay { 201e5c89e4eSSatish Balay PetscFunctionBegin; 202e32f2f54SBarry Smith if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times"); 203e5c89e4eSSatish Balay PetscTrMalloc = imalloc; 204e5c89e4eSSatish Balay PetscTrFree = ifree; 205e5c89e4eSSatish Balay petscsetmallocvisited = PETSC_TRUE; 206e5c89e4eSSatish Balay PetscFunctionReturn(0); 207e5c89e4eSSatish Balay } 208e5c89e4eSSatish Balay 209e5c89e4eSSatish Balay /*@C 2101d1a0024SBarry Smith PetscMallocClear - Resets the routines used to do mallocs and frees to the 211e5c89e4eSSatish Balay defaults. 212e5c89e4eSSatish Balay 213e5c89e4eSSatish Balay Not Collective 214e5c89e4eSSatish Balay 215e5c89e4eSSatish Balay Level: developer 216e5c89e4eSSatish Balay 217e5c89e4eSSatish Balay Notes: 218e5c89e4eSSatish Balay In general one should never run a PETSc program with different malloc() and 219e5c89e4eSSatish Balay free() settings for different parts; this is because one NEVER wants to 220e5c89e4eSSatish Balay free() an address that was malloced by a different memory management system 221e5c89e4eSSatish Balay 222e5c89e4eSSatish Balay @*/ 2237087cfbeSBarry Smith PetscErrorCode PetscMallocClear(void) 224e5c89e4eSSatish Balay { 225e5c89e4eSSatish Balay PetscFunctionBegin; 226e5c89e4eSSatish Balay PetscTrMalloc = PetscMallocAlign; 227e5c89e4eSSatish Balay PetscTrFree = PetscFreeAlign; 228e5c89e4eSSatish Balay petscsetmallocvisited = PETSC_FALSE; 229e5c89e4eSSatish Balay PetscFunctionReturn(0); 230e5c89e4eSSatish Balay } 231b44d5720SBarry Smith 232b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[]) 233b44d5720SBarry Smith { 234b44d5720SBarry Smith PetscErrorCode ierr; 235b44d5720SBarry Smith PetscLogDouble mem,mal; 236b44d5720SBarry Smith static PetscLogDouble oldmem = 0,oldmal = 0; 237b44d5720SBarry Smith 238b44d5720SBarry Smith PetscFunctionBegin; 239b44d5720SBarry Smith ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr); 240b44d5720SBarry Smith ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr); 241b44d5720SBarry Smith 242b44d5720SBarry Smith 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); 243b44d5720SBarry Smith oldmem = mem; 244b44d5720SBarry Smith oldmal = mal; 245b44d5720SBarry Smith PetscFunctionReturn(0); 246b44d5720SBarry Smith } 24713850c04SHong Zhang 24850a41461SHong Zhang static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 24950a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[]) = PetscFreeAlign; 250de1d6c17SHong Zhang 251de1d6c17SHong Zhang /*@C 252de1d6c17SHong Zhang PetscMallocSetDRAM - Set PetscMalloc to use DRAM. 253de1d6c17SHong Zhang If memkind is available, change the memkind type. Otherwise, switch the 254de1d6c17SHong Zhang current malloc and free routines to the PetscMallocAlign and 255de1d6c17SHong Zhang PetscFreeAlign (PETSc default). 256de1d6c17SHong Zhang 257de1d6c17SHong Zhang Not Collective 258de1d6c17SHong Zhang 259de1d6c17SHong Zhang Level: developer 260de1d6c17SHong Zhang 261de1d6c17SHong Zhang Notes: 262de1d6c17SHong Zhang This provides a way to do the allocation on DRAM temporarily. One 263de1d6c17SHong Zhang can switch back to the previous choice by calling PetscMallocReset(). 264de1d6c17SHong Zhang 265de1d6c17SHong Zhang .seealso: PetscMallocReset() 266de1d6c17SHong Zhang @*/ 26713850c04SHong Zhang PetscErrorCode PetscMallocSetDRAM(void) 26813850c04SHong Zhang { 26913850c04SHong Zhang PetscFunctionBegin; 270de1d6c17SHong Zhang if (PetscTrMalloc == PetscMallocAlign) { 271de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 272de1d6c17SHong Zhang previousmktype = currentmktype; 273de1d6c17SHong Zhang currentmktype = PETSC_MK_DEFAULT; 274de1d6c17SHong Zhang #endif 275de1d6c17SHong Zhang } else { 27613850c04SHong Zhang /* Save the previous choice */ 27713850c04SHong Zhang PetscTrMallocOld = PetscTrMalloc; 27813850c04SHong Zhang PetscTrFreeOld = PetscTrFree; 27913850c04SHong Zhang PetscTrMalloc = PetscMallocAlign; 28013850c04SHong Zhang PetscTrFree = PetscFreeAlign; 281de1d6c17SHong Zhang } 28213850c04SHong Zhang PetscFunctionReturn(0); 28313850c04SHong Zhang } 28413850c04SHong Zhang 285de1d6c17SHong Zhang /*@C 286de1d6c17SHong Zhang PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM 287de1d6c17SHong Zhang 288de1d6c17SHong Zhang Not Collective 289de1d6c17SHong Zhang 290de1d6c17SHong Zhang Level: developer 291de1d6c17SHong Zhang 292de1d6c17SHong Zhang .seealso: PetscMallocSetDRAM() 293de1d6c17SHong Zhang @*/ 29413850c04SHong Zhang PetscErrorCode PetscMallocResetDRAM(void) 29513850c04SHong Zhang { 29613850c04SHong Zhang PetscFunctionBegin; 297de1d6c17SHong Zhang if (PetscTrMalloc == PetscMallocAlign) { 298de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 299de1d6c17SHong Zhang currentmktype = previousmktype; 300de1d6c17SHong Zhang #endif 301de1d6c17SHong Zhang } else { 30213850c04SHong Zhang /* Reset to the previous choice */ 30313850c04SHong Zhang PetscTrMalloc = PetscTrMallocOld; 30413850c04SHong Zhang PetscTrFree = PetscTrFreeOld; 305de1d6c17SHong Zhang } 30613850c04SHong Zhang PetscFunctionReturn(0); 30713850c04SHong Zhang } 308