xref: /petsc/src/sys/memory/mtr.c (revision 668f157ea6d169bb50bcdb9ebcdd418abd089fa7)
1 #define PETSC_DLL
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 #if defined(PETSC_HAVE_STDLIB_H)
8 #include <stdlib.h>
9 #endif
10 #if defined(PETSC_HAVE_MALLOC_H)
11 #include <malloc.h>
12 #endif
13 
14 
15 /*
16      These are defined in mal.c and ensure that malloced space is PetscScalar aligned
17 */
18 EXTERN PetscErrorCode PETSC_DLLEXPORT PetscMallocAlign(size_t,int,const char[],const char[],const char[],void**);
19 EXTERN PetscErrorCode PETSC_DLLEXPORT PetscFreeAlign(void*,int,const char[],const char[],const char[]);
20 EXTERN PetscErrorCode PETSC_DLLEXPORT PetscTrMallocDefault(size_t,int,const char[],const char[],const char[],void**);
21 EXTERN PetscErrorCode PETSC_DLLEXPORT PetscTrFreeDefault(void*,int,const char[],const char[],const char[]);
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     const char      *dirname;
34     PetscClassId    classid;
35 #if defined(PETSC_USE_DEBUG)
36     PetscStack      stack;
37 #endif
38     struct _trSPACE *next,*prev;
39 } TRSPACE;
40 
41 /* HEADER_BYTES is the number of bytes in a PetscMalloc() header.
42    It is sizeof(TRSPACE) padded to be a multiple of PETSC_MEMALIGN.
43 */
44 
45 #define HEADER_BYTES      (sizeof(TRSPACE)+(PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1)
46 
47 
48 /* This union is used to insure that the block passed to the user retains
49    a minimum alignment of PETSC_MEMALIGN.
50 */
51 typedef union {
52     TRSPACE sp;
53     char    v[HEADER_BYTES];
54 } TrSPACE;
55 
56 
57 static size_t     TRallocated  = 0;
58 static int        TRfrags      = 0;
59 static TRSPACE    *TRhead      = 0;
60 static int        TRid         = 0;
61 static PetscTruth TRdebugLevel = PETSC_FALSE;
62 static size_t     TRMaxMem     = 0;
63 /*
64       Arrays to log information on all Mallocs
65 */
66 static int        PetscLogMallocMax = 10000,PetscLogMalloc = -1;
67 static size_t     *PetscLogMallocLength;
68 static const char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
69 
70 #undef __FUNCT__
71 #define __FUNCT__ "PetscSetUseTrMalloc_Private"
72 PetscErrorCode PetscSetUseTrMalloc_Private(void)
73 {
74   PetscErrorCode ierr;
75 
76   PetscFunctionBegin;
77   ierr              = PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault);CHKERRQ(ierr);
78   TRallocated       = 0;
79   TRfrags           = 0;
80   TRhead            = 0;
81   TRid              = 0;
82   TRdebugLevel      = PETSC_FALSE;
83   TRMaxMem          = 0;
84   PetscLogMallocMax = 10000;
85   PetscLogMalloc    = -1;
86   PetscFunctionReturn(0);
87 }
88 
89 #undef __FUNCT__
90 #define __FUNCT__ "PetscMallocValidate"
91 /*@C
92    PetscMallocValidate - Test the memory for corruption.  This can be used to
93    check for memory overwrites.
94 
95    Input Parameter:
96 +  line - line number where call originated.
97 .  function - name of function calling
98 .  file - file where function is
99 -  dir - directory where function is
100 
101    Return value:
102    The number of errors detected.
103 
104    Output Effect:
105    Error messages are written to stdout.
106 
107    Level: advanced
108 
109    Notes:
110     You should generally use CHKMEMQ as a short cut for calling this
111     routine.
112 
113     The line, function, file and dir are given by the C preprocessor as
114     __LINE__, __FUNCT__, __FILE__, and __DIR__
115 
116     The Fortran calling sequence is simply PetscMallocValidate(ierr)
117 
118    No output is generated if there are no problems detected.
119 
120 .seealso: CHKMEMQ
121 
122 @*/
123 PetscErrorCode PETSC_DLLEXPORT PetscMallocValidate(int line,const char function[],const char file[],const char dir[])
124 {
125   TRSPACE     *head,*lasthead;
126   char        *a;
127   PetscClassId *nend;
128 
129   PetscFunctionBegin;
130   head = TRhead; lasthead = NULL;
131   while (head) {
132     if (head->classid != CLASSID_VALUE) {
133       (*PetscErrorPrintf)("PetscMallocValidate: error detected at  %s() line %d in %s%s\n",function,line,dir,file);
134       (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
135       (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
136       if (lasthead)
137 	(*PetscErrorPrintf)("Last intact block allocated in %s() line %d in %s%s\n",lasthead->functionname,lasthead->lineno,lasthead->dirname,lasthead->filename);
138       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
139     }
140     a    = (char *)(((TrSPACE*)head) + 1);
141     nend = (PetscClassId *)(a + head->size);
142     if (*nend != CLASSID_VALUE) {
143       (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s%s\n",function,line,dir,file);
144       if (*nend == ALREADY_FREED) {
145         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n",head->id,(PetscLogDouble)head->size,a);
146         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
147       } else {
148         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
149         (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
150         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
151       }
152     }
153     lasthead = head;
154     head = head->next;
155   }
156   PetscFunctionReturn(0);
157 }
158 
159 #undef __FUNCT__
160 #define __FUNCT__ "PetscTrMallocDefault"
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 .   function - function calling routine. Use __FUNCT__ for this
168 .   filename  - file name where used.  Use __FILE__ for this
169 -   dir - directory where file is. Use __SDIR__ for this
170 
171     Returns:
172     double aligned pointer to requested storage, or null if not
173     available.
174  */
175 PetscErrorCode PETSC_DLLEXPORT PetscTrMallocDefault(size_t a,int lineno,const char function[],const char filename[],const char dir[],void**result)
176 {
177   TRSPACE        *head;
178   char           *inew;
179   size_t         nsize;
180   PetscErrorCode ierr;
181 
182   PetscFunctionBegin;
183   if (!a) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to malloc zero size array");
184 
185   if (TRdebugLevel) {
186     ierr = PetscMallocValidate(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
187   }
188 
189   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
190   ierr = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),lineno,function,filename,dir,(void**)&inew);CHKERRQ(ierr);
191 
192   head   = (TRSPACE *)inew;
193   inew  += sizeof(TrSPACE);
194 
195   if (TRhead) TRhead->prev = head;
196   head->next     = TRhead;
197   TRhead         = head;
198   head->prev     = 0;
199   head->size     = nsize;
200   head->id       = TRid;
201   head->lineno   = lineno;
202 
203   head->filename     = filename;
204   head->functionname = function;
205   head->dirname      = dir;
206   head->classid       = CLASSID_VALUE;
207   *(PetscClassId *)(inew + nsize) = CLASSID_VALUE;
208 
209   TRallocated += nsize;
210   if (TRallocated > TRMaxMem) {
211     TRMaxMem   = TRallocated;
212   }
213   TRfrags++;
214 
215 #if defined(PETSC_USE_DEBUG)
216   ierr = PetscStackCopy(petscstack,&head->stack);CHKERRQ(ierr);
217 #endif
218 
219   /*
220          Allow logging of all mallocs made
221   */
222   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax) {
223     if (!PetscLogMalloc) {
224       PetscLogMallocLength    = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
225       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
226       PetscLogMallocDirectory = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
227       if (!PetscLogMallocDirectory) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
228       PetscLogMallocFile      = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
229       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
230       PetscLogMallocFunction  = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
231       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
232     }
233     PetscLogMallocLength[PetscLogMalloc]      = nsize;
234     PetscLogMallocDirectory[PetscLogMalloc]   = dir;
235     PetscLogMallocFile[PetscLogMalloc]        = filename;
236     PetscLogMallocFunction[PetscLogMalloc++]  = function;
237   }
238   *result = (void*)inew;
239   PetscFunctionReturn(0);
240 }
241 
242 
243 #undef __FUNCT__
244 #define __FUNCT__ "PetscTrFreeDefault"
245 /*
246    PetscTrFreeDefault - Free with tracing.
247 
248    Input Parameters:
249 .   a    - pointer to a block allocated with PetscTrMalloc
250 .   lineno - line number where used.  Use __LINE__ for this
251 .   function - function calling routine. Use __FUNCT__ for this
252 .   file  - file name where used.  Use __FILE__ for this
253 .   dir - directory where file is. Use __SDIR__ for this
254  */
255 PetscErrorCode PETSC_DLLEXPORT PetscTrFreeDefault(void *aa,int line,const char function[],const char file[],const char dir[])
256 {
257   char           *a = (char*)aa;
258   TRSPACE        *head;
259   char           *ahead;
260   PetscErrorCode ierr;
261   PetscClassId   *nend;
262 
263   PetscFunctionBegin;
264   /* Do not try to handle empty blocks */
265   if (!a) {
266     (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%s\n",function,line,dir,file);
267     SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to free null block: Free called from %s() line %d in %s%s\n",function,line,dir,file);
268   }
269 
270   if (TRdebugLevel) {
271     ierr = PetscMallocValidate(line,function,file,dir);CHKERRQ(ierr);
272   }
273 
274   ahead = a;
275   a     = a - sizeof(TrSPACE);
276   head  = (TRSPACE *)a;
277 
278   if (head->classid != CLASSID_VALUE) {
279     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
280     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
281     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
282   }
283   nend = (PetscClassId *)(ahead + head->size);
284   if (*nend != CLASSID_VALUE) {
285     if (*nend == ALREADY_FREED) {
286       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
287       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
288       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
289 	(*PetscErrorPrintf)("Block freed in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
290       } else {
291         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,-head->lineno,head->dirname,head->filename);
292       }
293       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
294     } else {
295       /* Damaged tail */
296       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
297       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
298       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
299       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
300     }
301   }
302   /* Mark the location freed */
303   *nend        = ALREADY_FREED;
304   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
305   if (line > 0 && line < 50000) {
306     head->lineno       = line;
307     head->filename     = file;
308     head->functionname = function;
309     head->dirname      = dir;
310   } else {
311     head->lineno = - head->lineno;
312   }
313   /* zero out memory - helps to find some reuse of already freed memory */
314   ierr = PetscMemzero(aa,head->size);CHKERRQ(ierr);
315 
316   TRallocated -= head->size;
317   TRfrags     --;
318   if (head->prev) head->prev->next = head->next;
319   else TRhead = head->next;
320 
321   if (head->next) head->next->prev = head->prev;
322   ierr = PetscFreeAlign(a,line,function,file,dir);CHKERRQ(ierr);
323   PetscFunctionReturn(0);
324 }
325 
326 
327 #undef __FUNCT__
328 #define __FUNCT__ "PetscMemoryShowUsage"
329 /*@C
330     PetscMemoryShowUsage - Shows the amount of memory currently being used
331         in a communicator.
332 
333     Collective on PetscViewer
334 
335     Input Parameter:
336 +    viewer - the viewer that defines the communicator
337 -    message - string printed before values
338 
339     Level: intermediate
340 
341     Concepts: memory usage
342 
343 .seealso: PetscMallocDump(), PetscMemoryGetCurrentUsage()
344  @*/
345 PetscErrorCode PETSC_DLLEXPORT PetscMemoryShowUsage(PetscViewer viewer,const char message[])
346 {
347   PetscLogDouble allocated,maximum,resident,residentmax;
348   PetscErrorCode ierr;
349   PetscMPIInt    rank;
350   MPI_Comm       comm;
351 
352   PetscFunctionBegin;
353   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
354   ierr = PetscMallocGetCurrentUsage(&allocated);CHKERRQ(ierr);
355   ierr = PetscMallocGetMaximumUsage(&maximum);CHKERRQ(ierr);
356   ierr = PetscMemoryGetCurrentUsage(&resident);CHKERRQ(ierr);
357   ierr = PetscMemoryGetMaximumUsage(&residentmax);CHKERRQ(ierr);
358   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
359   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
360   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
361   ierr = PetscViewerASCIIPrintf(viewer,message);CHKERRQ(ierr);
362   if (resident && residentmax && allocated) {
363     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Current space PetscMalloc()ed %g, max space PetscMalloced() %g\n[%d]Current process memory %g max process memory %g\n",rank,allocated,maximum,rank,resident,residentmax);CHKERRQ(ierr);
364   } else if (resident && residentmax) {
365     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Run with -malloc to get statistics on PetscMalloc() calls\n[%d]Current process memory %g max process memory %g\n",rank,rank,resident,residentmax);CHKERRQ(ierr);
366   } else if (resident && allocated) {
367     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Current space PetscMalloc()ed %g, max space PetscMalloced() %g\n[%d]Current process memory %g, run with -memory_info to get max memory usage\n",rank,allocated,maximum,rank,resident);CHKERRQ(ierr);
368   } else if (allocated) {
369     ierr = PetscViewerASCIISynchronizedPrintf(viewer,"[%d]Current space PetscMalloc()ed %g, max space PetscMalloced() %g\n[%d]OS cannot compute process memory\n",rank,allocated,maximum,rank);CHKERRQ(ierr);
370   } else {
371     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
372   }
373   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
374   PetscFunctionReturn(0);
375 }
376 
377 #undef __FUNCT__
378 #define __FUNCT__ "PetscMallocGetCurrentUsage"
379 /*@C
380     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
381 
382     Not Collective
383 
384     Output Parameters:
385 .   space - number of bytes currently allocated
386 
387     Level: intermediate
388 
389     Concepts: memory usage
390 
391 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
392           PetscMemoryGetMaximumUsage()
393  @*/
394 PetscErrorCode PETSC_DLLEXPORT PetscMallocGetCurrentUsage(PetscLogDouble *space)
395 {
396   PetscFunctionBegin;
397   *space = (PetscLogDouble) TRallocated;
398   PetscFunctionReturn(0);
399 }
400 
401 #undef __FUNCT__
402 #define __FUNCT__ "PetscMallocGetMaximumUsage"
403 /*@C
404     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
405         during this run.
406 
407     Not Collective
408 
409     Output Parameters:
410 .   space - maximum number of bytes ever allocated at one time
411 
412     Level: intermediate
413 
414     Concepts: memory usage
415 
416 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
417           PetscMemoryGetCurrentUsage()
418  @*/
419 PetscErrorCode PETSC_DLLEXPORT PetscMallocGetMaximumUsage(PetscLogDouble *space)
420 {
421   PetscFunctionBegin;
422   *space = (PetscLogDouble) TRMaxMem;
423   PetscFunctionReturn(0);
424 }
425 
426 #undef __FUNCT__
427 #define __FUNCT__ "PetscMallocDump"
428 /*@C
429    PetscMallocDump - Dumps the allocated memory blocks to a file. The information
430    printed is: size of space (in bytes), address of space, id of space,
431    file in which space was allocated, and line number at which it was
432    allocated.
433 
434    Collective on PETSC_COMM_WORLD
435 
436    Input Parameter:
437 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
438 
439    Options Database Key:
440 .  -malloc_dump - Dumps unfreed memory during call to PetscFinalize()
441 
442    Level: intermediate
443 
444    Fortran Note:
445    The calling sequence in Fortran is PetscMallocDump(integer ierr)
446    The fp defaults to stdout.
447 
448    Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
449           has been freed.
450 
451    Concepts: memory usage
452    Concepts: memory bleeding
453    Concepts: bleeding memory
454 
455 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
456 @*/
457 PetscErrorCode PETSC_DLLEXPORT PetscMallocDump(FILE *fp)
458 {
459   TRSPACE        *head;
460   PetscErrorCode ierr;
461   PetscMPIInt    rank;
462 
463   PetscFunctionBegin;
464   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
465   if (!fp) fp = PETSC_STDOUT;
466   if (TRallocated > 0) {
467     fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
468   }
469   head = TRhead;
470   while (head) {
471     fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s%s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->dirname,head->filename);
472 #if defined(PETSC_USE_DEBUG)
473     ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
474 #endif
475     head = head->next;
476   }
477   PetscFunctionReturn(0);
478 }
479 
480 /* ---------------------------------------------------------------------------- */
481 
482 #undef __FUNCT__
483 #define __FUNCT__ "PetscMallocSetDumpLog"
484 /*@C
485     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
486 
487     Not Collective
488 
489     Options Database Key:
490 .  -malloc_log - Activates PetscMallocDumpLog()
491 
492     Level: advanced
493 
494 .seealso: PetscMallocDump(), PetscMallocDumpLog()
495 @*/
496 PetscErrorCode PETSC_DLLEXPORT PetscMallocSetDumpLog(void)
497 {
498   PetscErrorCode ierr;
499 
500   PetscFunctionBegin;
501   PetscLogMalloc = 0;
502   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
503   PetscFunctionReturn(0);
504 }
505 
506 #undef __FUNCT__
507 #define __FUNCT__ "PetscMallocDumpLog"
508 /*@C
509     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
510        PetscMemoryGetMaximumUsage()
511 
512     Collective on PETSC_COMM_WORLD
513 
514     Input Parameter:
515 .   fp - file pointer; or PETSC_NULL
516 
517     Options Database Key:
518 .  -malloc_log - Activates PetscMallocDumpLog()
519 
520     Level: advanced
521 
522    Fortran Note:
523    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
524    The fp defaults to stdout.
525 
526 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
527 @*/
528 PetscErrorCode PETSC_DLLEXPORT PetscMallocDumpLog(FILE *fp)
529 {
530   PetscInt       i,j,n,dummy,*perm;
531   size_t         *shortlength;
532   int            *shortcount,err;
533   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
534   PetscTruth     match;
535   const char     **shortfunction;
536   PetscLogDouble rss;
537   MPI_Status     status;
538   PetscErrorCode ierr;
539 
540   PetscFunctionBegin;
541   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
542   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
543   /*
544        Try to get the data printed in order by processor. This will only sometimes work
545   */
546   err = fflush(fp);
547   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
548 
549   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
550   if (rank) {
551     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
552   }
553 
554   if (!fp) fp = PETSC_STDOUT;
555   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
556   if (rss) {
557     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);
558   } else {
559     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);
560   }
561   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()");
562   shortcount       = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
563   shortlength      = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
564   shortfunction    = (const char**)malloc(PetscLogMalloc*sizeof(char *));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
565   shortfunction[0] = PetscLogMallocFunction[0];
566   shortlength[0]   = PetscLogMallocLength[0];
567   shortcount[0]    = 0;
568   n = 1;
569   for (i=1; i<PetscLogMalloc; i++) {
570     for (j=0; j<n; j++) {
571       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
572       if (match) {
573         shortlength[j] += PetscLogMallocLength[i];
574         shortcount[j]++;
575         goto foundit;
576       }
577     }
578     shortfunction[n] = PetscLogMallocFunction[i];
579     shortlength[n]   = PetscLogMallocLength[i];
580     shortcount[n]    = 1;
581     n++;
582     foundit:;
583   }
584 
585   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
586   for (i=0; i<n; i++) perm[i] = i;
587   ierr = PetscSortStrWithPermutation(n,(const char **)shortfunction,perm);CHKERRQ(ierr);
588 
589   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
590   for (i=0; i<n; i++) {
591     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
592   }
593   free(perm);
594   free(shortlength);
595   free(shortcount);
596   free((char **)shortfunction);
597   err = fflush(fp);
598   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
599   if (rank != size-1) {
600     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
601   }
602   PetscFunctionReturn(0);
603 }
604 
605 /* ---------------------------------------------------------------------------- */
606 
607 #undef __FUNCT__
608 #define __FUNCT__ "PetscMallocDebug"
609 /*@C
610     PetscMallocDebug - Turns on/off debugging for the memory management routines.
611 
612     Not Collective
613 
614     Input Parameter:
615 .   level - PETSC_TRUE or PETSC_FALSE
616 
617    Level: intermediate
618 
619 .seealso: CHKMEMQ(), PetscMallocValidate()
620 @*/
621 PetscErrorCode PETSC_DLLEXPORT PetscMallocDebug(PetscTruth level)
622 {
623   PetscFunctionBegin;
624   TRdebugLevel = level;
625   PetscFunctionReturn(0);
626 }
627