xref: /petsc/src/sys/memory/mtr.c (revision bef158480efac06de457f7a665168877ab3c2fd7)
1 
2 /*
3      Interface to malloc() and free(). This code allows for logging of memory usage and some error checking
4 */
5 #include <petscsys.h>           /*I "petscsys.h" I*/
6 #include <petscviewer.h>
7 #if defined(PETSC_HAVE_MALLOC_H)
8 #include <malloc.h>
9 #endif
10 
11 /*
12      These are defined in mal.c and ensure that malloced space is PetscScalar aligned
13 */
14 PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t,PetscBool,int,const char[],const char[],void**);
15 PETSC_EXTERN PetscErrorCode PetscFreeAlign(void*,int,const char[],const char[]);
16 PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t,int,const char[],const char[],void**);
17 
18 #define CLASSID_VALUE  ((PetscClassId) 0xf0e0d0c9)
19 #define ALREADY_FREED  ((PetscClassId) 0x0f0e0d9c)
20 
21 /*  this is the header put at the beginning of each malloc() using for tracking allocated space and checking of allocated space heap */
22 typedef struct _trSPACE {
23   size_t          size;
24   int             id;
25   int             lineno;
26   const char      *filename;
27   const char      *functionname;
28   PetscClassId    classid;
29 #if defined(PETSC_USE_DEBUG)
30   PetscStack      stack;
31 #endif
32   struct _trSPACE *next,*prev;
33 } TRSPACE;
34 
35 /* HEADER_BYTES is the number of bytes in a PetscMalloc() header.
36    It is sizeof(trSPACE) padded to be a multiple of PETSC_MEMALIGN.
37 */
38 #define HEADER_BYTES  ((sizeof(TRSPACE)+(PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1))
39 
40 /* This union is used to insure that the block passed to the user retains
41    a minimum alignment of PETSC_MEMALIGN.
42 */
43 typedef union {
44   TRSPACE sp;
45   char    v[HEADER_BYTES];
46 } TrSPACE;
47 
48 #define MAXTRMAXMEMS 50
49 static size_t    TRallocated          = 0;
50 static int       TRfrags              = 0;
51 static TRSPACE   *TRhead              = NULL;
52 static int       TRid                 = 0;
53 static PetscBool TRdebugLevel         = PETSC_FALSE;
54 static PetscBool TRdebugIinitializenan= PETSC_FALSE;
55 static size_t    TRMaxMem             = 0;
56 static int       NumTRMaxMems         = 0;
57 static size_t    TRMaxMems[MAXTRMAXMEMS];
58 static int       TRMaxMemsEvents[MAXTRMAXMEMS];
59 /*
60       Arrays to log information on mallocs for PetscMallocView()
61 */
62 static int        PetscLogMallocMax       = 10000;
63 static int        PetscLogMalloc          = -1;
64 static size_t     PetscLogMallocThreshold = 0;
65 static size_t     *PetscLogMallocLength;
66 static const char **PetscLogMallocFile,**PetscLogMallocFunction;
67 
68 /*@C
69    PetscMallocValidate - Test the memory for corruption.  This can be called at any time between PetscInitialize() and PetscFinalize()
70 
71    Input Parameters:
72 +  line - line number where call originated.
73 .  function - name of function calling
74 -  file - file where function is
75 
76    Return value:
77    The number of errors detected.
78 
79    Options Database:.
80 +  -malloc_test - turns this feature on when PETSc was not configured with --with-debugging=0
81 -  -malloc_debug - turns this feature on anytime
82 
83    Output Effect:
84    Error messages are written to stdout.
85 
86    Level: advanced
87 
88    Notes:
89     This is only run if PetscMallocSetDebug() has been called which is set by -malloc_test (if debugging is turned on) or -malloc_debug (any time)
90 
91     You should generally use CHKMEMQ as a short cut for calling this  routine.
92 
93     The Fortran calling sequence is simply PetscMallocValidate(ierr)
94 
95    No output is generated if there are no problems detected.
96 
97    Developers Note:
98      Uses the flg TRdebugLevel (set as the first argument to PetscMallocSetDebug()) to determine if it should run
99 
100 .seealso: CHKMEMQ
101 
102 @*/
103 PetscErrorCode  PetscMallocValidate(int line,const char function[],const char file[])
104 {
105   TRSPACE      *head,*lasthead;
106   char         *a;
107   PetscClassId *nend;
108 
109   if (!TRdebugLevel) return 0;
110   PetscFunctionBegin;
111   head = TRhead; lasthead = NULL;
112   if (head && head->prev) {
113     (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s\n",function,line,file);
114     (*PetscErrorPrintf)("Root memory header %p has invalid back pointer %p\n",head,head->prev);
115   }
116   while (head) {
117     if (head->classid != CLASSID_VALUE) {
118       (*PetscErrorPrintf)("PetscMallocValidate: error detected at  %s() line %d in %s\n",function,line,file);
119       (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
120       (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
121       if (lasthead) (*PetscErrorPrintf)("Last intact block allocated in %s() line %d in %s\n",lasthead->functionname,lasthead->lineno,lasthead->filename);
122       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
123     }
124     a    = (char*)(((TrSPACE*)head) + 1);
125     nend = (PetscClassId*)(a + head->size);
126     if (*nend != CLASSID_VALUE) {
127       (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s\n",function,line,file);
128       if (*nend == ALREADY_FREED) {
129         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n",head->id,(PetscLogDouble)head->size,a);
130         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
131       } else {
132         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
133         (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
134         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
135       }
136     }
137     if (head->prev && head->prev != lasthead) {
138       (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s\n",function,line,file);
139       (*PetscErrorPrintf)("Backpointer %p is invalid, should be %p\n",head->prev,lasthead);
140       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
141     }
142     if (head->next && head != head->next->prev) {
143       (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s\n",function,line,file);
144       (*PetscErrorPrintf)("Next memory header %p has invalid back pointer %p, should be %p\n",head->next,head->next->prev,head);
145       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
146     }
147     lasthead = head;
148     head     = head->next;
149   }
150   PetscFunctionReturn(0);
151 }
152 
153 /*
154     PetscTrMallocDefault - Malloc with tracing.
155 
156     Input Parameters:
157 +   a   - number of bytes to allocate
158 .   lineno - line number where used.  Use __LINE__ for this
159 -   filename  - file name where used.  Use __FILE__ for this
160 
161     Returns:
162     double aligned pointer to requested storage, or null if not  available.
163  */
164 PetscErrorCode  PetscTrMallocDefault(size_t a,PetscBool clear,int lineno,const char function[],const char filename[],void **result)
165 {
166   TRSPACE        *head;
167   char           *inew;
168   size_t         nsize;
169   PetscErrorCode ierr;
170 
171   PetscFunctionBegin;
172   /* Do not try to handle empty blocks */
173   if (!a) { *result = NULL; PetscFunctionReturn(0); }
174 
175   ierr = PetscMallocValidate(lineno,function,filename); if (ierr) PetscFunctionReturn(ierr);
176 
177   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
178   ierr  = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),clear,lineno,function,filename,(void**)&inew);CHKERRQ(ierr);
179 
180   head  = (TRSPACE*)inew;
181   inew += sizeof(TrSPACE);
182 
183   if (TRhead) TRhead->prev = head;
184   head->next   = TRhead;
185   TRhead       = head;
186   head->prev   = NULL;
187   head->size   = nsize;
188   head->id     = TRid;
189   head->lineno = lineno;
190 
191   head->filename                 = filename;
192   head->functionname             = function;
193   head->classid                  = CLASSID_VALUE;
194   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;
195 
196   TRallocated += nsize;
197   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
198   if (PetscLogMemory) {
199     PetscInt i;
200     for (i=0; i<NumTRMaxMems; i++) {
201       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
202     }
203   }
204   TRfrags++;
205 
206 #if defined(PETSC_USE_DEBUG)
207   if (PetscStackActive()) {
208     ierr = PetscStackCopy(petscstack,&head->stack);CHKERRQ(ierr);
209     /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
210     head->stack.line[head->stack.currentsize-2] = lineno;
211   } else {
212     head->stack.currentsize = 0;
213   }
214 #if defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE)
215   if (!clear && TRdebugIinitializenan) {
216     size_t     i, n = a/sizeof(PetscReal);
217     PetscReal *s = (PetscReal*) inew;
218     /* from https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html */
219 #if defined(PETSC_USE_REAL_SINGLE)
220     int        nas = 0x7F800002;
221 #else
222     PetscInt64 nas = 0x7FF0000000000002;
223 #endif
224     for (i=0; i<n; i++) {
225       memcpy(s+i,&nas,sizeof(PetscReal));
226     }
227   }
228 #endif
229 #endif
230 
231   /*
232          Allow logging of all mallocs made.
233          TODO: Currently this memory is never freed, it should be freed during PetscFinalize()
234   */
235   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && a >= PetscLogMallocThreshold) {
236     if (!PetscLogMalloc) {
237       PetscLogMallocLength = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
238       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
239 
240       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
241       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
242 
243       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
244       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
245     }
246     PetscLogMallocLength[PetscLogMalloc]     = nsize;
247     PetscLogMallocFile[PetscLogMalloc]       = filename;
248     PetscLogMallocFunction[PetscLogMalloc++] = function;
249   }
250   *result = (void*)inew;
251   PetscFunctionReturn(0);
252 }
253 
254 /*
255    PetscTrFreeDefault - Free with tracing.
256 
257    Input Parameters:
258 .   a    - pointer to a block allocated with PetscTrMalloc
259 .   lineno - line number where used.  Use __LINE__ for this
260 .   file  - file name where used.  Use __FILE__ for this
261  */
262 PetscErrorCode  PetscTrFreeDefault(void *aa,int line,const char function[],const char file[])
263 {
264   char           *a = (char*)aa;
265   TRSPACE        *head;
266   char           *ahead;
267   PetscErrorCode ierr;
268   PetscClassId   *nend;
269 
270   PetscFunctionBegin;
271   /* Do not try to handle empty blocks */
272   if (!a) PetscFunctionReturn(0);
273 
274   ierr = PetscMallocValidate(line,function,file);CHKERRQ(ierr);
275 
276   ahead = a;
277   a     = a - sizeof(TrSPACE);
278   head  = (TRSPACE*)a;
279 
280   if (head->classid != CLASSID_VALUE) {
281     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
282     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
283     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
284   }
285   nend = (PetscClassId*)(ahead + head->size);
286   if (*nend != CLASSID_VALUE) {
287     if (*nend == ALREADY_FREED) {
288       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
289       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
290       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
291         (*PetscErrorPrintf)("Block freed in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
292       } else {
293         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,-head->lineno,head->filename);
294       }
295       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
296     } else {
297       /* Damaged tail */
298       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
299       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
300       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
301       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
302     }
303   }
304   /* Mark the location freed */
305   *nend = ALREADY_FREED;
306   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
307   if (line > 0 && line < 50000) {
308     head->lineno       = line;
309     head->filename     = file;
310     head->functionname = function;
311   } else {
312     head->lineno = -head->lineno;
313   }
314   if (TRallocated < head->size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"TRallocate is smaller than memory just freed");
315   TRallocated -= head->size;
316   TRfrags--;
317   if (head->prev) head->prev->next = head->next;
318   else TRhead = head->next;
319 
320   if (head->next) head->next->prev = head->prev;
321   ierr = PetscFreeAlign(a,line,function,file);CHKERRQ(ierr);
322   PetscFunctionReturn(0);
323 }
324 
325 /*
326   PetscTrReallocDefault - Realloc with tracing.
327 
328   Input Parameters:
329 + len      - number of bytes to allocate
330 . lineno   - line number where used.  Use __LINE__ for this
331 . filename - file name where used.  Use __FILE__ for this
332 - result - original memory
333 
334   Output Parameter:
335 . result - double aligned pointer to requested storage, or null if not available.
336 
337   Level: developer
338 
339 .seealso: PetscTrMallocDefault(), PetscTrFreeDefault()
340 */
341 PetscErrorCode PetscTrReallocDefault(size_t len, int lineno, const char function[], const char filename[], void **result)
342 {
343   char           *a = (char *) *result;
344   TRSPACE        *head;
345   char           *ahead, *inew;
346   PetscClassId   *nend;
347   size_t         nsize;
348   PetscErrorCode ierr;
349 
350   PetscFunctionBegin;
351   /* Realloc requests zero space so just free the current space */
352   if (!len) {
353     ierr = PetscTrFreeDefault(*result,lineno,function,filename);CHKERRQ(ierr);
354     *result = NULL;
355     PetscFunctionReturn(0);
356   }
357   /* If the orginal space was NULL just use the regular malloc() */
358   if (!*result) {
359     ierr = PetscTrMallocDefault(len,PETSC_FALSE,lineno,function,filename,result);CHKERRQ(ierr);
360     PetscFunctionReturn(0);
361   }
362 
363   ierr = PetscMallocValidate(lineno,function,filename); if (ierr) PetscFunctionReturn(ierr);
364 
365   ahead = a;
366   a     = a - sizeof(TrSPACE);
367   head  = (TRSPACE *) a;
368   inew  = a;
369 
370   if (head->classid != CLASSID_VALUE) {
371     (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() line %d in %s\n",function,lineno,filename);
372     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
373     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
374   }
375   nend = (PetscClassId *)(ahead + head->size);
376   if (*nend != CLASSID_VALUE) {
377     if (*nend == ALREADY_FREED) {
378       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() line %d in %s\n",function,lineno,filename);
379       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
380       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
381         (*PetscErrorPrintf)("Block freed in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
382       } else {
383         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,-head->lineno,head->filename);
384       }
385       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
386     } else {
387       /* Damaged tail */
388       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() line %d in %s\n",function,lineno,filename);
389       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
390       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
391       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
392     }
393   }
394 
395   /* remove original reference to the memory allocated from the PETSc debugging heap */
396   TRallocated -= head->size;
397   TRfrags--;
398   if (head->prev) head->prev->next = head->next;
399   else TRhead = head->next;
400   if (head->next) head->next->prev = head->prev;
401 
402   nsize = (len + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
403   ierr  = PetscReallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),lineno,function,filename,(void**)&inew);CHKERRQ(ierr);
404 
405   head  = (TRSPACE*)inew;
406   inew += sizeof(TrSPACE);
407 
408   if (TRhead) TRhead->prev = head;
409   head->next   = TRhead;
410   TRhead       = head;
411   head->prev   = NULL;
412   head->size   = nsize;
413   head->id     = TRid;
414   head->lineno = lineno;
415 
416   head->filename                 = filename;
417   head->functionname             = function;
418   head->classid                  = CLASSID_VALUE;
419   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;
420 
421   TRallocated += nsize;
422   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
423   if (PetscLogMemory) {
424     PetscInt i;
425     for (i=0; i<NumTRMaxMems; i++) {
426       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
427     }
428   }
429   TRfrags++;
430 
431 #if defined(PETSC_USE_DEBUG)
432   if (PetscStackActive()) {
433     ierr = PetscStackCopy(petscstack,&head->stack);CHKERRQ(ierr);
434     /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
435     head->stack.line[head->stack.currentsize-2] = lineno;
436   } else {
437     head->stack.currentsize = 0;
438   }
439 #endif
440 
441   /*
442          Allow logging of all mallocs made. This adds a new entry to the list of allocated memory
443          and does not remove the previous entry to the list hence this memory is "double counted" in PetscMallocView()
444   */
445   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && len >= PetscLogMallocThreshold) {
446     if (!PetscLogMalloc) {
447       PetscLogMallocLength = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
448       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
449 
450       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
451       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
452 
453       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
454       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
455     }
456     PetscLogMallocLength[PetscLogMalloc]     = nsize;
457     PetscLogMallocFile[PetscLogMalloc]       = filename;
458     PetscLogMallocFunction[PetscLogMalloc++] = function;
459   }
460   *result = (void*)inew;
461   PetscFunctionReturn(0);
462 }
463 
464 /*@C
465     PetscMemoryView - Shows the amount of memory currently being used in a communicator.
466 
467     Collective on PetscViewer
468 
469     Input Parameter:
470 +    viewer - the viewer that defines the communicator
471 -    message - string printed before values
472 
473     Options Database:
474 +    -malloc_debug - have PETSc track how much memory it has allocated
475 -    -memory_view - during PetscFinalize() have this routine called
476 
477     Level: intermediate
478 
479 .seealso: PetscMallocDump(), PetscMemoryGetCurrentUsage(), PetscMemorySetGetMaximumUsage(), PetscMallocView()
480  @*/
481 PetscErrorCode  PetscMemoryView(PetscViewer viewer,const char message[])
482 {
483   PetscLogDouble allocated,allocatedmax,resident,residentmax,gallocated,gallocatedmax,gresident,gresidentmax,maxgallocated,maxgallocatedmax,maxgresident,maxgresidentmax;
484   PetscLogDouble mingallocated,mingallocatedmax,mingresident,mingresidentmax;
485   PetscErrorCode ierr;
486   MPI_Comm       comm;
487 
488   PetscFunctionBegin;
489   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
490   ierr = PetscMallocGetCurrentUsage(&allocated);CHKERRQ(ierr);
491   ierr = PetscMallocGetMaximumUsage(&allocatedmax);CHKERRQ(ierr);
492   ierr = PetscMemoryGetCurrentUsage(&resident);CHKERRQ(ierr);
493   ierr = PetscMemoryGetMaximumUsage(&residentmax);CHKERRQ(ierr);
494   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
495   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
496   ierr = PetscViewerASCIIPrintf(viewer,message);CHKERRQ(ierr);
497   if (resident && residentmax && allocated) {
498     ierr = MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
499     ierr = MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
500     ierr = MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
501     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);CHKERRQ(ierr);
502     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
503     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
504     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
505     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
506     ierr = MPI_Reduce(&allocatedmax,&gallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
507     ierr = MPI_Reduce(&allocatedmax,&maxgallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
508     ierr = MPI_Reduce(&allocatedmax,&mingallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
509     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) space PetscMalloc()ed: total %5.4e max %5.4e min %5.4e\n",gallocatedmax,maxgallocatedmax,mingallocatedmax);CHKERRQ(ierr);
510     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
511     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
512     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
513     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
514   } else if (resident && residentmax) {
515     ierr = MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
516     ierr = MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
517     ierr = MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
518     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);CHKERRQ(ierr);
519     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
520     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
521     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
522     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
523   } else if (resident && allocated) {
524     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
525     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
526     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
527     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
528     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
529     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
530     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
531     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
532     ierr = PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");CHKERRQ(ierr);
533   } else if (allocated) {
534     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
535     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
536     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
537     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
538     ierr = PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");CHKERRQ(ierr);
539     ierr = PetscViewerASCIIPrintf(viewer,"OS cannot compute process memory\n");CHKERRQ(ierr);
540   } else {
541     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc_debug to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
542   }
543   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
544   PetscFunctionReturn(0);
545 }
546 
547 /*@
548     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
549 
550     Not Collective
551 
552     Output Parameters:
553 .   space - number of bytes currently allocated
554 
555     Level: intermediate
556 
557 .seealso: PetscMallocDump(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
558           PetscMemoryGetMaximumUsage()
559  @*/
560 PetscErrorCode  PetscMallocGetCurrentUsage(PetscLogDouble *space)
561 {
562   PetscFunctionBegin;
563   *space = (PetscLogDouble) TRallocated;
564   PetscFunctionReturn(0);
565 }
566 
567 /*@
568     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
569         during this run.
570 
571     Not Collective
572 
573     Output Parameters:
574 .   space - maximum number of bytes ever allocated at one time
575 
576     Level: intermediate
577 
578 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
579           PetscMallocPushMaximumUsage()
580  @*/
581 PetscErrorCode  PetscMallocGetMaximumUsage(PetscLogDouble *space)
582 {
583   PetscFunctionBegin;
584   *space = (PetscLogDouble) TRMaxMem;
585   PetscFunctionReturn(0);
586 }
587 
588 /*@
589     PetscMallocPushMaximumUsage - Adds another event to collect the maximum memory usage over an event
590 
591     Not Collective
592 
593     Input Parameter:
594 .   event - an event id; this is just for error checking
595 
596     Level: developer
597 
598 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
599           PetscMallocPopMaximumUsage()
600  @*/
601 PetscErrorCode  PetscMallocPushMaximumUsage(int event)
602 {
603   PetscFunctionBegin;
604   if (++NumTRMaxMems > MAXTRMAXMEMS) PetscFunctionReturn(0);
605   TRMaxMems[NumTRMaxMems-1]       = TRallocated;
606   TRMaxMemsEvents[NumTRMaxMems-1] = event;
607   PetscFunctionReturn(0);
608 }
609 
610 /*@
611     PetscMallocPopMaximumUsage - collect the maximum memory usage over an event
612 
613     Not Collective
614 
615     Input Parameter:
616 .   event - an event id; this is just for error checking
617 
618     Output Parameter:
619 .   mu - maximum amount of memory malloced during this event; high water mark relative to the beginning of the event
620 
621     Level: developer
622 
623 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
624           PetscMallocPushMaximumUsage()
625  @*/
626 PetscErrorCode  PetscMallocPopMaximumUsage(int event,PetscLogDouble *mu)
627 {
628   PetscFunctionBegin;
629   *mu = 0;
630   if (NumTRMaxMems-- > MAXTRMAXMEMS) PetscFunctionReturn(0);
631   if (TRMaxMemsEvents[NumTRMaxMems] != event) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"PetscMallocPush/PopMaximumUsage() are not nested");
632   *mu = TRMaxMems[NumTRMaxMems];
633   PetscFunctionReturn(0);
634 }
635 
636 #if defined(PETSC_USE_DEBUG)
637 /*@C
638    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to PetscMalloc() was used to obtain that memory
639 
640    Collective on PETSC_COMM_WORLD
641 
642    Input Parameter:
643 .    ptr - the memory location
644 
645    Output Parameter:
646 .    stack - the stack indicating where the program allocated this memory
647 
648    Level: intermediate
649 
650 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocView()
651 @*/
652 PetscErrorCode  PetscMallocGetStack(void *ptr,PetscStack **stack)
653 {
654   TRSPACE *head;
655 
656   PetscFunctionBegin;
657   head   = (TRSPACE*) (((char*)ptr) - HEADER_BYTES);
658   *stack = &head->stack;
659   PetscFunctionReturn(0);
660 }
661 #else
662 PetscErrorCode  PetscMallocGetStack(void *ptr,void **stack)
663 {
664   PetscFunctionBegin;
665   *stack = NULL;
666   PetscFunctionReturn(0);
667 }
668 #endif
669 
670 /*@C
671    PetscMallocDump - Dumps the currently allocated memory blocks to a file. The information
672    printed is: size of space (in bytes), address of space, id of space,
673    file in which space was allocated, and line number at which it was
674    allocated.
675 
676    Not Collective
677 
678    Input Parameter:
679 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
680 
681    Options Database Key:
682 .  -malloc_dump <optional filename> - Dumps unfreed memory during call to PetscFinalize()
683 
684    Level: intermediate
685 
686    Fortran Note:
687    The calling sequence in Fortran is PetscMallocDump(integer ierr)
688    The fp defaults to stdout.
689 
690    Notes:
691      Uses MPI_COMM_WORLD to display rank, because this may be called in PetscFinalize() after PETSC_COMM_WORLD has been freed.
692 
693      When called in PetscFinalize() dumps only the allocations that have not been properly freed
694 
695      PetscMallocView() prints a list of all memory ever allocated
696 
697 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocView(), PetscMallocViewSet()
698 @*/
699 PetscErrorCode  PetscMallocDump(FILE *fp)
700 {
701   TRSPACE        *head;
702   size_t         libAlloc = 0;
703   PetscErrorCode ierr;
704   PetscMPIInt    rank;
705 
706   PetscFunctionBegin;
707   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
708   if (!fp) fp = PETSC_STDOUT;
709   head = TRhead;
710   while (head) {
711     libAlloc += head->size;
712     head = head->next;
713   }
714   if (TRallocated - libAlloc > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
715   head = TRhead;
716   while (head) {
717     PetscBool isLib;
718 
719     ierr = PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib);CHKERRQ(ierr);
720     if (!isLib) {
721       fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->filename);
722 #if defined(PETSC_USE_DEBUG)
723       ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
724 #endif
725     }
726     head = head->next;
727   }
728   PetscFunctionReturn(0);
729 }
730 
731 /*@
732     PetscMallocViewSet - Activates logging of all calls to PetscMalloc() with a minimum size to view
733 
734     Not Collective
735 
736     Input Arguments:
737 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
738 
739     Options Database Key:
740 +  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()
741 .  -malloc_view_threshold <min> - Sets a minimum size if -malloc_view is used
742 -  -log_view_memory - view the memory usage also with the -log_view option
743 
744     Level: advanced
745 
746     Notes: Must be called after PetscMallocSetDebug()
747 
748     Uses MPI_COMM_WORLD to determine rank because PETSc communicators may not be available
749 
750 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocViewSet()
751 @*/
752 PetscErrorCode PetscMallocViewSet(PetscLogDouble logmin)
753 {
754   PetscErrorCode ierr;
755 
756   PetscFunctionBegin;
757   PetscLogMalloc = 0;
758   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
759   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
760   PetscLogMallocThreshold = (size_t)logmin;
761   PetscFunctionReturn(0);
762 }
763 
764 /*@
765     PetscMallocViewGet - Determine whether all calls to PetscMalloc() are being logged
766 
767     Not Collective
768 
769     Output Arguments
770 .   logging - PETSC_TRUE if logging is active
771 
772     Options Database Key:
773 .  -malloc_view <optional filename> - Activates PetscMallocView()
774 
775     Level: advanced
776 
777 .seealso: PetscMallocDump(), PetscMallocView()
778 @*/
779 PetscErrorCode PetscMallocViewGet(PetscBool *logging)
780 {
781 
782   PetscFunctionBegin;
783   *logging = (PetscBool)(PetscLogMalloc >= 0);
784   PetscFunctionReturn(0);
785 }
786 
787 /*@C
788     PetscMallocView - Saves the log of all calls to PetscMalloc(); also calls
789        PetscMemoryGetMaximumUsage()
790 
791     Not Collective
792 
793     Input Parameter:
794 .   fp - file pointer; or NULL
795 
796     Options Database Key:
797 .  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()
798 
799     Level: advanced
800 
801    Fortran Note:
802    The calling sequence in Fortran is PetscMallocView(integer ierr)
803    The fp defaults to stdout.
804 
805    Notes:
806      PetscMallocDump() dumps only the currently unfreed memory, this dumps all memory ever allocated
807 
808      PetscMemoryView() gives a brief summary of current memory usage
809 
810 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocViewSet(), PetscMemoryView()
811 @*/
812 PetscErrorCode  PetscMallocView(FILE *fp)
813 {
814   PetscInt       i,j,n,*perm;
815   size_t         *shortlength;
816   int            *shortcount,err;
817   PetscMPIInt    rank;
818   PetscBool      match;
819   const char     **shortfunction;
820   PetscLogDouble rss;
821   PetscErrorCode ierr;
822 
823   PetscFunctionBegin;
824   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
825   err = fflush(fp);
826   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
827 
828   if (PetscLogMalloc < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscMallocView() called without call to PetscMallocViewSet() this is often due to\n                      setting the option -malloc_view AFTER PetscInitialize() with PetscOptionsInsert() or PetscOptionsInsertFile()");
829 
830   if (!fp) fp = PETSC_STDOUT;
831   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
832   if (rss) {
833     (void) fprintf(fp,"[%d] Maximum memory PetscMalloc()ed %.0f maximum size of entire process %.0f\n",rank,(PetscLogDouble)TRMaxMem,rss);
834   } else {
835     (void) fprintf(fp,"[%d] Maximum memory PetscMalloc()ed %.0f OS cannot compute size of entire process\n",rank,(PetscLogDouble)TRMaxMem);
836   }
837   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
838   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
839   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
840   for (i=0,n=0; i<PetscLogMalloc; i++) {
841     for (j=0; j<n; j++) {
842       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
843       if (match) {
844         shortlength[j] += PetscLogMallocLength[i];
845         shortcount[j]++;
846         goto foundit;
847       }
848     }
849     shortfunction[n] = PetscLogMallocFunction[i];
850     shortlength[n]   = PetscLogMallocLength[i];
851     shortcount[n]    = 1;
852     n++;
853 foundit:;
854   }
855 
856   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
857   for (i=0; i<n; i++) perm[i] = i;
858   ierr = PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);CHKERRQ(ierr);
859 
860   (void) fprintf(fp,"[%d] Memory usage sorted by function\n",rank);
861   for (i=0; i<n; i++) {
862     (void) fprintf(fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);
863   }
864   free(perm);
865   free(shortlength);
866   free(shortcount);
867   free((char**)shortfunction);
868   err = fflush(fp);
869   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
870   PetscFunctionReturn(0);
871 }
872 
873 /* ---------------------------------------------------------------------------- */
874 
875 /*@
876     PetscMallocSetDebug - Set's PETSc memory debugging
877 
878     Not Collective
879 
880     Input Parameter:
881 +   eachcall - checks the entire heap of allocated memory for issues on each call to PetscMalloc() and PetscFree()
882 -   initializenan - initializes all memory with NaN to catch use of uninitialized floating point arrays
883 
884     Options Database:
885 +   -malloc_debug <true or false> - turns on or off debugging
886 .   -malloc_test - turns on all debugging if PETSc was configured with debugging including -malloc_dump, otherwise ignored
887 .   -malloc_view_threshold t - log only allocations larger than t
888 .   -malloc_dump <filename> - print a list of all memory that has not been freed
889 .   -malloc no - (deprecated) same as -malloc_debug no
890 -   -malloc_log - (deprecated) same as -malloc_view
891 
892    Level: developer
893 
894     Notes: This is called in PetscInitialize() and should not be called elsewhere
895 
896 .seealso: CHKMEMQ(), PetscMallocValidate(), PetscMallocGetDebug()
897 @*/
898 PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan)
899 {
900   PetscErrorCode ierr;
901 
902   PetscFunctionBegin;
903   if (PetscTrMalloc == PetscTrMallocDefault) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot call this routine more than once, it can only be called in PetscInitialize()");
904   ierr = PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault,PetscTrReallocDefault);CHKERRQ(ierr);
905 
906   TRallocated         = 0;
907   TRfrags             = 0;
908   TRhead              = NULL;
909   TRid                = 0;
910   TRdebugLevel        = eachcall;
911   TRMaxMem            = 0;
912   PetscLogMallocMax   = 10000;
913   PetscLogMalloc      = -1;
914   TRdebugIinitializenan = initializenan;
915   PetscFunctionReturn(0);
916 }
917 
918 /*@
919     PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.
920 
921     Not Collective
922 
923     Output Parameters:
924 +    basic - doing basic debugging
925 .    eachcall - checks the entire memory heap at each PetscMalloc()/PetscFree()
926 -    initializenan - initializes memory with NaN
927 
928    Level: intermediate
929 
930    Notes:
931      By default, the debug version always does some debugging unless you run with -malloc_debug no
932 
933 .seealso: CHKMEMQ(), PetscMallocValidate(), PetscMallocSetDebug()
934 @*/
935 PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan)
936 {
937   PetscFunctionBegin;
938   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
939   if (eachcall) *eachcall           = TRdebugLevel;
940   if (initializenan) *initializenan = TRdebugIinitializenan;
941   PetscFunctionReturn(0);
942 }
943