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