xref: /petsc/src/sys/memory/mal.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1e5c89e4eSSatish Balay /*
2e5c89e4eSSatish Balay     Code that allows a user to dictate what malloc() PETSc uses.
3e5c89e4eSSatish Balay */
4d7976ebaSJed Brown #define PETSC_DESIRE_FEATURE_TEST_MACROS /* for posix_memalign() */
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)
11ca8c994eSHong Zhang   #include <errno.h>
12de1d6c17SHong Zhang   #include <memkind.h>
139371c9d4SSatish Balay typedef enum {
149371c9d4SSatish Balay   PETSC_MK_DEFAULT       = 0,
159371c9d4SSatish Balay   PETSC_MK_HBW_PREFERRED = 1
169371c9d4SSatish Balay } PetscMemkindType;
17e3acc61dSHong Zhang PetscMemkindType currentmktype  = PETSC_MK_HBW_PREFERRED;
18e3acc61dSHong Zhang PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED;
19de1d6c17SHong Zhang #endif
20e5c89e4eSSatish Balay /*
21e5c89e4eSSatish Balay         We want to make sure that all mallocs of double or complex numbers are complex aligned.
22e5c89e4eSSatish Balay     1) on systems with memalign() we call that routine to get an aligned memory location
23e5c89e4eSSatish Balay     2) on systems without memalign() we
24e5c89e4eSSatish Balay        - allocate one sizeof(PetscScalar) extra space
25e5c89e4eSSatish Balay        - we shift the pointer up slightly if needed to get PetscScalar aligned
260700a824SBarry Smith        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
27e5c89e4eSSatish Balay */
280700a824SBarry Smith #define SHIFT_CLASSID 456123
29e5c89e4eSSatish Balay 
30*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t mem, PetscBool clear, int line, const char func[], const char file[], void **result)
31*d71ae5a4SJacob Faibussowitsch {
329371c9d4SSatish Balay   if (!mem) {
339371c9d4SSatish Balay     *result = NULL;
349371c9d4SSatish Balay     return 0;
359371c9d4SSatish Balay   }
367f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
37fc2a7144SHong Zhang   {
387f18b027SJacob Faibussowitsch     int err;
397f18b027SJacob Faibussowitsch 
407f18b027SJacob Faibussowitsch     err = memkind_posix_memalign(currentmktype ? MEMKIND_HBW_PREFERRED : MEMKIND_DEFAULT, result, PETSC_MEMALIGN, mem);
417f18b027SJacob Faibussowitsch     PetscCheck(err != EINVAL, PETSC_COMM_SELF, PETSC_ERR_MEM, "Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
427f18b027SJacob Faibussowitsch     if (err == ENOMEM) PetscInfo(NULL, "Memkind: fail to request HBW memory %.0f, falling back to normal memory\n", (PetscLogDouble)mem);
437f18b027SJacob Faibussowitsch     PetscCheck(*result, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
449566063dSJacob Faibussowitsch     if (clear) PetscCall(PetscMemzero(*result, mem));
45fc2a7144SHong Zhang   }
467f18b027SJacob Faibussowitsch #else /* PetscDefined(HAVE_MEMKIND) */
477f18b027SJacob Faibussowitsch   #if PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
487f18b027SJacob Faibussowitsch   if (clear) *result = calloc(1 + mem / sizeof(int), sizeof(int));
497f18b027SJacob Faibussowitsch   else *result = malloc(mem);
507f18b027SJacob Faibussowitsch 
517f18b027SJacob Faibussowitsch   PetscCheck(*result, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
529566063dSJacob Faibussowitsch   if (PetscLogMemory) PetscCall(PetscMemzero(*result, mem));
53d7976ebaSJed Brown   #elif PetscDefined(HAVE_POSIX_MEMALIGN)
54d7976ebaSJed Brown   int ret = posix_memalign(result, PETSC_MEMALIGN, mem);
55d7976ebaSJed Brown   PetscCheck(ret == 0, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
567f18b027SJacob Faibussowitsch   if (clear || PetscLogMemory) PetscCall(PetscMemzero(*result, mem));
57d7976ebaSJed Brown   #else  /* PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) || PetscDefined(HAVE_POSIX_MEMALIGN) */
58e5c89e4eSSatish Balay   {
5966c772faSBarry Smith     int *ptr, shift;
60e5c89e4eSSatish Balay     /*
61e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
62e5c89e4eSSatish Balay     */
63071fcb05SBarry Smith     if (clear) {
64071fcb05SBarry Smith       ptr = (int *)calloc(1 + (mem + 2 * PETSC_MEMALIGN) / sizeof(int), sizeof(int));
65071fcb05SBarry Smith     } else {
66071fcb05SBarry Smith       ptr = (int *)malloc(mem + 2 * PETSC_MEMALIGN);
67071fcb05SBarry Smith     }
687f18b027SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
6966c772faSBarry Smith     shift          = (int)(((PETSC_UINTPTR_T)ptr) % PETSC_MEMALIGN);
70e5c89e4eSSatish Balay     shift          = (2 * PETSC_MEMALIGN - shift) / sizeof(int);
710700a824SBarry Smith     ptr[shift - 1] = shift + SHIFT_CLASSID;
72e5c89e4eSSatish Balay     ptr += shift;
73e5c89e4eSSatish Balay     *result = (void *)ptr;
749566063dSJacob Faibussowitsch     if (PetscLogMemory) PetscCall(PetscMemzero(*result, mem));
75e5c89e4eSSatish Balay   }
76d7976ebaSJed Brown   #endif /* PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) || PetscDefined(HAVE_POSIX_MEMALIGN) */
777f18b027SJacob Faibussowitsch #endif   /* PetscDefined(HAVE_MEMKIND) */
78e5c89e4eSSatish Balay   return 0;
79e5c89e4eSSatish Balay }
80e5c89e4eSSatish Balay 
81*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscFreeAlign(void *ptr, int line, const char func[], const char file[])
82*d71ae5a4SJacob Faibussowitsch {
83f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
847f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
85fc2a7144SHong Zhang   memkind_free(0, ptr); /* specify the kind to 0 so that memkind will look up for the right type */
867f18b027SJacob Faibussowitsch #else                   /* PetscDefined(HAVE_MEMKIND) */
87d7976ebaSJed Brown   #if (!(PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !PetscDefined(HAVE_POSIX_MEMALIGN))
88f0ba7cfcSLisandro Dalcin   {
89e5c89e4eSSatish Balay     /*
90e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
91e5c89e4eSSatish Balay       the original address provided by the system malloc().
92e5c89e4eSSatish Balay     */
937f18b027SJacob Faibussowitsch     const int shift = *(((int *)ptr) - 1) - SHIFT_CLASSID;
947f18b027SJacob Faibussowitsch 
957f18b027SJacob Faibussowitsch     PetscCheck(shift <= PETSC_MEMALIGN - 1, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
967f18b027SJacob Faibussowitsch     PetscCheck(shift >= 0, 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 
1017f18b027SJacob Faibussowitsch   #if PetscDefined(HAVE_FREE_RETURN_INT)
102e5c89e4eSSatish Balay   int err = free(ptr);
1037f18b027SJacob Faibussowitsch   PetscCheck(!err, 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 
111*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
112*d71ae5a4SJacob Faibussowitsch {
113c22f1541SToby Isaac   if (!mem) {
1147f18b027SJacob Faibussowitsch     PetscCall(PetscFreeAlign(*result, line, func, file));
115c22f1541SToby Isaac     *result = NULL;
116c22f1541SToby Isaac     return 0;
117c22f1541SToby Isaac   }
1187f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
1197f18b027SJacob Faibussowitsch   *result = memkind_realloc(currentmktype ? MEMKIND_HBW_PREFERRED : MEMKIND_DEFAULT, *result, mem);
120fc2a7144SHong Zhang #else
121d7976ebaSJed Brown   #if (!(PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !PetscDefined(HAVE_POSIX_MEMALIGN))
1223221ece2SMatthew G. Knepley   {
1233221ece2SMatthew G. Knepley     /*
1243221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
1253221ece2SMatthew G. Knepley       the original address provided by the system malloc().
1263221ece2SMatthew G. Knepley     */
1273221ece2SMatthew G. Knepley     int shift = *(((int *)*result) - 1) - SHIFT_CLASSID;
1287f18b027SJacob Faibussowitsch     PetscCheck(shift <= PETSC_MEMALIGN - 1, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
1297f18b027SJacob Faibussowitsch     PetscCheck(shift >= 0, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
1303221ece2SMatthew G. Knepley     *result = (void *)(((int *)*result) - shift);
1313221ece2SMatthew G. Knepley   }
1323221ece2SMatthew G. Knepley   #endif
1333221ece2SMatthew G. Knepley 
134d7976ebaSJed Brown   #if (PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || PetscDefined(HAVE_POSIX_MEMALIGN)
13541605b92SBarry Smith   *result = realloc(*result, mem);
1363221ece2SMatthew G. Knepley   #else
1373221ece2SMatthew G. Knepley   {
1383221ece2SMatthew G. Knepley     /*
1393221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1403221ece2SMatthew G. Knepley     */
1413221ece2SMatthew G. Knepley     int *ptr = (int *)realloc(*result, mem + 2 * PETSC_MEMALIGN);
1423221ece2SMatthew G. Knepley     if (ptr) {
1433221ece2SMatthew G. Knepley       int shift      = (int)(((PETSC_UINTPTR_T)ptr) % PETSC_MEMALIGN);
1443221ece2SMatthew G. Knepley       shift          = (2 * PETSC_MEMALIGN - shift) / sizeof(int);
1453221ece2SMatthew G. Knepley       ptr[shift - 1] = shift + SHIFT_CLASSID;
1463221ece2SMatthew G. Knepley       ptr += shift;
1473221ece2SMatthew G. Knepley       *result = (void *)ptr;
1483221ece2SMatthew G. Knepley     } else {
1493221ece2SMatthew G. Knepley       *result = NULL;
1503221ece2SMatthew G. Knepley     }
1513221ece2SMatthew G. Knepley   }
1523221ece2SMatthew G. Knepley   #endif
153fc2a7144SHong Zhang #endif
1547f18b027SJacob Faibussowitsch   PetscCheck(*result, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
155d7976ebaSJed Brown #if PetscDefined(HAVE_POSIX_MEMALIGN)
156c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
157c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
158c22f1541SToby Isaac   if (((size_t)(*result)) % PETSC_MEMALIGN) {
159c22f1541SToby Isaac     void *newResult;
1607f18b027SJacob Faibussowitsch   #if PetscDefined(HAVE_MEMKIND)
161fc2a7144SHong Zhang     {
1622da392ccSBarry Smith       int err;
1637f18b027SJacob Faibussowitsch       err = memkind_posix_memalign(currentmktype ? MEMKIND_HBW_PREFERRED : MEMKIND_DEFAULT, &newResult, PETSC_MEMALIGN, mem);
1647f18b027SJacob Faibussowitsch       PetscCheck(err != EINVAL, PETSC_COMM_SELF, PETSC_ERR_MEM, "Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
1657f18b027SJacob Faibussowitsch       if (err == ENOMEM) PetscInfo(NULL, "Memkind: fail to request HBW memory %.0f, falling back to normal memory\n", (PetscLogDouble)mem);
166fc2a7144SHong Zhang     }
1677f18b027SJacob Faibussowitsch     PetscCheck(newResult, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
168d7976ebaSJed Brown   #else
169d7976ebaSJed Brown     PetscCheck(posix_memalign(&newResult, PETSC_MEMALIGN, mem) == 0, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
170d7976ebaSJed Brown   #endif
1717f18b027SJacob Faibussowitsch     PetscCall(PetscMemcpy(newResult, *result, mem));
1727f18b027SJacob Faibussowitsch   #if PetscDefined(HAVE_FREE_RETURN_INT)
173c22f1541SToby Isaac     {
174c22f1541SToby Isaac       int err = free(*result);
1757f18b027SJacob Faibussowitsch       PetscCheck(!err, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "System free returned error %d\n", err);
176c22f1541SToby Isaac     }
177c22f1541SToby Isaac   #else
178de1d6c17SHong Zhang     #if defined(PETSC_HAVE_MEMKIND)
179de1d6c17SHong Zhang     memkind_free(0, *result);
180de1d6c17SHong Zhang     #else
181c22f1541SToby Isaac     free(*result);
182c22f1541SToby Isaac     #endif
183de1d6c17SHong Zhang   #endif
184c22f1541SToby Isaac     *result = newResult;
185c22f1541SToby Isaac   }
186c22f1541SToby Isaac #endif
1873221ece2SMatthew G. Knepley   return 0;
1883221ece2SMatthew G. Knepley }
1893221ece2SMatthew G. Knepley 
190071fcb05SBarry Smith PetscErrorCode (*PetscTrMalloc)(size_t, PetscBool, int, const char[], const char[], void **) = PetscMallocAlign;
191efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void *, int, const char[], const char[])                       = PetscFreeAlign;
1923221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t, int, const char[], const char[], void **)           = PetscReallocAlign;
193e5c89e4eSSatish Balay 
19495c0884eSLisandro Dalcin PETSC_INTERN PetscBool petscsetmallocvisited;
195ace3abfcSBarry Smith PetscBool              petscsetmallocvisited = PETSC_FALSE;
196e5c89e4eSSatish Balay 
197e5c89e4eSSatish Balay /*@C
1981d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
199811af0c4SBarry Smith    This routine MUST be called before `PetscInitialize()` and may be
200e5c89e4eSSatish Balay    called only once.
201e5c89e4eSSatish Balay 
202e5c89e4eSSatish Balay    Not Collective
203e5c89e4eSSatish Balay 
204e5c89e4eSSatish Balay    Input Parameters:
20592f119d6SBarry Smith +  imalloc - the routine that provides the malloc (also provides calloc(), which is used depends on the second argument)
20692f119d6SBarry Smith .  ifree - the routine that provides the free
20792f119d6SBarry Smith -  iralloc - the routine that provides the realloc
208e5c89e4eSSatish Balay 
209e5c89e4eSSatish Balay    Level: developer
210e5c89e4eSSatish Balay 
211811af0c4SBarry Smith .seealso: `PetscMallocClear()`
212e5c89e4eSSatish Balay @*/
213*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMallocSet(PetscErrorCode (*imalloc)(size_t, PetscBool, int, const char[], const char[], void **), PetscErrorCode (*ifree)(void *, int, const char[], const char[]), PetscErrorCode (*iralloc)(size_t, int, const char[], const char[], void **))
214*d71ae5a4SJacob Faibussowitsch {
215e5c89e4eSSatish Balay   PetscFunctionBegin;
21608401ef6SPierre Jolivet   PetscCheck(!petscsetmallocvisited || !(imalloc != PetscTrMalloc || ifree != PetscTrFree), PETSC_COMM_SELF, PETSC_ERR_SUP, "cannot call multiple times");
217e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
218e5c89e4eSSatish Balay   PetscTrFree           = ifree;
21992f119d6SBarry Smith   PetscTrRealloc        = iralloc;
220e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
221e5c89e4eSSatish Balay   PetscFunctionReturn(0);
222e5c89e4eSSatish Balay }
223e5c89e4eSSatish Balay 
224e5c89e4eSSatish Balay /*@C
22592f119d6SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the defaults.
226e5c89e4eSSatish Balay 
227e5c89e4eSSatish Balay    Not Collective
228e5c89e4eSSatish Balay 
229e5c89e4eSSatish Balay    Level: developer
230e5c89e4eSSatish Balay 
231811af0c4SBarry Smith    Note:
232e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
233e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
234e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
235e5c89e4eSSatish Balay 
236811af0c4SBarry Smith     Called in `PetscFinalize()` so that if `PetscInitialize()` is called again it starts with a fresh slate of allocation information
23792f119d6SBarry Smith 
238811af0c4SBarry Smith .seealso: `PetscMallocSet`
239e5c89e4eSSatish Balay @*/
240*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMallocClear(void)
241*d71ae5a4SJacob Faibussowitsch {
242e5c89e4eSSatish Balay   PetscFunctionBegin;
243e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
244e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
24592f119d6SBarry Smith   PetscTrRealloc        = PetscReallocAlign;
246e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
247e5c89e4eSSatish Balay   PetscFunctionReturn(0);
248e5c89e4eSSatish Balay }
249b44d5720SBarry Smith 
250*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMemoryTrace(const char label[])
251*d71ae5a4SJacob Faibussowitsch {
252b44d5720SBarry Smith   PetscLogDouble        mem, mal;
253b44d5720SBarry Smith   static PetscLogDouble oldmem = 0, oldmal = 0;
254b44d5720SBarry Smith 
255b44d5720SBarry Smith   PetscFunctionBegin;
2569566063dSJacob Faibussowitsch   PetscCall(PetscMemoryGetCurrentUsage(&mem));
2579566063dSJacob Faibussowitsch   PetscCall(PetscMallocGetCurrentUsage(&mal));
258b44d5720SBarry Smith 
2599566063dSJacob 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));
260b44d5720SBarry Smith   oldmem = mem;
261b44d5720SBarry Smith   oldmal = mal;
262b44d5720SBarry Smith   PetscFunctionReturn(0);
263b44d5720SBarry Smith }
26413850c04SHong Zhang 
265071fcb05SBarry Smith static PetscErrorCode (*PetscTrMallocOld)(size_t, PetscBool, int, const char[], const char[], void **) = PetscMallocAlign;
26692f119d6SBarry Smith static PetscErrorCode (*PetscTrReallocOld)(size_t, int, const char[], const char[], void **)           = PetscReallocAlign;
26750a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void *, int, const char[], const char[])                       = PetscFreeAlign;
268de1d6c17SHong Zhang 
269de1d6c17SHong Zhang /*@C
270811af0c4SBarry Smith    PetscMallocSetDRAM - Set `PetscMalloc()` to use DRAM.
271de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
272811af0c4SBarry Smith      current malloc and free routines to the `PetscMallocAlign()` and
273811af0c4SBarry Smith      `PetscFreeAlign()` (PETSc default).
274de1d6c17SHong Zhang 
275de1d6c17SHong Zhang    Not Collective
276de1d6c17SHong Zhang 
277de1d6c17SHong Zhang    Level: developer
278de1d6c17SHong Zhang 
279811af0c4SBarry Smith    Note:
280de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
281811af0c4SBarry Smith      can switch back to the previous choice by calling `PetscMallocReset()`.
282de1d6c17SHong Zhang 
283db781477SPatrick Sanan .seealso: `PetscMallocReset()`
284de1d6c17SHong Zhang @*/
285*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMallocSetDRAM(void)
286*d71ae5a4SJacob Faibussowitsch {
28713850c04SHong Zhang   PetscFunctionBegin;
288de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
289de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
290de1d6c17SHong Zhang     previousmktype = currentmktype;
291de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
292de1d6c17SHong Zhang #endif
293de1d6c17SHong Zhang   } else {
29413850c04SHong Zhang     /* Save the previous choice */
29513850c04SHong Zhang     PetscTrMallocOld  = PetscTrMalloc;
29692f119d6SBarry Smith     PetscTrReallocOld = PetscTrRealloc;
29713850c04SHong Zhang     PetscTrFreeOld    = PetscTrFree;
29813850c04SHong Zhang     PetscTrMalloc     = PetscMallocAlign;
29913850c04SHong Zhang     PetscTrFree       = PetscFreeAlign;
30092f119d6SBarry Smith     PetscTrRealloc    = PetscReallocAlign;
301de1d6c17SHong Zhang   }
30213850c04SHong Zhang   PetscFunctionReturn(0);
30313850c04SHong Zhang }
30413850c04SHong Zhang 
305de1d6c17SHong Zhang /*@C
306811af0c4SBarry Smith    PetscMallocResetDRAM - Reset the changes made by `PetscMallocSetDRAM()`
307de1d6c17SHong Zhang 
308de1d6c17SHong Zhang    Not Collective
309de1d6c17SHong Zhang 
310de1d6c17SHong Zhang    Level: developer
311de1d6c17SHong Zhang 
312db781477SPatrick Sanan .seealso: `PetscMallocSetDRAM()`
313de1d6c17SHong Zhang @*/
314*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMallocResetDRAM(void)
315*d71ae5a4SJacob Faibussowitsch {
31613850c04SHong Zhang   PetscFunctionBegin;
317de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
318de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
319de1d6c17SHong Zhang     currentmktype = previousmktype;
320de1d6c17SHong Zhang #endif
321de1d6c17SHong Zhang   } else {
32213850c04SHong Zhang     /* Reset to the previous choice */
32313850c04SHong Zhang     PetscTrMalloc  = PetscTrMallocOld;
32492f119d6SBarry Smith     PetscTrRealloc = PetscTrReallocOld;
32513850c04SHong Zhang     PetscTrFree    = PetscTrFreeOld;
326de1d6c17SHong Zhang   }
32713850c04SHong Zhang   PetscFunctionReturn(0);
32813850c04SHong Zhang }
329ba282f50SJed Brown 
330ba282f50SJed Brown static PetscBool petscmalloccoalesce =
331ba282f50SJed Brown #if defined(PETSC_USE_MALLOC_COALESCED)
332ba282f50SJed Brown   PETSC_TRUE;
333ba282f50SJed Brown #else
334ba282f50SJed Brown   PETSC_FALSE;
335ba282f50SJed Brown #endif
336ba282f50SJed Brown 
337ba282f50SJed Brown /*@C
338ba282f50SJed Brown    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects
339ba282f50SJed Brown 
340ba282f50SJed Brown    Not Collective
341ba282f50SJed Brown 
342ba282f50SJed Brown    Input Parameters:
343811af0c4SBarry Smith .  coalesce - `PETSC_TRUE` to use coalesced malloc for multi-object allocation.
344ba282f50SJed Brown 
345ba282f50SJed Brown    Options Database Keys:
346ba282f50SJed Brown .  -malloc_coalesce - turn coalesced malloc on or off
347ba282f50SJed Brown 
348811af0c4SBarry Smith    Notes:
349811af0c4SBarry Smith    PETSc uses coalesced malloc by default for optimized builds and not for debugging builds.
350811af0c4SBarry Smith 
351811af0c4SBarry Smith    This default can be changed via the command-line option -malloc_coalesce or by calling this function.
352811af0c4SBarry Smith 
353811af0c4SBarry Smith    This function can only be called immediately after `PetscInitialize()`
354ba282f50SJed Brown 
355ba282f50SJed Brown    Level: developer
356ba282f50SJed Brown 
357db781477SPatrick Sanan .seealso: `PetscMallocA()`
358ba282f50SJed Brown @*/
359*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce)
360*d71ae5a4SJacob Faibussowitsch {
361ba282f50SJed Brown   PetscFunctionBegin;
362ba282f50SJed Brown   petscmalloccoalesce = coalesce;
363ba282f50SJed Brown   PetscFunctionReturn(0);
364ba282f50SJed Brown }
365ba282f50SJed Brown 
366ba282f50SJed Brown /*@C
367ba282f50SJed Brown    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc
368ba282f50SJed Brown 
369ba282f50SJed Brown    Not Collective
370ba282f50SJed Brown 
371ba282f50SJed Brown    Input Parameters:
372ba282f50SJed Brown +  n - number of objects to allocate (at least 1)
37389407d75SBarry Smith .  clear - use calloc() to allocate space initialized to zero
374ba282f50SJed Brown .  lineno - line number to attribute allocation (typically __LINE__)
375ba282f50SJed Brown .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
376ba282f50SJed Brown .  filename - file name to attribute allocation (typically __FILE__)
377ba282f50SJed Brown -  bytes0 - first of n object sizes
378ba282f50SJed Brown 
379ba282f50SJed Brown    Output Parameters:
380ba282f50SJed Brown .  ptr0 - first of n pointers to allocate
381ba282f50SJed Brown 
382811af0c4SBarry Smith    Notes
383811af0c4SBarry Smith    This function is not normally called directly by users, but rather via the macros `PetscMalloc1()`, `PetscMalloc2()`, or `PetscCalloc1()`, etc.
384ba282f50SJed Brown 
385ba282f50SJed Brown    Level: developer
386ba282f50SJed Brown 
387db781477SPatrick Sanan .seealso: `PetscMallocAlign()`, `PetscMallocSet()`, `PetscMalloc1()`, `PetscMalloc2()`, `PetscMalloc3()`, `PetscMalloc4()`, `PetscMalloc5()`, `PetscMalloc6()`, `PetscMalloc7()`, `PetscCalloc1()`, `PetscCalloc2()`, `PetscCalloc3()`, `PetscCalloc4()`, `PetscCalloc5()`, `PetscCalloc6()`, `PetscCalloc7()`, `PetscFreeA()`
388ba282f50SJed Brown @*/
389*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscMallocA(int n, PetscBool clear, int lineno, const char *function, const char *filename, size_t bytes0, void *ptr0, ...)
390*d71ae5a4SJacob Faibussowitsch {
391ba282f50SJed Brown   va_list Argp;
392ba282f50SJed Brown   size_t  bytes[8], sumbytes;
393ba282f50SJed Brown   void  **ptr[8];
394ba282f50SJed Brown   int     i;
395ba282f50SJed Brown 
396ba282f50SJed Brown   PetscFunctionBegin;
3977f18b027SJacob Faibussowitsch   PetscCheck(n <= 8, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to allocate %d objects but only 8 supported", n);
398ba282f50SJed Brown   bytes[0] = bytes0;
399ba282f50SJed Brown   ptr[0]   = (void **)ptr0;
400ba282f50SJed Brown   sumbytes = (bytes0 + PETSC_MEMALIGN - 1) & ~(PETSC_MEMALIGN - 1);
401ba282f50SJed Brown   va_start(Argp, ptr0);
402ba282f50SJed Brown   for (i = 1; i < n; i++) {
403ba282f50SJed Brown     bytes[i] = va_arg(Argp, size_t);
404ba282f50SJed Brown     ptr[i]   = va_arg(Argp, void **);
405ba282f50SJed Brown     sumbytes += (bytes[i] + PETSC_MEMALIGN - 1) & ~(PETSC_MEMALIGN - 1);
406ba282f50SJed Brown   }
407ba282f50SJed Brown   va_end(Argp);
408ba282f50SJed Brown   if (petscmalloccoalesce) {
409ba282f50SJed Brown     char *p;
4109566063dSJacob Faibussowitsch     PetscCall((*PetscTrMalloc)(sumbytes, clear, lineno, function, filename, (void **)&p));
411640c8569SMatthew Woehlke     if (p == NULL) {
412ad540459SPierre Jolivet       for (i = 0; i < n; i++) *ptr[i] = NULL;
413640c8569SMatthew Woehlke     } else {
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       }
418640c8569SMatthew Woehlke     }
419ba282f50SJed Brown   } else {
42048a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall((*PetscTrMalloc)(bytes[i], clear, lineno, function, filename, (void **)ptr[i]));
421ba282f50SJed Brown   }
422ba282f50SJed Brown   PetscFunctionReturn(0);
423ba282f50SJed Brown }
424ba282f50SJed Brown 
425ba282f50SJed Brown /*@C
426ba282f50SJed Brown    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc
427ba282f50SJed Brown 
428ba282f50SJed Brown    Not Collective
429ba282f50SJed Brown 
430ba282f50SJed Brown    Input Parameters:
431ba282f50SJed Brown +  n - number of objects to free (at least 1)
432ba282f50SJed Brown .  lineno - line number to attribute deallocation (typically __LINE__)
433ba282f50SJed Brown .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
434ba282f50SJed Brown .  filename - file name to attribute deallocation (typically __FILE__)
435ba282f50SJed Brown -  ptr0 ... - first of n pointers to free
436ba282f50SJed Brown 
437811af0c4SBarry Smith    Notes:
438811af0c4SBarry Smith    This function is not normally called directly by users, but rather via the macros `PetscFree()`, `PetscFree2()`, etc.
439ba282f50SJed Brown 
440a5b23f4aSJose E. Roman    The pointers are zeroed to prevent users from accidentally reusing space that has been freed.
44189407d75SBarry Smith 
442ba282f50SJed Brown    Level: developer
443ba282f50SJed Brown 
444db781477SPatrick Sanan .seealso: `PetscMallocAlign()`, `PetscMallocSet()`, `PetscMallocA()`, `PetscFree1()`, `PetscFree2()`, `PetscFree3()`, `PetscFree4()`, `PetscFree5()`, `PetscFree6()`, `PetscFree7()`
445ba282f50SJed Brown @*/
446*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFreeA(int n, int lineno, const char *function, const char *filename, void *ptr0, ...)
447*d71ae5a4SJacob Faibussowitsch {
448ba282f50SJed Brown   va_list Argp;
449ba282f50SJed Brown   void  **ptr[8];
450ba282f50SJed Brown   int     i;
451ba282f50SJed Brown 
452ba282f50SJed Brown   PetscFunctionBegin;
4537f18b027SJacob Faibussowitsch   PetscCheck(n <= 8, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to allocate %d objects but only up to 8 supported", n);
454ba282f50SJed Brown   ptr[0] = (void **)ptr0;
455ba282f50SJed Brown   va_start(Argp, ptr0);
456ad540459SPierre Jolivet   for (i = 1; i < n; i++) ptr[i] = va_arg(Argp, void **);
457ba282f50SJed Brown   va_end(Argp);
458ba282f50SJed Brown   if (petscmalloccoalesce) {
459ba282f50SJed Brown     for (i = 0; i < n; i++) { /* Find first nonempty allocation */
460ba282f50SJed Brown       if (*ptr[i]) break;
461ba282f50SJed Brown     }
462ad540459SPierre Jolivet     while (--n > i) *ptr[n] = NULL;
4639566063dSJacob Faibussowitsch     PetscCall((*PetscTrFree)(*ptr[n], lineno, function, filename));
464ba282f50SJed Brown     *ptr[n] = NULL;
465ba282f50SJed Brown   } else {
466ba282f50SJed Brown     while (--n >= 0) {
4679566063dSJacob Faibussowitsch       PetscCall((*PetscTrFree)(*ptr[n], lineno, function, filename));
468ba282f50SJed Brown       *ptr[n] = NULL;
469ba282f50SJed Brown     }
470ba282f50SJed Brown   }
471ba282f50SJed Brown   PetscFunctionReturn(0);
472ba282f50SJed Brown }
473