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