xref: /petsc/src/sys/memory/mal.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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 
309371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t mem, PetscBool clear, int line, const char func[], const char file[], void **result) {
319371c9d4SSatish Balay   if (!mem) {
329371c9d4SSatish Balay     *result = NULL;
339371c9d4SSatish Balay     return 0;
349371c9d4SSatish Balay   }
357f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
36fc2a7144SHong Zhang   {
377f18b027SJacob Faibussowitsch     int err;
387f18b027SJacob Faibussowitsch 
397f18b027SJacob Faibussowitsch     err = memkind_posix_memalign(currentmktype ? MEMKIND_HBW_PREFERRED : MEMKIND_DEFAULT, result, PETSC_MEMALIGN, mem);
407f18b027SJacob Faibussowitsch     PetscCheck(err != EINVAL, PETSC_COMM_SELF, PETSC_ERR_MEM, "Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
417f18b027SJacob Faibussowitsch     if (err == ENOMEM) PetscInfo(NULL, "Memkind: fail to request HBW memory %.0f, falling back to normal memory\n", (PetscLogDouble)mem);
427f18b027SJacob Faibussowitsch     PetscCheck(*result, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
439566063dSJacob Faibussowitsch     if (clear) PetscCall(PetscMemzero(*result, mem));
44fc2a7144SHong Zhang   }
457f18b027SJacob Faibussowitsch #else /* PetscDefined(HAVE_MEMKIND) */
467f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
477f18b027SJacob Faibussowitsch   if (clear) *result = calloc(1 + mem / sizeof(int), sizeof(int));
487f18b027SJacob Faibussowitsch   else *result = malloc(mem);
497f18b027SJacob Faibussowitsch 
507f18b027SJacob Faibussowitsch   PetscCheck(*result, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
519566063dSJacob Faibussowitsch   if (PetscLogMemory) PetscCall(PetscMemzero(*result, mem));
52d7976ebaSJed Brown #elif PetscDefined(HAVE_POSIX_MEMALIGN)
53d7976ebaSJed Brown   int ret = posix_memalign(result, PETSC_MEMALIGN, mem);
54d7976ebaSJed Brown   PetscCheck(ret == 0, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
557f18b027SJacob Faibussowitsch   if (clear || PetscLogMemory) PetscCall(PetscMemzero(*result, mem));
56d7976ebaSJed Brown #else  /* PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) || PetscDefined(HAVE_POSIX_MEMALIGN) */
57e5c89e4eSSatish Balay   {
5866c772faSBarry Smith     int *ptr, shift;
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     }
677f18b027SJacob Faibussowitsch     PetscCheck(ptr, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
6866c772faSBarry Smith     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;
739566063dSJacob Faibussowitsch     if (PetscLogMemory) PetscCall(PetscMemzero(*result, mem));
74e5c89e4eSSatish Balay   }
75d7976ebaSJed Brown #endif /* PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) || PetscDefined(HAVE_POSIX_MEMALIGN) */
767f18b027SJacob Faibussowitsch #endif /* PetscDefined(HAVE_MEMKIND) */
77e5c89e4eSSatish Balay   return 0;
78e5c89e4eSSatish Balay }
79e5c89e4eSSatish Balay 
809371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscFreeAlign(void *ptr, int line, const char func[], const char file[]) {
81f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
827f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
83fc2a7144SHong Zhang   memkind_free(0, ptr); /* specify the kind to 0 so that memkind will look up for the right type */
847f18b027SJacob Faibussowitsch #else                   /* PetscDefined(HAVE_MEMKIND) */
85d7976ebaSJed Brown #if (!(PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !PetscDefined(HAVE_POSIX_MEMALIGN))
86f0ba7cfcSLisandro Dalcin   {
87e5c89e4eSSatish Balay     /*
88e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
89e5c89e4eSSatish Balay       the original address provided by the system malloc().
90e5c89e4eSSatish Balay     */
917f18b027SJacob Faibussowitsch     const int shift = *(((int *)ptr) - 1) - SHIFT_CLASSID;
927f18b027SJacob Faibussowitsch 
937f18b027SJacob Faibussowitsch     PetscCheck(shift <= PETSC_MEMALIGN - 1, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
947f18b027SJacob Faibussowitsch     PetscCheck(shift >= 0, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
95e5c89e4eSSatish Balay     ptr = (void *)(((int *)ptr) - shift);
96e5c89e4eSSatish Balay   }
97f0ba7cfcSLisandro Dalcin #endif
98e5c89e4eSSatish Balay 
997f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_FREE_RETURN_INT)
100e5c89e4eSSatish Balay   int err = free(ptr);
1017f18b027SJacob Faibussowitsch   PetscCheck(!err, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "System free returned error %d\n", err);
102e5c89e4eSSatish Balay #else
103e5c89e4eSSatish Balay   free(ptr);
104e5c89e4eSSatish Balay #endif
105fc2a7144SHong Zhang #endif
106e5c89e4eSSatish Balay   return 0;
107e5c89e4eSSatish Balay }
108e5c89e4eSSatish Balay 
1099371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result) {
110c22f1541SToby Isaac   if (!mem) {
1117f18b027SJacob Faibussowitsch     PetscCall(PetscFreeAlign(*result, line, func, file));
112c22f1541SToby Isaac     *result = NULL;
113c22f1541SToby Isaac     return 0;
114c22f1541SToby Isaac   }
1157f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
1167f18b027SJacob Faibussowitsch   *result = memkind_realloc(currentmktype ? MEMKIND_HBW_PREFERRED : MEMKIND_DEFAULT, *result, mem);
117fc2a7144SHong Zhang #else
118d7976ebaSJed Brown #if (!(PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !PetscDefined(HAVE_POSIX_MEMALIGN))
1193221ece2SMatthew G. Knepley   {
1203221ece2SMatthew G. Knepley     /*
1213221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
1223221ece2SMatthew G. Knepley       the original address provided by the system malloc().
1233221ece2SMatthew G. Knepley     */
1243221ece2SMatthew G. Knepley     int shift = *(((int *)*result) - 1) - SHIFT_CLASSID;
1257f18b027SJacob Faibussowitsch     PetscCheck(shift <= PETSC_MEMALIGN - 1, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
1267f18b027SJacob Faibussowitsch     PetscCheck(shift >= 0, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "Likely memory corruption in heap");
1273221ece2SMatthew G. Knepley     *result = (void *)(((int *)*result) - shift);
1283221ece2SMatthew G. Knepley   }
1293221ece2SMatthew G. Knepley #endif
1303221ece2SMatthew G. Knepley 
131d7976ebaSJed Brown #if (PetscDefined(HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || PetscDefined(HAVE_POSIX_MEMALIGN)
13241605b92SBarry Smith   *result = realloc(*result, mem);
1333221ece2SMatthew G. Knepley #else
1343221ece2SMatthew G. Knepley   {
1353221ece2SMatthew G. Knepley     /*
1363221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1373221ece2SMatthew G. Knepley     */
1383221ece2SMatthew G. Knepley     int *ptr = (int *)realloc(*result, mem + 2 * PETSC_MEMALIGN);
1393221ece2SMatthew G. Knepley     if (ptr) {
1403221ece2SMatthew G. Knepley       int shift      = (int)(((PETSC_UINTPTR_T)ptr) % PETSC_MEMALIGN);
1413221ece2SMatthew G. Knepley       shift          = (2 * PETSC_MEMALIGN - shift) / sizeof(int);
1423221ece2SMatthew G. Knepley       ptr[shift - 1] = shift + SHIFT_CLASSID;
1433221ece2SMatthew G. Knepley       ptr += shift;
1443221ece2SMatthew G. Knepley       *result = (void *)ptr;
1453221ece2SMatthew G. Knepley     } else {
1463221ece2SMatthew G. Knepley       *result = NULL;
1473221ece2SMatthew G. Knepley     }
1483221ece2SMatthew G. Knepley   }
1493221ece2SMatthew G. Knepley #endif
150fc2a7144SHong Zhang #endif
1517f18b027SJacob Faibussowitsch   PetscCheck(*result, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
152d7976ebaSJed Brown #if PetscDefined(HAVE_POSIX_MEMALIGN)
153c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
154c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
155c22f1541SToby Isaac   if (((size_t)(*result)) % PETSC_MEMALIGN) {
156c22f1541SToby Isaac     void *newResult;
1577f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_MEMKIND)
158fc2a7144SHong Zhang     {
1592da392ccSBarry Smith       int err;
1607f18b027SJacob Faibussowitsch       err = memkind_posix_memalign(currentmktype ? MEMKIND_HBW_PREFERRED : MEMKIND_DEFAULT, &newResult, PETSC_MEMALIGN, mem);
1617f18b027SJacob Faibussowitsch       PetscCheck(err != EINVAL, PETSC_COMM_SELF, PETSC_ERR_MEM, "Memkind: invalid 3rd or 4th argument of memkind_posix_memalign()");
1627f18b027SJacob Faibussowitsch       if (err == ENOMEM) PetscInfo(NULL, "Memkind: fail to request HBW memory %.0f, falling back to normal memory\n", (PetscLogDouble)mem);
163fc2a7144SHong Zhang     }
1647f18b027SJacob Faibussowitsch     PetscCheck(newResult, PETSC_COMM_SELF, line, func, file, PETSC_ERR_MEM, PETSC_ERROR_INITIAL, "Memory requested %.0f", (PetscLogDouble)mem);
165d7976ebaSJed Brown #else
166d7976ebaSJed 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);
167d7976ebaSJed Brown #endif
1687f18b027SJacob Faibussowitsch     PetscCall(PetscMemcpy(newResult, *result, mem));
1697f18b027SJacob Faibussowitsch #if PetscDefined(HAVE_FREE_RETURN_INT)
170c22f1541SToby Isaac     {
171c22f1541SToby Isaac       int err = free(*result);
1727f18b027SJacob Faibussowitsch       PetscCheck(!err, PETSC_COMM_SELF, line, func, file, PETSC_ERR_PLIB, PETSC_ERROR_INITIAL, "System free returned error %d\n", err);
173c22f1541SToby Isaac     }
174c22f1541SToby Isaac #else
175de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
176de1d6c17SHong Zhang     memkind_free(0, *result);
177de1d6c17SHong Zhang #else
178c22f1541SToby Isaac     free(*result);
179c22f1541SToby Isaac #endif
180de1d6c17SHong Zhang #endif
181c22f1541SToby Isaac     *result = newResult;
182c22f1541SToby Isaac   }
183c22f1541SToby Isaac #endif
1843221ece2SMatthew G. Knepley   return 0;
1853221ece2SMatthew G. Knepley }
1863221ece2SMatthew G. Knepley 
187071fcb05SBarry Smith PetscErrorCode (*PetscTrMalloc)(size_t, PetscBool, int, const char[], const char[], void **) = PetscMallocAlign;
188efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void *, int, const char[], const char[])                       = PetscFreeAlign;
1893221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t, int, const char[], const char[], void **)           = PetscReallocAlign;
190e5c89e4eSSatish Balay 
19195c0884eSLisandro Dalcin PETSC_INTERN PetscBool petscsetmallocvisited;
192ace3abfcSBarry Smith PetscBool              petscsetmallocvisited = PETSC_FALSE;
193e5c89e4eSSatish Balay 
194e5c89e4eSSatish Balay /*@C
1951d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
196e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
197e5c89e4eSSatish Balay    called only once.
198e5c89e4eSSatish Balay 
199e5c89e4eSSatish Balay    Not Collective
200e5c89e4eSSatish Balay 
201e5c89e4eSSatish Balay    Input Parameters:
20292f119d6SBarry Smith + imalloc - the routine that provides the malloc (also provides calloc(), which is used depends on the second argument)
20392f119d6SBarry Smith . ifree - the routine that provides the free
20492f119d6SBarry Smith - iralloc - the routine that provides the realloc
205e5c89e4eSSatish Balay 
206e5c89e4eSSatish Balay    Level: developer
207e5c89e4eSSatish Balay 
208e5c89e4eSSatish Balay @*/
2099371c9d4SSatish Balay 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 **)) {
210e5c89e4eSSatish Balay   PetscFunctionBegin;
21108401ef6SPierre Jolivet   PetscCheck(!petscsetmallocvisited || !(imalloc != PetscTrMalloc || ifree != PetscTrFree), PETSC_COMM_SELF, PETSC_ERR_SUP, "cannot call multiple times");
212e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
213e5c89e4eSSatish Balay   PetscTrFree           = ifree;
21492f119d6SBarry Smith   PetscTrRealloc        = iralloc;
215e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
216e5c89e4eSSatish Balay   PetscFunctionReturn(0);
217e5c89e4eSSatish Balay }
218e5c89e4eSSatish Balay 
219e5c89e4eSSatish Balay /*@C
22092f119d6SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the defaults.
221e5c89e4eSSatish Balay 
222e5c89e4eSSatish Balay    Not Collective
223e5c89e4eSSatish Balay 
224e5c89e4eSSatish Balay    Level: developer
225e5c89e4eSSatish Balay 
226e5c89e4eSSatish Balay    Notes:
227e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
228e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
229e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
230e5c89e4eSSatish Balay 
23192f119d6SBarry Smith     Called in PetscFinalize() so that if PetscInitialize() is called again it starts with a fresh slate of allocation information
23292f119d6SBarry Smith 
233e5c89e4eSSatish Balay @*/
2349371c9d4SSatish Balay PetscErrorCode PetscMallocClear(void) {
235e5c89e4eSSatish Balay   PetscFunctionBegin;
236e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
237e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
23892f119d6SBarry Smith   PetscTrRealloc        = PetscReallocAlign;
239e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
240e5c89e4eSSatish Balay   PetscFunctionReturn(0);
241e5c89e4eSSatish Balay }
242b44d5720SBarry Smith 
2439371c9d4SSatish Balay PetscErrorCode PetscMemoryTrace(const char label[]) {
244b44d5720SBarry Smith   PetscLogDouble        mem, mal;
245b44d5720SBarry Smith   static PetscLogDouble oldmem = 0, oldmal = 0;
246b44d5720SBarry Smith 
247b44d5720SBarry Smith   PetscFunctionBegin;
2489566063dSJacob Faibussowitsch   PetscCall(PetscMemoryGetCurrentUsage(&mem));
2499566063dSJacob Faibussowitsch   PetscCall(PetscMallocGetCurrentUsage(&mal));
250b44d5720SBarry Smith 
2519566063dSJacob 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));
252b44d5720SBarry Smith   oldmem = mem;
253b44d5720SBarry Smith   oldmal = mal;
254b44d5720SBarry Smith   PetscFunctionReturn(0);
255b44d5720SBarry Smith }
25613850c04SHong Zhang 
257071fcb05SBarry Smith static PetscErrorCode (*PetscTrMallocOld)(size_t, PetscBool, int, const char[], const char[], void **) = PetscMallocAlign;
25892f119d6SBarry Smith static PetscErrorCode (*PetscTrReallocOld)(size_t, int, const char[], const char[], void **)           = PetscReallocAlign;
25950a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void *, int, const char[], const char[])                       = PetscFreeAlign;
260de1d6c17SHong Zhang 
261de1d6c17SHong Zhang /*@C
262de1d6c17SHong Zhang    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
263de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
264de1d6c17SHong Zhang      current malloc and free routines to the PetscMallocAlign and
265de1d6c17SHong Zhang      PetscFreeAlign (PETSc default).
266de1d6c17SHong Zhang 
267de1d6c17SHong Zhang    Not Collective
268de1d6c17SHong Zhang 
269de1d6c17SHong Zhang    Level: developer
270de1d6c17SHong Zhang 
271de1d6c17SHong Zhang    Notes:
272de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
273de1d6c17SHong Zhang      can switch back to the previous choice by calling PetscMallocReset().
274de1d6c17SHong Zhang 
275db781477SPatrick Sanan .seealso: `PetscMallocReset()`
276de1d6c17SHong Zhang @*/
2779371c9d4SSatish Balay PetscErrorCode PetscMallocSetDRAM(void) {
27813850c04SHong Zhang   PetscFunctionBegin;
279de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
280de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
281de1d6c17SHong Zhang     previousmktype = currentmktype;
282de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
283de1d6c17SHong Zhang #endif
284de1d6c17SHong Zhang   } else {
28513850c04SHong Zhang     /* Save the previous choice */
28613850c04SHong Zhang     PetscTrMallocOld  = PetscTrMalloc;
28792f119d6SBarry Smith     PetscTrReallocOld = PetscTrRealloc;
28813850c04SHong Zhang     PetscTrFreeOld    = PetscTrFree;
28913850c04SHong Zhang     PetscTrMalloc     = PetscMallocAlign;
29013850c04SHong Zhang     PetscTrFree       = PetscFreeAlign;
29192f119d6SBarry Smith     PetscTrRealloc    = PetscReallocAlign;
292de1d6c17SHong Zhang   }
29313850c04SHong Zhang   PetscFunctionReturn(0);
29413850c04SHong Zhang }
29513850c04SHong Zhang 
296de1d6c17SHong Zhang /*@C
297de1d6c17SHong Zhang    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM
298de1d6c17SHong Zhang 
299de1d6c17SHong Zhang    Not Collective
300de1d6c17SHong Zhang 
301de1d6c17SHong Zhang    Level: developer
302de1d6c17SHong Zhang 
303db781477SPatrick Sanan .seealso: `PetscMallocSetDRAM()`
304de1d6c17SHong Zhang @*/
3059371c9d4SSatish Balay PetscErrorCode PetscMallocResetDRAM(void) {
30613850c04SHong Zhang   PetscFunctionBegin;
307de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
308de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
309de1d6c17SHong Zhang     currentmktype = previousmktype;
310de1d6c17SHong Zhang #endif
311de1d6c17SHong Zhang   } else {
31213850c04SHong Zhang     /* Reset to the previous choice */
31313850c04SHong Zhang     PetscTrMalloc  = PetscTrMallocOld;
31492f119d6SBarry Smith     PetscTrRealloc = PetscTrReallocOld;
31513850c04SHong Zhang     PetscTrFree    = PetscTrFreeOld;
316de1d6c17SHong Zhang   }
31713850c04SHong Zhang   PetscFunctionReturn(0);
31813850c04SHong Zhang }
319ba282f50SJed Brown 
320ba282f50SJed Brown static PetscBool petscmalloccoalesce =
321ba282f50SJed Brown #if defined(PETSC_USE_MALLOC_COALESCED)
322ba282f50SJed Brown   PETSC_TRUE;
323ba282f50SJed Brown #else
324ba282f50SJed Brown   PETSC_FALSE;
325ba282f50SJed Brown #endif
326ba282f50SJed Brown 
327ba282f50SJed Brown /*@C
328ba282f50SJed Brown    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects
329ba282f50SJed Brown 
330ba282f50SJed Brown    Not Collective
331ba282f50SJed Brown 
332ba282f50SJed Brown    Input Parameters:
333ba282f50SJed Brown .  coalesce - PETSC_TRUE to use coalesced malloc for multi-object allocation.
334ba282f50SJed Brown 
335ba282f50SJed Brown    Options Database Keys:
336ba282f50SJed Brown .  -malloc_coalesce - turn coalesced malloc on or off
337ba282f50SJed Brown 
338ba282f50SJed Brown    Note:
339ba282f50SJed 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.
34092f119d6SBarry Smith    This function can only be called immediately after PetscInitialize()
341ba282f50SJed Brown 
342ba282f50SJed Brown    Level: developer
343ba282f50SJed Brown 
344db781477SPatrick Sanan .seealso: `PetscMallocA()`
345ba282f50SJed Brown @*/
3469371c9d4SSatish Balay PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce) {
347ba282f50SJed Brown   PetscFunctionBegin;
348ba282f50SJed Brown   petscmalloccoalesce = coalesce;
349ba282f50SJed Brown   PetscFunctionReturn(0);
350ba282f50SJed Brown }
351ba282f50SJed Brown 
352ba282f50SJed Brown /*@C
353ba282f50SJed Brown    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc
354ba282f50SJed Brown 
355ba282f50SJed Brown    Not Collective
356ba282f50SJed Brown 
357ba282f50SJed Brown    Input Parameters:
358ba282f50SJed Brown +  n - number of objects to allocate (at least 1)
35989407d75SBarry Smith .  clear - use calloc() to allocate space initialized to zero
360ba282f50SJed Brown .  lineno - line number to attribute allocation (typically __LINE__)
361ba282f50SJed Brown .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
362ba282f50SJed Brown .  filename - file name to attribute allocation (typically __FILE__)
363ba282f50SJed Brown -  bytes0 - first of n object sizes
364ba282f50SJed Brown 
365ba282f50SJed Brown    Output Parameters:
366ba282f50SJed Brown .  ptr0 - first of n pointers to allocate
367ba282f50SJed Brown 
368ba282f50SJed Brown    Notes:
369ba282f50SJed Brown    This function is not normally called directly by users, but rather via the macros PetscMalloc1(), PetscMalloc2(), or PetscCalloc1(), etc.
370ba282f50SJed Brown 
371ba282f50SJed Brown    Level: developer
372ba282f50SJed Brown 
373db781477SPatrick Sanan .seealso: `PetscMallocAlign()`, `PetscMallocSet()`, `PetscMalloc1()`, `PetscMalloc2()`, `PetscMalloc3()`, `PetscMalloc4()`, `PetscMalloc5()`, `PetscMalloc6()`, `PetscMalloc7()`, `PetscCalloc1()`, `PetscCalloc2()`, `PetscCalloc3()`, `PetscCalloc4()`, `PetscCalloc5()`, `PetscCalloc6()`, `PetscCalloc7()`, `PetscFreeA()`
374ba282f50SJed Brown @*/
3759371c9d4SSatish Balay PetscErrorCode PetscMallocA(int n, PetscBool clear, int lineno, const char *function, const char *filename, size_t bytes0, void *ptr0, ...) {
376ba282f50SJed Brown   va_list Argp;
377ba282f50SJed Brown   size_t  bytes[8], sumbytes;
378ba282f50SJed Brown   void  **ptr[8];
379ba282f50SJed Brown   int     i;
380ba282f50SJed Brown 
381ba282f50SJed Brown   PetscFunctionBegin;
3827f18b027SJacob Faibussowitsch   PetscCheck(n <= 8, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to allocate %d objects but only 8 supported", n);
383ba282f50SJed Brown   bytes[0] = bytes0;
384ba282f50SJed Brown   ptr[0]   = (void **)ptr0;
385ba282f50SJed Brown   sumbytes = (bytes0 + PETSC_MEMALIGN - 1) & ~(PETSC_MEMALIGN - 1);
386ba282f50SJed Brown   va_start(Argp, ptr0);
387ba282f50SJed Brown   for (i = 1; i < n; i++) {
388ba282f50SJed Brown     bytes[i] = va_arg(Argp, size_t);
389ba282f50SJed Brown     ptr[i]   = va_arg(Argp, void **);
390ba282f50SJed Brown     sumbytes += (bytes[i] + PETSC_MEMALIGN - 1) & ~(PETSC_MEMALIGN - 1);
391ba282f50SJed Brown   }
392ba282f50SJed Brown   va_end(Argp);
393ba282f50SJed Brown   if (petscmalloccoalesce) {
394ba282f50SJed Brown     char *p;
3959566063dSJacob Faibussowitsch     PetscCall((*PetscTrMalloc)(sumbytes, clear, lineno, function, filename, (void **)&p));
396640c8569SMatthew Woehlke     if (p == NULL) {
3979371c9d4SSatish Balay       for (i = 0; i < n; i++) { *ptr[i] = NULL; }
398640c8569SMatthew Woehlke     } else {
399ba282f50SJed Brown       for (i = 0; i < n; i++) {
400ba282f50SJed Brown         *ptr[i] = bytes[i] ? p : NULL;
401ba282f50SJed Brown         p       = (char *)PetscAddrAlign(p + bytes[i]);
402ba282f50SJed Brown       }
403640c8569SMatthew Woehlke     }
404ba282f50SJed Brown   } else {
405*48a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall((*PetscTrMalloc)(bytes[i], clear, lineno, function, filename, (void **)ptr[i]));
406ba282f50SJed Brown   }
407ba282f50SJed Brown   PetscFunctionReturn(0);
408ba282f50SJed Brown }
409ba282f50SJed Brown 
410ba282f50SJed Brown /*@C
411ba282f50SJed Brown    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc
412ba282f50SJed Brown 
413ba282f50SJed Brown    Not Collective
414ba282f50SJed Brown 
415ba282f50SJed Brown    Input Parameters:
416ba282f50SJed Brown +  n - number of objects to free (at least 1)
417ba282f50SJed Brown .  lineno - line number to attribute deallocation (typically __LINE__)
418ba282f50SJed Brown .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
419ba282f50SJed Brown .  filename - file name to attribute deallocation (typically __FILE__)
420ba282f50SJed Brown -  ptr0 ... - first of n pointers to free
421ba282f50SJed Brown 
422ba282f50SJed Brown    Note:
423071fcb05SBarry Smith    This function is not normally called directly by users, but rather via the macros PetscFree(), PetscFree2(), etc.
424ba282f50SJed Brown 
425a5b23f4aSJose E. Roman    The pointers are zeroed to prevent users from accidentally reusing space that has been freed.
42689407d75SBarry Smith 
427ba282f50SJed Brown    Level: developer
428ba282f50SJed Brown 
429db781477SPatrick Sanan .seealso: `PetscMallocAlign()`, `PetscMallocSet()`, `PetscMallocA()`, `PetscFree1()`, `PetscFree2()`, `PetscFree3()`, `PetscFree4()`, `PetscFree5()`, `PetscFree6()`, `PetscFree7()`
430ba282f50SJed Brown @*/
4319371c9d4SSatish Balay PetscErrorCode PetscFreeA(int n, int lineno, const char *function, const char *filename, void *ptr0, ...) {
432ba282f50SJed Brown   va_list Argp;
433ba282f50SJed Brown   void  **ptr[8];
434ba282f50SJed Brown   int     i;
435ba282f50SJed Brown 
436ba282f50SJed Brown   PetscFunctionBegin;
4377f18b027SJacob Faibussowitsch   PetscCheck(n <= 8, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to allocate %d objects but only up to 8 supported", n);
438ba282f50SJed Brown   ptr[0] = (void **)ptr0;
439ba282f50SJed Brown   va_start(Argp, ptr0);
4409371c9d4SSatish Balay   for (i = 1; i < n; i++) { ptr[i] = va_arg(Argp, void **); }
441ba282f50SJed Brown   va_end(Argp);
442ba282f50SJed Brown   if (petscmalloccoalesce) {
443ba282f50SJed Brown     for (i = 0; i < n; i++) { /* Find first nonempty allocation */
444ba282f50SJed Brown       if (*ptr[i]) break;
445ba282f50SJed Brown     }
4469371c9d4SSatish Balay     while (--n > i) { *ptr[n] = NULL; }
4479566063dSJacob Faibussowitsch     PetscCall((*PetscTrFree)(*ptr[n], lineno, function, filename));
448ba282f50SJed Brown     *ptr[n] = NULL;
449ba282f50SJed Brown   } else {
450ba282f50SJed Brown     while (--n >= 0) {
4519566063dSJacob Faibussowitsch       PetscCall((*PetscTrFree)(*ptr[n], lineno, function, filename));
452ba282f50SJed Brown       *ptr[n] = NULL;
453ba282f50SJed Brown     }
454ba282f50SJed Brown   }
455ba282f50SJed Brown   PetscFunctionReturn(0);
456ba282f50SJed Brown }
457