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