xref: /petsc/src/sys/memory/mal.c (revision 5b2326240e3f846305538e6a3a4c68e00f5bc645)
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*/
6e5c89e4eSSatish Balay #if defined(PETSC_HAVE_MALLOC_H)
7e5c89e4eSSatish Balay #include <malloc.h>
8e5c89e4eSSatish Balay #endif
9de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
10de1d6c17SHong Zhang #include <memkind.h>
11de1d6c17SHong Zhang typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType;
12de1d6c17SHong Zhang PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED;
13de1d6c17SHong Zhang PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED;
14de1d6c17SHong Zhang #endif
15e5c89e4eSSatish Balay /*
16e5c89e4eSSatish Balay         We want to make sure that all mallocs of double or complex numbers are complex aligned.
17e5c89e4eSSatish Balay     1) on systems with memalign() we call that routine to get an aligned memory location
18e5c89e4eSSatish Balay     2) on systems without memalign() we
19e5c89e4eSSatish Balay        - allocate one sizeof(PetscScalar) extra space
20e5c89e4eSSatish Balay        - we shift the pointer up slightly if needed to get PetscScalar aligned
210700a824SBarry Smith        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
22e5c89e4eSSatish Balay */
230700a824SBarry Smith #define SHIFT_CLASSID 456123
24e5c89e4eSSatish Balay 
25efca3c55SSatish Balay PetscErrorCode  PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
26e5c89e4eSSatish Balay {
27f0ba7cfcSLisandro Dalcin   if (!mem) { *result = NULL; return 0; }
28fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
29fc2a7144SHong Zhang   {
30fc2a7144SHong Zhang     int ierr;
31fc2a7144SHong Zhang     if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem);
32fc2a7144SHong Zhang     else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem);
33fc2a7144SHong Zhang     if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem);
34fc2a7144SHong Zhang   }
35fc2a7144SHong Zhang #else
36e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
37e5c89e4eSSatish Balay   *result = malloc(mem);
38e5c89e4eSSatish Balay #  elif defined(PETSC_HAVE_MEMALIGN)
39e5c89e4eSSatish Balay   *result = memalign(PETSC_MEMALIGN,mem);
40e5c89e4eSSatish Balay #  else
41e5c89e4eSSatish Balay   {
42e5c89e4eSSatish Balay     /*
43e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
44e5c89e4eSSatish Balay     */
45*5b232624SHong Zhang     int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
46e5c89e4eSSatish Balay     if (ptr) {
47f0ba7cfcSLisandro Dalcin       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
48e5c89e4eSSatish Balay       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
490700a824SBarry Smith       ptr[shift-1] = shift + SHIFT_CLASSID;
50e5c89e4eSSatish Balay       ptr         += shift;
51e5c89e4eSSatish Balay       *result      = (void*)ptr;
52e5c89e4eSSatish Balay     } else {
53f0ba7cfcSLisandro Dalcin       *result      = NULL;
54e5c89e4eSSatish Balay     }
55e5c89e4eSSatish Balay   }
56e5c89e4eSSatish Balay #  endif
57fc2a7144SHong Zhang #endif
58f0ba7cfcSLisandro Dalcin   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
59e5c89e4eSSatish Balay   return 0;
60e5c89e4eSSatish Balay }
61e5c89e4eSSatish Balay 
62efca3c55SSatish Balay PetscErrorCode  PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
63e5c89e4eSSatish Balay {
64f0ba7cfcSLisandro Dalcin   if (!ptr) return 0;
65fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
66fc2a7144SHong Zhang   memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */
67fc2a7144SHong Zhang #else
68e5c89e4eSSatish Balay #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
69f0ba7cfcSLisandro Dalcin   {
70e5c89e4eSSatish Balay     /*
71e5c89e4eSSatish Balay       Previous int tells us how many ints the pointer has been shifted from
72e5c89e4eSSatish Balay       the original address provided by the system malloc().
73e5c89e4eSSatish Balay     */
74f0ba7cfcSLisandro Dalcin     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
75efca3c55SSatish 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");
76efca3c55SSatish Balay     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
77e5c89e4eSSatish Balay     ptr = (void*)(((int*)ptr) - shift);
78e5c89e4eSSatish Balay   }
79f0ba7cfcSLisandro Dalcin #  endif
80e5c89e4eSSatish Balay 
81e5c89e4eSSatish Balay #  if defined(PETSC_HAVE_FREE_RETURN_INT)
82e5c89e4eSSatish Balay   int err = free(ptr);
83efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
84e5c89e4eSSatish Balay #  else
85e5c89e4eSSatish Balay   free(ptr);
86e5c89e4eSSatish Balay #  endif
87fc2a7144SHong Zhang #endif
88e5c89e4eSSatish Balay   return 0;
89e5c89e4eSSatish Balay }
90e5c89e4eSSatish Balay 
913221ece2SMatthew G. Knepley PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
923221ece2SMatthew G. Knepley {
93c22f1541SToby Isaac   PetscErrorCode ierr;
94c22f1541SToby Isaac 
95c22f1541SToby Isaac   if (!mem) {
96c22f1541SToby Isaac     ierr = PetscFreeAlign(*result, line, func, file);
97c22f1541SToby Isaac     if (ierr) return ierr;
98c22f1541SToby Isaac     *result = NULL;
99c22f1541SToby Isaac     return 0;
100c22f1541SToby Isaac   }
101fc2a7144SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
102fc2a7144SHong Zhang   if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem);
103fc2a7144SHong Zhang   else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem);
104fc2a7144SHong Zhang #else
1053221ece2SMatthew G. Knepley #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
1063221ece2SMatthew G. Knepley   {
1073221ece2SMatthew G. Knepley     /*
1083221ece2SMatthew G. Knepley       Previous int tells us how many ints the pointer has been shifted from
1093221ece2SMatthew G. Knepley       the original address provided by the system malloc().
1103221ece2SMatthew G. Knepley     */
1113221ece2SMatthew G. Knepley     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
1123221ece2SMatthew 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");
1133221ece2SMatthew G. Knepley     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
1143221ece2SMatthew G. Knepley     *result = (void*)(((int*)*result) - shift);
1153221ece2SMatthew G. Knepley   }
1163221ece2SMatthew G. Knepley #  endif
1173221ece2SMatthew G. Knepley 
118c22f1541SToby Isaac #  if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
1193221ece2SMatthew G. Knepley   *result = realloc(*result, mem);
1203221ece2SMatthew G. Knepley #  else
1213221ece2SMatthew G. Knepley   {
1223221ece2SMatthew G. Knepley     /*
1233221ece2SMatthew G. Knepley       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
1243221ece2SMatthew G. Knepley     */
1253221ece2SMatthew G. Knepley     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
1263221ece2SMatthew G. Knepley     if (ptr) {
1273221ece2SMatthew G. Knepley       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
1283221ece2SMatthew G. Knepley       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
1293221ece2SMatthew G. Knepley       ptr[shift-1] = shift + SHIFT_CLASSID;
1303221ece2SMatthew G. Knepley       ptr         += shift;
1313221ece2SMatthew G. Knepley       *result      = (void*)ptr;
1323221ece2SMatthew G. Knepley     } else {
1333221ece2SMatthew G. Knepley       *result      = NULL;
1343221ece2SMatthew G. Knepley     }
1353221ece2SMatthew G. Knepley   }
1363221ece2SMatthew G. Knepley #  endif
137fc2a7144SHong Zhang #endif
1383221ece2SMatthew G. Knepley   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
139c22f1541SToby Isaac #if defined(PETSC_HAVE_MEMALIGN)
140c22f1541SToby Isaac   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
141c22f1541SToby Isaac    * realloc and, if the alignment is wrong, malloc/copy/free. */
142c22f1541SToby Isaac   if (((size_t) (*result)) % PETSC_MEMALIGN) {
143c22f1541SToby Isaac     void *newResult;
144fc2a7144SHong Zhang #  if defined(PETSC_HAVE_MEMKIND)
145fc2a7144SHong Zhang     {
146fc2a7144SHong Zhang       int ierr;
147fc2a7144SHong Zhang       if (!currentmktype) ierr = memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem);
148fc2a7144SHong Zhang       else ierr = memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem);
149fc2a7144SHong Zhang       if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem);
150fc2a7144SHong Zhang     }
151fc2a7144SHong Zhang #  else
152c22f1541SToby Isaac     newResult = memalign(PETSC_MEMALIGN,mem);
153fc2a7144SHong Zhang #  endif
154c22f1541SToby Isaac     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
155c22f1541SToby Isaac     ierr = PetscMemcpy(newResult,*result,mem);
156c22f1541SToby Isaac     if (ierr) return ierr;
157c22f1541SToby Isaac #  if defined(PETSC_HAVE_FREE_RETURN_INT)
158c22f1541SToby Isaac     {
159c22f1541SToby Isaac       int err = free(*result);
160c22f1541SToby Isaac       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
161c22f1541SToby Isaac     }
162c22f1541SToby Isaac #  else
163de1d6c17SHong Zhang #    if defined(PETSC_HAVE_MEMKIND)
164de1d6c17SHong Zhang     memkind_free(0,*result);
165de1d6c17SHong Zhang #    else
166c22f1541SToby Isaac     free(*result);
167c22f1541SToby Isaac #    endif
168de1d6c17SHong Zhang #  endif
169c22f1541SToby Isaac     *result = newResult;
170c22f1541SToby Isaac   }
171c22f1541SToby Isaac #endif
1723221ece2SMatthew G. Knepley   return 0;
1733221ece2SMatthew G. Knepley }
1743221ece2SMatthew G. Knepley 
175efca3c55SSatish Balay PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
176efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
1773221ece2SMatthew G. Knepley PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign;
178e5c89e4eSSatish Balay 
179ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE;
180e5c89e4eSSatish Balay 
181e5c89e4eSSatish Balay /*@C
1821d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
183e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
184e5c89e4eSSatish Balay    called only once.
185e5c89e4eSSatish Balay 
186e5c89e4eSSatish Balay    Not Collective
187e5c89e4eSSatish Balay 
188e5c89e4eSSatish Balay    Input Parameters:
189e5c89e4eSSatish Balay +  malloc - the malloc routine
190e5c89e4eSSatish Balay -  free - the free routine
191e5c89e4eSSatish Balay 
192e5c89e4eSSatish Balay    Level: developer
193e5c89e4eSSatish Balay 
194e5c89e4eSSatish Balay    Concepts: malloc
195e5c89e4eSSatish Balay    Concepts: memory^allocation
196e5c89e4eSSatish Balay 
197e5c89e4eSSatish Balay @*/
198efca3c55SSatish Balay PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
199efca3c55SSatish Balay                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
200e5c89e4eSSatish Balay {
201e5c89e4eSSatish Balay   PetscFunctionBegin;
202e32f2f54SBarry Smith   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
203e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
204e5c89e4eSSatish Balay   PetscTrFree           = ifree;
205e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
206e5c89e4eSSatish Balay   PetscFunctionReturn(0);
207e5c89e4eSSatish Balay }
208e5c89e4eSSatish Balay 
209e5c89e4eSSatish Balay /*@C
2101d1a0024SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the
211e5c89e4eSSatish Balay         defaults.
212e5c89e4eSSatish Balay 
213e5c89e4eSSatish Balay    Not Collective
214e5c89e4eSSatish Balay 
215e5c89e4eSSatish Balay    Level: developer
216e5c89e4eSSatish Balay 
217e5c89e4eSSatish Balay    Notes:
218e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
219e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
220e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
221e5c89e4eSSatish Balay 
222e5c89e4eSSatish Balay @*/
2237087cfbeSBarry Smith PetscErrorCode  PetscMallocClear(void)
224e5c89e4eSSatish Balay {
225e5c89e4eSSatish Balay   PetscFunctionBegin;
226e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
227e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
228e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
229e5c89e4eSSatish Balay   PetscFunctionReturn(0);
230e5c89e4eSSatish Balay }
231b44d5720SBarry Smith 
232b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[])
233b44d5720SBarry Smith {
234b44d5720SBarry Smith   PetscErrorCode        ierr;
235b44d5720SBarry Smith   PetscLogDouble        mem,mal;
236b44d5720SBarry Smith   static PetscLogDouble oldmem = 0,oldmal = 0;
237b44d5720SBarry Smith 
238b44d5720SBarry Smith   PetscFunctionBegin;
239b44d5720SBarry Smith   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
240b44d5720SBarry Smith   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
241b44d5720SBarry Smith 
242b44d5720SBarry 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);
243b44d5720SBarry Smith   oldmem = mem;
244b44d5720SBarry Smith   oldmal = mal;
245b44d5720SBarry Smith   PetscFunctionReturn(0);
246b44d5720SBarry Smith }
24713850c04SHong Zhang 
24850a41461SHong Zhang static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
24950a41461SHong Zhang static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[])           = PetscFreeAlign;
250de1d6c17SHong Zhang 
251de1d6c17SHong Zhang /*@C
252de1d6c17SHong Zhang    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
253de1d6c17SHong Zhang      If memkind is available, change the memkind type. Otherwise, switch the
254de1d6c17SHong Zhang      current malloc and free routines to the PetscMallocAlign and
255de1d6c17SHong Zhang      PetscFreeAlign (PETSc default).
256de1d6c17SHong Zhang 
257de1d6c17SHong Zhang    Not Collective
258de1d6c17SHong Zhang 
259de1d6c17SHong Zhang    Level: developer
260de1d6c17SHong Zhang 
261de1d6c17SHong Zhang    Notes:
262de1d6c17SHong Zhang      This provides a way to do the allocation on DRAM temporarily. One
263de1d6c17SHong Zhang      can switch back to the previous choice by calling PetscMallocReset().
264de1d6c17SHong Zhang 
265de1d6c17SHong Zhang .seealso: PetscMallocReset()
266de1d6c17SHong Zhang @*/
26713850c04SHong Zhang PetscErrorCode PetscMallocSetDRAM(void)
26813850c04SHong Zhang {
26913850c04SHong Zhang   PetscFunctionBegin;
270de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
271de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
272de1d6c17SHong Zhang     previousmktype = currentmktype;
273de1d6c17SHong Zhang     currentmktype  = PETSC_MK_DEFAULT;
274de1d6c17SHong Zhang #endif
275de1d6c17SHong Zhang   } else {
27613850c04SHong Zhang     /* Save the previous choice */
27713850c04SHong Zhang     PetscTrMallocOld = PetscTrMalloc;
27813850c04SHong Zhang     PetscTrFreeOld   = PetscTrFree;
27913850c04SHong Zhang     PetscTrMalloc    = PetscMallocAlign;
28013850c04SHong Zhang     PetscTrFree      = PetscFreeAlign;
281de1d6c17SHong Zhang   }
28213850c04SHong Zhang   PetscFunctionReturn(0);
28313850c04SHong Zhang }
28413850c04SHong Zhang 
285de1d6c17SHong Zhang /*@C
286de1d6c17SHong Zhang    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM
287de1d6c17SHong Zhang 
288de1d6c17SHong Zhang    Not Collective
289de1d6c17SHong Zhang 
290de1d6c17SHong Zhang    Level: developer
291de1d6c17SHong Zhang 
292de1d6c17SHong Zhang .seealso: PetscMallocSetDRAM()
293de1d6c17SHong Zhang @*/
29413850c04SHong Zhang PetscErrorCode PetscMallocResetDRAM(void)
29513850c04SHong Zhang {
29613850c04SHong Zhang   PetscFunctionBegin;
297de1d6c17SHong Zhang   if (PetscTrMalloc == PetscMallocAlign) {
298de1d6c17SHong Zhang #if defined(PETSC_HAVE_MEMKIND)
299de1d6c17SHong Zhang     currentmktype = previousmktype;
300de1d6c17SHong Zhang #endif
301de1d6c17SHong Zhang   } else {
30213850c04SHong Zhang     /* Reset to the previous choice */
30313850c04SHong Zhang     PetscTrMalloc = PetscTrMallocOld;
30413850c04SHong Zhang     PetscTrFree   = PetscTrFreeOld;
305de1d6c17SHong Zhang   }
30613850c04SHong Zhang   PetscFunctionReturn(0);
30713850c04SHong Zhang }
308