Actual source code: mal.c

petsc-3.8.4 2018-03-24
Report Typos and Errors

  2: /*
  3:     Code that allows a user to dictate what malloc() PETSc uses.
  4: */
  5:  #include <petscsys.h>
  6: #if defined(PETSC_HAVE_MALLOC_H)
  7: #include <malloc.h>
  8: #endif
  9: #if defined(PETSC_HAVE_MEMKIND)
 10: #include <memkind.h>
 11: typedef enum {PETSC_MK_DEFAULT=0,PETSC_MK_HBW_PREFERRED=1} PetscMemkindType;
 12: PetscMemkindType currentmktype = PETSC_MK_HBW_PREFERRED;
 13: PetscMemkindType previousmktype = PETSC_MK_HBW_PREFERRED;
 14: #endif
 15: /*
 16:         We want to make sure that all mallocs of double or complex numbers are complex aligned.
 17:     1) on systems with memalign() we call that routine to get an aligned memory location
 18:     2) on systems without memalign() we
 19:        - allocate one sizeof(PetscScalar) extra space
 20:        - we shift the pointer up slightly if needed to get PetscScalar aligned
 21:        - if shifted we store at ptr[-1] the amount of shift (plus a classid)
 22: */
 23: #define SHIFT_CLASSID 456123

 25: PetscErrorCode  PetscMallocAlign(size_t mem,int line,const char func[],const char file[],void **result)
 26: {
 27:   if (!mem) { *result = NULL; return 0; }
 28: #if defined(PETSC_HAVE_MEMKIND)
 29:   {
 30:     int ierr;
 31:     if (!currentmktype) memkind_posix_memalign(MEMKIND_DEFAULT,result,PETSC_MEMALIGN,mem);
 32:     else memkind_posix_memalign(MEMKIND_HBW_PREFERRED,result,PETSC_MEMALIGN,mem);
 33:     if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem);
 34:   }
 35: #else
 36: #  if defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)
 37:   *result = malloc(mem);
 38: #  elif defined(PETSC_HAVE_MEMALIGN)
 39:   *result = memalign(PETSC_MEMALIGN,mem);
 40: #  else
 41:   {
 42:     /*
 43:       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
 44:     */
 45:     int *ptr = (int*)malloc(mem + 2*PETSC_MEMALIGN);
 46:     if (ptr) {
 47:       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
 48:       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
 49:       ptr[shift-1] = shift + SHIFT_CLASSID;
 50:       ptr         += shift;
 51:       *result      = (void*)ptr;
 52:     } else {
 53:       *result      = NULL;
 54:     }
 55:   }
 56: #  endif
 57: #endif
 58:   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
 59:   return 0;
 60: }

 62: PetscErrorCode  PetscFreeAlign(void *ptr,int line,const char func[],const char file[])
 63: {
 64:   if (!ptr) return 0;
 65: #if defined(PETSC_HAVE_MEMKIND)
 66:   memkind_free(0,ptr); /* specify the kind to 0 so that memkind will look up for the right type */
 67: #else
 68: #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
 69:   {
 70:     /*
 71:       Previous int tells us how many ints the pointer has been shifted from
 72:       the original address provided by the system malloc().
 73:     */
 74:     int shift = *(((int*)ptr)-1) - SHIFT_CLASSID;
 75:     if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
 76:     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
 77:     ptr = (void*)(((int*)ptr) - shift);
 78:   }
 79: #  endif

 81: #  if defined(PETSC_HAVE_FREE_RETURN_INT)
 82:   int err = free(ptr);
 83:   if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
 84: #  else
 85:   free(ptr);
 86: #  endif
 87: #endif
 88:   return 0;
 89: }

 91: PetscErrorCode PetscReallocAlign(size_t mem, int line, const char func[], const char file[], void **result)
 92: {

 95:   if (!mem) {
 96:     PetscFreeAlign(*result, line, func, file);
 97:     if (ierr) return ierr;
 98:     *result = NULL;
 99:     return 0;
100:   }
101: #if defined(PETSC_HAVE_MEMKIND)
102:   if (!currentmktype) *result = memkind_realloc(MEMKIND_DEFAULT,*result,mem);
103:   else *result = memkind_realloc(MEMKIND_HBW_PREFERRED,*result,mem);
104: #else
105: #  if (!(defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) && !defined(PETSC_HAVE_MEMALIGN))
106:   {
107:     /*
108:       Previous int tells us how many ints the pointer has been shifted from
109:       the original address provided by the system malloc().
110:     */
111:     int shift = *(((int*)*result)-1) - SHIFT_CLASSID;
112:     if (shift > PETSC_MEMALIGN-1) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
113:     if (shift < 0) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"Likely memory corruption in heap");
114:     *result = (void*)(((int*)*result) - shift);
115:   }
116: #  endif

118: #  if (defined(PETSC_HAVE_DOUBLE_ALIGN_MALLOC) && (PETSC_MEMALIGN == 8)) || defined(PETSC_HAVE_MEMALIGN)
119:   *result = realloc(*result, mem);
120: #  else
121:   {
122:     /*
123:       malloc space for two extra chunks and shift ptr 1 + enough to get it PetscScalar aligned
124:     */
125:     int *ptr = (int *) realloc(*result, mem + 2*PETSC_MEMALIGN);
126:     if (ptr) {
127:       int shift    = (int)(((PETSC_UINTPTR_T) ptr) % PETSC_MEMALIGN);
128:       shift        = (2*PETSC_MEMALIGN - shift)/sizeof(int);
129:       ptr[shift-1] = shift + SHIFT_CLASSID;
130:       ptr         += shift;
131:       *result      = (void*)ptr;
132:     } else {
133:       *result      = NULL;
134:     }
135:   }
136: #  endif
137: #endif
138:   if (!*result) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
139: #if defined(PETSC_HAVE_MEMALIGN)
140:   /* There are no standard guarantees that realloc() maintains the alignment of memalign(), so I think we have to
141:    * realloc and, if the alignment is wrong, malloc/copy/free. */
142:   if (((size_t) (*result)) % PETSC_MEMALIGN) {
143:     void *newResult;
144: #  if defined(PETSC_HAVE_MEMKIND)
145:     {
146:       int ierr;
147:       if (!currentmktype) memkind_posix_memalign(MEMKIND_DEFAULT,&newResult,PETSC_MEMALIGN,mem);
148:       else memkind_posix_memalign(MEMKIND_HBW_PREFERRED,&newResult,PETSC_MEMALIGN,mem);
149:       if (ierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_MEM,"Memory requested with memkind %.0f",(PetscLogDouble)mem);
150:     }
151: #  else
152:     newResult = memalign(PETSC_MEMALIGN,mem);
153: #  endif
154:     if (!newResult) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_MEM,PETSC_ERROR_INITIAL,"Memory requested %.0f",(PetscLogDouble)mem);
155:     PetscMemcpy(newResult,*result,mem);
156:     if (ierr) return ierr;
157: #  if defined(PETSC_HAVE_FREE_RETURN_INT)
158:     {
159:       int err = free(*result);
160:       if (err) return PetscError(PETSC_COMM_SELF,line,func,file,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL,"System free returned error %d\n",err);
161:     }
162: #  else
163: #    if defined(PETSC_HAVE_MEMKIND)
164:     memkind_free(0,*result);
165: #    else
166:     free(*result);
167: #    endif
168: #  endif
169:     *result = newResult;
170:   }
171: #endif
172:   return 0;
173: }

175: PetscErrorCode (*PetscTrMalloc)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
176: PetscErrorCode (*PetscTrFree)(void*,int,const char[],const char[])           = PetscFreeAlign;
177: PetscErrorCode (*PetscTrRealloc)(size_t,int,const char[],const char[],void**) = PetscReallocAlign;

179: PetscBool petscsetmallocvisited = PETSC_FALSE;

181: /*@C
182:    PetscMallocSet - Sets the routines used to do mallocs and frees.
183:    This routine MUST be called before PetscInitialize() and may be
184:    called only once.

186:    Not Collective

188:    Input Parameters:
189: +  malloc - the malloc routine
190: -  free - the free routine

192:    Level: developer

194:    Concepts: malloc
195:    Concepts: memory^allocation

197: @*/
198: PetscErrorCode  PetscMallocSet(PetscErrorCode (*imalloc)(size_t,int,const char[],const char[],void**),
199:                                               PetscErrorCode (*ifree)(void*,int,const char[],const char[]))
200: {
202:   if (petscsetmallocvisited && (imalloc != PetscTrMalloc || ifree != PetscTrFree)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"cannot call multiple times");
203:   PetscTrMalloc         = imalloc;
204:   PetscTrFree           = ifree;
205:   petscsetmallocvisited = PETSC_TRUE;
206:   return(0);
207: }

209: /*@C
210:    PetscMallocClear - Resets the routines used to do mallocs and frees to the
211:         defaults.

213:    Not Collective

215:    Level: developer

217:    Notes:
218:     In general one should never run a PETSc program with different malloc() and
219:     free() settings for different parts; this is because one NEVER wants to
220:     free() an address that was malloced by a different memory management system

222: @*/
223: PetscErrorCode  PetscMallocClear(void)
224: {
226:   PetscTrMalloc         = PetscMallocAlign;
227:   PetscTrFree           = PetscFreeAlign;
228:   petscsetmallocvisited = PETSC_FALSE;
229:   return(0);
230: }

232: PetscErrorCode PetscMemoryTrace(const char label[])
233: {
234:   PetscErrorCode        ierr;
235:   PetscLogDouble        mem,mal;
236:   static PetscLogDouble oldmem = 0,oldmal = 0;

239:   PetscMemoryGetCurrentUsage(&mem);
240:   PetscMallocGetCurrentUsage(&mal);

242:   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);
243:   oldmem = mem;
244:   oldmal = mal;
245:   return(0);
246: }

248: static PetscErrorCode (*PetscTrMallocOld)(size_t,int,const char[],const char[],void**) = PetscMallocAlign;
249: static PetscErrorCode (*PetscTrFreeOld)(void*,int,const char[],const char[])           = PetscFreeAlign;

251: /*@C
252:    PetscMallocSetDRAM - Set PetscMalloc to use DRAM.
253:      If memkind is available, change the memkind type. Otherwise, switch the
254:      current malloc and free routines to the PetscMallocAlign and
255:      PetscFreeAlign (PETSc default).

257:    Not Collective

259:    Level: developer

261:    Notes:
262:      This provides a way to do the allocation on DRAM temporarily. One
263:      can switch back to the previous choice by calling PetscMallocReset().
264:  
265: .seealso: PetscMallocReset()
266: @*/
267: PetscErrorCode PetscMallocSetDRAM(void)
268: {
270:   if (PetscTrMalloc == PetscMallocAlign) {
271: #if defined(PETSC_HAVE_MEMKIND)
272:     previousmktype = currentmktype;
273:     currentmktype  = PETSC_MK_DEFAULT;
274: #endif
275:   } else {
276:     /* Save the previous choice */
277:     PetscTrMallocOld = PetscTrMalloc;
278:     PetscTrFreeOld   = PetscTrFree;
279:     PetscTrMalloc    = PetscMallocAlign;
280:     PetscTrFree      = PetscFreeAlign;
281:   }
282:   return(0);
283: }

285: /*@C
286:    PetscMallocResetDRAM - Reset the changes made by PetscMallocSetDRAM

288:    Not Collective

290:    Level: developer

292: .seealso: PetscMallocSetDRAM()
293: @*/
294: PetscErrorCode PetscMallocResetDRAM(void)
295: {
297:   if (PetscTrMalloc == PetscMallocAlign) {
298: #if defined(PETSC_HAVE_MEMKIND)
299:     currentmktype = previousmktype;
300: #endif 
301:   } else {
302:     /* Reset to the previous choice */
303:     PetscTrMalloc = PetscTrMallocOld;
304:     PetscTrFree   = PetscTrFreeOld;
305:   }
306:   return(0);
307: }