xref: /petsc/src/sys/memory/mal.c (revision b44d572041b6e43c5988e2e130e60a5b4238767e)
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
9e5c89e4eSSatish Balay 
10e5c89e4eSSatish Balay /*
11e5c89e4eSSatish Balay         We want to make sure that all mallocs of double or complex numbers are complex aligned.
12e5c89e4eSSatish Balay     1) on systems with memalign() we call that routine to get an aligned memory location
13e5c89e4eSSatish Balay     2) on systems without memalign() we
14e5c89e4eSSatish Balay        - allocate one sizeof(PetscScalar) extra space
15e5c89e4eSSatish Balay        - we shift the pointer up slightly if needed to get PetscScalar aligned
160700a824SBarry Smith        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
17e5c89e4eSSatish Balay */
180700a824SBarry Smith #define SHIFT_CLASSID 456123
19e5c89e4eSSatish Balay 
20e5c89e4eSSatish Balay #undef __FUNCT__
21e5c89e4eSSatish Balay #define __FUNCT__ "PetscMallocAlign"
22efca3c55SSatish Balay PetscErrorCode  PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
23e5c89e4eSSatish Balay {
24e5c89e4eSSatish Balay #if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
25e5c89e4eSSatish Balay   *result = malloc(mem);
26e5c89e4eSSatish Balay #elif defined(PETSC_HAVE_MEMALIGN)
27e5c89e4eSSatish Balay   *result = memalign(PETSC_MEMALIGN,mem);
28e5c89e4eSSatish Balay #else
29e5c89e4eSSatish Balay   {
30e5c89e4eSSatish Balay     int *ptr,shift;
31e5c89e4eSSatish Balay     /*
32e5c89e4eSSatish Balay       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
33e5c89e4eSSatish Balay     */
34e5c89e4eSSatish Balay     ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
35e5c89e4eSSatish Balay     if (ptr) {
36c82284b1SJed Brown       shift        = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
37e5c89e4eSSatish Balay       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
380700a824SBarry Smith       ptr[shift-1] = shift + SHIFT_CLASSID;
39e5c89e4eSSatish Balay       ptr         += shift;
40e5c89e4eSSatish Balay       *result      = (void*)ptr;
41e5c89e4eSSatish Balay     } else {
42e5c89e4eSSatish Balay       *result      = 0;
43e5c89e4eSSatish Balay     }
44e5c89e4eSSatish Balay   }
45e5c89e4eSSatish Balay #endif
46e32f2f54SBarry Smith   if (!*result) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested %.0f",(PetscLogDouble)mem);
47e5c89e4eSSatish Balay   return 0;
48e5c89e4eSSatish Balay }
49e5c89e4eSSatish Balay 
50e5c89e4eSSatish Balay #undef __FUNCT__
51e5c89e4eSSatish Balay #define __FUNCT__ "PetscFreeAlign"
52efca3c55SSatish Balay PetscErrorCode  PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
53e5c89e4eSSatish Balay {
54e5c89e4eSSatish Balay #if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
55e5c89e4eSSatish Balay   int shift;
56103af891SJed Brown 
57103af891SJed Brown   if (!ptr) PetscFunctionReturn(0);
58e5c89e4eSSatish Balay   /*
59e5c89e4eSSatish Balay        Previous int tells us how many ints the pointer has been shifted from
60e5c89e4eSSatish Balay     the original address provided by the system malloc().
61e5c89e4eSSatish Balay   */
620700a824SBarry Smith   shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
63efca3c55SSatish 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");
64efca3c55SSatish Balay   if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
65e5c89e4eSSatish Balay   ptr = (void*)(((int*)ptr) - shift);
66e5c89e4eSSatish Balay #endif
67e5c89e4eSSatish Balay 
68e5c89e4eSSatish Balay #if defined(PETSC_HAVE_FREE_RETURN_INT)
69e5c89e4eSSatish Balay   int err = free(ptr);
70efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
71e5c89e4eSSatish Balay #else
72e5c89e4eSSatish Balay   free(ptr);
73e5c89e4eSSatish Balay #endif
74e5c89e4eSSatish Balay   return 0;
75e5c89e4eSSatish Balay }
76e5c89e4eSSatish Balay 
77e5c89e4eSSatish Balay /*
78e5c89e4eSSatish Balay         We never use the system free directly because on many machines it
79e5c89e4eSSatish Balay     does not return an error code.
80e5c89e4eSSatish Balay */
81e5c89e4eSSatish Balay #undef __FUNCT__
82e5c89e4eSSatish Balay #define __FUNCT__ "PetscFreeDefault"
83efca3c55SSatish Balay PetscErrorCode  PetscFreeDefault(void *ptr,int line,char *func,char *file)
84e5c89e4eSSatish Balay {
85e5c89e4eSSatish Balay #if defined(PETSC_HAVE_FREE_RETURN_INT)
86e5c89e4eSSatish Balay   int err = free(ptr);
87efca3c55SSatish Balay   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
88e5c89e4eSSatish Balay #else
89e5c89e4eSSatish Balay   free(ptr);
90e5c89e4eSSatish Balay #endif
91e5c89e4eSSatish Balay   return 0;
92e5c89e4eSSatish Balay }
93e5c89e4eSSatish Balay 
94efca3c55SSatish Balay PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
95efca3c55SSatish Balay PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
96e5c89e4eSSatish Balay 
97ace3abfcSBarry Smith PetscBool petscsetmallocvisited = PETSC_FALSE;
98e5c89e4eSSatish Balay 
99e5c89e4eSSatish Balay #undef __FUNCT__
1001d1a0024SBarry Smith #define __FUNCT__ "PetscMallocSet"
101e5c89e4eSSatish Balay /*@C
1021d1a0024SBarry Smith    PetscMallocSet - Sets the routines used to do mallocs and frees.
103e5c89e4eSSatish Balay    This routine MUST be called before PetscInitialize() and may be
104e5c89e4eSSatish Balay    called only once.
105e5c89e4eSSatish Balay 
106e5c89e4eSSatish Balay    Not Collective
107e5c89e4eSSatish Balay 
108e5c89e4eSSatish Balay    Input Parameters:
109e5c89e4eSSatish Balay +  malloc - the malloc routine
110e5c89e4eSSatish Balay -  free - the free routine
111e5c89e4eSSatish Balay 
112e5c89e4eSSatish Balay    Level: developer
113e5c89e4eSSatish Balay 
114e5c89e4eSSatish Balay    Concepts: malloc
115e5c89e4eSSatish Balay    Concepts: memory^allocation
116e5c89e4eSSatish Balay 
117e5c89e4eSSatish Balay @*/
118efca3c55SSatish Balay PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
119efca3c55SSatish Balay                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
120e5c89e4eSSatish Balay {
121e5c89e4eSSatish Balay   PetscFunctionBegin;
122e32f2f54SBarry Smith   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
123e5c89e4eSSatish Balay   PetscTrMalloc         = imalloc;
124e5c89e4eSSatish Balay   PetscTrFree           = ifree;
125e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_TRUE;
126e5c89e4eSSatish Balay   PetscFunctionReturn(0);
127e5c89e4eSSatish Balay }
128e5c89e4eSSatish Balay 
129e5c89e4eSSatish Balay #undef __FUNCT__
1301d1a0024SBarry Smith #define __FUNCT__ "PetscMallocClear"
131e5c89e4eSSatish Balay /*@C
1321d1a0024SBarry Smith    PetscMallocClear - Resets the routines used to do mallocs and frees to the
133e5c89e4eSSatish Balay         defaults.
134e5c89e4eSSatish Balay 
135e5c89e4eSSatish Balay    Not Collective
136e5c89e4eSSatish Balay 
137e5c89e4eSSatish Balay    Level: developer
138e5c89e4eSSatish Balay 
139e5c89e4eSSatish Balay    Notes:
140e5c89e4eSSatish Balay     In general one should never run a PETSc program with different malloc() and
141e5c89e4eSSatish Balay     free() settings for different parts; this is because one NEVER wants to
142e5c89e4eSSatish Balay     free() an address that was malloced by a different memory management system
143e5c89e4eSSatish Balay 
144e5c89e4eSSatish Balay @*/
1457087cfbeSBarry Smith PetscErrorCode  PetscMallocClear(void)
146e5c89e4eSSatish Balay {
147e5c89e4eSSatish Balay   PetscFunctionBegin;
148e5c89e4eSSatish Balay   PetscTrMalloc         = PetscMallocAlign;
149e5c89e4eSSatish Balay   PetscTrFree           = PetscFreeAlign;
150e5c89e4eSSatish Balay   petscsetmallocvisited = PETSC_FALSE;
151e5c89e4eSSatish Balay   PetscFunctionReturn(0);
152e5c89e4eSSatish Balay }
153*b44d5720SBarry Smith 
154*b44d5720SBarry Smith #undef __FUNCT__
155*b44d5720SBarry Smith #define __FUNCT__ "PetscMemoryTrace"
156*b44d5720SBarry Smith PetscErrorCode PetscMemoryTrace(const char label[])
157*b44d5720SBarry Smith {
158*b44d5720SBarry Smith   PetscErrorCode        ierr;
159*b44d5720SBarry Smith   PetscLogDouble        mem,mal;
160*b44d5720SBarry Smith   static PetscLogDouble oldmem = 0,oldmal = 0;
161*b44d5720SBarry Smith 
162*b44d5720SBarry Smith   PetscFunctionBegin;
163*b44d5720SBarry Smith   ierr = PetscMemoryGetCurrentUsage(&mem);CHKERRQ(ierr);
164*b44d5720SBarry Smith   ierr = PetscMallocGetCurrentUsage(&mal);CHKERRQ(ierr);
165*b44d5720SBarry Smith 
166*b44d5720SBarry 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);
167*b44d5720SBarry Smith   oldmem = mem;
168*b44d5720SBarry Smith   oldmal = mal;
169*b44d5720SBarry Smith   PetscFunctionReturn(0);
170*b44d5720SBarry Smith }
171