xref: /petsc/src/sys/memory/mal.c (revision ca8c994e11c30d691841512eba3c7759a53135e0)
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*/
6ba282f50SJed Brown #include <stdarg.h>
7e5c89e4eSSatish Balay #if defined(PETSC_HAVE_MALLOC_H)
8e5c89e4eSSatish Balay #include <malloc.h>
9e5c89e4eSSatish Balay #endif
10de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
11*ca8c994eSHong Zhang #include <errno.h>
12de1d6c17SHong Zhang #include <memkind.h>
13e3acc61dSHong Zhang typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType;
14e3acc61dSHong Zhang PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED;
15e3acc61dSHong Zhang PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED;
16de1d6c17SHong Zhang #endif
17e5c89e4eSSatish Balay /*
18e5c89e4eSSatish Balay         We want to make sure that all mallocs of double or complex numbers are complex aligned.
19e5c89e4eSSatish Balay     1) on systems with memalign() we call that routine to get an aligned memory location
20e5c89e4eSSatish Balay     2) on systems without memalign() we
21e5c89e4eSSatish Balay        - allocate one sizeof(PetscScalar) extra space
22e5c89e4eSSatish Balay        - we shift the pointer up slightly if needed to get PetscScalar aligned
230700a824SBarry Smith        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
24e5c89e4eSSatish Balay */
250700a824SBarry Smith #define SHIFT_CLASSID 456123
26e5c89e4eSSatish Balay 
27efca3c55SSatish Balay PetscErrorCode  PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
28e5c89e4eSSatish Balay {
29f0ba7cfcSLisandro Dalcin   if (!mem) { *result = NULL; return 0; }
30fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
31fc2a7144SHong Zhang   {
32fc2a7144SHong Zhang     int ierr;
33fc2a7144SHong Zhang     if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem);
34e3acc61dSHong Zhang     else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem);
35*ca8c994eSHong Zhang     if (ierr == EINVAL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
36*ca8c994eSHong Zhang     if (ierr == ENOMEM) PetscInfo1(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
37fc2a7144SHong Zhang   }
38fc2a7144SHong Zhang #else
39e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
40e5c89e4eSSatish Balay   *result = malloc(mem);
41e5c89e4eSSatish Balay #  elif defined(PETSC_HAVE_MEMALIGN)
42e5c89e4eSSatish Balay   *result = memalign(PETSC_MEMALIGN,mem);
43e5c89e4eSSatish Balay #  else
44e5c89e4eSSatish Balay   {
45e5c89e4eSSatish Balay     /*
46e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
47e5c89e4eSSatish Balay     */
485b232624SHong Zhang     int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
49e5c89e4eSSatish Balay     if (ptr) {
50f0ba7cfcSLisandro Dalcin       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
51e5c89e4eSSatish Balay       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
520700a824SBarry Smith       ptr[shift-1] = shift + SHIFT_CLASSID;
53e5c89e4eSSatish Balay       ptr         += shift;
54e5c89e4eSSatish Balay       *result      = (void*)ptr;
55e5c89e4eSSatish Balay     } else {
56f0ba7cfcSLisandro Dalcin       *result      = NULL;
57e5c89e4eSSatish Balay     }
58e5c89e4eSSatish Balay   }
59e5c89e4eSSatish Balay #  endif
60fc2a7144SHong Zhang #endif
61f0ba7cfcSLisandro Dalcin   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
62e5c89e4eSSatish Balay   return 0;
63e5c89e4eSSatish Balay }
64e5c89e4eSSatish Balay 
65efca3c55SSatish Balay PetscErrorCode  PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
66e5c89e4eSSatish Balay {
67f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
68fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
69fc2a7144SHong Zhang   memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */
70fc2a7144SHong Zhang #else
71e5c89e4eSSatish Balay #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
72f0ba7cfcSLisandro Dalcin   {
73e5c89e4eSSatish Balay     /*
74e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
75e5c89e4eSSatish Balay       the original address provided by the system malloc().
76e5c89e4eSSatish Balay     */
77f0ba7cfcSLisandro Dalcin     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
78efca3c55SSatish 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");
79efca3c55SSatish Balay     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
80e5c89e4eSSatish Balay     ptr = (void*)(((int*)ptr) - shift);
81e5c89e4eSSatish Balay   }
82f0ba7cfcSLisandro Dalcin #  endif
83e5c89e4eSSatish Balay 
84e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_FREE_RETURN_INT)
85e5c89e4eSSatish Balay   int err = free(ptr);
86efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
87e5c89e4eSSatish Balay #  else
88e5c89e4eSSatish Balay   free(ptr);
89e5c89e4eSSatish Balay #  endif
90fc2a7144SHong Zhang #endif
91e5c89e4eSSatish Balay   return 0;
92e5c89e4eSSatish Balay }
93e5c89e4eSSatish Balay 
943221ece2SMatthew G. Knepley PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
953221ece2SMatthew G. Knepley {
96c22f1541SToby Isaac   PetscErrorCode ierr;
97c22f1541SToby Isaac 
98c22f1541SToby Isaac   if (!mem) {
99c22f1541SToby Isaac     ierr = PetscFreeAlign(*result, line, func, file);
100c22f1541SToby Isaac     if (ierr) return ierr;
101c22f1541SToby Isaac     *result = NULL;
102c22f1541SToby Isaac     return 0;
103c22f1541SToby Isaac   }
104fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
105fc2a7144SHong Zhang   if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem);
106e3acc61dSHong Zhang   else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem);
107fc2a7144SHong Zhang #else
1083221ece2SMatthew G. Knepley #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
1093221ece2SMatthew G. Knepley   {
1103221ece2SMatthew G. Knepley     /*
1113221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
1123221ece2SMatthew G. Knepley       the original address provided by the system malloc().
1133221ece2SMatthew G. Knepley     */
1143221ece2SMatthew G. Knepley     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
1153221ece2SMatthew 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");
1163221ece2SMatthew G. Knepley     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
1173221ece2SMatthew G. Knepley     *result = (void*)(((int*)*result) - shift);
1183221ece2SMatthew G. Knepley   }
1193221ece2SMatthew G. Knepley #  endif
1203221ece2SMatthew G. Knepley 
121c22f1541SToby Isaac #  if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
1223221ece2SMatthew G. Knepley   *result = realloc(*result, mem);
1233221ece2SMatthew G. Knepley #  else
1243221ece2SMatthew G. Knepley   {
1253221ece2SMatthew G. Knepley     /*
1263221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1273221ece2SMatthew G. Knepley     */
1283221ece2SMatthew G. Knepley     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
1293221ece2SMatthew G. Knepley     if (ptr) {
1303221ece2SMatthew G. Knepley       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
1313221ece2SMatthew G. Knepley       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
1323221ece2SMatthew G. Knepley       ptr[shift-1] = shift + SHIFT_CLASSID;
1333221ece2SMatthew G. Knepley       ptr         += shift;
1343221ece2SMatthew G. Knepley       *result      = (void*)ptr;
1353221ece2SMatthew G. Knepley     } else {
1363221ece2SMatthew G. Knepley       *result      = NULL;
1373221ece2SMatthew G. Knepley     }
1383221ece2SMatthew G. Knepley   }
1393221ece2SMatthew G. Knepley #  endif
140fc2a7144SHong Zhang #endif
1413221ece2SMatthew G. Knepley   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
142c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN)
143c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
144c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
145c22f1541SToby Isaac   if (((size_t) (*result)) % PETSC_MEMALIGN) {
146c22f1541SToby Isaac     void *newResult;
147fc2a7144SHong Zhang #  if defined(PETSC_HAVE_MEMKIND)
148fc2a7144SHong Zhang     {
149fc2a7144SHong Zhang       int ierr;
150fc2a7144SHong Zhang       if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem);
151e3acc61dSHong Zhang       else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem);
152*ca8c994eSHong Zhang       if (ierr == EINVAL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
153*ca8c994eSHong Zhang       if (ierr == ENOMEM) PetscInfo1(0,"Memkind: fail to request HBW memory %.0f, falling back to normal memory\n",(PetscLogDouble)mem);
154fc2a7144SHong Zhang     }
155fc2a7144SHong Zhang #  else
156c22f1541SToby Isaac     newResult = memalign(PETSC_MEMALIGN,mem);
157fc2a7144SHong Zhang #  endif
158c22f1541SToby Isaac     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
159c22f1541SToby Isaac     ierr = PetscMemcpy(newResult,*result,mem);
160c22f1541SToby Isaac     if (ierr) return ierr;
161c22f1541SToby Isaac #  if defined(PETSC_HAVE_FREE_RETURN_INT)
162c22f1541SToby Isaac     {
163c22f1541SToby Isaac       int err = free(*result);
164c22f1541SToby Isaac       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
165c22f1541SToby Isaac     }
166c22f1541SToby Isaac #  else
167de1d6c17SHong Zhang #    if defined(PETSC_HAVE_MEMKIND)
168de1d6c17SHong Zhang     memkind_free(0,*result);
169de1d6c17SHong Zhang #    else
170c22f1541SToby Isaac     free(*result);
171c22f1541SToby Isaac #    endif
172de1d6c17SHong Zhang #  endif
173c22f1541SToby Isaac     *result = newResult;
174c22f1541SToby Isaac   }
175c22f1541SToby Isaac #endif
1763221ece2SMatthew G. Knepley   return 0;
1773221ece2SMatthew G. Knepley }
1783221ece2SMatthew G. Knepley 
179efca3c55SSatish Balay PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
180efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
1813221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign;
182e5c89e4eSSatish Balay 
183ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE;
184e5c89e4eSSatish Balay 
185e5c89e4eSSatish Balay /*@C
1861d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
187e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
188e5c89e4eSSatish Balay    called only once.
189e5c89e4eSSatish Balay 
190e5c89e4eSSatish Balay    Not Collective
191e5c89e4eSSatish Balay 
192e5c89e4eSSatish Balay    Input Parameters:
193e5c89e4eSSatish Balay +  malloc - the malloc routine
194e5c89e4eSSatish Balay -  free - the free routine
195e5c89e4eSSatish Balay 
196e5c89e4eSSatish Balay    Level: developer
197e5c89e4eSSatish Balay 
198e5c89e4eSSatish Balay    Concepts: malloc
199e5c89e4eSSatish Balay    Concepts: memory^allocation
200e5c89e4eSSatish Balay 
201e5c89e4eSSatish Balay @*/
202efca3c55SSatish Balay PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
203efca3c55SSatish Balay                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
204e5c89e4eSSatish Balay {
205e5c89e4eSSatish Balay   PetscFunctionBegin;
206e32f2f54SBarry Smith   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
207e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
208e5c89e4eSSatish Balay   PetscTrFree           = ifree;
209e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
210e5c89e4eSSatish Balay   PetscFunctionReturn(0);
211e5c89e4eSSatish Balay }
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay /*@C
2141d1a0024SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the
215e5c89e4eSSatish Balay         defaults.
216e5c89e4eSSatish Balay 
217e5c89e4eSSatish Balay    Not Collective
218e5c89e4eSSatish Balay 
219e5c89e4eSSatish Balay    Level: developer
220e5c89e4eSSatish Balay 
221e5c89e4eSSatish Balay    Notes:
222e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
223e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
224e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
225e5c89e4eSSatish Balay 
226e5c89e4eSSatish Balay @*/
2277087cfbeSBarry Smith PetscErrorCode  PetscMallocClear(void)
228e5c89e4eSSatish Balay {
229e5c89e4eSSatish Balay   PetscFunctionBegin;
230e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
231e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
232e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
233e5c89e4eSSatish Balay   PetscFunctionReturn(0);
234e5c89e4eSSatish Balay }
235b44d5720SBarry Smith 
236b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[])
237b44d5720SBarry Smith {
238b44d5720SBarry Smith   PetscErrorCode        ierr;
239b44d5720SBarry Smith   PetscLogDouble        mem,mal;
240b44d5720SBarry Smith   static PetscLogDouble oldmem = 0,oldmal = 0;
241b44d5720SBarry Smith 
242b44d5720SBarry Smith   PetscFunctionBegin;
243b44d5720SBarry Smith   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
244b44d5720SBarry Smith   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
245b44d5720SBarry Smith 
246b44d5720SBarry 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);
247b44d5720SBarry Smith   oldmem = mem;
248b44d5720SBarry Smith   oldmal = mal;
249b44d5720SBarry Smith   PetscFunctionReturn(0);
250b44d5720SBarry Smith }
25113850c04SHong Zhang 
25250a41461SHong Zhang static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
25350a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[])           = PetscFreeAlign;
254de1d6c17SHong Zhang 
255de1d6c17SHong Zhang /*@C
256de1d6c17SHong Zhang    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
257de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
258de1d6c17SHong Zhang      current malloc and free routines to the PetscMallocAlign and
259de1d6c17SHong Zhang      PetscFreeAlign (PETSc default).
260de1d6c17SHong Zhang 
261de1d6c17SHong Zhang    Not Collective
262de1d6c17SHong Zhang 
263de1d6c17SHong Zhang    Level: developer
264de1d6c17SHong Zhang 
265de1d6c17SHong Zhang    Notes:
266de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
267de1d6c17SHong Zhang      can switch back to the previous choice by calling PetscMallocReset().
268de1d6c17SHong Zhang 
269de1d6c17SHong Zhang .seealso: PetscMallocReset()
270de1d6c17SHong Zhang @*/
27113850c04SHong Zhang PetscErrorCode PetscMallocSetDRAM(void)
27213850c04SHong Zhang {
27313850c04SHong Zhang   PetscFunctionBegin;
274de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
275de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
276de1d6c17SHong Zhang     previousmktype = currentmktype;
277de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
278de1d6c17SHong Zhang #endif
279de1d6c17SHong Zhang   } else {
28013850c04SHong Zhang     /* Save the previous choice */
28113850c04SHong Zhang     PetscTrMallocOld = PetscTrMalloc;
28213850c04SHong Zhang     PetscTrFreeOld   = PetscTrFree;
28313850c04SHong Zhang     PetscTrMalloc    = PetscMallocAlign;
28413850c04SHong Zhang     PetscTrFree      = PetscFreeAlign;
285de1d6c17SHong Zhang   }
28613850c04SHong Zhang   PetscFunctionReturn(0);
28713850c04SHong Zhang }
28813850c04SHong Zhang 
289de1d6c17SHong Zhang /*@C
290de1d6c17SHong Zhang    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM
291de1d6c17SHong Zhang 
292de1d6c17SHong Zhang    Not Collective
293de1d6c17SHong Zhang 
294de1d6c17SHong Zhang    Level: developer
295de1d6c17SHong Zhang 
296de1d6c17SHong Zhang .seealso: PetscMallocSetDRAM()
297de1d6c17SHong Zhang @*/
29813850c04SHong Zhang PetscErrorCode PetscMallocResetDRAM(void)
29913850c04SHong Zhang {
30013850c04SHong Zhang   PetscFunctionBegin;
301de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
302de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
303de1d6c17SHong Zhang     currentmktype = previousmktype;
304de1d6c17SHong Zhang #endif
305de1d6c17SHong Zhang   } else {
30613850c04SHong Zhang     /* Reset to the previous choice */
30713850c04SHong Zhang     PetscTrMalloc = PetscTrMallocOld;
30813850c04SHong Zhang     PetscTrFree   = PetscTrFreeOld;
309de1d6c17SHong Zhang   }
31013850c04SHong Zhang   PetscFunctionReturn(0);
31113850c04SHong Zhang }
312ba282f50SJed Brown 
313ba282f50SJed Brown static PetscBool petscmalloccoalesce =
314ba282f50SJed Brown #if defined(PETSC_USE_MALLOC_COALESCED)
315ba282f50SJed Brown   PETSC_TRUE;
316ba282f50SJed Brown #else
317ba282f50SJed Brown   PETSC_FALSE;
318ba282f50SJed Brown #endif
319ba282f50SJed Brown 
320ba282f50SJed Brown /*@C
321ba282f50SJed Brown    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects
322ba282f50SJed Brown 
323ba282f50SJed Brown    Not Collective
324ba282f50SJed Brown 
325ba282f50SJed Brown    Input Parameters:
326ba282f50SJed Brown .  coalesce - PETSC_TRUE to use coalesced malloc for multi-object allocation.
327ba282f50SJed Brown 
328ba282f50SJed Brown    Options Database Keys:
329ba282f50SJed Brown .  -malloc_coalesce - turn coalesced malloc on or off
330ba282f50SJed Brown 
331ba282f50SJed Brown    Note:
332ba282f50SJed 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.
333ba282f50SJed Brown 
334ba282f50SJed Brown    Level: developer
335ba282f50SJed Brown 
336ba282f50SJed Brown .seealso: PetscMallocA()
337ba282f50SJed Brown @*/
338ba282f50SJed Brown PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce)
339ba282f50SJed Brown {
340ba282f50SJed Brown   PetscFunctionBegin;
341ba282f50SJed Brown   petscmalloccoalesce = coalesce;
342ba282f50SJed Brown   PetscFunctionReturn(0);
343ba282f50SJed Brown }
344ba282f50SJed Brown 
345ba282f50SJed Brown /*@C
346ba282f50SJed Brown    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc
347ba282f50SJed Brown 
348ba282f50SJed Brown    Not Collective
349ba282f50SJed Brown 
350ba282f50SJed Brown    Input Parameters:
351ba282f50SJed Brown +  n - number of objects to allocate (at least 1)
352ba282f50SJed Brown .  lineno - line number to attribute allocation (typically __LINE__)
353ba282f50SJed Brown .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
354ba282f50SJed Brown .  filename - file name to attribute allocation (typically __FILE__)
355ba282f50SJed Brown -  bytes0 - first of n object sizes
356ba282f50SJed Brown 
357ba282f50SJed Brown    Output Parameters:
358ba282f50SJed Brown .  ptr0 - first of n pointers to allocate
359ba282f50SJed Brown 
360ba282f50SJed Brown    Notes:
361ba282f50SJed Brown    This function is not normally called directly by users, but rather via the macros PetscMalloc1(), PetscMalloc2(), or PetscCalloc1(), etc.
362ba282f50SJed Brown 
363ba282f50SJed Brown    Level: developer
364ba282f50SJed Brown 
365ba282f50SJed Brown .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMalloc1(), PetscMalloc2(), PetscMalloc3(), PetscMalloc4(), PetscMalloc5(), PetscMalloc6(), PetscMalloc7(), PetscCalloc1(), PetscCalloc2(), PetscCalloc3(), PetscCalloc4(), PetscCalloc5(), PetscCalloc6(), PetscCalloc7(), PetscFreeA()
366ba282f50SJed Brown @*/
367ba282f50SJed Brown PetscErrorCode PetscMallocA(int n,PetscBool clear,int lineno,const char *function,const char *filename,size_t bytes0,void *ptr0,...)
368ba282f50SJed Brown {
369ba282f50SJed Brown   PetscErrorCode ierr;
370ba282f50SJed Brown   va_list Argp;
371ba282f50SJed Brown   size_t bytes[8],sumbytes;
372ba282f50SJed Brown   void **ptr[8];
373ba282f50SJed Brown   int i;
374ba282f50SJed Brown 
375ba282f50SJed Brown   PetscFunctionBegin;
376ba282f50SJed Brown   if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n);
377ba282f50SJed Brown   bytes[0] = bytes0;
378ba282f50SJed Brown   ptr[0] = (void**)ptr0;
379ba282f50SJed Brown   sumbytes = (bytes0 + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
380ba282f50SJed Brown   va_start(Argp,ptr0);
381ba282f50SJed Brown   for (i=1; i<n; i++) {
382ba282f50SJed Brown     bytes[i] = va_arg(Argp,size_t);
383ba282f50SJed Brown     ptr[i] = va_arg(Argp,void**);
384ba282f50SJed Brown     sumbytes += (bytes[i] + PETSC_MEMALIGN-1) & ~(PETSC_MEMALIGN-1);
385ba282f50SJed Brown   }
386ba282f50SJed Brown   va_end(Argp);
387ba282f50SJed Brown   if (petscmalloccoalesce) {
388ba282f50SJed Brown     char *p;
389ba282f50SJed Brown     ierr = (*PetscTrMalloc)(sumbytes,lineno,function,filename,(void**)&p);CHKERRQ(ierr);
390ba282f50SJed Brown     for (i=0; i<n; i++) {
391ba282f50SJed Brown       *ptr[i] = bytes[i] ? p : NULL;
392ba282f50SJed Brown       p = (char*)PetscAddrAlign(p + bytes[i]);
393ba282f50SJed Brown     }
394ba282f50SJed Brown   } else {
395ba282f50SJed Brown     for (i=0; i<n; i++) {
396ba282f50SJed Brown       ierr = (*PetscTrMalloc)(bytes[i],lineno,function,filename,(void**)ptr[i]);CHKERRQ(ierr);
397ba282f50SJed Brown     }
398ba282f50SJed Brown   }
399ba282f50SJed Brown   if (clear) {
400ba282f50SJed Brown     for (i=0; i<n; i++) {
401ba282f50SJed Brown       ierr = PetscMemzero(*ptr[i],bytes[i]);CHKERRQ(ierr);
402ba282f50SJed Brown     }
403ba282f50SJed Brown   }
404ba282f50SJed Brown   PetscFunctionReturn(0);
405ba282f50SJed Brown }
406ba282f50SJed Brown 
407ba282f50SJed Brown /*@C
408ba282f50SJed Brown    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc
409ba282f50SJed Brown 
410ba282f50SJed Brown    Not Collective
411ba282f50SJed Brown 
412ba282f50SJed Brown    Input Parameters:
413ba282f50SJed Brown +  n - number of objects to free (at least 1)
414ba282f50SJed Brown .  lineno - line number to attribute deallocation (typically __LINE__)
415ba282f50SJed Brown .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
416ba282f50SJed Brown .  filename - file name to attribute deallocation (typically __FILE__)
417ba282f50SJed Brown -  ptr0 ... - first of n pointers to free
418ba282f50SJed Brown 
419ba282f50SJed Brown    Note:
420ba282f50SJed Brown    This function is not normally called directly by users, but rather via the macros PetscFree1(), PetscFree2(), etc.
421ba282f50SJed Brown 
422ba282f50SJed Brown    Level: developer
423ba282f50SJed Brown 
424ba282f50SJed Brown .seealso: PetscMallocAlign(), PetscMallocSet(), PetscMallocA(), PetscFree1(), PetscFree2(), PetscFree3(), PetscFree4(), PetscFree5(), PetscFree6(), PetscFree7()
425ba282f50SJed Brown @*/
426ba282f50SJed Brown PetscErrorCode PetscFreeA(int n,int lineno,const char *function,const char *filename,void *ptr0,...)
427ba282f50SJed Brown {
428ba282f50SJed Brown   PetscErrorCode ierr;
429ba282f50SJed Brown   va_list Argp;
430ba282f50SJed Brown   void **ptr[8];
431ba282f50SJed Brown   int i;
432ba282f50SJed Brown 
433ba282f50SJed Brown   PetscFunctionBegin;
434ba282f50SJed Brown   if (n > 8) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Attempt to allocate %d objects but only 8 supported",n);
435ba282f50SJed Brown   ptr[0] = (void**)ptr0;
436ba282f50SJed Brown   va_start(Argp,ptr0);
437ba282f50SJed Brown   for (i=1; i<n; i++) {
438ba282f50SJed Brown     ptr[i] = va_arg(Argp,void**);
439ba282f50SJed Brown   }
440ba282f50SJed Brown   va_end(Argp);
441ba282f50SJed Brown   if (petscmalloccoalesce) {
442ba282f50SJed Brown     for (i=0; i<n; i++) {       /* Find first nonempty allocation */
443ba282f50SJed Brown       if (*ptr[i]) break;
444ba282f50SJed Brown     }
445ba282f50SJed Brown     while (--n > i) {
446ba282f50SJed Brown       *ptr[n] = NULL;
447ba282f50SJed Brown     }
448c53cf884SJed Brown     ierr = (*PetscTrFree)(*ptr[n],lineno,function,filename);CHKERRQ(ierr);
449ba282f50SJed Brown     *ptr[n] = NULL;
450ba282f50SJed Brown   } else {
451ba282f50SJed Brown     while (--n >= 0) {
452c53cf884SJed Brown       ierr = (*PetscTrFree)(*ptr[n],lineno,function,filename);CHKERRQ(ierr);
453ba282f50SJed Brown       *ptr[n] = NULL;
454ba282f50SJed Brown     }
455ba282f50SJed Brown   }
456ba282f50SJed Brown   PetscFunctionReturn(0);
457ba282f50SJed Brown }
458