xref: /petsc/src/sys/memory/mal.c (revision 811af0c4b09a35de4306c442f88bd09fdc09897d)
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.
196*811af0c4SBarry Smith    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 
208*811af0c4SBarry Smith .seealso: `PetscMallocClear()`
209e5c89e4eSSatish Balay @*/
2109371c9d4SSatish 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 **)) {
211e5c89e4eSSatish Balay   PetscFunctionBegin;
21208401ef6SPierre Jolivet   PetscCheck(!petscsetmallocvisited || !(imalloc != PetscTrMalloc || ifree != PetscTrFree), PETSC_COMM_SELF, PETSC_ERR_SUP, "cannot call multiple times");
213e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
214e5c89e4eSSatish Balay   PetscTrFree           = ifree;
21592f119d6SBarry Smith   PetscTrRealloc        = iralloc;
216e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
217e5c89e4eSSatish Balay   PetscFunctionReturn(0);
218e5c89e4eSSatish Balay }
219e5c89e4eSSatish Balay 
220e5c89e4eSSatish Balay /*@C
22192f119d6SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the defaults.
222e5c89e4eSSatish Balay 
223e5c89e4eSSatish Balay    Not Collective
224e5c89e4eSSatish Balay 
225e5c89e4eSSatish Balay    Level: developer
226e5c89e4eSSatish Balay 
227*811af0c4SBarry Smith    Note:
228e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
229e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
230e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
231e5c89e4eSSatish Balay 
232*811af0c4SBarry Smith     Called in `PetscFinalize()` so that if `PetscInitialize()` is called again it starts with a fresh slate of allocation information
23392f119d6SBarry Smith 
234*811af0c4SBarry Smith .seealso: `PetscMallocSet`
235e5c89e4eSSatish Balay @*/
2369371c9d4SSatish Balay PetscErrorCode PetscMallocClear(void) {
237e5c89e4eSSatish Balay   PetscFunctionBegin;
238e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
239e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
24092f119d6SBarry Smith   PetscTrRealloc        = PetscReallocAlign;
241e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
242e5c89e4eSSatish Balay   PetscFunctionReturn(0);
243e5c89e4eSSatish Balay }
244b44d5720SBarry Smith 
2459371c9d4SSatish Balay PetscErrorCode PetscMemoryTrace(const char label[]) {
246b44d5720SBarry Smith   PetscLogDouble        mem, mal;
247b44d5720SBarry Smith   static PetscLogDouble oldmem = 0, oldmal = 0;
248b44d5720SBarry Smith 
249b44d5720SBarry Smith   PetscFunctionBegin;
2509566063dSJacob Faibussowitsch   PetscCall(PetscMemoryGetCurrentUsage(&mem));
2519566063dSJacob Faibussowitsch   PetscCall(PetscMallocGetCurrentUsage(&mal));
252b44d5720SBarry Smith 
2539566063dSJacob 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));
254b44d5720SBarry Smith   oldmem = mem;
255b44d5720SBarry Smith   oldmal = mal;
256b44d5720SBarry Smith   PetscFunctionReturn(0);
257b44d5720SBarry Smith }
25813850c04SHong Zhang 
259071fcb05SBarry Smith static PetscErrorCode (*PetscTrMallocOld)(size_t, PetscBool, int, const char[], const char[], void **) = PetscMallocAlign;
26092f119d6SBarry Smith static PetscErrorCode (*PetscTrReallocOld)(size_t, int, const char[], const char[], void **)           = PetscReallocAlign;
26150a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void *, int, const char[], const char[])                       = PetscFreeAlign;
262de1d6c17SHong Zhang 
263de1d6c17SHong Zhang /*@C
264*811af0c4SBarry Smith    PetscMallocSetDRAM - Set `PetscMalloc()` to use DRAM.
265de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
266*811af0c4SBarry Smith      current malloc and free routines to the `PetscMallocAlign()` and
267*811af0c4SBarry Smith      `PetscFreeAlign()` (PETSc default).
268de1d6c17SHong Zhang 
269de1d6c17SHong Zhang    Not Collective
270de1d6c17SHong Zhang 
271de1d6c17SHong Zhang    Level: developer
272de1d6c17SHong Zhang 
273*811af0c4SBarry Smith    Note:
274de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
275*811af0c4SBarry Smith      can switch back to the previous choice by calling `PetscMallocReset()`.
276de1d6c17SHong Zhang 
277db781477SPatrick Sanan .seealso: `PetscMallocReset()`
278de1d6c17SHong Zhang @*/
2799371c9d4SSatish Balay PetscErrorCode PetscMallocSetDRAM(void) {
28013850c04SHong Zhang   PetscFunctionBegin;
281de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
282de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
283de1d6c17SHong Zhang     previousmktype = currentmktype;
284de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
285de1d6c17SHong Zhang #endif
286de1d6c17SHong Zhang   } else {
28713850c04SHong Zhang     /* Save the previous choice */
28813850c04SHong Zhang     PetscTrMallocOld  = PetscTrMalloc;
28992f119d6SBarry Smith     PetscTrReallocOld = PetscTrRealloc;
29013850c04SHong Zhang     PetscTrFreeOld    = PetscTrFree;
29113850c04SHong Zhang     PetscTrMalloc     = PetscMallocAlign;
29213850c04SHong Zhang     PetscTrFree       = PetscFreeAlign;
29392f119d6SBarry Smith     PetscTrRealloc    = PetscReallocAlign;
294de1d6c17SHong Zhang   }
29513850c04SHong Zhang   PetscFunctionReturn(0);
29613850c04SHong Zhang }
29713850c04SHong Zhang 
298de1d6c17SHong Zhang /*@C
299*811af0c4SBarry Smith    PetscMallocResetDRAM - Reset the changes made by `PetscMallocSetDRAM()`
300de1d6c17SHong Zhang 
301de1d6c17SHong Zhang    Not Collective
302de1d6c17SHong Zhang 
303de1d6c17SHong Zhang    Level: developer
304de1d6c17SHong Zhang 
305db781477SPatrick Sanan .seealso: `PetscMallocSetDRAM()`
306de1d6c17SHong Zhang @*/
3079371c9d4SSatish Balay PetscErrorCode PetscMallocResetDRAM(void) {
30813850c04SHong Zhang   PetscFunctionBegin;
309de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
310de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
311de1d6c17SHong Zhang     currentmktype = previousmktype;
312de1d6c17SHong Zhang #endif
313de1d6c17SHong Zhang   } else {
31413850c04SHong Zhang     /* Reset to the previous choice */
31513850c04SHong Zhang     PetscTrMalloc  = PetscTrMallocOld;
31692f119d6SBarry Smith     PetscTrRealloc = PetscTrReallocOld;
31713850c04SHong Zhang     PetscTrFree    = PetscTrFreeOld;
318de1d6c17SHong Zhang   }
31913850c04SHong Zhang   PetscFunctionReturn(0);
32013850c04SHong Zhang }
321ba282f50SJed Brown 
322ba282f50SJed Brown static PetscBool petscmalloccoalesce =
323ba282f50SJed Brown #if defined(PETSC_USE_MALLOC_COALESCED)
324ba282f50SJed Brown   PETSC_TRUE;
325ba282f50SJed Brown #else
326ba282f50SJed Brown   PETSC_FALSE;
327ba282f50SJed Brown #endif
328ba282f50SJed Brown 
329ba282f50SJed Brown /*@C
330ba282f50SJed Brown    PetscMallocSetCoalesce - Use coalesced malloc when allocating groups of objects
331ba282f50SJed Brown 
332ba282f50SJed Brown    Not Collective
333ba282f50SJed Brown 
334ba282f50SJed Brown    Input Parameters:
335*811af0c4SBarry Smith .  coalesce - `PETSC_TRUE` to use coalesced malloc for multi-object allocation.
336ba282f50SJed Brown 
337ba282f50SJed Brown    Options Database Keys:
338ba282f50SJed Brown .  -malloc_coalesce - turn coalesced malloc on or off
339ba282f50SJed Brown 
340*811af0c4SBarry Smith    Notes:
341*811af0c4SBarry Smith    PETSc uses coalesced malloc by default for optimized builds and not for debugging builds.
342*811af0c4SBarry Smith 
343*811af0c4SBarry Smith    This default can be changed via the command-line option -malloc_coalesce or by calling this function.
344*811af0c4SBarry Smith 
345*811af0c4SBarry Smith    This function can only be called immediately after `PetscInitialize()`
346ba282f50SJed Brown 
347ba282f50SJed Brown    Level: developer
348ba282f50SJed Brown 
349db781477SPatrick Sanan .seealso: `PetscMallocA()`
350ba282f50SJed Brown @*/
3519371c9d4SSatish Balay PetscErrorCode PetscMallocSetCoalesce(PetscBool coalesce) {
352ba282f50SJed Brown   PetscFunctionBegin;
353ba282f50SJed Brown   petscmalloccoalesce = coalesce;
354ba282f50SJed Brown   PetscFunctionReturn(0);
355ba282f50SJed Brown }
356ba282f50SJed Brown 
357ba282f50SJed Brown /*@C
358ba282f50SJed Brown    PetscMallocA - Allocate and optionally clear one or more objects, possibly using coalesced malloc
359ba282f50SJed Brown 
360ba282f50SJed Brown    Not Collective
361ba282f50SJed Brown 
362ba282f50SJed Brown    Input Parameters:
363ba282f50SJed Brown +  n - number of objects to allocate (at least 1)
36489407d75SBarry Smith .  clear - use calloc() to allocate space initialized to zero
365ba282f50SJed Brown .  lineno - line number to attribute allocation (typically __LINE__)
366ba282f50SJed Brown .  function - function to attribute allocation (typically PETSC_FUNCTION_NAME)
367ba282f50SJed Brown .  filename - file name to attribute allocation (typically __FILE__)
368ba282f50SJed Brown -  bytes0 - first of n object sizes
369ba282f50SJed Brown 
370ba282f50SJed Brown    Output Parameters:
371ba282f50SJed Brown .  ptr0 - first of n pointers to allocate
372ba282f50SJed Brown 
373*811af0c4SBarry Smith    Notes
374*811af0c4SBarry Smith    This function is not normally called directly by users, but rather via the macros `PetscMalloc1()`, `PetscMalloc2()`, or `PetscCalloc1()`, etc.
375ba282f50SJed Brown 
376ba282f50SJed Brown    Level: developer
377ba282f50SJed Brown 
378db781477SPatrick Sanan .seealso: `PetscMallocAlign()`, `PetscMallocSet()`, `PetscMalloc1()`, `PetscMalloc2()`, `PetscMalloc3()`, `PetscMalloc4()`, `PetscMalloc5()`, `PetscMalloc6()`, `PetscMalloc7()`, `PetscCalloc1()`, `PetscCalloc2()`, `PetscCalloc3()`, `PetscCalloc4()`, `PetscCalloc5()`, `PetscCalloc6()`, `PetscCalloc7()`, `PetscFreeA()`
379ba282f50SJed Brown @*/
3809371c9d4SSatish Balay PetscErrorCode PetscMallocA(int n, PetscBool clear, int lineno, const char *function, const char *filename, size_t bytes0, void *ptr0, ...) {
381ba282f50SJed Brown   va_list Argp;
382ba282f50SJed Brown   size_t  bytes[8], sumbytes;
383ba282f50SJed Brown   void  **ptr[8];
384ba282f50SJed Brown   int     i;
385ba282f50SJed Brown 
386ba282f50SJed Brown   PetscFunctionBegin;
3877f18b027SJacob Faibussowitsch   PetscCheck(n <= 8, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to allocate %d objects but only 8 supported", n);
388ba282f50SJed Brown   bytes[0] = bytes0;
389ba282f50SJed Brown   ptr[0]   = (void **)ptr0;
390ba282f50SJed Brown   sumbytes = (bytes0 + PETSC_MEMALIGN - 1) & ~(PETSC_MEMALIGN - 1);
391ba282f50SJed Brown   va_start(Argp, ptr0);
392ba282f50SJed Brown   for (i = 1; i < n; i++) {
393ba282f50SJed Brown     bytes[i] = va_arg(Argp, size_t);
394ba282f50SJed Brown     ptr[i]   = va_arg(Argp, void **);
395ba282f50SJed Brown     sumbytes += (bytes[i] + PETSC_MEMALIGN - 1) & ~(PETSC_MEMALIGN - 1);
396ba282f50SJed Brown   }
397ba282f50SJed Brown   va_end(Argp);
398ba282f50SJed Brown   if (petscmalloccoalesce) {
399ba282f50SJed Brown     char *p;
4009566063dSJacob Faibussowitsch     PetscCall((*PetscTrMalloc)(sumbytes, clear, lineno, function, filename, (void **)&p));
401640c8569SMatthew Woehlke     if (p == NULL) {
402ad540459SPierre Jolivet       for (i = 0; i < n; i++) *ptr[i] = NULL;
403640c8569SMatthew Woehlke     } else {
404ba282f50SJed Brown       for (i = 0; i < n; i++) {
405ba282f50SJed Brown         *ptr[i] = bytes[i] ? p : NULL;
406ba282f50SJed Brown         p       = (char *)PetscAddrAlign(p + bytes[i]);
407ba282f50SJed Brown       }
408640c8569SMatthew Woehlke     }
409ba282f50SJed Brown   } else {
41048a46eb9SPierre Jolivet     for (i = 0; i < n; i++) PetscCall((*PetscTrMalloc)(bytes[i], clear, lineno, function, filename, (void **)ptr[i]));
411ba282f50SJed Brown   }
412ba282f50SJed Brown   PetscFunctionReturn(0);
413ba282f50SJed Brown }
414ba282f50SJed Brown 
415ba282f50SJed Brown /*@C
416ba282f50SJed Brown    PetscFreeA - Free one or more objects, possibly allocated using coalesced malloc
417ba282f50SJed Brown 
418ba282f50SJed Brown    Not Collective
419ba282f50SJed Brown 
420ba282f50SJed Brown    Input Parameters:
421ba282f50SJed Brown +  n - number of objects to free (at least 1)
422ba282f50SJed Brown .  lineno - line number to attribute deallocation (typically __LINE__)
423ba282f50SJed Brown .  function - function to attribute deallocation (typically PETSC_FUNCTION_NAME)
424ba282f50SJed Brown .  filename - file name to attribute deallocation (typically __FILE__)
425ba282f50SJed Brown -  ptr0 ... - first of n pointers to free
426ba282f50SJed Brown 
427*811af0c4SBarry Smith    Notes:
428*811af0c4SBarry Smith    This function is not normally called directly by users, but rather via the macros `PetscFree()`, `PetscFree2()`, etc.
429ba282f50SJed Brown 
430a5b23f4aSJose E. Roman    The pointers are zeroed to prevent users from accidentally reusing space that has been freed.
43189407d75SBarry Smith 
432ba282f50SJed Brown    Level: developer
433ba282f50SJed Brown 
434db781477SPatrick Sanan .seealso: `PetscMallocAlign()`, `PetscMallocSet()`, `PetscMallocA()`, `PetscFree1()`, `PetscFree2()`, `PetscFree3()`, `PetscFree4()`, `PetscFree5()`, `PetscFree6()`, `PetscFree7()`
435ba282f50SJed Brown @*/
4369371c9d4SSatish Balay PetscErrorCode PetscFreeA(int n, int lineno, const char *function, const char *filename, void *ptr0, ...) {
437ba282f50SJed Brown   va_list Argp;
438ba282f50SJed Brown   void  **ptr[8];
439ba282f50SJed Brown   int     i;
440ba282f50SJed Brown 
441ba282f50SJed Brown   PetscFunctionBegin;
4427f18b027SJacob Faibussowitsch   PetscCheck(n <= 8, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Attempt to allocate %d objects but only up to 8 supported", n);
443ba282f50SJed Brown   ptr[0] = (void **)ptr0;
444ba282f50SJed Brown   va_start(Argp, ptr0);
445ad540459SPierre Jolivet   for (i = 1; i < n; i++) ptr[i] = va_arg(Argp, void **);
446ba282f50SJed Brown   va_end(Argp);
447ba282f50SJed Brown   if (petscmalloccoalesce) {
448ba282f50SJed Brown     for (i = 0; i < n; i++) { /* Find first nonempty allocation */
449ba282f50SJed Brown       if (*ptr[i]) break;
450ba282f50SJed Brown     }
451ad540459SPierre Jolivet     while (--n > i) *ptr[n] = NULL;
4529566063dSJacob Faibussowitsch     PetscCall((*PetscTrFree)(*ptr[n], lineno, function, filename));
453ba282f50SJed Brown     *ptr[n] = NULL;
454ba282f50SJed Brown   } else {
455ba282f50SJed Brown     while (--n >= 0) {
4569566063dSJacob Faibussowitsch       PetscCall((*PetscTrFree)(*ptr[n], lineno, function, filename));
457ba282f50SJed Brown       *ptr[n] = NULL;
458ba282f50SJed Brown     }
459ba282f50SJed Brown   }
460ba282f50SJed Brown   PetscFunctionReturn(0);
461ba282f50SJed Brown }
462