xref: /petsc/src/sys/memory/mtr.c (revision 3e1910f1ab6113d8365e15c6b8c907ccce7ce4ea)
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   ierr = PetscStackCopy((PetscStack*)PetscThreadLocalGetValue(petscstack),&head->stack);CHKERRQ(ierr);
214   /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
215   head->stack.line[head->stack.currentsize-2] = lineno;
216 #endif
217 
218   /*
219          Allow logging of all mallocs made
220   */
221   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && a >= PetscLogMallocThreshold) {
222     if (!PetscLogMalloc) {
223       PetscLogMallocLength = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
224       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
225 
226       PetscLogMallocDirectory = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
227       if (!PetscLogMallocDirectory) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
228 
229       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
230       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
231 
232       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
233       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
234     }
235     PetscLogMallocLength[PetscLogMalloc]     = nsize;
236     PetscLogMallocDirectory[PetscLogMalloc]  = dir;
237     PetscLogMallocFile[PetscLogMalloc]       = filename;
238     PetscLogMallocFunction[PetscLogMalloc++] = function;
239   }
240   *result = (void*)inew;
241   PetscFunctionReturn(0);
242 }
243 
244 
245 #undef __FUNCT__
246 #define __FUNCT__ "PetscTrFreeDefault"
247 /*
248    PetscTrFreeDefault - Free with tracing.
249 
250    Input Parameters:
251 .   a    - pointer to a block allocated with PetscTrMalloc
252 .   lineno - line number where used.  Use __LINE__ for this
253 .   function - function calling routine. Use __FUNCT__ for this
254 .   file  - file name where used.  Use __FILE__ for this
255 .   dir - directory where file is. Use __SDIR__ for this
256  */
257 PetscErrorCode  PetscTrFreeDefault(void *aa,int line,const char function[],const char file[],const char dir[])
258 {
259   char           *a = (char*)aa;
260   TRSPACE        *head;
261   char           *ahead;
262   PetscErrorCode ierr;
263   PetscClassId   *nend;
264 
265   PetscFunctionBegin;
266   /* Do not try to handle empty blocks */
267   if (!a) {
268     (*PetscErrorPrintf)("PetscTrFreeDefault called from %s() line %d in %s%s\n",function,line,dir,file);
269     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);
270   }
271 
272   if (TRdebugLevel) {
273     ierr = PetscMallocValidate(line,function,file,dir);CHKERRQ(ierr);
274   }
275 
276   ahead = a;
277   a     = a - sizeof(TrSPACE);
278   head  = (TRSPACE*)a;
279 
280   if (head->classid != CLASSID_VALUE) {
281     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
282     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
283     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
284   }
285   nend = (PetscClassId*)(ahead + head->size);
286   if (*nend != CLASSID_VALUE) {
287     if (*nend == ALREADY_FREED) {
288       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
289       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
290       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
291         (*PetscErrorPrintf)("Block freed in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
292       } else {
293         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,-head->lineno,head->dirname,head->filename);
294       }
295       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
296     } else {
297       /* Damaged tail */
298       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s%s\n",function,line,dir,file);
299       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
300       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s%s\n",head->functionname,head->lineno,head->dirname,head->filename);
301       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
302     }
303   }
304   /* Mark the location freed */
305   *nend = ALREADY_FREED;
306   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
307   if (line > 0 && line < 50000) {
308     head->lineno       = line;
309     head->filename     = file;
310     head->functionname = function;
311     head->dirname      = dir;
312   } else {
313     head->lineno = -head->lineno;
314   }
315   /* zero out memory - helps to find some reuse of already freed memory */
316   ierr = PetscMemzero(aa,head->size);CHKERRQ(ierr);
317 
318   TRallocated -= head->size;
319   TRfrags--;
320   if (head->prev) head->prev->next = head->next;
321   else TRhead = head->next;
322 
323   if (head->next) head->next->prev = head->prev;
324   ierr = PetscFreeAlign(a,line,function,file,dir);CHKERRQ(ierr);
325   PetscFunctionReturn(0);
326 }
327 
328 
329 #undef __FUNCT__
330 #define __FUNCT__ "PetscMemoryShowUsage"
331 /*@C
332     PetscMemoryShowUsage - Shows the amount of memory currently being used
333         in a communicator.
334 
335     Collective on PetscViewer
336 
337     Input Parameter:
338 +    viewer - the viewer that defines the communicator
339 -    message - string printed before values
340 
341     Level: intermediate
342 
343     Concepts: memory usage
344 
345 .seealso: PetscMallocDump(), PetscMemoryGetCurrentUsage()
346  @*/
347 PetscErrorCode  PetscMemoryShowUsage(PetscViewer viewer,const char message[])
348 {
349   PetscLogDouble allocated,maximum,resident,residentmax;
350   PetscErrorCode ierr;
351   PetscMPIInt    rank;
352   MPI_Comm       comm;
353 
354   PetscFunctionBegin;
355   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
356   ierr = PetscMallocGetCurrentUsage(&allocated);CHKERRQ(ierr);
357   ierr = PetscMallocGetMaximumUsage(&maximum);CHKERRQ(ierr);
358   ierr = PetscMemoryGetCurrentUsage(&resident);CHKERRQ(ierr);
359   ierr = PetscMemoryGetMaximumUsage(&residentmax);CHKERRQ(ierr);
360   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
361   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
362   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
363   ierr = PetscViewerASCIIPrintf(viewer,message);CHKERRQ(ierr);
364   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_TRUE);CHKERRQ(ierr);
365   if (resident && residentmax && allocated) {
366     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);
367   } else if (resident && residentmax) {
368     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);
369   } else if (resident && allocated) {
370     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);
371   } else if (allocated) {
372     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);
373   } else {
374     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
375   }
376   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
377   ierr = PetscViewerASCIISynchronizedAllow(viewer,PETSC_FALSE);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  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  PetscMallocGetMaximumUsage(PetscLogDouble *space)
424 {
425   PetscFunctionBegin;
426   *space = (PetscLogDouble) TRMaxMem;
427   PetscFunctionReturn(0);
428 }
429 
430 #if defined(PETSC_USE_DEBUG)
431 #undef __FUNCT__
432 #define __FUNCT__ "PetscMallocGetStack"
433 /*@C
434    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to PetscMalloc() was used to obtain that memory
435 
436    Collective on PETSC_COMM_WORLD
437 
438    Input Parameter:
439 .    ptr - the memory location
440 
441    Output Paramter:
442 .    stack - the stack indicating where the program allocated this memory
443 
444    Level: intermediate
445 
446 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
447 @*/
448 PetscErrorCode  PetscMallocGetStack(void *ptr,PetscStack **stack)
449 {
450   TRSPACE *head;
451 
452   PetscFunctionBegin;
453   head   = (TRSPACE*) (((char*)ptr) - HEADER_BYTES);
454   *stack = &head->stack;
455   PetscFunctionReturn(0);
456 }
457 #endif
458 
459 #undef __FUNCT__
460 #define __FUNCT__ "PetscMallocDump"
461 /*@C
462    PetscMallocDump - Dumps the allocated memory blocks to a file. The information
463    printed is: size of space (in bytes), address of space, id of space,
464    file in which space was allocated, and line number at which it was
465    allocated.
466 
467    Collective on PETSC_COMM_WORLD
468 
469    Input Parameter:
470 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
471 
472    Options Database Key:
473 .  -malloc_dump - Dumps unfreed memory during call to PetscFinalize()
474 
475    Level: intermediate
476 
477    Fortran Note:
478    The calling sequence in Fortran is PetscMallocDump(integer ierr)
479    The fp defaults to stdout.
480 
481    Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
482           has been freed.
483 
484    Concepts: memory usage
485    Concepts: memory bleeding
486    Concepts: bleeding memory
487 
488 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
489 @*/
490 PetscErrorCode  PetscMallocDump(FILE *fp)
491 {
492   TRSPACE        *head;
493   PetscErrorCode ierr;
494   PetscMPIInt    rank;
495 
496   PetscFunctionBegin;
497   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
498   if (!fp) fp = PETSC_STDOUT;
499   if (TRallocated > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
500   head = TRhead;
501   while (head) {
502     fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s%s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->dirname,head->filename);
503 #if defined(PETSC_USE_DEBUG)
504     ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
505 #endif
506     head = head->next;
507   }
508   PetscFunctionReturn(0);
509 }
510 
511 /* ---------------------------------------------------------------------------- */
512 
513 #undef __FUNCT__
514 #define __FUNCT__ "PetscMallocSetDumpLog"
515 /*@C
516     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
517 
518     Not Collective
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(), PetscMallocSetDumpLogThreshold()
527 @*/
528 PetscErrorCode PetscMallocSetDumpLog(void)
529 {
530   PetscErrorCode ierr;
531 
532   PetscFunctionBegin;
533   PetscLogMalloc = 0;
534 
535   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
536   PetscFunctionReturn(0);
537 }
538 
539 #undef __FUNCT__
540 #define __FUNCT__ "PetscMallocSetDumpLogThreshold"
541 /*@C
542     PetscMallocSetDumpLogThreshold - Activates logging of all calls to PetscMalloc().
543 
544     Not Collective
545 
546     Input Arguments:
547 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
548 
549     Options Database Key:
550 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
551 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
552 
553     Level: advanced
554 
555 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLog()
556 @*/
557 PetscErrorCode PetscMallocSetDumpLogThreshold(PetscLogDouble logmin)
558 {
559   PetscErrorCode ierr;
560 
561   PetscFunctionBegin;
562   ierr = PetscMallocSetDumpLog();CHKERRQ(ierr);
563   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
564   PetscLogMallocThreshold = (size_t)logmin;
565   PetscFunctionReturn(0);
566 }
567 
568 #undef __FUNCT__
569 #define __FUNCT__ "PetscMallocGetDumpLog"
570 /*@C
571     PetscMallocGetDumpLog - Determine whether all calls to PetscMalloc() are being logged
572 
573     Not Collective
574 
575     Output Arguments
576 .   logging - PETSC_TRUE if logging is active
577 
578     Options Database Key:
579 .  -malloc_log - Activates PetscMallocDumpLog()
580 
581     Level: advanced
582 
583 .seealso: PetscMallocDump(), PetscMallocDumpLog()
584 @*/
585 PetscErrorCode PetscMallocGetDumpLog(PetscBool *logging)
586 {
587 
588   PetscFunctionBegin;
589   *logging = (PetscBool)(PetscLogMalloc >= 0);
590   PetscFunctionReturn(0);
591 }
592 
593 #undef __FUNCT__
594 #define __FUNCT__ "PetscMallocDumpLog"
595 /*@C
596     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
597        PetscMemoryGetMaximumUsage()
598 
599     Collective on PETSC_COMM_WORLD
600 
601     Input Parameter:
602 .   fp - file pointer; or NULL
603 
604     Options Database Key:
605 .  -malloc_log - Activates PetscMallocDumpLog()
606 
607     Level: advanced
608 
609    Fortran Note:
610    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
611    The fp defaults to stdout.
612 
613 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
614 @*/
615 PetscErrorCode  PetscMallocDumpLog(FILE *fp)
616 {
617   PetscInt       i,j,n,dummy,*perm;
618   size_t         *shortlength;
619   int            *shortcount,err;
620   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
621   PetscBool      match;
622   const char     **shortfunction;
623   PetscLogDouble rss;
624   MPI_Status     status;
625   PetscErrorCode ierr;
626 
627   PetscFunctionBegin;
628   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
629   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
630   /*
631        Try to get the data printed in order by processor. This will only sometimes work
632   */
633   err = fflush(fp);
634   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
635 
636   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
637   if (rank) {
638     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
639   }
640 
641   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()");
642 
643   if (!fp) fp = PETSC_STDOUT;
644   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
645   if (rss) {
646     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);
647   } else {
648     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);
649   }
650   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
651   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
652   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
653   for (i=0,n=0; i<PetscLogMalloc; i++) {
654     for (j=0; j<n; j++) {
655       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
656       if (match) {
657         shortlength[j] += PetscLogMallocLength[i];
658         shortcount[j]++;
659         goto foundit;
660       }
661     }
662     shortfunction[n] = PetscLogMallocFunction[i];
663     shortlength[n]   = PetscLogMallocLength[i];
664     shortcount[n]    = 1;
665     n++;
666 foundit:;
667   }
668 
669   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
670   for (i=0; i<n; i++) perm[i] = i;
671   ierr = PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);CHKERRQ(ierr);
672 
673   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
674   for (i=0; i<n; i++) {
675     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
676   }
677   free(perm);
678   free(shortlength);
679   free(shortcount);
680   free((char**)shortfunction);
681   err = fflush(fp);
682   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
683   if (rank != size-1) {
684     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
685   }
686   PetscFunctionReturn(0);
687 }
688 
689 /* ---------------------------------------------------------------------------- */
690 
691 #undef __FUNCT__
692 #define __FUNCT__ "PetscMallocDebug"
693 /*@C
694     PetscMallocDebug - Turns on/off debugging for the memory management routines.
695 
696     Not Collective
697 
698     Input Parameter:
699 .   level - PETSC_TRUE or PETSC_FALSE
700 
701    Level: intermediate
702 
703 .seealso: CHKMEMQ(), PetscMallocValidate()
704 @*/
705 PetscErrorCode  PetscMallocDebug(PetscBool level)
706 {
707   PetscFunctionBegin;
708   TRdebugLevel = level;
709   PetscFunctionReturn(0);
710 }
711 
712 #undef __FUNCT__
713 #define __FUNCT__ "PetscMallocGetDebug"
714 /*@C
715     PetscMallocGetDebug - Indicates if any PETSc is doing ANY memory debugging.
716 
717     Not Collective
718 
719     Output Parameter:
720 .    flg - PETSC_TRUE if any debugger
721 
722    Level: intermediate
723 
724     Note that by default, the debug version always does some debugging unless you run with -malloc no
725 
726 
727 .seealso: CHKMEMQ(), PetscMallocValidate()
728 @*/
729 PetscErrorCode  PetscMallocGetDebug(PetscBool *flg)
730 {
731   PetscFunctionBegin;
732   if (PetscTrMalloc == PetscTrMallocDefault) *flg = PETSC_TRUE;
733   else *flg = PETSC_FALSE;
734   PetscFunctionReturn(0);
735 }
736