xref: /petsc/src/sys/memory/mal.c (revision 13850c04a7377a91d5b1bff18e84c75ea74ba331)
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