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