Actual source code: mal.c
petsc-3.8.4 2018-03-24
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: }