xref: /petsc/src/sys/memory/mtr.c (revision 36366135a1972fb09bc2b7bdc4a57b3879d4b6c7)
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 
26 #define COOKIE_VALUE   ((PetscCookie) 0xf0e0d0c9)
27 #define ALREADY_FREED  ((PetscCookie) 0x0f0e0d9c)
28 
29 typedef struct _trSPACE {
30     size_t          size;
31     int             id;
32     int             lineno;
33     const char      *filename;
34     const char      *functionname;
35     const char      *dirname;
36     PetscCookie     cookie;
37 #if defined(PETSC_USE_DEBUG)
38     PetscStack      stack;
39 #endif
40     struct _trSPACE *next,*prev;
41 } TRSPACE;
42 
43 /* HEADER_BYTES is the number of bytes in a PetscMalloc() header.
44    It is sizeof(TRSPACE) padded to be a multiple of PETSC_MEMALIGN.
45 */
46 
47 #define HEADER_BYTES      (sizeof(TRSPACE)+(PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1)
48 
49 
50 /* This union is used to insure that the block passed to the user retains
51    a minimum alignment of PETSC_MEMALIGN.
52 */
53 typedef union {
54     TRSPACE sp;
55     char    v[HEADER_BYTES];
56 } TrSPACE;
57 
58 
59 static size_t     TRallocated  = 0;
60 static int        TRfrags      = 0;
61 static TRSPACE    *TRhead      = 0;
62 static int        TRid         = 0;
63 static PetscTruth TRdebugLevel = PETSC_FALSE;
64 static size_t     TRMaxMem     = 0;
65 /*
66       Arrays to log information on all Mallocs
67 */
68 static int        PetscLogMallocMax = 10000,PetscLogMalloc = -1;
69 static size_t     *PetscLogMallocLength;
70 static const char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
71 
72 #undef __FUNCT__
73 #define __FUNCT__ "PetscSetUseTrMalloc_Private"
74 PetscErrorCode PetscSetUseTrMalloc_Private(void)
75 {
76   PetscErrorCode ierr;
77 
78   PetscFunctionBegin;
79   ierr              = PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault);CHKERRQ(ierr);
80   TRallocated       = 0;
81   TRfrags           = 0;
82   TRhead            = 0;
83   TRid              = 0;
84   TRdebugLevel      = PETSC_FALSE;
85   TRMaxMem          = 0;
86   PetscLogMallocMax = 10000;
87   PetscLogMalloc    = -1;
88   PetscFunctionReturn(0);
89 }
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "PetscMallocValidate"
93 /*@C
94    PetscMallocValidate - Test the memory for corruption.  This can be used to
95    check for memory overwrites.
96 
97    Input Parameter:
98 +  line - line number where call originated.
99 .  function - name of function calling
100 .  file - file where function is
101 -  dir - directory where function is
102 
103    Return value:
104    The number of errors detected.
105 
106    Output Effect:
107    Error messages are written to stdout.
108 
109    Level: advanced
110 
111    Notes:
112     You should generally use CHKMEMQ as a short cut for calling this
113     routine.
114 
115     The line, function, file and dir are given by the C preprocessor as
116     __LINE__, __FUNCT__, __FILE__, and __DIR__
117 
118     The Fortran calling sequence is simply PetscMallocValidate(ierr)
119 
120    No output is generated if there are no problems detected.
121 
122 .seealso: CHKMEMQ
123 
124 @*/
125 PetscErrorCode PETSC_DLLEXPORT PetscMallocValidate(int line,const char function[],const char file[],const char dir[])
126 {
127   TRSPACE     *head,*lasthead;
128   char        *a;
129   PetscCookie *nend;
130 
131   PetscFunctionBegin;
132   head = TRhead; lasthead = NULL;
133   while (head) {
134     if (head->cookie != COOKIE_VALUE) {
135       (*PetscErrorPrintf)("PetscMallocValidate: error detected at  %s() line %d in %s%s\n",function,line,dir,file);
136       (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
137       (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
138       if (lasthead)
139 	(*PetscErrorPrintf)("Last intact block allocated in %s() line %d in %s%s\n",lasthead->functionname,lasthead->lineno,lasthead->dirname,lasthead->filename);
140       SETERRQ(PETSC_ERR_MEMC," ");
141     }
142     a    = (char *)(((TrSPACE*)head) + 1);
143     nend = (PetscCookie *)(a + head->size);
144     if (*nend != COOKIE_VALUE) {
145       (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s%s\n",function,line,dir,file);
146       if (*nend == ALREADY_FREED) {
147         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n",head->id,(PetscLogDouble)head->size,a);
148         SETERRQ(PETSC_ERR_MEMC," ");
149       } else {
150         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
151         (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
152         SETERRQ(PETSC_ERR_MEMC," ");
153       }
154     }
155     lasthead = head;
156     head = head->next;
157   }
158   PetscFunctionReturn(0);
159 }
160 
161 #undef __FUNCT__
162 #define __FUNCT__ "PetscTrMallocDefault"
163 /*
164     PetscTrMallocDefault - Malloc with tracing.
165 
166     Input Parameters:
167 +   a   - number of bytes to allocate
168 .   lineno - line number where used.  Use __LINE__ for this
169 .   function - function calling routine. Use __FUNCT__ for this
170 .   filename  - file name where used.  Use __FILE__ for this
171 -   dir - directory where file is. Use __SDIR__ for this
172 
173     Returns:
174     double aligned pointer to requested storage, or null if not
175     available.
176  */
177 PetscErrorCode PETSC_DLLEXPORT PetscTrMallocDefault(size_t a,int lineno,const char function[],const char filename[],const char dir[],void**result)
178 {
179   TRSPACE        *head;
180   char           *inew;
181   size_t         nsize;
182   PetscErrorCode ierr;
183 
184   PetscFunctionBegin;
185   if (!a) {
186     SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Trying to malloc zero size array");
187   }
188 
189   if (TRdebugLevel) {
190     ierr = PetscMallocValidate(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
191   }
192 
193   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
194   ierr = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscCookie),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   *(PetscCookie *)(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   PetscCookie    *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 = (PetscCookie *)(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:  PetscMallocGetCurrentUsage(), 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   PetscErrorCode ierr;
503 
504   PetscFunctionBegin;
505   PetscLogMalloc = 0;
506   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
507   PetscFunctionReturn(0);
508 }
509 
510 #undef __FUNCT__
511 #define __FUNCT__ "PetscMallocDumpLog"
512 /*@C
513     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
514        PetscMemoryGetMaximumUsage()
515 
516     Collective on PETSC_COMM_WORLD
517 
518     Input Parameter:
519 .   fp - file pointer; or PETSC_NULL
520 
521     Options Database Key:
522 .  -malloc_log - Activates PetscMallocDumpLog()
523 
524     Level: advanced
525 
526    Fortran Note:
527    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
528    The fp defaults to stdout.
529 
530 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
531 @*/
532 PetscErrorCode PETSC_DLLEXPORT PetscMallocDumpLog(FILE *fp)
533 {
534   PetscInt       i,j,n,dummy,*perm;
535   size_t         *shortlength;
536   int            *shortcount,err;
537   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
538   PetscTruth     match;
539   const char     **shortfunction;
540   PetscLogDouble rss;
541   MPI_Status     status;
542   PetscErrorCode ierr;
543 
544   PetscFunctionBegin;
545   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
546   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
547   /*
548        Try to get the data printed in order by processor. This will only sometimes work
549   */
550   err = fflush(fp);
551   if (err) SETERRQ(PETSC_ERR_SYS,"fflush() failed on file");
552 
553   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
554   if (rank) {
555     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
556   }
557 
558   if (!fp) fp = PETSC_STDOUT;
559   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
560   if (rss) {
561     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);
562   } else {
563     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);
564   }
565   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()");
566   shortcount       = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_ERR_MEM,"Out of memory");
567   shortlength      = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_ERR_MEM,"Out of memory");
568   shortfunction    = (const char**)malloc(PetscLogMalloc*sizeof(char *));if (!shortfunction) SETERRQ(PETSC_ERR_MEM,"Out of memory");
569   shortfunction[0] = PetscLogMallocFunction[0];
570   shortlength[0]   = PetscLogMallocLength[0];
571   shortcount[0]    = 0;
572   n = 1;
573   for (i=1; i<PetscLogMalloc; i++) {
574     for (j=0; j<n; j++) {
575       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
576       if (match) {
577         shortlength[j] += PetscLogMallocLength[i];
578         shortcount[j]++;
579         goto foundit;
580       }
581     }
582     shortfunction[n] = PetscLogMallocFunction[i];
583     shortlength[n]   = PetscLogMallocLength[i];
584     shortcount[n]    = 1;
585     n++;
586     foundit:;
587   }
588 
589   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_ERR_MEM,"Out of memory");
590   for (i=0; i<n; i++) perm[i] = i;
591   ierr = PetscSortStrWithPermutation(n,(const char **)shortfunction,perm);CHKERRQ(ierr);
592 
593   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
594   for (i=0; i<n; i++) {
595     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
596   }
597   free(perm);
598   free(shortlength);
599   free(shortcount);
600   free((char **)shortfunction);
601   err = fflush(fp);
602   if (err) SETERRQ(PETSC_ERR_SYS,"fflush() failed on file");
603   if (rank != size-1) {
604     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
605   }
606   PetscFunctionReturn(0);
607 }
608 
609 /* ---------------------------------------------------------------------------- */
610 
611 #undef __FUNCT__
612 #define __FUNCT__ "PetscMallocDebug"
613 /*@C
614     PetscMallocDebug - Turns on/off debugging for the memory management routines.
615 
616     Not Collective
617 
618     Input Parameter:
619 .   level - PETSC_TRUE or PETSC_FALSE
620 
621    Level: intermediate
622 
623 .seealso: CHKMEMQ(), PetscMallocValidate()
624 @*/
625 PetscErrorCode PETSC_DLLEXPORT PetscMallocDebug(PetscTruth level)
626 {
627   PetscFunctionBegin;
628   TRdebugLevel = level;
629   PetscFunctionReturn(0);
630 }
631