xref: /petsc/src/sys/memory/mtr.c (revision 1f46d60f66d2379a7cf045b103b4a98b2ddbb736)
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)
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     PetscLogMallocThreshold = 0;
68 static size_t     *PetscLogMallocLength;
69 static const char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
70 
71 #undef __FUNCT__
72 #define __FUNCT__ "PetscSetUseTrMalloc_Private"
73 PetscErrorCode PetscSetUseTrMalloc_Private(void)
74 {
75   PetscErrorCode ierr;
76 
77   PetscFunctionBegin;
78   ierr = PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault);CHKERRQ(ierr);
79   TRallocated       = 0;
80   TRfrags           = 0;
81   TRhead            = 0;
82   TRid              = 0;
83   TRdebugLevel      = PETSC_FALSE;
84   TRMaxMem          = 0;
85   PetscLogMallocMax = 10000;
86   PetscLogMalloc    = -1;
87   PetscFunctionReturn(0);
88 }
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  PetscMallocValidate(int line,const char function[],const char file[],const char dir[])
125 {
126   TRSPACE     *head,*lasthead;
127   char        *a;
128   PetscClassId *nend;
129 
130   PetscFunctionBegin;
131   head = TRhead; lasthead = NULL;
132   while (head) {
133     if (head->classid != CLASSID_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_COMM_SELF,PETSC_ERR_MEMC," ");
140     }
141     a    = (char *)(((TrSPACE*)head) + 1);
142     nend = (PetscClassId *)(a + head->size);
143     if (*nend != CLASSID_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_COMM_SELF,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_COMM_SELF,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  PetscTrMallocDefault(size_t a,int lineno,const char function[],const char filename[],const char dir[],void**result)
177 {
178   TRSPACE        *head;
179   char           *inew;
180   size_t         nsize;
181   PetscErrorCode ierr;
182 
183   PetscFunctionBegin;
184   if (!a) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to malloc zero size array");
185 
186   if (TRdebugLevel) {
187     ierr = PetscMallocValidate(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
188   }
189 
190   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
191   ierr = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),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->classid       = CLASSID_VALUE;
208   *(PetscClassId *)(inew + nsize) = CLASSID_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*)PetscThreadLocalGetValue(petscstack),&head->stack);CHKERRQ(ierr);
218 #endif
219 
220   /*
221          Allow logging of all mallocs made
222   */
223   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && a >= PetscLogMallocThreshold) {
224     if (!PetscLogMalloc) {
225       PetscLogMallocLength    = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
226       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
227       PetscLogMallocDirectory = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
228       if (!PetscLogMallocDirectory) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
229       PetscLogMallocFile      = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
230       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
231       PetscLogMallocFunction  = (const char**)malloc(PetscLogMallocMax*sizeof(char**));
232       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,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  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   PetscClassId   *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     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);
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->classid != CLASSID_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_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
283   }
284   nend = (PetscClassId *)(ahead + head->size);
285   if (*nend != CLASSID_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_COMM_SELF,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_COMM_SELF,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 /*@C
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: PetscMallocDump(), PetscMemoryGetCurrentUsage()
345  @*/
346 PetscErrorCode  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   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
364   if (resident && residentmax && allocated) {
365     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);
366   } else if (resident && residentmax) {
367     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);
368   } else if (resident && allocated) {
369     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);
370   } else if (allocated) {
371     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);
372   } else {
373     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
374   }
375   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
376   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
377   PetscFunctionReturn(0);
378 }
379 
380 #undef __FUNCT__
381 #define __FUNCT__ "PetscMallocGetCurrentUsage"
382 /*@C
383     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
384 
385     Not Collective
386 
387     Output Parameters:
388 .   space - number of bytes currently allocated
389 
390     Level: intermediate
391 
392     Concepts: memory usage
393 
394 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
395           PetscMemoryGetMaximumUsage()
396  @*/
397 PetscErrorCode  PetscMallocGetCurrentUsage(PetscLogDouble *space)
398 {
399   PetscFunctionBegin;
400   *space = (PetscLogDouble) TRallocated;
401   PetscFunctionReturn(0);
402 }
403 
404 #undef __FUNCT__
405 #define __FUNCT__ "PetscMallocGetMaximumUsage"
406 /*@C
407     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
408         during this run.
409 
410     Not Collective
411 
412     Output Parameters:
413 .   space - maximum number of bytes ever allocated at one time
414 
415     Level: intermediate
416 
417     Concepts: memory usage
418 
419 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
420           PetscMemoryGetCurrentUsage()
421  @*/
422 PetscErrorCode  PetscMallocGetMaximumUsage(PetscLogDouble *space)
423 {
424   PetscFunctionBegin;
425   *space = (PetscLogDouble) TRMaxMem;
426   PetscFunctionReturn(0);
427 }
428 
429 #undef __FUNCT__
430 #define __FUNCT__ "PetscMallocDump"
431 /*@C
432    PetscMallocDump - Dumps the allocated memory blocks to a file. The information
433    printed is: size of space (in bytes), address of space, id of space,
434    file in which space was allocated, and line number at which it was
435    allocated.
436 
437    Collective on PETSC_COMM_WORLD
438 
439    Input Parameter:
440 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
441 
442    Options Database Key:
443 .  -malloc_dump - Dumps unfreed memory during call to PetscFinalize()
444 
445    Level: intermediate
446 
447    Fortran Note:
448    The calling sequence in Fortran is PetscMallocDump(integer ierr)
449    The fp defaults to stdout.
450 
451    Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
452           has been freed.
453 
454    Concepts: memory usage
455    Concepts: memory bleeding
456    Concepts: bleeding memory
457 
458 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
459 @*/
460 PetscErrorCode  PetscMallocDump(FILE *fp)
461 {
462   TRSPACE        *head;
463   PetscErrorCode ierr;
464   PetscMPIInt    rank;
465 
466   PetscFunctionBegin;
467   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
468   if (!fp) fp = PETSC_STDOUT;
469   if (TRallocated > 0) {
470     fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
471   }
472   head = TRhead;
473   while (head) {
474     fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s%s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->dirname,head->filename);
475 #if defined(PETSC_USE_DEBUG)
476     ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
477 #endif
478     head = head->next;
479   }
480   PetscFunctionReturn(0);
481 }
482 
483 /* ---------------------------------------------------------------------------- */
484 
485 #undef __FUNCT__
486 #define __FUNCT__ "PetscMallocSetDumpLog"
487 /*@C
488     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
489 
490     Not Collective
491 
492     Options Database Key:
493 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
494 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
495 
496     Level: advanced
497 
498 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLogThreshold()
499 @*/
500 PetscErrorCode 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__ "PetscMallocSetDumpLogThreshold"
512 /*@C
513     PetscMallocSetDumpLogThreshold - Activates logging of all calls to PetscMalloc().
514 
515     Not Collective
516 
517     Input Arguments:
518 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
519 
520     Options Database Key:
521 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
522 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
523 
524     Level: advanced
525 
526 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLog()
527 @*/
528 PetscErrorCode PetscMallocSetDumpLogThreshold(PetscLogDouble logmin)
529 {
530   PetscErrorCode ierr;
531 
532   PetscFunctionBegin;
533   ierr = PetscMallocSetDumpLog();CHKERRQ(ierr);
534   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
535   PetscLogMallocThreshold = (size_t)logmin;
536   PetscFunctionReturn(0);
537 }
538 
539 #undef __FUNCT__
540 #define __FUNCT__ "PetscMallocGetDumpLog"
541 /*@C
542     PetscMallocGetDumpLog - Determine whether all calls to PetscMalloc() are being logged
543 
544     Not Collective
545 
546     Output Arguments
547 .   logging - PETSC_TRUE if logging is active
548 
549     Options Database Key:
550 .  -malloc_log - Activates PetscMallocDumpLog()
551 
552     Level: advanced
553 
554 .seealso: PetscMallocDump(), PetscMallocDumpLog()
555 @*/
556 PetscErrorCode PetscMallocGetDumpLog(PetscBool *logging)
557 {
558 
559   PetscFunctionBegin;
560   *logging = (PetscBool)(PetscLogMalloc >= 0);
561   PetscFunctionReturn(0);
562 }
563 
564 #undef __FUNCT__
565 #define __FUNCT__ "PetscMallocDumpLog"
566 /*@C
567     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
568        PetscMemoryGetMaximumUsage()
569 
570     Collective on PETSC_COMM_WORLD
571 
572     Input Parameter:
573 .   fp - file pointer; or PETSC_NULL
574 
575     Options Database Key:
576 .  -malloc_log - Activates PetscMallocDumpLog()
577 
578     Level: advanced
579 
580    Fortran Note:
581    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
582    The fp defaults to stdout.
583 
584 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
585 @*/
586 PetscErrorCode  PetscMallocDumpLog(FILE *fp)
587 {
588   PetscInt       i,j,n,dummy,*perm;
589   size_t         *shortlength;
590   int            *shortcount,err;
591   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
592   PetscBool      match;
593   const char     **shortfunction;
594   PetscLogDouble rss;
595   MPI_Status     status;
596   PetscErrorCode ierr;
597 
598   PetscFunctionBegin;
599   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
600   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
601   /*
602        Try to get the data printed in order by processor. This will only sometimes work
603   */
604   err = fflush(fp);
605   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
606 
607   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
608   if (rank) {
609     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
610   }
611 
612   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()");
613 
614   if (!fp) fp = PETSC_STDOUT;
615   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
616   if (rss) {
617     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);
618   } else {
619     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);
620   }
621   shortcount       = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
622   shortlength      = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
623   shortfunction    = (const char**)malloc(PetscLogMalloc*sizeof(char *));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
624   for (i=0,n=0; i<PetscLogMalloc; i++) {
625     for (j=0; j<n; j++) {
626       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
627       if (match) {
628         shortlength[j] += PetscLogMallocLength[i];
629         shortcount[j]++;
630         goto foundit;
631       }
632     }
633     shortfunction[n] = PetscLogMallocFunction[i];
634     shortlength[n]   = PetscLogMallocLength[i];
635     shortcount[n]    = 1;
636     n++;
637     foundit:;
638   }
639 
640   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
641   for (i=0; i<n; i++) perm[i] = i;
642   ierr = PetscSortStrWithPermutation(n,(const char **)shortfunction,perm);CHKERRQ(ierr);
643 
644   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
645   for (i=0; i<n; i++) {
646     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
647   }
648   free(perm);
649   free(shortlength);
650   free(shortcount);
651   free((char **)shortfunction);
652   err = fflush(fp);
653   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
654   if (rank != size-1) {
655     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
656   }
657   PetscFunctionReturn(0);
658 }
659 
660 /* ---------------------------------------------------------------------------- */
661 
662 #undef __FUNCT__
663 #define __FUNCT__ "PetscMallocDebug"
664 /*@C
665     PetscMallocDebug - Turns on/off debugging for the memory management routines.
666 
667     Not Collective
668 
669     Input Parameter:
670 .   level - PETSC_TRUE or PETSC_FALSE
671 
672    Level: intermediate
673 
674 .seealso: CHKMEMQ(), PetscMallocValidate()
675 @*/
676 PetscErrorCode  PetscMallocDebug(PetscBool  level)
677 {
678   PetscFunctionBegin;
679   TRdebugLevel = level;
680   PetscFunctionReturn(0);
681 }
682