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