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