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