xref: /petsc/src/sys/memory/mtr.c (revision 2cfcea2917e9827eeaf4fa9c2e8dd75b054ced7b)
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 (TRdebugLevel) {
185     ierr = PetscMallocValidate(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
186   }
187   if (!a) SETERRQ(PETSC_ERR_MEM_MALLOC_0,"Cannot malloc size zero");
188 
189   nsize = a;
190   if (nsize & TR_ALIGN_MASK) nsize += (TR_ALIGN_BYTES - (nsize & TR_ALIGN_MASK));
191   ierr = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscScalar),lineno,function,filename,dir,(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     = 0;
200   head->size     = nsize;
201   head->id       = TRid;
202   head->lineno   = lineno;
203 
204   head->filename     = filename;
205   head->functionname = function;
206   head->dirname      = dir;
207   head->cookie       = COOKIE_VALUE;
208   *(unsigned long *)(inew + nsize) = COOKIE_VALUE;
209 
210   TRallocated += nsize;
211   if (TRallocated > TRMaxMem) {
212     TRMaxMem   = TRallocated;
213   }
214   TRfrags++;
215 
216 #if defined(PETSC_USE_DEBUG)
217   ierr = PetscStackCopy(petscstack,&head->stack);CHKERRQ(ierr);
218 #endif
219 
220   /*
221          Allow logging of all mallocs made
222   */
223   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax) {
224     if (!PetscLogMalloc) {
225       PetscLogMallocLength    = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
226       if (!PetscLogMallocLength) SETERRQ(PETSC_ERR_MEM," ");
227       PetscLogMallocDirectory = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
228       if (!PetscLogMallocDirectory) SETERRQ(PETSC_ERR_MEM," ");
229       PetscLogMallocFile      = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
230       if (!PetscLogMallocFile) SETERRQ(PETSC_ERR_MEM," ");
231       PetscLogMallocFunction  = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
232       if (!PetscLogMallocFunction) SETERRQ(PETSC_ERR_MEM," ");
233     }
234     PetscLogMallocLength[PetscLogMalloc]      = nsize;
235     PetscLogMallocDirectory[PetscLogMalloc]   = dir;
236     PetscLogMallocFile[PetscLogMalloc]        = filename;
237     PetscLogMallocFunction[PetscLogMalloc++]  = function;
238   }
239   *result = (void*)inew;
240   PetscFunctionReturn(0);
241 }
242 
243 
244 #undef __FUNCT__
245 #define __FUNCT__ "PetscTrFreeDefault"
246 /*
247    PetscTrFreeDefault - Free with tracing.
248 
249    Input Parameters:
250 .   a    - pointer to a block allocated with PetscTrMalloc
251 .   lineno - line number where used.  Use __LINE__ for this
252 .   function - function calling routine. Use __FUNCT__ for this
253 .   file  - file name where used.  Use __FILE__ for this
254 .   dir - directory where file is. Use __SDIR__ for this
255  */
256 PetscErrorCode PETSC_DLLEXPORT PetscTrFreeDefault(void *aa,int line,const char function[],const char file[],const char dir[])
257 {
258   char           *a = (char*)aa;
259   TRSPACE        *head;
260   char           *ahead;
261   PetscErrorCode ierr;
262   unsigned long  *nend;
263 
264   PetscFunctionBegin;
265   /* Do not try to handle empty blocks */
266   if (!a) {
267     (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%s\n",function,line,dir,file);
268     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Trying to free null block");
269   }
270 
271   if (TRdebugLevel) {
272     ierr = PetscMallocValidate(line,function,file,dir);CHKERRQ(ierr);
273   }
274 
275   ahead = a;
276   a     = a - sizeof(TrSPACE);
277   head  = (TRSPACE *)a;
278 
279   if (head->cookie != COOKIE_VALUE) {
280     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
281     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
282     SETERRQ(PETSC_ERR_MEMC,"Bad location or corrupted memory");
283   }
284   nend = (unsigned long *)(ahead + head->size);
285   if (*nend != COOKIE_VALUE) {
286     if (*nend == ALREADY_FREED) {
287       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
288       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
289       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
290 	(*PetscErrorPrintf)("Block freed in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
291       } else {
292         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,-head->lineno,head->dirname,head->filename);
293       }
294       SETERRQ(PETSC_ERR_ARG_WRONG,"Memory already freed");
295     } else {
296       /* Damaged tail */
297       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
298       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
299       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
300       SETERRQ(PETSC_ERR_MEMC,"Corrupted memory");
301     }
302   }
303   /* Mark the location freed */
304   *nend        = ALREADY_FREED;
305   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
306   if (line > 0 && line < 50000) {
307     head->lineno       = line;
308     head->filename     = file;
309     head->functionname = function;
310     head->dirname      = dir;
311   } else {
312     head->lineno = - head->lineno;
313   }
314   /* zero out memory - helps to find some reuse of already freed memory */
315   ierr = PetscMemzero(aa,head->size);CHKERRQ(ierr);
316 
317   TRallocated -= head->size;
318   TRfrags     --;
319   if (head->prev) head->prev->next = head->next;
320   else TRhead = head->next;
321 
322   if (head->next) head->next->prev = head->prev;
323   ierr = PetscFreeAlign(a,line,function,file,dir);CHKERRQ(ierr);
324   PetscFunctionReturn(0);
325 }
326 
327 
328 #undef __FUNCT__
329 #define __FUNCT__ "PetscMemoryShowUsage"
330 /*@
331     PetscMemoryShowUsage - Shows the amount of memory currently being used
332         in a communicator.
333 
334     Collective on PetscViewer
335 
336     Input Parameter:
337 +    viewer - the viewer that defines the communicator
338 -    message - string printed before values
339 
340     Level: intermediate
341 
342     Concepts: memory usage
343 
344 .seealso: PetscMemoryDump(), PetscMemoryGetCurrentUsage()
345  @*/
346 PetscErrorCode PETSC_DLLEXPORT PetscMemoryShowUsage(PetscViewer viewer,const char message[])
347 {
348   PetscLogDouble allocated,maximum,resident,residentmax;
349   PetscErrorCode ierr;
350   PetscMPIInt    rank;
351   MPI_Comm       comm;
352 
353   PetscFunctionBegin;
354   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
355   ierr = PetscMallocGetCurrentUsage(&allocated);CHKERRQ(ierr);
356   ierr = PetscMallocGetMaximumUsage(&maximum);CHKERRQ(ierr);
357   ierr = PetscMemoryGetCurrentUsage(&resident);CHKERRQ(ierr);
358   ierr = PetscMemoryGetMaximumUsage(&residentmax);CHKERRQ(ierr);
359   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
360   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
361   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
362   ierr = PetscViewerASCIIPrintf(viewer,message);CHKERRQ(ierr);
363   if (resident && residentmax && allocated) {
364     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);
365   } else if (resident && residentmax) {
366     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);
367   } else if (resident && allocated) {
368     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);
369   } else if (allocated) {
370     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);
371   } else {
372     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
373   }
374   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
375   PetscFunctionReturn(0);
376 }
377 
378 #undef __FUNCT__
379 #define __FUNCT__ "PetscMallocGetCurrentUsage"
380 /*@C
381     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
382 
383     Not Collective
384 
385     Output Parameters:
386 .   space - number of bytes currently allocated
387 
388     Level: intermediate
389 
390     Concepts: memory usage
391 
392 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
393           PetscMemoryGetMaximumUsage()
394  @*/
395 PetscErrorCode PETSC_DLLEXPORT PetscMallocGetCurrentUsage(PetscLogDouble *space)
396 {
397   PetscFunctionBegin;
398   *space = (PetscLogDouble) TRallocated;
399   PetscFunctionReturn(0);
400 }
401 
402 #undef __FUNCT__
403 #define __FUNCT__ "PetscMallocGetMaximumUsage"
404 /*@C
405     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
406         during this run.
407 
408     Not Collective
409 
410     Output Parameters:
411 .   space - maximum number of bytes ever allocated at one time
412 
413     Level: intermediate
414 
415     Concepts: memory usage
416 
417 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
418           PetscMemoryGetCurrentUsage()
419  @*/
420 PetscErrorCode PETSC_DLLEXPORT PetscMallocGetMaximumUsage(PetscLogDouble *space)
421 {
422   PetscFunctionBegin;
423   *space = (PetscLogDouble) TRMaxMem;
424   PetscFunctionReturn(0);
425 }
426 
427 #undef __FUNCT__
428 #define __FUNCT__ "PetscMallocDump"
429 /*@C
430    PetscMallocDump - Dumps the allocated memory blocks to a file. The information
431    printed is: size of space (in bytes), address of space, id of space,
432    file in which space was allocated, and line number at which it was
433    allocated.
434 
435    Collective on PETSC_COMM_WORLD
436 
437    Input Parameter:
438 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
439 
440    Options Database Key:
441 .  -malloc_dump - Dumps unfreed memory during call to PetscFinalize()
442 
443    Level: intermediate
444 
445    Fortran Note:
446    The calling sequence in Fortran is PetscMallocDump(integer ierr)
447    The fp defaults to stdout.
448 
449    Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
450           has been freed.
451 
452    Concepts: memory usage
453    Concepts: memory bleeding
454    Concepts: bleeding memory
455 
456 .seealso:  PetscMallocGetCurrentSize(), PetscMallocDumpLog()
457 @*/
458 PetscErrorCode PETSC_DLLEXPORT PetscMallocDump(FILE *fp)
459 {
460   TRSPACE        *head;
461   PetscErrorCode ierr;
462   PetscMPIInt    rank;
463 
464   PetscFunctionBegin;
465   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
466   if (!fp) fp = stdout;
467   if (TRallocated > 0) {
468     fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
469   }
470   head = TRhead;
471   while (head) {
472     fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s%s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->dirname,head->filename);
473 #if defined(PETSC_USE_DEBUG)
474     ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
475 #endif
476     head = head->next;
477   }
478   PetscFunctionReturn(0);
479 }
480 
481 /* ---------------------------------------------------------------------------- */
482 
483 #undef __FUNCT__
484 #define __FUNCT__ "PetscMallocSetDumpLog"
485 /*@C
486     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
487 
488     Not Collective
489 
490     Options Database Key:
491 .  -malloc_log - Activates PetscMallocDumpLog()
492 
493     Level: advanced
494 
495 .seealso: PetscMallocDump(), PetscMallocDumpLog()
496 @*/
497 PetscErrorCode PETSC_DLLEXPORT PetscMallocSetDumpLog(void)
498 {
499   PetscFunctionBegin;
500   PetscLogMalloc = 0;
501   PetscFunctionReturn(0);
502 }
503 
504 #undef __FUNCT__
505 #define __FUNCT__ "PetscMallocDumpLog"
506 /*@C
507     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
508        PetscMemoryGetCurrentUsage() and PetscMemoryGetMaximumUsage()
509 
510     Collective on PETSC_COMM_WORLD
511 
512     Input Parameter:
513 .   fp - file pointer; or PETSC_NULL
514 
515     Options Database Key:
516 .  -malloc_log - Activates PetscMallocDumpLog()
517 
518     Level: advanced
519 
520    Fortran Note:
521    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
522    The fp defaults to stdout.
523 
524 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
525 @*/
526 PetscErrorCode PETSC_DLLEXPORT PetscMallocDumpLog(FILE *fp)
527 {
528   PetscInt       i,j,n,dummy,*perm;
529   size_t         *shortlength;
530   int            *shortcount;
531   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
532   PetscTruth     match;
533   const char     **shortfunction;
534   PetscLogDouble rss;
535   MPI_Status     status;
536   PetscErrorCode ierr;
537 
538   PetscFunctionBegin;
539   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
540   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
541   /*
542        Try to get the data printed in order by processor. This will only sometimes work
543   */
544   fflush(fp);
545   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
546   if (rank) {
547     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
548   }
549 
550   if (!fp) fp = stdout;
551   ierr = PetscMemoryGetCurrentUsage(&rss);CHKERRQ(ierr);
552   if (rss) {
553     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);
554   } else {
555     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);
556   }
557   shortcount       = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_ERR_MEM,"Out of memory");
558   shortlength      = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_ERR_MEM,"Out of memory");
559   shortfunction    = (const char**)malloc(PetscLogMalloc*sizeof(char *));if (!shortfunction) SETERRQ(PETSC_ERR_MEM,"Out of memory");
560   shortfunction[0] = PetscLogMallocFunction[0];
561   shortlength[0]   = PetscLogMallocLength[0];
562   shortcount[0]    = 0;
563   n = 1;
564   for (i=1; i<PetscLogMalloc; i++) {
565     for (j=0; j<n; j++) {
566       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
567       if (match) {
568         shortlength[j] += PetscLogMallocLength[i];
569         shortcount[j]++;
570         goto foundit;
571       }
572     }
573     shortfunction[n] = PetscLogMallocFunction[i];
574     shortlength[n]   = PetscLogMallocLength[i];
575     shortcount[n]    = 1;
576     n++;
577     foundit:;
578   }
579 
580   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_ERR_MEM,"Out of memory");
581   for (i=0; i<n; i++) perm[i] = i;
582   ierr = PetscSortStrWithPermutation(n,(const char **)shortfunction,perm);CHKERRQ(ierr);
583 
584   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
585   for (i=0; i<n; i++) {
586     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
587   }
588   free(perm);
589   free(shortlength);
590   free(shortcount);
591   free((char **)shortfunction);
592   fflush(fp);
593   if (rank != size-1) {
594     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
595   }
596   PetscFunctionReturn(0);
597 }
598 
599 /* ---------------------------------------------------------------------------- */
600 
601 #undef __FUNCT__
602 #define __FUNCT__ "PetscMallocDebug"
603 /*@C
604     PetscMallocDebug - Turns on/off debugging for the memory management routines.
605 
606     Not Collective
607 
608     Input Parameter:
609 .   level - PETSC_TRUE or PETSC_FALSE
610 
611    Level: intermediate
612 
613 .seealso: CHKMEMQ(), PetscMallocValidate()
614 @*/
615 PetscErrorCode PETSC_DLLEXPORT PetscMallocDebug(PetscTruth level)
616 {
617   PetscFunctionBegin;
618   TRdebugLevel = level;
619   PetscFunctionReturn(0);
620 }
621