xref: /petsc/src/sys/memory/mal.c (revision 2da392cc7c10228af19ad9843ce5155178acb644)
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 {
28071fcb05SBarry Smith   PetscErrorCode ierr;
29*2da392ccSBarry Smith #if defined(PETSC_HAVE_MEMKIND)
30*2da392ccSBarry Smith   int            err;
31*2da392ccSBarry Smith #endif
32071fcb05SBarry Smith 
33f0ba7cfcSLisandro Dalcin   if (!mem) {*result = NULL; return 0;}
34fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
35fc2a7144SHong Zhang   {
36*2da392ccSBarry Smith     if (!currentmktype) err = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem);
37*2da392ccSBarry Smith     else err = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem);
38*2da392ccSBarry Smith     if (err == EINVAL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
39*2da392ccSBarry Smith     if (err == ENOMEM) PetscInfo1(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
40071fcb05SBarry Smith     if (clear) {ierr = PetscMemzero(*result,mem);CHKERRQ(ierr);}
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   }
49071fcb05SBarry Smith   if (PetscLogMemory) {ierr = PetscMemzero(*result,mem);CHKERRQ(ierr);}
50071fcb05SBarry Smith 
51e5c89e4eSSatish Balay #  elif defined(PETSC_HAVE_MEMALIGN)
52e5c89e4eSSatish Balay   *result = memalign(PETSC_MEMALIGN,mem);
53071fcb05SBarry Smith   if (clear || PetscLogMemory) {
54071fcb05SBarry Smith     ierr = PetscMemzero(*result,mem);CHKERRQ(ierr);
55071fcb05SBarry Smith   }
56e5c89e4eSSatish Balay #  else
57e5c89e4eSSatish Balay   {
58071fcb05SBarry Smith     int *ptr;
59e5c89e4eSSatish Balay     /*
60e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
61e5c89e4eSSatish Balay     */
62071fcb05SBarry Smith     if (clear) {
63071fcb05SBarry Smith       ptr = (int*)calloc(1+(mem + 2*PETSC_MEMALIGN)/sizeof(int),sizeof(int));
64071fcb05SBarry Smith     } else {
65071fcb05SBarry Smith       ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
66071fcb05SBarry Smith     }
67e5c89e4eSSatish Balay     if (ptr) {
68f0ba7cfcSLisandro Dalcin       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
69e5c89e4eSSatish Balay       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
700700a824SBarry Smith       ptr[shift-1] = shift + SHIFT_CLASSID;
71e5c89e4eSSatish Balay       ptr         += shift;
72e5c89e4eSSatish Balay       *result      = (void*)ptr;
73071fcb05SBarry Smith       if (PetscLogMemory) {ierr = PetscMemzero(*result,mem);CHKERRQ(ierr);}
74e5c89e4eSSatish Balay     } else {
75f0ba7cfcSLisandro Dalcin       *result      = NULL;
76e5c89e4eSSatish Balay     }
77e5c89e4eSSatish Balay   }
78e5c89e4eSSatish Balay #  endif
79fc2a7144SHong Zhang #endif
80071fcb05SBarry Smith 
81f0ba7cfcSLisandro Dalcin   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
82e5c89e4eSSatish Balay   return 0;
83e5c89e4eSSatish Balay }
84e5c89e4eSSatish Balay 
8595c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
86e5c89e4eSSatish Balay {
87f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
88fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
89fc2a7144SHong Zhang   memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */
90fc2a7144SHong Zhang #else
91e5c89e4eSSatish Balay #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
92f0ba7cfcSLisandro Dalcin   {
93e5c89e4eSSatish Balay     /*
94e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
95e5c89e4eSSatish Balay       the original address provided by the system malloc().
96e5c89e4eSSatish Balay     */
97f0ba7cfcSLisandro Dalcin     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
98efca3c55SSatish 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");
99efca3c55SSatish Balay     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
100e5c89e4eSSatish Balay     ptr = (void*)(((int*)ptr) - shift);
101e5c89e4eSSatish Balay   }
102f0ba7cfcSLisandro Dalcin #  endif
103e5c89e4eSSatish Balay 
104e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_FREE_RETURN_INT)
105e5c89e4eSSatish Balay   int err = free(ptr);
106efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
107e5c89e4eSSatish Balay #  else
108e5c89e4eSSatish Balay   free(ptr);
109e5c89e4eSSatish Balay #  endif
110fc2a7144SHong Zhang #endif
111e5c89e4eSSatish Balay   return 0;
112e5c89e4eSSatish Balay }
113e5c89e4eSSatish Balay 
11495c0884eSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
1153221ece2SMatthew G. Knepley {
116c22f1541SToby Isaac   PetscErrorCode ierr;
117c22f1541SToby Isaac 
118c22f1541SToby Isaac   if (!mem) {
119c22f1541SToby Isaac     ierr = PetscFreeAlign(*result, line, func, file);
120c22f1541SToby Isaac     if (ierr) return ierr;
121c22f1541SToby Isaac     *result = NULL;
122c22f1541SToby Isaac     return 0;
123c22f1541SToby Isaac   }
124fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
125fc2a7144SHong Zhang   if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem);
126e3acc61dSHong Zhang   else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem);
127fc2a7144SHong Zhang #else
1283221ece2SMatthew G. Knepley #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
1293221ece2SMatthew G. Knepley   {
1303221ece2SMatthew G. Knepley     /*
1313221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
1323221ece2SMatthew G. Knepley       the original address provided by the system malloc().
1333221ece2SMatthew G. Knepley     */
1343221ece2SMatthew G. Knepley     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
1353221ece2SMatthew 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");
1363221ece2SMatthew G. Knepley     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
1373221ece2SMatthew G. Knepley     *result = (void*)(((int*)*result) - shift);
1383221ece2SMatthew G. Knepley   }
1393221ece2SMatthew G. Knepley #  endif
1403221ece2SMatthew G. Knepley 
141c22f1541SToby Isaac #  if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
14241605b92SBarry Smith   *result = realloc(*result, mem);
1433221ece2SMatthew G. Knepley #  else
1443221ece2SMatthew G. Knepley   {
1453221ece2SMatthew G. Knepley     /*
1463221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1473221ece2SMatthew G. Knepley     */
1483221ece2SMatthew G. Knepley     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
1493221ece2SMatthew G. Knepley     if (ptr) {
1503221ece2SMatthew G. Knepley       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
1513221ece2SMatthew G. Knepley       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
1523221ece2SMatthew G. Knepley       ptr[shift-1] = shift + SHIFT_CLASSID;
1533221ece2SMatthew G. Knepley       ptr         += shift;
1543221ece2SMatthew G. Knepley       *result      = (void*)ptr;
1553221ece2SMatthew G. Knepley     } else {
1563221ece2SMatthew G. Knepley       *result      = NULL;
1573221ece2SMatthew G. Knepley     }
1583221ece2SMatthew G. Knepley   }
1593221ece2SMatthew G. Knepley #  endif
160fc2a7144SHong Zhang #endif
1613221ece2SMatthew G. Knepley   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
162c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN)
163c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
164c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
165c22f1541SToby Isaac   if (((size_t) (*result)) % PETSC_MEMALIGN) {
166c22f1541SToby Isaac     void *newResult;
167fc2a7144SHong Zhang #  if defined(PETSC_HAVE_MEMKIND)
168fc2a7144SHong Zhang     {
169*2da392ccSBarry Smith       int err;
170*2da392ccSBarry Smith       if (!currentmktype) err = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem);
171*2da392ccSBarry Smith       else err = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem);
172*2da392ccSBarry Smith       if (err == EINVAL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
173*2da392ccSBarry Smith       if (err == ENOMEM) PetscInfo1(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
174fc2a7144SHong Zhang     }
175fc2a7144SHong Zhang #  else
176c22f1541SToby Isaac     newResult = memalign(PETSC_MEMALIGN,mem);
177fc2a7144SHong Zhang #  endif
178c22f1541SToby Isaac     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
179c22f1541SToby Isaac     ierr = PetscMemcpy(newResult,*result,mem);
180c22f1541SToby Isaac     if (ierr) return ierr;
181c22f1541SToby Isaac #  if defined(PETSC_HAVE_FREE_RETURN_INT)
182c22f1541SToby Isaac     {
183c22f1541SToby Isaac       int err = free(*result);
184c22f1541SToby Isaac       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
185c22f1541SToby Isaac     }
186c22f1541SToby Isaac #  else
187de1d6c17SHong Zhang #    if defined(PETSC_HAVE_MEMKIND)
188de1d6c17SHong Zhang     memkind_free(0,*result);
189de1d6c17SHong Zhang #    else
190c22f1541SToby Isaac     free(*result);
191c22f1541SToby Isaac #    endif
192de1d6c17SHong Zhang #  endif
193c22f1541SToby Isaac     *result = newResult;
194c22f1541SToby Isaac   }
195c22f1541SToby Isaac #endif
1963221ece2SMatthew G. Knepley   return 0;
1973221ece2SMatthew G. Knepley }
1983221ece2SMatthew G. Knepley 
199071fcb05SBarry Smith PetscErrorCode (*PetscTrMalloc)(size_t,PetscBool,int,const char[],const char[],void**) = PetscMallocAlign;
200efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])                     = PetscFreeAlign;
2013221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**)          = PetscReallocAlign;
202e5c89e4eSSatish Balay 
20395c0884eSLisandro Dalcin PETSC_INTERN PetscBool petscsetmallocvisited;
204ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE;
205e5c89e4eSSatish Balay 
206e5c89e4eSSatish Balay /*@C
2071d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
208e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
209e5c89e4eSSatish Balay    called only once.
210e5c89e4eSSatish Balay 
211e5c89e4eSSatish Balay    Not Collective
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay    Input Parameters:
21492f119d6SBarry Smith + imalloc - the routine that provides the malloc (also provides calloc(), which is used depends on the second argument)
21592f119d6SBarry Smith . ifree - the routine that provides the free
21692f119d6SBarry Smith - iralloc - the routine that provides the realloc
217e5c89e4eSSatish Balay 
218e5c89e4eSSatish Balay    Level: developer
219e5c89e4eSSatish Balay 
220e5c89e4eSSatish Balay @*/
221071fcb05SBarry Smith PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t,PetscBool,int,const char[],const char[],void**),
22292f119d6SBarry Smith                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]),
22392f119d6SBarry Smith                               PetscErrorCode (*iralloc)(size_t, int, const char[], const char[], void **))
224e5c89e4eSSatish Balay {
225e5c89e4eSSatish Balay   PetscFunctionBegin;
226e32f2f54SBarry Smith   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
227e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
228e5c89e4eSSatish Balay   PetscTrFree           = ifree;
22992f119d6SBarry Smith   PetscTrRealloc        = iralloc;
230e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
231e5c89e4eSSatish Balay   PetscFunctionReturn(0);
232e5c89e4eSSatish Balay }
233e5c89e4eSSatish Balay 
234e5c89e4eSSatish Balay /*@C
23592f119d6SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the defaults.
236e5c89e4eSSatish Balay 
237e5c89e4eSSatish Balay    Not Collective
238e5c89e4eSSatish Balay 
239e5c89e4eSSatish Balay    Level: developer
240e5c89e4eSSatish Balay 
241e5c89e4eSSatish Balay    Notes:
242e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
243e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
244e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
245e5c89e4eSSatish Balay 
24692f119d6SBarry Smith     Called in PetscFinalize() so that if PetscInitialize() is called again it starts with a fresh slate of allocation information
24792f119d6SBarry Smith 
248e5c89e4eSSatish Balay @*/
2497087cfbeSBarry Smith PetscErrorCode PetscMallocClear(void)
250e5c89e4eSSatish Balay {
251e5c89e4eSSatish Balay   PetscFunctionBegin;
252e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
253e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
25492f119d6SBarry Smith   PetscTrRealloc        = PetscReallocAlign;
255e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
256e5c89e4eSSatish Balay   PetscFunctionReturn(0);
257e5c89e4eSSatish Balay }
258b44d5720SBarry Smith 
259b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[])
260b44d5720SBarry Smith {
261b44d5720SBarry Smith   PetscErrorCode        ierr;
262b44d5720SBarry Smith   PetscLogDouble        mem,mal;
263b44d5720SBarry Smith   static PetscLogDouble oldmem = 0,oldmal = 0;
264b44d5720SBarry Smith 
265b44d5720SBarry Smith   PetscFunctionBegin;
266b44d5720SBarry Smith   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
267b44d5720SBarry Smith   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
268b44d5720SBarry Smith 
269b44d5720SBarry 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);
270b44d5720SBarry Smith   oldmem = mem;
271b44d5720SBarry Smith   oldmal = mal;
272b44d5720SBarry Smith   PetscFunctionReturn(0);
273b44d5720SBarry Smith }
27413850c04SHong Zhang 
275071fcb05SBarry Smith static PetscErrorCode (*PetscTrMallocOld)(size_t,PetscBool,int,const char[],const char[],void**) = PetscMallocAlign;
27692f119d6SBarry Smith static PetscErrorCode (*PetscTrReallocOld)(size_t,int,const char[],const char[],void**)          = PetscReallocAlign;
27750a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[])                     = PetscFreeAlign;
278de1d6c17SHong Zhang 
279de1d6c17SHong Zhang /*@C
280de1d6c17SHong Zhang    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
281de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
282de1d6c17SHong Zhang      current malloc and free routines to the PetscMallocAlign and
283de1d6c17SHong Zhang      PetscFreeAlign (PETSc default).
284de1d6c17SHong Zhang 
285de1d6c17SHong Zhang    Not Collective
286de1d6c17SHong Zhang 
287de1d6c17SHong Zhang    Level: developer
288de1d6c17SHong Zhang 
289de1d6c17SHong Zhang    Notes:
290de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
291de1d6c17SHong Zhang      can switch back to the previous choice by calling PetscMallocReset().
292de1d6c17SHong Zhang 
293de1d6c17SHong Zhang .seealso: PetscMallocReset()
294de1d6c17SHong Zhang @*/
29513850c04SHong Zhang PetscErrorCode PetscMallocSetDRAM(void)
29613850c04SHong Zhang {
29713850c04SHong Zhang   PetscFunctionBegin;
298de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
299de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
300de1d6c17SHong Zhang     previousmktype = currentmktype;
301de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
302de1d6c17SHong Zhang #endif
303de1d6c17SHong Zhang   } else {
30413850c04SHong Zhang     /* Save the previous choice */
30513850c04SHong Zhang     PetscTrMallocOld  = PetscTrMalloc;
30692f119d6SBarry Smith     PetscTrReallocOld = PetscTrRealloc;
30713850c04SHong Zhang     PetscTrFreeOld    = PetscTrFree;
30813850c04SHong Zhang     PetscTrMalloc     = PetscMallocAlign;
30913850c04SHong Zhang     PetscTrFree       = PetscFreeAlign;
31092f119d6SBarry Smith     PetscTrRealloc    = PetscReallocAlign;
311de1d6c17SHong Zhang   }
31213850c04SHong Zhang   PetscFunctionReturn(0);
31313850c04SHong Zhang }
31413850c04SHong Zhang 
315de1d6c17SHong Zhang /*@C
316de1d6c17SHong Zhang    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM
317de1d6c17SHong Zhang 
318de1d6c17SHong Zhang    Not Collective
319de1d6c17SHong Zhang 
320de1d6c17SHong Zhang    Level: developer
321de1d6c17SHong Zhang 
322de1d6c17SHong Zhang .seealso: PetscMallocSetDRAM()
323de1d6c17SHong Zhang @*/
32413850c04SHong Zhang PetscErrorCode PetscMallocResetDRAM(void)
32513850c04SHong Zhang {
32613850c04SHong Zhang   PetscFunctionBegin;
327de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
328de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
329de1d6c17SHong Zhang     currentmktype = previousmktype;
330de1d6c17SHong Zhang #endif
331de1d6c17SHong Zhang   } else {
33213850c04SHong Zhang     /* Reset to the previous choice */
33313850c04SHong Zhang     PetscTrMalloc  = PetscTrMallocOld;
33492f119d6SBarry Smith     PetscTrRealloc = PetscTrReallocOld;
33513850c04SHong Zhang     PetscTrFree    = PetscTrFreeOld;
336de1d6c17SHong Zhang   }
33713850c04SHong Zhang   PetscFunctionReturn(0);
33813850c04SHong Zhang }
339ba282f50SJed Brown 
340ba282f50SJed Brown static PetscBool petscmalloccoalesce =
341ba282f50SJed Brown #if defined(PETSC_USE_MALLOC_COALESCED)
342ba282f50SJed Brown   PETSC_TRUE;
343ba282f50SJed Brown #else
344ba282f50SJed Brown   PETSC_FALSE;
345ba282f50SJed Brown #endif
346ba282f50SJed Brown 
347ba282f50SJed Brown /*@C
348ba282f50SJed Brown    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects
349ba282f50SJed Brown 
350ba282f50SJed Brown    Not Collective
351ba282f50SJed Brown 
352ba282f50SJed Brown    Input Parameters:
353ba282f50SJed Brown .  coalesce - PETSC_TRUE to use coalesced malloc for multi-object allocation.
354ba282f50SJed Brown 
355ba282f50SJed Brown    Options Database Keys:
356ba282f50SJed Brown .  -malloc_coalesce - turn coalesced malloc on or off
357ba282f50SJed Brown 
358ba282f50SJed Brown    Note:
359ba282f50SJed 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.
36092f119d6SBarry Smith    This function can only be called immediately after PetscInitialize()
361ba282f50SJed Brown 
362ba282f50SJed Brown    Level: developer
363ba282f50SJed Brown 
364ba282f50SJed Brown .seealso: PetscMallocA()
365ba282f50SJed Brown @*/
366ba282f50SJed Brown PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce)
367ba282f50SJed Brown {
368ba282f50SJed Brown   PetscFunctionBegin;
369ba282f50SJed Brown   petscmalloccoalesce = coalesce;
370ba282f50SJed Brown   PetscFunctionReturn(0);
371ba282f50SJed Brown }
372ba282f50SJed Brown 
373ba282f50SJed Brown /*@C
374ba282f50SJed Brown    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc
375ba282f50SJed Brown 
376ba282f50SJed Brown    Not Collective
377ba282f50SJed Brown 
378ba282f50SJed Brown    Input Parameters:
379ba282f50SJed Brown +  n - number of objects to allocate (at least 1)
38089407d75SBarry Smith .  clear - use calloc() to allocate space initialized to zero
381ba282f50SJed Brown .  lineno - line number to attribute allocation (typically __LINE__)
382ba282f50SJed Brown .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
383ba282f50SJed Brown .  filename - file name to attribute allocation (typically __FILE__)
384ba282f50SJed Brown -  bytes0 - first of n object sizes
385ba282f50SJed Brown 
386ba282f50SJed Brown    Output Parameters:
387ba282f50SJed Brown .  ptr0 - first of n pointers to allocate
388ba282f50SJed Brown 
389ba282f50SJed Brown    Notes:
390ba282f50SJed Brown    This function is not normally called directly by users, but rather via the macros PetscMalloc1(), PetscMalloc2(), or PetscCalloc1(), etc.
391ba282f50SJed Brown 
392ba282f50SJed Brown    Level: developer
393ba282f50SJed Brown 
394ba282f50SJed Brown .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMalloc1(), PetscMalloc2(), PetscMalloc3(), PetscMalloc4(), PetscMalloc5(), PetscMalloc6(), PetscMalloc7(), PetscCalloc1(), PetscCalloc2(), PetscCalloc3(), PetscCalloc4(), PetscCalloc5(), PetscCalloc6(), PetscCalloc7(), PetscFreeA()
395ba282f50SJed Brown @*/
396ba282f50SJed Brown PetscErrorCode PetscMallocA(int n,PetscBool clear,int lineno,const char *function,const char *filename,size_t bytes0,void *ptr0,...)
397ba282f50SJed Brown {
398ba282f50SJed Brown   PetscErrorCode ierr;
399ba282f50SJed Brown   va_list        Argp;
400ba282f50SJed Brown   size_t         bytes[8],sumbytes;
401ba282f50SJed Brown   void           **ptr[8];
402ba282f50SJed Brown   int            i;
403ba282f50SJed Brown 
404ba282f50SJed Brown   PetscFunctionBegin;
405ba282f50SJed Brown   if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n);
406ba282f50SJed Brown   bytes[0] = bytes0;
407ba282f50SJed Brown   ptr[0] = (void**)ptr0;
408ba282f50SJed Brown   sumbytes = (bytes0 + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
409ba282f50SJed Brown   va_start(Argp,ptr0);
410ba282f50SJed Brown   for (i=1; i<n; i++) {
411ba282f50SJed Brown     bytes[i] = va_arg(Argp,size_t);
412ba282f50SJed Brown     ptr[i] = va_arg(Argp,void**);
413ba282f50SJed Brown     sumbytes += (bytes[i] + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
414ba282f50SJed Brown   }
415ba282f50SJed Brown   va_end(Argp);
416ba282f50SJed Brown   if (petscmalloccoalesce) {
417ba282f50SJed Brown     char *p;
418071fcb05SBarry Smith     ierr = (*PetscTrMalloc)(sumbytes,clear,lineno,function,filename,(void**)&p);CHKERRQ(ierr);
419ba282f50SJed Brown     for (i=0; i<n; i++) {
420ba282f50SJed Brown       *ptr[i] = bytes[i] ? p : NULL;
421ba282f50SJed Brown       p = (char*)PetscAddrAlign(p + bytes[i]);
422ba282f50SJed Brown     }
423ba282f50SJed Brown   } else {
424ba282f50SJed Brown     for (i=0; i<n; i++) {
425071fcb05SBarry Smith       ierr = (*PetscTrMalloc)(bytes[i],clear,lineno,function,filename,(void**)ptr[i]);CHKERRQ(ierr);
426ba282f50SJed Brown     }
427ba282f50SJed Brown   }
428ba282f50SJed Brown   PetscFunctionReturn(0);
429ba282f50SJed Brown }
430ba282f50SJed Brown 
431ba282f50SJed Brown /*@C
432ba282f50SJed Brown    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc
433ba282f50SJed Brown 
434ba282f50SJed Brown    Not Collective
435ba282f50SJed Brown 
436ba282f50SJed Brown    Input Parameters:
437ba282f50SJed Brown +  n - number of objects to free (at least 1)
438ba282f50SJed Brown .  lineno - line number to attribute deallocation (typically __LINE__)
439ba282f50SJed Brown .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
440ba282f50SJed Brown .  filename - file name to attribute deallocation (typically __FILE__)
441ba282f50SJed Brown -  ptr0 ... - first of n pointers to free
442ba282f50SJed Brown 
443ba282f50SJed Brown    Note:
444071fcb05SBarry Smith    This function is not normally called directly by users, but rather via the macros PetscFree(), PetscFree2(), etc.
445ba282f50SJed Brown 
44689407d75SBarry Smith    The pointers are zeroed to prevent users from accidently reusing space that has been freed.
44789407d75SBarry Smith 
448ba282f50SJed Brown    Level: developer
449ba282f50SJed Brown 
450ba282f50SJed Brown .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMallocA(), PetscFree1(), PetscFree2(), PetscFree3(), PetscFree4(), PetscFree5(), PetscFree6(), PetscFree7()
451ba282f50SJed Brown @*/
452ba282f50SJed Brown PetscErrorCode PetscFreeA(int n,int lineno,const char *function,const char *filename,void *ptr0,...)
453ba282f50SJed Brown {
454ba282f50SJed Brown   PetscErrorCode ierr;
455ba282f50SJed Brown   va_list        Argp;
456ba282f50SJed Brown   void           **ptr[8];
457ba282f50SJed Brown   int            i;
458ba282f50SJed Brown 
459ba282f50SJed Brown   PetscFunctionBegin;
46089407d75SBarry Smith   if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only up to 8 supported",n);
461ba282f50SJed Brown   ptr[0] = (void**)ptr0;
462ba282f50SJed Brown   va_start(Argp,ptr0);
463ba282f50SJed Brown   for (i=1; i<n; i++) {
464ba282f50SJed Brown     ptr[i] = va_arg(Argp,void**);
465ba282f50SJed Brown   }
466ba282f50SJed Brown   va_end(Argp);
467ba282f50SJed Brown   if (petscmalloccoalesce) {
468ba282f50SJed Brown     for (i=0; i<n; i++) {       /* Find first nonempty allocation */
469ba282f50SJed Brown       if (*ptr[i]) break;
470ba282f50SJed Brown     }
471ba282f50SJed Brown     while (--n > i) {
472ba282f50SJed Brown       *ptr[n] = NULL;
473ba282f50SJed Brown     }
474c53cf884SJed Brown     ierr = (*PetscTrFree)(*ptr[n],lineno,function,filename);CHKERRQ(ierr);
475ba282f50SJed Brown     *ptr[n] = NULL;
476ba282f50SJed Brown   } else {
477ba282f50SJed Brown     while (--n >= 0) {
478c53cf884SJed Brown       ierr = (*PetscTrFree)(*ptr[n],lineno,function,filename);CHKERRQ(ierr);
479ba282f50SJed Brown       *ptr[n] = NULL;
480ba282f50SJed Brown     }
481ba282f50SJed Brown   }
482ba282f50SJed Brown   PetscFunctionReturn(0);
483ba282f50SJed Brown }
484