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