xref: /petsc/src/sys/memory/mal.c (revision fbfcfee5110779e3d6a9465ca0a2e0f9a1a6e5e3)
1 
2 /*
3     Code that allows a user to dictate what malloc() PETSc uses.
4 */
5 #include <petscsys.h>             /*I   "petscsys.h"   I*/
6 #if defined(PETSC_HAVE_MALLOC_H)
7 #include <malloc.h>
8 #endif
9 
10 /*
11         We want to make sure that all mallocs of double or complex numbers are complex aligned.
12     1) on systems with memalign() we call that routine to get an aligned memory location
13     2) on systems without memalign() we
14        - allocate one sizeof(PetscScalar) extra space
15        - we shift the pointer up slightly if needed to get PetscScalar aligned
16        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
17 */
18 #define SHIFT_CLASSID 456123
19 
20 PetscErrorCode  PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
21 {
22   if (!mem) { *result = NULL; return 0; }
23 #if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
24   *result = malloc(mem);
25 #elif defined(PETSC_HAVE_MEMALIGN)
26   *result = memalign(PETSC_MEMALIGN,mem);
27 #else
28   {
29     /*
30       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
31     */
32     int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
33     if (ptr) {
34       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
35       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
36       ptr[shift-1] = shift + SHIFT_CLASSID;
37       ptr         += shift;
38       *result      = (void*)ptr;
39     } else {
40       *result      = NULL;
41     }
42   }
43 #endif
44   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
45   return 0;
46 }
47 
48 PetscErrorCode  PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
49 {
50   if (!ptr) return 0;
51 #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
52   {
53     /*
54       Previous int tells us how many ints the pointer has been shifted from
55       the original address provided by the system malloc().
56     */
57     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
58     if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
59     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
60     ptr = (void*)(((int*)ptr) - shift);
61   }
62 #endif
63 
64 #if defined(PETSC_HAVE_FREE_RETURN_INT)
65   int err = free(ptr);
66   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
67 #else
68   free(ptr);
69 #endif
70   return 0;
71 }
72 
73 PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
74 {
75   PetscErrorCode ierr;
76 
77   if (!mem) {
78     ierr = PetscFreeAlign(*result, line, func, file);
79     if (ierr) return ierr;
80     *result = NULL;
81     return 0;
82   }
83 #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
84   {
85     /*
86       Previous int tells us how many ints the pointer has been shifted from
87       the original address provided by the system malloc().
88     */
89     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
90     if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
91     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
92     *result = (void*)(((int*)*result) - shift);
93   }
94 #endif
95 
96 #if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
97   *result = realloc(*result, mem);
98 #else
99   {
100     /*
101       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
102     */
103     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
104     if (ptr) {
105       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
106       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
107       ptr[shift-1] = shift + SHIFT_CLASSID;
108       ptr         += shift;
109       *result      = (void*)ptr;
110     } else {
111       *result      = NULL;
112     }
113   }
114 #endif
115   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
116 #if defined(PETSC_HAVE_MEMALIGN)
117   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
118    * realloc and, if the alignment is wrong, malloc/copy/free. */
119   if (((size_t) (*result)) % PETSC_MEMALIGN) {
120     void *newResult;
121 
122     newResult = memalign(PETSC_MEMALIGN,mem);
123     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
124     ierr = PetscMemcpy(newResult,*result,mem);
125     if (ierr) return ierr;
126 #if defined(PETSC_HAVE_FREE_RETURN_INT)
127     {
128       int err = free(*result);
129       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
130     }
131 #else
132     free(*result);
133 #endif
134     *result = newResult;
135   }
136 #endif
137   return 0;
138 }
139 
140 PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
141 PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
142 PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign;
143 
144 PetscBool petscsetmallocvisited = PETSC_FALSE;
145 
146 /*@C
147    PetscMallocSet - Sets the routines used to do mallocs and frees.
148    This routine MUST be called before PetscInitialize() and may be
149    called only once.
150 
151    Not Collective
152 
153    Input Parameters:
154 +  malloc - the malloc routine
155 -  free - the free routine
156 
157    Level: developer
158 
159    Concepts: malloc
160    Concepts: memory^allocation
161 
162 @*/
163 PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
164                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
165 {
166   PetscFunctionBegin;
167   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
168   PetscTrMalloc         = imalloc;
169   PetscTrFree           = ifree;
170   petscsetmallocvisited = PETSC_TRUE;
171   PetscFunctionReturn(0);
172 }
173 
174 /*@C
175    PetscMallocClear - Resets the routines used to do mallocs and frees to the
176         defaults.
177 
178    Not Collective
179 
180    Level: developer
181 
182    Notes:
183     In general one should never run a PETSc program with different malloc() and
184     free() settings for different parts; this is because one NEVER wants to
185     free() an address that was malloced by a different memory management system
186 
187 @*/
188 PetscErrorCode  PetscMallocClear(void)
189 {
190   PetscFunctionBegin;
191   PetscTrMalloc         = PetscMallocAlign;
192   PetscTrFree           = PetscFreeAlign;
193   petscsetmallocvisited = PETSC_FALSE;
194   PetscFunctionReturn(0);
195 }
196 
197 PetscErrorCode PetscMemoryTrace(const char label[])
198 {
199   PetscErrorCode        ierr;
200   PetscLogDouble        mem,mal;
201   static PetscLogDouble oldmem = 0,oldmal = 0;
202 
203   PetscFunctionBegin;
204   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
205   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
206 
207   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);
208   oldmem = mem;
209   oldmal = mal;
210   PetscFunctionReturn(0);
211 }
212