xref: /petsc/src/sys/memory/mal.c (revision 9566063d113dddea24716c546802770db7481bc0)
1e5c89e4eSSatish Balay /*
2e5c89e4eSSatish Balay     Code that allows a user to dictate what malloc() PETSc uses.
3e5c89e4eSSatish Balay */
4c6db04a5SJed Brown #include <petscsys.h>             /*I   "petscsys.h"   I*/
5ba282f50SJed Brown #include <stdarg.h>
6e5c89e4eSSatish Balay #if defined(PETSC_HAVE_MALLOC_H)
7e5c89e4eSSatish Balay #include <malloc.h>
8e5c89e4eSSatish Balay #endif
9de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
10ca8c994eSHong Zhang #include <errno.h>
11de1d6c17SHong Zhang #include <memkind.h>
12e3acc61dSHong Zhang typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType;
13e3acc61dSHong Zhang PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED;
14e3acc61dSHong Zhang PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED;
15de1d6c17SHong Zhang #endif
16e5c89e4eSSatish Balay /*
17e5c89e4eSSatish Balay         We want to make sure that all mallocs of double or complex numbers are complex aligned.
18e5c89e4eSSatish Balay     1) on systems with memalign() we call that routine to get an aligned memory location
19e5c89e4eSSatish Balay     2) on systems without memalign() we
20e5c89e4eSSatish Balay        - allocate one sizeof(PetscScalar) extra space
21e5c89e4eSSatish Balay        - we shift the pointer up slightly if needed to get PetscScalar aligned
220700a824SBarry Smith        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
23e5c89e4eSSatish Balay */
240700a824SBarry Smith #define SHIFT_CLASSID 456123
25e5c89e4eSSatish Balay 
26071fcb05SBarry Smith PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t mem,PetscBool clear,int line,const char func[],const char file[],void **result)
27e5c89e4eSSatish Balay {
282da392ccSBarry Smith #if defined(PETSC_HAVE_MEMKIND)
292da392ccSBarry Smith   int            err;
302da392ccSBarry Smith #endif
31071fcb05SBarry Smith 
32f0ba7cfcSLisandro Dalcin   if (!mem) {*result = NULL; return 0;}
33fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
34fc2a7144SHong Zhang   {
352da392ccSBarry Smith     if (!currentmktype) err = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem);
362da392ccSBarry Smith     else err = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem);
372c71b3e2SJacob Faibussowitsch     PetscCheckFalse(err == EINVAL,PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
387d3de750SJacob Faibussowitsch     if (err == ENOMEM) PetscInfo(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
3966c772faSBarry Smith     if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
40*9566063dSJacob Faibussowitsch     if (clear) PetscCall(PetscMemzero(*result,mem));
41fc2a7144SHong Zhang   }
42fc2a7144SHong Zhang #else
43e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
44071fcb05SBarry Smith   if (clear) {
45071fcb05SBarry Smith     *result = calloc(1+mem/sizeof(int),sizeof(int));
46071fcb05SBarry Smith   } else {
47e5c89e4eSSatish Balay     *result = malloc(mem);
48071fcb05SBarry Smith   }
4966c772faSBarry Smith   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
50*9566063dSJacob Faibussowitsch   if (PetscLogMemory) PetscCall(PetscMemzero(*result,mem));
51071fcb05SBarry Smith 
52e5c89e4eSSatish Balay #  elif defined(PETSC_HAVE_MEMALIGN)
53e5c89e4eSSatish Balay   *result = memalign(PETSC_MEMALIGN,mem);
5466c772faSBarry Smith   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
55071fcb05SBarry Smith   if (clear || PetscLogMemory) {
56*9566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(*result,mem));
57071fcb05SBarry Smith   }
58e5c89e4eSSatish Balay #  else
59e5c89e4eSSatish Balay   {
6066c772faSBarry Smith     int *ptr,shift;
61e5c89e4eSSatish Balay     /*
62e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
63e5c89e4eSSatish Balay     */
64071fcb05SBarry Smith     if (clear) {
65071fcb05SBarry Smith       ptr = (int*)calloc(1+(mem + 2*PETSC_MEMALIGN)/sizeof(int),sizeof(int));
66071fcb05SBarry Smith     } else {
67071fcb05SBarry Smith       ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
68071fcb05SBarry Smith     }
6966c772faSBarry Smith     if (!ptr) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
7066c772faSBarry Smith     shift        = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
71e5c89e4eSSatish Balay     shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
720700a824SBarry Smith     ptr[shift-1] = shift + SHIFT_CLASSID;
73e5c89e4eSSatish Balay     ptr         += shift;
74e5c89e4eSSatish Balay     *result      = (void*)ptr;
75*9566063dSJacob Faibussowitsch     if (PetscLogMemory) PetscCall(PetscMemzero(*result,mem));
76e5c89e4eSSatish Balay   }
77e5c89e4eSSatish Balay #  endif
78fc2a7144SHong Zhang #endif
79e5c89e4eSSatish Balay   return 0;
80e5c89e4eSSatish Balay }
81e5c89e4eSSatish Balay 
8295c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
83e5c89e4eSSatish Balay {
84f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
85fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
86fc2a7144SHong Zhang   memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */
87fc2a7144SHong Zhang #else
88e5c89e4eSSatish Balay #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
89f0ba7cfcSLisandro Dalcin   {
90e5c89e4eSSatish Balay     /*
91e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
92e5c89e4eSSatish Balay       the original address provided by the system malloc().
93e5c89e4eSSatish Balay     */
94f0ba7cfcSLisandro Dalcin     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
95efca3c55SSatish 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");
96efca3c55SSatish Balay     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
97e5c89e4eSSatish Balay     ptr = (void*)(((int*)ptr) - shift);
98e5c89e4eSSatish Balay   }
99f0ba7cfcSLisandro Dalcin #  endif
100e5c89e4eSSatish Balay 
101e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_FREE_RETURN_INT)
102e5c89e4eSSatish Balay   int err = free(ptr);
103efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
104e5c89e4eSSatish Balay #  else
105e5c89e4eSSatish Balay   free(ptr);
106e5c89e4eSSatish Balay #  endif
107fc2a7144SHong Zhang #endif
108e5c89e4eSSatish Balay   return 0;
109e5c89e4eSSatish Balay }
110e5c89e4eSSatish Balay 
11195c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
1123221ece2SMatthew G. Knepley {
113c22f1541SToby Isaac   PetscErrorCode ierr;
114c22f1541SToby Isaac 
115c22f1541SToby Isaac   if (!mem) {
116c22f1541SToby Isaac     ierr = PetscFreeAlign(*result, line, func, file);
117c22f1541SToby Isaac     if (ierr) return ierr;
118c22f1541SToby Isaac     *result = NULL;
119c22f1541SToby Isaac     return 0;
120c22f1541SToby Isaac   }
121fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
122fc2a7144SHong Zhang   if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem);
123e3acc61dSHong Zhang   else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem);
124fc2a7144SHong Zhang #else
1253221ece2SMatthew G. Knepley #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
1263221ece2SMatthew G. Knepley   {
1273221ece2SMatthew G. Knepley     /*
1283221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
1293221ece2SMatthew G. Knepley       the original address provided by the system malloc().
1303221ece2SMatthew G. Knepley     */
1313221ece2SMatthew G. Knepley     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
1323221ece2SMatthew 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");
1333221ece2SMatthew G. Knepley     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
1343221ece2SMatthew G. Knepley     *result = (void*)(((int*)*result) - shift);
1353221ece2SMatthew G. Knepley   }
1363221ece2SMatthew G. Knepley #  endif
1373221ece2SMatthew G. Knepley 
138c22f1541SToby Isaac #  if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
13941605b92SBarry Smith   *result = realloc(*result, mem);
1403221ece2SMatthew G. Knepley #  else
1413221ece2SMatthew G. Knepley   {
1423221ece2SMatthew G. Knepley     /*
1433221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1443221ece2SMatthew G. Knepley     */
1453221ece2SMatthew G. Knepley     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
1463221ece2SMatthew G. Knepley     if (ptr) {
1473221ece2SMatthew G. Knepley       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
1483221ece2SMatthew G. Knepley       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
1493221ece2SMatthew G. Knepley       ptr[shift-1] = shift + SHIFT_CLASSID;
1503221ece2SMatthew G. Knepley       ptr         += shift;
1513221ece2SMatthew G. Knepley       *result      = (void*)ptr;
1523221ece2SMatthew G. Knepley     } else {
1533221ece2SMatthew G. Knepley       *result      = NULL;
1543221ece2SMatthew G. Knepley     }
1553221ece2SMatthew G. Knepley   }
1563221ece2SMatthew G. Knepley #  endif
157fc2a7144SHong Zhang #endif
1583221ece2SMatthew G. Knepley   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
159c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN)
160c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
161c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
162c22f1541SToby Isaac   if (((size_t) (*result)) % PETSC_MEMALIGN) {
163c22f1541SToby Isaac     void *newResult;
164fc2a7144SHong Zhang #  if defined(PETSC_HAVE_MEMKIND)
165fc2a7144SHong Zhang     {
1662da392ccSBarry Smith       int err;
1672da392ccSBarry Smith       if (!currentmktype) err = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem);
1682da392ccSBarry Smith       else err = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem);
1692c71b3e2SJacob Faibussowitsch       PetscCheckFalse(err == EINVAL,PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
1707d3de750SJacob Faibussowitsch       if (err == ENOMEM) PetscInfo(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
171fc2a7144SHong Zhang     }
172fc2a7144SHong Zhang #  else
173c22f1541SToby Isaac     newResult = memalign(PETSC_MEMALIGN,mem);
174fc2a7144SHong Zhang #  endif
175c22f1541SToby Isaac     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
176c22f1541SToby Isaac     ierr = PetscMemcpy(newResult,*result,mem);
177c22f1541SToby Isaac     if (ierr) return ierr;
178c22f1541SToby Isaac #  if defined(PETSC_HAVE_FREE_RETURN_INT)
179c22f1541SToby Isaac     {
180c22f1541SToby Isaac       int err = free(*result);
181c22f1541SToby Isaac       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
182c22f1541SToby Isaac     }
183c22f1541SToby Isaac #  else
184de1d6c17SHong Zhang #    if defined(PETSC_HAVE_MEMKIND)
185de1d6c17SHong Zhang     memkind_free(0,*result);
186de1d6c17SHong Zhang #    else
187c22f1541SToby Isaac     free(*result);
188c22f1541SToby Isaac #    endif
189de1d6c17SHong Zhang #  endif
190c22f1541SToby Isaac     *result = newResult;
191c22f1541SToby Isaac   }
192c22f1541SToby Isaac #endif
1933221ece2SMatthew G. Knepley   return 0;
1943221ece2SMatthew G. Knepley }
1953221ece2SMatthew G. Knepley 
196071fcb05SBarry Smith PetscErrorCode (*PetscTrMalloc)(size_t,PetscBool,int,const char[],const char[],void**) = PetscMallocAlign;
197efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])                     = PetscFreeAlign;
1983221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**)          = PetscReallocAlign;
199e5c89e4eSSatish Balay 
20095c0884eSLisandro Dalcin PETSC_INTERN PetscBool petscsetmallocvisited;
201ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE;
202e5c89e4eSSatish Balay 
203e5c89e4eSSatish Balay /*@C
2041d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
205e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
206e5c89e4eSSatish Balay    called only once.
207e5c89e4eSSatish Balay 
208e5c89e4eSSatish Balay    Not Collective
209e5c89e4eSSatish Balay 
210e5c89e4eSSatish Balay    Input Parameters:
21192f119d6SBarry Smith + imalloc - the routine that provides the malloc (also provides calloc(), which is used depends on the second argument)
21292f119d6SBarry Smith . ifree - the routine that provides the free
21392f119d6SBarry Smith - iralloc - the routine that provides the realloc
214e5c89e4eSSatish Balay 
215e5c89e4eSSatish Balay    Level: developer
216e5c89e4eSSatish Balay 
217e5c89e4eSSatish Balay @*/
218071fcb05SBarry Smith PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,PetscBool,int,const char[],const char[],void**),
21992f119d6SBarry Smith                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]),
22092f119d6SBarry Smith                               PetscErrorCode (*iralloc)(size_t, int, const char[], const char[], void **))
221e5c89e4eSSatish Balay {
222e5c89e4eSSatish Balay   PetscFunctionBegin;
2232c71b3e2SJacob Faibussowitsch   PetscCheckFalse(petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree),PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
224e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
225e5c89e4eSSatish Balay   PetscTrFree           = ifree;
22692f119d6SBarry Smith   PetscTrRealloc        = iralloc;
227e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
228e5c89e4eSSatish Balay   PetscFunctionReturn(0);
229e5c89e4eSSatish Balay }
230e5c89e4eSSatish Balay 
231e5c89e4eSSatish Balay /*@C
23292f119d6SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the defaults.
233e5c89e4eSSatish Balay 
234e5c89e4eSSatish Balay    Not Collective
235e5c89e4eSSatish Balay 
236e5c89e4eSSatish Balay    Level: developer
237e5c89e4eSSatish Balay 
238e5c89e4eSSatish Balay    Notes:
239e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
240e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
241e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
242e5c89e4eSSatish Balay 
24392f119d6SBarry Smith     Called in PetscFinalize() so that if PetscInitialize() is called again it starts with a fresh slate of allocation information
24492f119d6SBarry Smith 
245e5c89e4eSSatish Balay @*/
2467087cfbeSBarry Smith PetscErrorCode PetscMallocClear(void)
247e5c89e4eSSatish Balay {
248e5c89e4eSSatish Balay   PetscFunctionBegin;
249e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
250e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
25192f119d6SBarry Smith   PetscTrRealloc        = PetscReallocAlign;
252e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
253e5c89e4eSSatish Balay   PetscFunctionReturn(0);
254e5c89e4eSSatish Balay }
255b44d5720SBarry Smith 
256b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[])
257b44d5720SBarry Smith {
258b44d5720SBarry Smith   PetscLogDouble        mem,mal;
259b44d5720SBarry Smith   static PetscLogDouble oldmem = 0,oldmal = 0;
260b44d5720SBarry Smith 
261b44d5720SBarry Smith   PetscFunctionBegin;
262*9566063dSJacob Faibussowitsch   PetscCall(PetscMemoryGetCurrentUsage(&mem));
263*9566063dSJacob Faibussowitsch   PetscCall(PetscMallocGetCurrentUsage(&mal));
264b44d5720SBarry Smith 
265*9566063dSJacob Faibussowitsch   PetscCall(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));
266b44d5720SBarry Smith   oldmem = mem;
267b44d5720SBarry Smith   oldmal = mal;
268b44d5720SBarry Smith   PetscFunctionReturn(0);
269b44d5720SBarry Smith }
27013850c04SHong Zhang 
271071fcb05SBarry Smith static PetscErrorCode (*PetscTrMallocOld)(size_t,PetscBool,int,const char[],const char[],void**) = PetscMallocAlign;
27292f119d6SBarry Smith static PetscErrorCode (*PetscTrReallocOld)(size_t,int,const char[],const char[],void**)          = PetscReallocAlign;
27350a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[])                     = PetscFreeAlign;
274de1d6c17SHong Zhang 
275de1d6c17SHong Zhang /*@C
276de1d6c17SHong Zhang    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
277de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
278de1d6c17SHong Zhang      current malloc and free routines to the PetscMallocAlign and
279de1d6c17SHong Zhang      PetscFreeAlign (PETSc default).
280de1d6c17SHong Zhang 
281de1d6c17SHong Zhang    Not Collective
282de1d6c17SHong Zhang 
283de1d6c17SHong Zhang    Level: developer
284de1d6c17SHong Zhang 
285de1d6c17SHong Zhang    Notes:
286de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
287de1d6c17SHong Zhang      can switch back to the previous choice by calling PetscMallocReset().
288de1d6c17SHong Zhang 
289de1d6c17SHong Zhang .seealso: PetscMallocReset()
290de1d6c17SHong Zhang @*/
29113850c04SHong Zhang PetscErrorCode PetscMallocSetDRAM(void)
29213850c04SHong Zhang {
29313850c04SHong Zhang   PetscFunctionBegin;
294de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
295de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
296de1d6c17SHong Zhang     previousmktype = currentmktype;
297de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
298de1d6c17SHong Zhang #endif
299de1d6c17SHong Zhang   } else {
30013850c04SHong Zhang     /* Save the previous choice */
30113850c04SHong Zhang     PetscTrMallocOld  = PetscTrMalloc;
30292f119d6SBarry Smith     PetscTrReallocOld = PetscTrRealloc;
30313850c04SHong Zhang     PetscTrFreeOld    = PetscTrFree;
30413850c04SHong Zhang     PetscTrMalloc     = PetscMallocAlign;
30513850c04SHong Zhang     PetscTrFree       = PetscFreeAlign;
30692f119d6SBarry Smith     PetscTrRealloc    = PetscReallocAlign;
307de1d6c17SHong Zhang   }
30813850c04SHong Zhang   PetscFunctionReturn(0);
30913850c04SHong Zhang }
31013850c04SHong Zhang 
311de1d6c17SHong Zhang /*@C
312de1d6c17SHong Zhang    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM
313de1d6c17SHong Zhang 
314de1d6c17SHong Zhang    Not Collective
315de1d6c17SHong Zhang 
316de1d6c17SHong Zhang    Level: developer
317de1d6c17SHong Zhang 
318de1d6c17SHong Zhang .seealso: PetscMallocSetDRAM()
319de1d6c17SHong Zhang @*/
32013850c04SHong Zhang PetscErrorCode PetscMallocResetDRAM(void)
32113850c04SHong Zhang {
32213850c04SHong Zhang   PetscFunctionBegin;
323de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
324de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
325de1d6c17SHong Zhang     currentmktype = previousmktype;
326de1d6c17SHong Zhang #endif
327de1d6c17SHong Zhang   } else {
32813850c04SHong Zhang     /* Reset to the previous choice */
32913850c04SHong Zhang     PetscTrMalloc  = PetscTrMallocOld;
33092f119d6SBarry Smith     PetscTrRealloc = PetscTrReallocOld;
33113850c04SHong Zhang     PetscTrFree    = PetscTrFreeOld;
332de1d6c17SHong Zhang   }
33313850c04SHong Zhang   PetscFunctionReturn(0);
33413850c04SHong Zhang }
335ba282f50SJed Brown 
336ba282f50SJed Brown static PetscBool petscmalloccoalesce =
337ba282f50SJed Brown #if defined(PETSC_USE_MALLOC_COALESCED)
338ba282f50SJed Brown   PETSC_TRUE;
339ba282f50SJed Brown #else
340ba282f50SJed Brown   PETSC_FALSE;
341ba282f50SJed Brown #endif
342ba282f50SJed Brown 
343ba282f50SJed Brown /*@C
344ba282f50SJed Brown    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects
345ba282f50SJed Brown 
346ba282f50SJed Brown    Not Collective
347ba282f50SJed Brown 
348ba282f50SJed Brown    Input Parameters:
349ba282f50SJed Brown .  coalesce - PETSC_TRUE to use coalesced malloc for multi-object allocation.
350ba282f50SJed Brown 
351ba282f50SJed Brown    Options Database Keys:
352ba282f50SJed Brown .  -malloc_coalesce - turn coalesced malloc on or off
353ba282f50SJed Brown 
354ba282f50SJed Brown    Note:
355ba282f50SJed Brown    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.
35692f119d6SBarry Smith    This function can only be called immediately after PetscInitialize()
357ba282f50SJed Brown 
358ba282f50SJed Brown    Level: developer
359ba282f50SJed Brown 
360ba282f50SJed Brown .seealso: PetscMallocA()
361ba282f50SJed Brown @*/
362ba282f50SJed Brown PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce)
363ba282f50SJed Brown {
364ba282f50SJed Brown   PetscFunctionBegin;
365ba282f50SJed Brown   petscmalloccoalesce = coalesce;
366ba282f50SJed Brown   PetscFunctionReturn(0);
367ba282f50SJed Brown }
368ba282f50SJed Brown 
369ba282f50SJed Brown /*@C
370ba282f50SJed Brown    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc
371ba282f50SJed Brown 
372ba282f50SJed Brown    Not Collective
373ba282f50SJed Brown 
374ba282f50SJed Brown    Input Parameters:
375ba282f50SJed Brown +  n - number of objects to allocate (at least 1)
37689407d75SBarry Smith .  clear - use calloc() to allocate space initialized to zero
377ba282f50SJed Brown .  lineno - line number to attribute allocation (typically __LINE__)
378ba282f50SJed Brown .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
379ba282f50SJed Brown .  filename - file name to attribute allocation (typically __FILE__)
380ba282f50SJed Brown -  bytes0 - first of n object sizes
381ba282f50SJed Brown 
382ba282f50SJed Brown    Output Parameters:
383ba282f50SJed Brown .  ptr0 - first of n pointers to allocate
384ba282f50SJed Brown 
385ba282f50SJed Brown    Notes:
386ba282f50SJed Brown    This function is not normally called directly by users, but rather via the macros PetscMalloc1(), PetscMalloc2(), or PetscCalloc1(), etc.
387ba282f50SJed Brown 
388ba282f50SJed Brown    Level: developer
389ba282f50SJed Brown 
390ba282f50SJed Brown .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMalloc1(), PetscMalloc2(), PetscMalloc3(), PetscMalloc4(), PetscMalloc5(), PetscMalloc6(), PetscMalloc7(), PetscCalloc1(), PetscCalloc2(), PetscCalloc3(), PetscCalloc4(), PetscCalloc5(), PetscCalloc6(), PetscCalloc7(), PetscFreeA()
391ba282f50SJed Brown @*/
392ba282f50SJed Brown PetscErrorCode PetscMallocA(int n,PetscBool clear,int lineno,const char *function,const char *filename,size_t bytes0,void *ptr0,...)
393ba282f50SJed Brown {
394ba282f50SJed Brown   va_list        Argp;
395ba282f50SJed Brown   size_t         bytes[8],sumbytes;
396ba282f50SJed Brown   void           **ptr[8];
397ba282f50SJed Brown   int            i;
398ba282f50SJed Brown 
399ba282f50SJed Brown   PetscFunctionBegin;
4002c71b3e2SJacob Faibussowitsch   PetscCheckFalse(n > 8,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n);
401ba282f50SJed Brown   bytes[0] = bytes0;
402ba282f50SJed Brown   ptr[0] = (void**)ptr0;
403ba282f50SJed Brown   sumbytes = (bytes0 + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
404ba282f50SJed Brown   va_start(Argp,ptr0);
405ba282f50SJed Brown   for (i=1; i<n; i++) {
406ba282f50SJed Brown     bytes[i] = va_arg(Argp,size_t);
407ba282f50SJed Brown     ptr[i] = va_arg(Argp,void**);
408ba282f50SJed Brown     sumbytes += (bytes[i] + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
409ba282f50SJed Brown   }
410ba282f50SJed Brown   va_end(Argp);
411ba282f50SJed Brown   if (petscmalloccoalesce) {
412ba282f50SJed Brown     char *p;
413*9566063dSJacob Faibussowitsch     PetscCall((*PetscTrMalloc)(sumbytes,clear,lineno,function,filename,(void**)&p));
414ba282f50SJed Brown     for (i=0; i<n; i++) {
415ba282f50SJed Brown       *ptr[i] = bytes[i] ? p : NULL;
416ba282f50SJed Brown       p = (char*)PetscAddrAlign(p + bytes[i]);
417ba282f50SJed Brown     }
418ba282f50SJed Brown   } else {
419ba282f50SJed Brown     for (i=0; i<n; i++) {
420*9566063dSJacob Faibussowitsch       PetscCall((*PetscTrMalloc)(bytes[i],clear,lineno,function,filename,(void**)ptr[i]));
421ba282f50SJed Brown     }
422ba282f50SJed Brown   }
423ba282f50SJed Brown   PetscFunctionReturn(0);
424ba282f50SJed Brown }
425ba282f50SJed Brown 
426ba282f50SJed Brown /*@C
427ba282f50SJed Brown    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc
428ba282f50SJed Brown 
429ba282f50SJed Brown    Not Collective
430ba282f50SJed Brown 
431ba282f50SJed Brown    Input Parameters:
432ba282f50SJed Brown +  n - number of objects to free (at least 1)
433ba282f50SJed Brown .  lineno - line number to attribute deallocation (typically __LINE__)
434ba282f50SJed Brown .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
435ba282f50SJed Brown .  filename - file name to attribute deallocation (typically __FILE__)
436ba282f50SJed Brown -  ptr0 ... - first of n pointers to free
437ba282f50SJed Brown 
438ba282f50SJed Brown    Note:
439071fcb05SBarry Smith    This function is not normally called directly by users, but rather via the macros PetscFree(), PetscFree2(), etc.
440ba282f50SJed Brown 
441a5b23f4aSJose E. Roman    The pointers are zeroed to prevent users from accidentally reusing space that has been freed.
44289407d75SBarry Smith 
443ba282f50SJed Brown    Level: developer
444ba282f50SJed Brown 
445ba282f50SJed Brown .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMallocA(), PetscFree1(), PetscFree2(), PetscFree3(), PetscFree4(), PetscFree5(), PetscFree6(), PetscFree7()
446ba282f50SJed Brown @*/
447ba282f50SJed Brown PetscErrorCode PetscFreeA(int n,int lineno,const char *function,const char *filename,void *ptr0,...)
448ba282f50SJed Brown {
449ba282f50SJed Brown   va_list        Argp;
450ba282f50SJed Brown   void           **ptr[8];
451ba282f50SJed Brown   int            i;
452ba282f50SJed Brown 
453ba282f50SJed Brown   PetscFunctionBegin;
4542c71b3e2SJacob Faibussowitsch   PetscCheckFalse(n > 8,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only up to 8 supported",n);
455ba282f50SJed Brown   ptr[0] = (void**)ptr0;
456ba282f50SJed Brown   va_start(Argp,ptr0);
457ba282f50SJed Brown   for (i=1; i<n; i++) {
458ba282f50SJed Brown     ptr[i] = va_arg(Argp,void**);
459ba282f50SJed Brown   }
460ba282f50SJed Brown   va_end(Argp);
461ba282f50SJed Brown   if (petscmalloccoalesce) {
462ba282f50SJed Brown     for (i=0; i<n; i++) {       /* Find first nonempty allocation */
463ba282f50SJed Brown       if (*ptr[i]) break;
464ba282f50SJed Brown     }
465ba282f50SJed Brown     while (--n > i) {
466ba282f50SJed Brown       *ptr[n] = NULL;
467ba282f50SJed Brown     }
468*9566063dSJacob Faibussowitsch     PetscCall((*PetscTrFree)(*ptr[n],lineno,function,filename));
469ba282f50SJed Brown     *ptr[n] = NULL;
470ba282f50SJed Brown   } else {
471ba282f50SJed Brown     while (--n >= 0) {
472*9566063dSJacob Faibussowitsch       PetscCall((*PetscTrFree)(*ptr[n],lineno,function,filename));
473ba282f50SJed Brown       *ptr[n] = NULL;
474ba282f50SJed Brown     }
475ba282f50SJed Brown   }
476ba282f50SJed Brown   PetscFunctionReturn(0);
477ba282f50SJed Brown }
478