xref: /petsc/src/sys/memory/mal.c (revision 8a05737ace67b9faae7b8244947d96f158779ffb)
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 PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
78 PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
79 
80 PetscBool petscsetmallocvisited = PETSC_FALSE;
81 
82 #undef __FUNCT__
83 #define __FUNCT__ "PetscMallocSet"
84 /*@C
85    PetscMallocSet - Sets the routines used to do mallocs and frees.
86    This routine MUST be called before PetscInitialize() and may be
87    called only once.
88 
89    Not Collective
90 
91    Input Parameters:
92 +  malloc - the malloc routine
93 -  free - the free routine
94 
95    Level: developer
96 
97    Concepts: malloc
98    Concepts: memory^allocation
99 
100 @*/
101 PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
102                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
103 {
104   PetscFunctionBegin;
105   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
106   PetscTrMalloc         = imalloc;
107   PetscTrFree           = ifree;
108   petscsetmallocvisited = PETSC_TRUE;
109   PetscFunctionReturn(0);
110 }
111 
112 #undef __FUNCT__
113 #define __FUNCT__ "PetscMallocClear"
114 /*@C
115    PetscMallocClear - Resets the routines used to do mallocs and frees to the
116         defaults.
117 
118    Not Collective
119 
120    Level: developer
121 
122    Notes:
123     In general one should never run a PETSc program with different malloc() and
124     free() settings for different parts; this is because one NEVER wants to
125     free() an address that was malloced by a different memory management system
126 
127 @*/
128 PetscErrorCode  PetscMallocClear(void)
129 {
130   PetscFunctionBegin;
131   PetscTrMalloc         = PetscMallocAlign;
132   PetscTrFree           = PetscFreeAlign;
133   petscsetmallocvisited = PETSC_FALSE;
134   PetscFunctionReturn(0);
135 }
136 
137 #undef __FUNCT__
138 #define __FUNCT__ "PetscMemoryTrace"
139 PetscErrorCode PetscMemoryTrace(const char label[])
140 {
141   PetscErrorCode        ierr;
142   PetscLogDouble        mem,mal;
143   static PetscLogDouble oldmem = 0,oldmal = 0;
144 
145   PetscFunctionBegin;
146   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
147   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
148 
149   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);
150   oldmem = mem;
151   oldmal = mal;
152   PetscFunctionReturn(0);
153 }
154