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 9e5c89e4eSSatish Balay 10e5c89e4eSSatish Balay /* 11e5c89e4eSSatish Balay We want to make sure that all mallocs of double or complex numbers are complex aligned. 12e5c89e4eSSatish Balay 1) on systems with memalign() we call that routine to get an aligned memory location 13e5c89e4eSSatish Balay 2) on systems without memalign() we 14e5c89e4eSSatish Balay - allocate one sizeof(PetscScalar) extra space 15e5c89e4eSSatish Balay - we shift the pointer up slightly if needed to get PetscScalar aligned 160700a824SBarry Smith - if shifted we store at ptr[-1] the amount of shift (plus a classid) 17e5c89e4eSSatish Balay */ 180700a824SBarry Smith #define SHIFT_CLASSID 456123 19e5c89e4eSSatish Balay 20efca3c55SSatish Balay PetscErrorCode PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result) 21e5c89e4eSSatish Balay { 22f0ba7cfcSLisandro Dalcin if (!mem) { *result = NULL; return 0; } 23e5c89e4eSSatish Balay #if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8) 24e5c89e4eSSatish Balay *result = malloc(mem); 25e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_MEMALIGN) 26e5c89e4eSSatish Balay *result = memalign(PETSC_MEMALIGN,mem); 27e5c89e4eSSatish Balay #else 28e5c89e4eSSatish Balay { 29e5c89e4eSSatish Balay /* 30e5c89e4eSSatish Balay malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 31e5c89e4eSSatish Balay */ 32f0ba7cfcSLisandro Dalcin int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN); 33e5c89e4eSSatish Balay if (ptr) { 34f0ba7cfcSLisandro Dalcin int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 35e5c89e4eSSatish Balay shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 360700a824SBarry Smith ptr[shift-1] = shift + SHIFT_CLASSID; 37e5c89e4eSSatish Balay ptr += shift; 38e5c89e4eSSatish Balay *result = (void*)ptr; 39e5c89e4eSSatish Balay } else { 40f0ba7cfcSLisandro Dalcin *result = NULL; 41e5c89e4eSSatish Balay } 42e5c89e4eSSatish Balay } 43e5c89e4eSSatish Balay #endif 44f0ba7cfcSLisandro Dalcin if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 45e5c89e4eSSatish Balay return 0; 46e5c89e4eSSatish Balay } 47e5c89e4eSSatish Balay 48efca3c55SSatish Balay PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[]) 49e5c89e4eSSatish Balay { 50f0ba7cfcSLisandro Dalcin if (!ptr) return 0; 51e5c89e4eSSatish Balay #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 52f0ba7cfcSLisandro Dalcin { 53e5c89e4eSSatish Balay /* 54e5c89e4eSSatish Balay Previous int tells us how many ints the pointer has been shifted from 55e5c89e4eSSatish Balay the original address provided by the system malloc(). 56e5c89e4eSSatish Balay */ 57f0ba7cfcSLisandro Dalcin int shift = *(((int*)ptr)-1) - SHIFT_CLASSID; 58efca3c55SSatish 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"); 59efca3c55SSatish Balay if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 60e5c89e4eSSatish Balay ptr = (void*)(((int*)ptr) - shift); 61e5c89e4eSSatish Balay } 62f0ba7cfcSLisandro Dalcin #endif 63e5c89e4eSSatish Balay 64e5c89e4eSSatish Balay #if defined(PETSC_HAVE_FREE_RETURN_INT) 65e5c89e4eSSatish Balay int err = free(ptr); 66efca3c55SSatish Balay if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 67e5c89e4eSSatish Balay #else 68e5c89e4eSSatish Balay free(ptr); 69e5c89e4eSSatish Balay #endif 70e5c89e4eSSatish Balay return 0; 71e5c89e4eSSatish Balay } 72e5c89e4eSSatish Balay 733221ece2SMatthew G. Knepley PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result) 743221ece2SMatthew G. Knepley { 75c22f1541SToby Isaac PetscErrorCode ierr; 76c22f1541SToby Isaac 77c22f1541SToby Isaac if (!mem) { 78c22f1541SToby Isaac ierr = PetscFreeAlign(*result, line, func, file); 79c22f1541SToby Isaac if (ierr) return ierr; 80c22f1541SToby Isaac *result = NULL; 81c22f1541SToby Isaac return 0; 82c22f1541SToby Isaac } 833221ece2SMatthew G. Knepley #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN)) 843221ece2SMatthew G. Knepley { 853221ece2SMatthew G. Knepley /* 863221ece2SMatthew G. Knepley Previous int tells us how many ints the pointer has been shifted from 873221ece2SMatthew G. Knepley the original address provided by the system malloc(). 883221ece2SMatthew G. Knepley */ 893221ece2SMatthew G. Knepley int shift = *(((int*)*result)-1) - SHIFT_CLASSID; 903221ece2SMatthew 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"); 913221ece2SMatthew G. Knepley if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap"); 923221ece2SMatthew G. Knepley *result = (void*)(((int*)*result) - shift); 933221ece2SMatthew G. Knepley } 943221ece2SMatthew G. Knepley #endif 953221ece2SMatthew G. Knepley 96c22f1541SToby Isaac #if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN) 973221ece2SMatthew G. Knepley *result = realloc(*result, mem); 983221ece2SMatthew G. Knepley #else 993221ece2SMatthew G. Knepley { 1003221ece2SMatthew G. Knepley /* 1013221ece2SMatthew G. Knepley malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned 1023221ece2SMatthew G. Knepley */ 1033221ece2SMatthew G. Knepley int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN); 1043221ece2SMatthew G. Knepley if (ptr) { 1053221ece2SMatthew G. Knepley int shift = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN); 1063221ece2SMatthew G. Knepley shift = (2*PETSC_MEMALIGN - shift)/sizeof(int); 1073221ece2SMatthew G. Knepley ptr[shift-1] = shift + SHIFT_CLASSID; 1083221ece2SMatthew G. Knepley ptr += shift; 1093221ece2SMatthew G. Knepley *result = (void*)ptr; 1103221ece2SMatthew G. Knepley } else { 1113221ece2SMatthew G. Knepley *result = NULL; 1123221ece2SMatthew G. Knepley } 1133221ece2SMatthew G. Knepley } 1143221ece2SMatthew G. Knepley #endif 1153221ece2SMatthew G. Knepley if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 116c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN) 117c22f1541SToby Isaac /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to 118c22f1541SToby Isaac * realloc and, if the alignment is wrong, malloc/copy/free. */ 119c22f1541SToby Isaac if (((size_t) (*result)) % PETSC_MEMALIGN) { 120c22f1541SToby Isaac void *newResult; 121c22f1541SToby Isaac 122c22f1541SToby Isaac newResult = memalign(PETSC_MEMALIGN,mem); 123c22f1541SToby Isaac if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem); 124c22f1541SToby Isaac ierr = PetscMemcpy(newResult,*result,mem); 125c22f1541SToby Isaac if (ierr) return ierr; 126c22f1541SToby Isaac #if defined(PETSC_HAVE_FREE_RETURN_INT) 127c22f1541SToby Isaac { 128c22f1541SToby Isaac int err = free(*result); 129c22f1541SToby Isaac if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err); 130c22f1541SToby Isaac } 131c22f1541SToby Isaac #else 132c22f1541SToby Isaac free(*result); 133c22f1541SToby Isaac #endif 134c22f1541SToby Isaac *result = newResult; 135c22f1541SToby Isaac } 136c22f1541SToby Isaac #endif 1373221ece2SMatthew G. Knepley return 0; 1383221ece2SMatthew G. Knepley } 1393221ece2SMatthew G. Knepley 140efca3c55SSatish Balay PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 141efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[]) = PetscFreeAlign; 1423221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign; 143e5c89e4eSSatish Balay 144ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE; 145e5c89e4eSSatish Balay 146e5c89e4eSSatish Balay /*@C 1471d1a0024SBarry Smith PetscMallocSet - Sets the routines used to do mallocs and frees. 148e5c89e4eSSatish Balay This routine MUST be called before PetscInitialize() and may be 149e5c89e4eSSatish Balay called only once. 150e5c89e4eSSatish Balay 151e5c89e4eSSatish Balay Not Collective 152e5c89e4eSSatish Balay 153e5c89e4eSSatish Balay Input Parameters: 154e5c89e4eSSatish Balay + malloc - the malloc routine 155e5c89e4eSSatish Balay - free - the free routine 156e5c89e4eSSatish Balay 157e5c89e4eSSatish Balay Level: developer 158e5c89e4eSSatish Balay 159e5c89e4eSSatish Balay Concepts: malloc 160e5c89e4eSSatish Balay Concepts: memory^allocation 161e5c89e4eSSatish Balay 162e5c89e4eSSatish Balay @*/ 163efca3c55SSatish Balay PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**), 164efca3c55SSatish Balay PetscErrorCode (*ifree)(void*,int,const char[],const char[])) 165e5c89e4eSSatish Balay { 166e5c89e4eSSatish Balay PetscFunctionBegin; 167e32f2f54SBarry Smith if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times"); 168e5c89e4eSSatish Balay PetscTrMalloc = imalloc; 169e5c89e4eSSatish Balay PetscTrFree = ifree; 170e5c89e4eSSatish Balay petscsetmallocvisited = PETSC_TRUE; 171e5c89e4eSSatish Balay PetscFunctionReturn(0); 172e5c89e4eSSatish Balay } 173e5c89e4eSSatish Balay 174e5c89e4eSSatish Balay /*@C 1751d1a0024SBarry Smith PetscMallocClear - Resets the routines used to do mallocs and frees to the 176e5c89e4eSSatish Balay defaults. 177e5c89e4eSSatish Balay 178e5c89e4eSSatish Balay Not Collective 179e5c89e4eSSatish Balay 180e5c89e4eSSatish Balay Level: developer 181e5c89e4eSSatish Balay 182e5c89e4eSSatish Balay Notes: 183e5c89e4eSSatish Balay In general one should never run a PETSc program with different malloc() and 184e5c89e4eSSatish Balay free() settings for different parts; this is because one NEVER wants to 185e5c89e4eSSatish Balay free() an address that was malloced by a different memory management system 186e5c89e4eSSatish Balay 187e5c89e4eSSatish Balay @*/ 1887087cfbeSBarry Smith PetscErrorCode PetscMallocClear(void) 189e5c89e4eSSatish Balay { 190e5c89e4eSSatish Balay PetscFunctionBegin; 191e5c89e4eSSatish Balay PetscTrMalloc = PetscMallocAlign; 192e5c89e4eSSatish Balay PetscTrFree = PetscFreeAlign; 193e5c89e4eSSatish Balay petscsetmallocvisited = PETSC_FALSE; 194e5c89e4eSSatish Balay PetscFunctionReturn(0); 195e5c89e4eSSatish Balay } 196b44d5720SBarry Smith 197b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[]) 198b44d5720SBarry Smith { 199b44d5720SBarry Smith PetscErrorCode ierr; 200b44d5720SBarry Smith PetscLogDouble mem,mal; 201b44d5720SBarry Smith static PetscLogDouble oldmem = 0,oldmal = 0; 202b44d5720SBarry Smith 203b44d5720SBarry Smith PetscFunctionBegin; 204b44d5720SBarry Smith ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr); 205b44d5720SBarry Smith ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr); 206b44d5720SBarry Smith 207b44d5720SBarry 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); 208b44d5720SBarry Smith oldmem = mem; 209b44d5720SBarry Smith oldmal = mal; 210b44d5720SBarry Smith PetscFunctionReturn(0); 211b44d5720SBarry Smith } 212*13850c04SHong Zhang 213*13850c04SHong Zhang #if defined(PETSC_HAVE_MEMKIND) 214*13850c04SHong Zhang PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign; 215*13850c04SHong Zhang PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[]) = PetscFreeAlign; 216*13850c04SHong Zhang PetscErrorCode PetscMallocSetDRAM(void) 217*13850c04SHong Zhang { 218*13850c04SHong Zhang PetscFunctionBegin; 219*13850c04SHong Zhang /* Save the previous choice */ 220*13850c04SHong Zhang PetscTrMallocOld = PetscTrMalloc; 221*13850c04SHong Zhang PetscTrFreeOld = PetscTrFree; 222*13850c04SHong Zhang PetscTrMalloc = PetscMallocAlign; 223*13850c04SHong Zhang PetscTrFree = PetscFreeAlign; 224*13850c04SHong Zhang PetscFunctionReturn(0); 225*13850c04SHong Zhang } 226*13850c04SHong Zhang 227*13850c04SHong Zhang PetscErrorCode PetscMallocResetDRAM(void) 228*13850c04SHong Zhang { 229*13850c04SHong Zhang PetscFunctionBegin; 230*13850c04SHong Zhang /* Reset to the previous choice */ 231*13850c04SHong Zhang PetscTrMalloc = PetscTrMallocOld; 232*13850c04SHong Zhang PetscTrFree = PetscTrFreeOld; 233*13850c04SHong Zhang PetscFunctionReturn(0); 234*13850c04SHong Zhang } 235*13850c04SHong Zhang #endif 236