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