xref: /petsc/src/sys/memory/mal.c (revision c22f1541d8ffcf94c7d4e322602d9a74548a783a)
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 
20e5c89e4eSSatish Balay #undef __FUNCT__
21e5c89e4eSSatish Balay #define __FUNCT__ "PetscMallocAlign"
22efca3c55SSatish Balay PetscErrorCode  PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
23e5c89e4eSSatish Balay {
24f0ba7cfcSLisandro Dalcin   if (!mem) { *result = NULL; return 0; }
25e5c89e4eSSatish Balay #if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
26e5c89e4eSSatish Balay   *result = malloc(mem);
27e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_MEMALIGN)
28e5c89e4eSSatish Balay   *result = memalign(PETSC_MEMALIGN,mem);
29e5c89e4eSSatish Balay #else
30e5c89e4eSSatish Balay   {
31e5c89e4eSSatish Balay     /*
32e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
33e5c89e4eSSatish Balay     */
34f0ba7cfcSLisandro Dalcin     int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
35e5c89e4eSSatish Balay     if (ptr) {
36f0ba7cfcSLisandro Dalcin       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
37e5c89e4eSSatish Balay       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
380700a824SBarry Smith       ptr[shift-1] = shift + SHIFT_CLASSID;
39e5c89e4eSSatish Balay       ptr         += shift;
40e5c89e4eSSatish Balay       *result      = (void*)ptr;
41e5c89e4eSSatish Balay     } else {
42f0ba7cfcSLisandro Dalcin       *result      = NULL;
43e5c89e4eSSatish Balay     }
44e5c89e4eSSatish Balay   }
45e5c89e4eSSatish Balay #endif
46f0ba7cfcSLisandro Dalcin   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
47e5c89e4eSSatish Balay   return 0;
48e5c89e4eSSatish Balay }
49e5c89e4eSSatish Balay 
50e5c89e4eSSatish Balay #undef __FUNCT__
51e5c89e4eSSatish Balay #define __FUNCT__ "PetscFreeAlign"
52efca3c55SSatish Balay PetscErrorCode  PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
53e5c89e4eSSatish Balay {
54f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
55e5c89e4eSSatish Balay #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
56f0ba7cfcSLisandro Dalcin   {
57e5c89e4eSSatish Balay     /*
58e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
59e5c89e4eSSatish Balay       the original address provided by the system malloc().
60e5c89e4eSSatish Balay     */
61f0ba7cfcSLisandro Dalcin     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
62efca3c55SSatish 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");
63efca3c55SSatish Balay     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
64e5c89e4eSSatish Balay     ptr = (void*)(((int*)ptr) - shift);
65e5c89e4eSSatish Balay   }
66f0ba7cfcSLisandro Dalcin #endif
67e5c89e4eSSatish Balay 
68e5c89e4eSSatish Balay #if defined(PETSC_HAVE_FREE_RETURN_INT)
69e5c89e4eSSatish Balay   int err = free(ptr);
70efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
71e5c89e4eSSatish Balay #else
72e5c89e4eSSatish Balay   free(ptr);
73e5c89e4eSSatish Balay #endif
74e5c89e4eSSatish Balay   return 0;
75e5c89e4eSSatish Balay }
76e5c89e4eSSatish Balay 
773221ece2SMatthew G. Knepley #undef __FUNCT__
783221ece2SMatthew G. Knepley #define __FUNCT__ "PetscReallocAlign"
793221ece2SMatthew G. Knepley PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
803221ece2SMatthew G. Knepley {
81*c22f1541SToby Isaac   PetscErrorCode ierr;
82*c22f1541SToby Isaac 
83*c22f1541SToby Isaac   if (!mem) {
84*c22f1541SToby Isaac     ierr = PetscFreeAlign(*result, line, func, file);
85*c22f1541SToby Isaac     if (ierr) return ierr;
86*c22f1541SToby Isaac     *result = NULL;
87*c22f1541SToby Isaac     return 0;
88*c22f1541SToby Isaac   }
893221ece2SMatthew G. Knepley #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
903221ece2SMatthew G. Knepley   {
913221ece2SMatthew G. Knepley     /*
923221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
933221ece2SMatthew G. Knepley       the original address provided by the system malloc().
943221ece2SMatthew G. Knepley     */
953221ece2SMatthew G. Knepley     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
963221ece2SMatthew 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");
973221ece2SMatthew G. Knepley     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
983221ece2SMatthew G. Knepley     *result = (void*)(((int*)*result) - shift);
993221ece2SMatthew G. Knepley   }
1003221ece2SMatthew G. Knepley #endif
1013221ece2SMatthew G. Knepley 
102*c22f1541SToby Isaac #if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
1033221ece2SMatthew G. Knepley   *result = realloc(*result, mem);
1043221ece2SMatthew G. Knepley #else
1053221ece2SMatthew G. Knepley   {
1063221ece2SMatthew G. Knepley     /*
1073221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1083221ece2SMatthew G. Knepley     */
1093221ece2SMatthew G. Knepley     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
1103221ece2SMatthew G. Knepley     if (ptr) {
1113221ece2SMatthew G. Knepley       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
1123221ece2SMatthew G. Knepley       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
1133221ece2SMatthew G. Knepley       ptr[shift-1] = shift + SHIFT_CLASSID;
1143221ece2SMatthew G. Knepley       ptr         += shift;
1153221ece2SMatthew G. Knepley       *result      = (void*)ptr;
1163221ece2SMatthew G. Knepley     } else {
1173221ece2SMatthew G. Knepley       *result      = NULL;
1183221ece2SMatthew G. Knepley     }
1193221ece2SMatthew G. Knepley   }
1203221ece2SMatthew G. Knepley #endif
1213221ece2SMatthew G. Knepley   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
122*c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN)
123*c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
124*c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
125*c22f1541SToby Isaac   if (((size_t) (*result)) % PETSC_MEMALIGN) {
126*c22f1541SToby Isaac     void *newResult;
127*c22f1541SToby Isaac 
128*c22f1541SToby Isaac     newResult = memalign(PETSC_MEMALIGN,mem);
129*c22f1541SToby Isaac     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
130*c22f1541SToby Isaac     ierr = PetscMemcpy(newResult,*result,mem);
131*c22f1541SToby Isaac     if (ierr) return ierr;
132*c22f1541SToby Isaac #if defined(PETSC_HAVE_FREE_RETURN_INT)
133*c22f1541SToby Isaac     {
134*c22f1541SToby Isaac       int err = free(*result);
135*c22f1541SToby Isaac       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
136*c22f1541SToby Isaac     }
137*c22f1541SToby Isaac #else
138*c22f1541SToby Isaac     free(*result);
139*c22f1541SToby Isaac #endif
140*c22f1541SToby Isaac     *result = newResult;
141*c22f1541SToby Isaac   }
142*c22f1541SToby Isaac #endif
1433221ece2SMatthew G. Knepley   return 0;
1443221ece2SMatthew G. Knepley }
1453221ece2SMatthew G. Knepley 
146efca3c55SSatish Balay PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
147efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
1483221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign;
149e5c89e4eSSatish Balay 
150ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE;
151e5c89e4eSSatish Balay 
152e5c89e4eSSatish Balay #undef __FUNCT__
1531d1a0024SBarry Smith #define __FUNCT__ "PetscMallocSet"
154e5c89e4eSSatish Balay /*@C
1551d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
156e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
157e5c89e4eSSatish Balay    called only once.
158e5c89e4eSSatish Balay 
159e5c89e4eSSatish Balay    Not Collective
160e5c89e4eSSatish Balay 
161e5c89e4eSSatish Balay    Input Parameters:
162e5c89e4eSSatish Balay +  malloc - the malloc routine
163e5c89e4eSSatish Balay -  free - the free routine
164e5c89e4eSSatish Balay 
165e5c89e4eSSatish Balay    Level: developer
166e5c89e4eSSatish Balay 
167e5c89e4eSSatish Balay    Concepts: malloc
168e5c89e4eSSatish Balay    Concepts: memory^allocation
169e5c89e4eSSatish Balay 
170e5c89e4eSSatish Balay @*/
171efca3c55SSatish Balay PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
172efca3c55SSatish Balay                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
173e5c89e4eSSatish Balay {
174e5c89e4eSSatish Balay   PetscFunctionBegin;
175e32f2f54SBarry Smith   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
176e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
177e5c89e4eSSatish Balay   PetscTrFree           = ifree;
178e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
179e5c89e4eSSatish Balay   PetscFunctionReturn(0);
180e5c89e4eSSatish Balay }
181e5c89e4eSSatish Balay 
182e5c89e4eSSatish Balay #undef __FUNCT__
1831d1a0024SBarry Smith #define __FUNCT__ "PetscMallocClear"
184e5c89e4eSSatish Balay /*@C
1851d1a0024SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the
186e5c89e4eSSatish Balay         defaults.
187e5c89e4eSSatish Balay 
188e5c89e4eSSatish Balay    Not Collective
189e5c89e4eSSatish Balay 
190e5c89e4eSSatish Balay    Level: developer
191e5c89e4eSSatish Balay 
192e5c89e4eSSatish Balay    Notes:
193e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
194e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
195e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
196e5c89e4eSSatish Balay 
197e5c89e4eSSatish Balay @*/
1987087cfbeSBarry Smith PetscErrorCode  PetscMallocClear(void)
199e5c89e4eSSatish Balay {
200e5c89e4eSSatish Balay   PetscFunctionBegin;
201e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
202e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
203e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
204e5c89e4eSSatish Balay   PetscFunctionReturn(0);
205e5c89e4eSSatish Balay }
206b44d5720SBarry Smith 
207b44d5720SBarry Smith #undef __FUNCT__
208b44d5720SBarry Smith #define __FUNCT__ "PetscMemoryTrace"
209b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[])
210b44d5720SBarry Smith {
211b44d5720SBarry Smith   PetscErrorCode        ierr;
212b44d5720SBarry Smith   PetscLogDouble        mem,mal;
213b44d5720SBarry Smith   static PetscLogDouble oldmem = 0,oldmal = 0;
214b44d5720SBarry Smith 
215b44d5720SBarry Smith   PetscFunctionBegin;
216b44d5720SBarry Smith   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
217b44d5720SBarry Smith   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
218b44d5720SBarry Smith 
219b44d5720SBarry 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);
220b44d5720SBarry Smith   oldmem = mem;
221b44d5720SBarry Smith   oldmal = mal;
222b44d5720SBarry Smith   PetscFunctionReturn(0);
223b44d5720SBarry Smith }
224