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