xref: /petsc/src/sys/memory/mtr.c (revision 22a7b760d1bac7490ac2e75bf367dc393fb2e18c)
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 #include <petscviewer.h>
8 #if defined(PETSC_HAVE_MALLOC_H)
9 #include <malloc.h>
10 #endif
11 
12 
13 /*
14      These are defined in mal.c and ensure that malloced space is PetscScalar aligned
15 */
16 extern PetscErrorCode  PetscMallocAlign(size_t,int,const char[],const char[],const char[],void**);
17 extern PetscErrorCode  PetscFreeAlign(void*,int,const char[],const char[],const char[]);
18 extern PetscErrorCode  PetscTrMallocDefault(size_t,int,const char[],const char[],const char[],void**);
19 extern PetscErrorCode  PetscTrFreeDefault(void*,int,const char[],const char[],const char[]);
20 
21 
22 #define CLASSID_VALUE   ((PetscClassId) 0xf0e0d0c9)
23 #define ALREADY_FREED  ((PetscClassId) 0x0f0e0d9c)
24 
25 typedef struct _trSPACE {
26   size_t       size;
27   int          id;
28   int          lineno;
29   const char   *filename;
30   const char   *functionname;
31   const char   *dirname;
32   PetscClassId classid;
33 #if defined(PETSC_USE_DEBUG)
34   PetscStack   stack;
35 #endif
36   struct _trSPACE *next,*prev;
37 } TRSPACE;
38 
39 /* HEADER_BYTES is the number of bytes in a PetscMalloc() header.
40    It is sizeof(TRSPACE) padded to be a multiple of PETSC_MEMALIGN.
41 */
42 
43 #define HEADER_BYTES      ((sizeof(TRSPACE)+(PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1))
44 
45 
46 /* This union is used to insure that the block passed to the user retains
47    a minimum alignment of PETSC_MEMALIGN.
48 */
49 typedef union {
50   TRSPACE sp;
51   char    v[HEADER_BYTES];
52 } TrSPACE;
53 
54 
55 static size_t    TRallocated  = 0;
56 static int       TRfrags      = 0;
57 static TRSPACE   *TRhead      = 0;
58 static int       TRid         = 0;
59 static PetscBool TRdebugLevel = PETSC_FALSE;
60 static size_t    TRMaxMem     = 0;
61 /*
62       Arrays to log information on all Mallocs
63 */
64 static int        PetscLogMallocMax       = 10000,PetscLogMalloc = -1;
65 static size_t     PetscLogMallocThreshold = 0;
66 static size_t     *PetscLogMallocLength;
67 static const char **PetscLogMallocDirectory,**PetscLogMallocFile,**PetscLogMallocFunction;
68 
69 #undef __FUNCT__
70 #define __FUNCT__ "PetscSetUseTrMalloc_Private"
71 PetscErrorCode PetscSetUseTrMalloc_Private(void)
72 {
73   PetscErrorCode ierr;
74 
75   PetscFunctionBegin;
76   ierr = PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault);CHKERRQ(ierr);
77 
78   TRallocated       = 0;
79   TRfrags           = 0;
80   TRhead            = 0;
81   TRid              = 0;
82   TRdebugLevel      = PETSC_FALSE;
83   TRMaxMem          = 0;
84   PetscLogMallocMax = 10000;
85   PetscLogMalloc    = -1;
86   PetscFunctionReturn(0);
87 }
88 
89 #undef __FUNCT__
90 #define __FUNCT__ "PetscMallocValidate"
91 /*@C
92    PetscMallocValidate - Test the memory for corruption.  This can be used to
93    check for memory overwrites.
94 
95    Input Parameter:
96 +  line - line number where call originated.
97 .  function - name of function calling
98 .  file - file where function is
99 -  dir - directory where function is
100 
101    Return value:
102    The number of errors detected.
103 
104    Output Effect:
105    Error messages are written to stdout.
106 
107    Level: advanced
108 
109    Notes:
110     You should generally use CHKMEMQ as a short cut for calling this
111     routine.
112 
113     The line, function, file and dir are given by the C preprocessor as
114     __LINE__, __FUNCT__, __FILE__, and __DIR__
115 
116     The Fortran calling sequence is simply PetscMallocValidate(ierr)
117 
118    No output is generated if there are no problems detected.
119 
120 .seealso: CHKMEMQ
121 
122 @*/
123 PetscErrorCode  PetscMallocValidate(int line,const char function[],const char file[],const char dir[])
124 {
125   TRSPACE      *head,*lasthead;
126   char         *a;
127   PetscClassId *nend;
128 
129   PetscFunctionBegin;
130   head = TRhead; lasthead = NULL;
131   while (head) {
132     if (head->classid != CLASSID_VALUE) {
133       (*PetscErrorPrintf)("PetscMallocValidate: error detected at  %s() line %d in %s%s\n",function,line,dir,file);
134       (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
135       (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
136       if (lasthead) (*PetscErrorPrintf)("Last intact block allocated in %s() line %d in %s%s\n",lasthead->functionname,lasthead->lineno,lasthead->dirname,lasthead->filename);
137       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
138     }
139     a    = (char*)(((TrSPACE*)head) + 1);
140     nend = (PetscClassId*)(a + head->size);
141     if (*nend != CLASSID_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_COMM_SELF,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_COMM_SELF,PETSC_ERR_MEMC," ");
150       }
151     }
152     lasthead = head;
153     head     = head->next;
154   }
155   PetscFunctionReturn(0);
156 }
157 
158 #undef __FUNCT__
159 #define __FUNCT__ "PetscTrMallocDefault"
160 /*
161     PetscTrMallocDefault - Malloc with tracing.
162 
163     Input Parameters:
164 +   a   - number of bytes to allocate
165 .   lineno - line number where used.  Use __LINE__ for this
166 .   function - function calling routine. Use __FUNCT__ for this
167 .   filename  - file name where used.  Use __FILE__ for this
168 -   dir - directory where file is. Use __SDIR__ for this
169 
170     Returns:
171     double aligned pointer to requested storage, or null if not
172     available.
173  */
174 PetscErrorCode  PetscTrMallocDefault(size_t a,int lineno,const char function[],const char filename[],const char dir[],void **result)
175 {
176   TRSPACE        *head;
177   char           *inew;
178   size_t         nsize;
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   if (!a) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Trying to malloc zero size array");
183 
184   if (TRdebugLevel) {
185     ierr = PetscMallocValidate(lineno,function,filename,dir); if (ierr) PetscFunctionReturn(ierr);
186   }
187 
188   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
189   ierr  = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),lineno,function,filename,dir,(void**)&inew);CHKERRQ(ierr);
190 
191   head  = (TRSPACE*)inew;
192   inew += sizeof(TrSPACE);
193 
194   if (TRhead) TRhead->prev = head;
195   head->next   = TRhead;
196   TRhead       = head;
197   head->prev   = 0;
198   head->size   = nsize;
199   head->id     = TRid;
200   head->lineno = lineno;
201 
202   head->filename                 = filename;
203   head->functionname             = function;
204   head->dirname                  = dir;
205   head->classid                  = CLASSID_VALUE;
206   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;
207 
208   TRallocated += nsize;
209   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
210   TRfrags++;
211 
212 #if defined(PETSC_USE_DEBUG)
213   if (PetscStackActive()) {
214     ierr = PetscStackCopy((PetscStack*)PetscThreadLocalGetValue(petscstack),&head->stack);CHKERRQ(ierr);
215     /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
216     head->stack.line[head->stack.currentsize-2] = lineno;
217   }
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 
228       PetscLogMallocDirectory = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
229       if (!PetscLogMallocDirectory) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
230 
231       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
232       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
233 
234       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
235       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,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  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   PetscClassId   *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_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);
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->classid != CLASSID_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_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
286   }
287   nend = (PetscClassId*)(ahead + head->size);
288   if (*nend != CLASSID_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_COMM_SELF,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_COMM_SELF,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  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   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
367   if (resident && residentmax && allocated) {
368     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);
369   } else if (resident && residentmax) {
370     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);
371   } else if (resident && allocated) {
372     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);
373   } else if (allocated) {
374     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);
375   } else {
376     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
377   }
378   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
379   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);CHKERRQ(ierr);
380   PetscFunctionReturn(0);
381 }
382 
383 #undef __FUNCT__
384 #define __FUNCT__ "PetscMallocGetCurrentUsage"
385 /*@C
386     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
387 
388     Not Collective
389 
390     Output Parameters:
391 .   space - number of bytes currently allocated
392 
393     Level: intermediate
394 
395     Concepts: memory usage
396 
397 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
398           PetscMemoryGetMaximumUsage()
399  @*/
400 PetscErrorCode  PetscMallocGetCurrentUsage(PetscLogDouble *space)
401 {
402   PetscFunctionBegin;
403   *space = (PetscLogDouble) TRallocated;
404   PetscFunctionReturn(0);
405 }
406 
407 #undef __FUNCT__
408 #define __FUNCT__ "PetscMallocGetMaximumUsage"
409 /*@C
410     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
411         during this run.
412 
413     Not Collective
414 
415     Output Parameters:
416 .   space - maximum number of bytes ever allocated at one time
417 
418     Level: intermediate
419 
420     Concepts: memory usage
421 
422 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
423           PetscMemoryGetCurrentUsage()
424  @*/
425 PetscErrorCode  PetscMallocGetMaximumUsage(PetscLogDouble *space)
426 {
427   PetscFunctionBegin;
428   *space = (PetscLogDouble) TRMaxMem;
429   PetscFunctionReturn(0);
430 }
431 
432 #if defined(PETSC_USE_DEBUG)
433 #undef __FUNCT__
434 #define __FUNCT__ "PetscMallocGetStack"
435 /*@C
436    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to PetscMalloc() was used to obtain that memory
437 
438    Collective on PETSC_COMM_WORLD
439 
440    Input Parameter:
441 .    ptr - the memory location
442 
443    Output Paramter:
444 .    stack - the stack indicating where the program allocated this memory
445 
446    Level: intermediate
447 
448 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
449 @*/
450 PetscErrorCode  PetscMallocGetStack(void *ptr,PetscStack **stack)
451 {
452   TRSPACE *head;
453 
454   PetscFunctionBegin;
455   head   = (TRSPACE*) (((char*)ptr) - HEADER_BYTES);
456   *stack = &head->stack;
457   PetscFunctionReturn(0);
458 }
459 #else
460 #undef __FUNCT__
461 #define __FUNCT__ "PetscMallocGetStack"
462 PetscErrorCode  PetscMallocGetStack(void *ptr,void **stack)
463 {
464   PetscFunctionBegin;
465   *stack = 0;
466   PetscFunctionReturn(0);
467 }
468 #endif
469 
470 #undef __FUNCT__
471 #define __FUNCT__ "PetscMallocDump"
472 /*@C
473    PetscMallocDump - Dumps the allocated memory blocks to a file. The information
474    printed is: size of space (in bytes), address of space, id of space,
475    file in which space was allocated, and line number at which it was
476    allocated.
477 
478    Collective on PETSC_COMM_WORLD
479 
480    Input Parameter:
481 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
482 
483    Options Database Key:
484 .  -malloc_dump - Dumps unfreed memory during call to PetscFinalize()
485 
486    Level: intermediate
487 
488    Fortran Note:
489    The calling sequence in Fortran is PetscMallocDump(integer ierr)
490    The fp defaults to stdout.
491 
492    Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
493           has been freed.
494 
495    Concepts: memory usage
496    Concepts: memory bleeding
497    Concepts: bleeding memory
498 
499 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
500 @*/
501 PetscErrorCode  PetscMallocDump(FILE *fp)
502 {
503   TRSPACE        *head;
504   PetscErrorCode ierr;
505   PetscMPIInt    rank;
506 
507   PetscFunctionBegin;
508   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
509   if (!fp) fp = PETSC_STDOUT;
510   if (TRallocated > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
511   head = TRhead;
512   while (head) {
513     fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s%s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->dirname,head->filename);
514 #if defined(PETSC_USE_DEBUG)
515     ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
516 #endif
517     head = head->next;
518   }
519   PetscFunctionReturn(0);
520 }
521 
522 /* ---------------------------------------------------------------------------- */
523 
524 #undef __FUNCT__
525 #define __FUNCT__ "PetscMallocSetDumpLog"
526 /*@C
527     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
528 
529     Not Collective
530 
531     Options Database Key:
532 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
533 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
534 
535     Level: advanced
536 
537 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLogThreshold()
538 @*/
539 PetscErrorCode PetscMallocSetDumpLog(void)
540 {
541   PetscErrorCode ierr;
542 
543   PetscFunctionBegin;
544   PetscLogMalloc = 0;
545 
546   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
547   PetscFunctionReturn(0);
548 }
549 
550 #undef __FUNCT__
551 #define __FUNCT__ "PetscMallocSetDumpLogThreshold"
552 /*@C
553     PetscMallocSetDumpLogThreshold - Activates logging of all calls to PetscMalloc().
554 
555     Not Collective
556 
557     Input Arguments:
558 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
559 
560     Options Database Key:
561 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
562 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
563 
564     Level: advanced
565 
566 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLog()
567 @*/
568 PetscErrorCode PetscMallocSetDumpLogThreshold(PetscLogDouble logmin)
569 {
570   PetscErrorCode ierr;
571 
572   PetscFunctionBegin;
573   ierr = PetscMallocSetDumpLog();CHKERRQ(ierr);
574   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
575   PetscLogMallocThreshold = (size_t)logmin;
576   PetscFunctionReturn(0);
577 }
578 
579 #undef __FUNCT__
580 #define __FUNCT__ "PetscMallocGetDumpLog"
581 /*@C
582     PetscMallocGetDumpLog - Determine whether all calls to PetscMalloc() are being logged
583 
584     Not Collective
585 
586     Output Arguments
587 .   logging - PETSC_TRUE if logging is active
588 
589     Options Database Key:
590 .  -malloc_log - Activates PetscMallocDumpLog()
591 
592     Level: advanced
593 
594 .seealso: PetscMallocDump(), PetscMallocDumpLog()
595 @*/
596 PetscErrorCode PetscMallocGetDumpLog(PetscBool *logging)
597 {
598 
599   PetscFunctionBegin;
600   *logging = (PetscBool)(PetscLogMalloc >= 0);
601   PetscFunctionReturn(0);
602 }
603 
604 #undef __FUNCT__
605 #define __FUNCT__ "PetscMallocDumpLog"
606 /*@C
607     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
608        PetscMemoryGetMaximumUsage()
609 
610     Collective on PETSC_COMM_WORLD
611 
612     Input Parameter:
613 .   fp - file pointer; or NULL
614 
615     Options Database Key:
616 .  -malloc_log - Activates PetscMallocDumpLog()
617 
618     Level: advanced
619 
620    Fortran Note:
621    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
622    The fp defaults to stdout.
623 
624 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
625 @*/
626 PetscErrorCode  PetscMallocDumpLog(FILE *fp)
627 {
628   PetscInt       i,j,n,dummy,*perm;
629   size_t         *shortlength;
630   int            *shortcount,err;
631   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
632   PetscBool      match;
633   const char     **shortfunction;
634   PetscLogDouble rss;
635   MPI_Status     status;
636   PetscErrorCode ierr;
637 
638   PetscFunctionBegin;
639   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
640   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
641   /*
642        Try to get the data printed in order by processor. This will only sometimes work
643   */
644   err = fflush(fp);
645   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
646 
647   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
648   if (rank) {
649     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
650   }
651 
652   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()");
653 
654   if (!fp) fp = PETSC_STDOUT;
655   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
656   if (rss) {
657     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);
658   } else {
659     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);
660   }
661   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
662   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
663   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
664   for (i=0,n=0; i<PetscLogMalloc; i++) {
665     for (j=0; j<n; j++) {
666       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
667       if (match) {
668         shortlength[j] += PetscLogMallocLength[i];
669         shortcount[j]++;
670         goto foundit;
671       }
672     }
673     shortfunction[n] = PetscLogMallocFunction[i];
674     shortlength[n]   = PetscLogMallocLength[i];
675     shortcount[n]    = 1;
676     n++;
677 foundit:;
678   }
679 
680   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
681   for (i=0; i<n; i++) perm[i] = i;
682   ierr = PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);CHKERRQ(ierr);
683 
684   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
685   for (i=0; i<n; i++) {
686     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
687   }
688   free(perm);
689   free(shortlength);
690   free(shortcount);
691   free((char**)shortfunction);
692   err = fflush(fp);
693   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
694   if (rank != size-1) {
695     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
696   }
697   PetscFunctionReturn(0);
698 }
699 
700 /* ---------------------------------------------------------------------------- */
701 
702 #undef __FUNCT__
703 #define __FUNCT__ "PetscMallocDebug"
704 /*@C
705     PetscMallocDebug - Turns on/off debugging for the memory management routines.
706 
707     Not Collective
708 
709     Input Parameter:
710 .   level - PETSC_TRUE or PETSC_FALSE
711 
712    Level: intermediate
713 
714 .seealso: CHKMEMQ(), PetscMallocValidate()
715 @*/
716 PetscErrorCode  PetscMallocDebug(PetscBool level)
717 {
718   PetscFunctionBegin;
719   TRdebugLevel = level;
720   PetscFunctionReturn(0);
721 }
722 
723 #undef __FUNCT__
724 #define __FUNCT__ "PetscMallocGetDebug"
725 /*@C
726     PetscMallocGetDebug - Indicates if any PETSc is doing ANY memory debugging.
727 
728     Not Collective
729 
730     Output Parameter:
731 .    flg - PETSC_TRUE if any debugger
732 
733    Level: intermediate
734 
735     Note that by default, the debug version always does some debugging unless you run with -malloc no
736 
737 
738 .seealso: CHKMEMQ(), PetscMallocValidate()
739 @*/
740 PetscErrorCode  PetscMallocGetDebug(PetscBool *flg)
741 {
742   PetscFunctionBegin;
743   if (PetscTrMalloc == PetscTrMallocDefault) *flg = PETSC_TRUE;
744   else *flg = PETSC_FALSE;
745   PetscFunctionReturn(0);
746 }
747