xref: /petsc/src/sys/memory/mtr.c (revision 966be33a19c9230d4aa438248a644248d45cc287)
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[],void**);
17 extern PetscErrorCode  PetscFreeAlign(void*,int,const char[],const char[]);
18 extern PetscErrorCode  PetscTrMallocDefault(size_t,int,const char[],const char[],void**);
19 extern PetscErrorCode  PetscTrFreeDefault(void*,int,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   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      = NULL;
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;
64 static int        PetscLogMalloc          = -1;
65 static size_t     PetscLogMallocThreshold = 0;
66 static size_t     *PetscLogMallocLength;
67 static const char **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            = NULL;
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 
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 are given by the C preprocessor as
113     __LINE__, __FUNCT__, __FILE__
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[])
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\n",function,line,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\n",lasthead->functionname,lasthead->lineno,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\n",function,line,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\n",head->functionname,head->lineno,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 
168     Returns:
169     double aligned pointer to requested storage, or null if not
170     available.
171  */
172 PetscErrorCode  PetscTrMallocDefault(size_t a,int lineno,const char function[],const char filename[],void **result)
173 {
174   TRSPACE        *head;
175   char           *inew;
176   size_t         nsize;
177   PetscErrorCode ierr;
178 
179   PetscFunctionBegin;
180   /* Do not try to handle empty blocks */
181   if (!a) { *result = NULL; PetscFunctionReturn(0); }
182 
183   if (TRdebugLevel) {
184     ierr = PetscMallocValidate(lineno,function,filename); 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,(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   = NULL;
197   head->size   = nsize;
198   head->id     = TRid;
199   head->lineno = lineno;
200 
201   head->filename                 = filename;
202   head->functionname             = function;
203   head->classid                  = CLASSID_VALUE;
204   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;
205 
206   TRallocated += nsize;
207   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
208   TRfrags++;
209 
210 #if defined(PETSC_USE_DEBUG)
211   if (PetscStackActive()) {
212     ierr = PetscStackCopy(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   } else {
216     head->stack.currentsize = 0;
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       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     PetscLogMallocFile[PetscLogMalloc]       = filename;
236     PetscLogMallocFunction[PetscLogMalloc++] = function;
237   }
238   *result = (void*)inew;
239   PetscFunctionReturn(0);
240 }
241 
242 
243 #undef __FUNCT__
244 #define __FUNCT__ "PetscTrFreeDefault"
245 /*
246    PetscTrFreeDefault - Free with tracing.
247 
248    Input Parameters:
249 .   a    - pointer to a block allocated with PetscTrMalloc
250 .   lineno - line number where used.  Use __LINE__ for this
251 .   function - function calling routine. Use __FUNCT__ for this
252 .   file  - file name where used.  Use __FILE__ for this
253  */
254 PetscErrorCode  PetscTrFreeDefault(void *aa,int line,const char function[],const char file[])
255 {
256   char           *a = (char*)aa;
257   TRSPACE        *head;
258   char           *ahead;
259   PetscErrorCode ierr;
260   PetscClassId   *nend;
261 
262   PetscFunctionBegin;
263   /* Do not try to handle empty blocks */
264   if (!a) PetscFunctionReturn(0);
265 
266   if (TRdebugLevel) {
267     ierr = PetscMallocValidate(line,function,file);CHKERRQ(ierr);
268   }
269 
270   ahead = a;
271   a     = a - sizeof(TrSPACE);
272   head  = (TRSPACE*)a;
273 
274   if (head->classid != CLASSID_VALUE) {
275     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
276     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
277     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
278   }
279   nend = (PetscClassId*)(ahead + head->size);
280   if (*nend != CLASSID_VALUE) {
281     if (*nend == ALREADY_FREED) {
282       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
283       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
284       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
285         (*PetscErrorPrintf)("Block freed in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
286       } else {
287         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,-head->lineno,head->filename);
288       }
289       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
290     } else {
291       /* Damaged tail */
292       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
293       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
294       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
295       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
296     }
297   }
298   /* Mark the location freed */
299   *nend = ALREADY_FREED;
300   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
301   if (line > 0 && line < 50000) {
302     head->lineno       = line;
303     head->filename     = file;
304     head->functionname = function;
305   } else {
306     head->lineno = -head->lineno;
307   }
308   /* zero out memory - helps to find some reuse of already freed memory */
309   ierr = PetscMemzero(aa,head->size);CHKERRQ(ierr);
310 
311   TRallocated -= head->size;
312   TRfrags--;
313   if (head->prev) head->prev->next = head->next;
314   else TRhead = head->next;
315 
316   if (head->next) head->next->prev = head->prev;
317   ierr = PetscFreeAlign(a,line,function,file);CHKERRQ(ierr);
318   PetscFunctionReturn(0);
319 }
320 
321 
322 #undef __FUNCT__
323 #define __FUNCT__ "PetscMemoryView"
324 /*@C
325     PetscMemoryView - Shows the amount of memory currently being used
326         in a communicator.
327 
328     Collective on PetscViewer
329 
330     Input Parameter:
331 +    viewer - the viewer that defines the communicator
332 -    message - string printed before values
333 
334     Options Database:
335 +    -malloc - have PETSc track how much memory it has allocated
336 -    -memory_view - during PetscFinalize() have this routine called
337 
338     Level: intermediate
339 
340     Concepts: memory usage
341 
342 .seealso: PetscMallocDump(), PetscMemoryGetCurrentUsage(), PetscMemorySetGetMaximumUsage()
343  @*/
344 PetscErrorCode  PetscMemoryView(PetscViewer viewer,const char message[])
345 {
346   PetscLogDouble allocated,allocatedmax,resident,residentmax,gallocated,gallocatedmax,gresident,gresidentmax,maxgallocated,maxgallocatedmax,maxgresident,maxgresidentmax;
347   PetscLogDouble mingallocated,mingallocatedmax,mingresident,mingresidentmax;
348   PetscErrorCode ierr;
349   MPI_Comm       comm;
350 
351   PetscFunctionBegin;
352   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
353   ierr = PetscMallocGetCurrentUsage(&allocated);CHKERRQ(ierr);
354   ierr = PetscMallocGetMaximumUsage(&allocatedmax);CHKERRQ(ierr);
355   ierr = PetscMemoryGetCurrentUsage(&resident);CHKERRQ(ierr);
356   ierr = PetscMemoryGetMaximumUsage(&residentmax);CHKERRQ(ierr);
357   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
358   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
359   ierr = PetscViewerASCIIPrintf(viewer,message);CHKERRQ(ierr);
360   if (resident && residentmax && allocated) {
361     ierr = MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
362     ierr = MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
363     ierr = MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
364     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);CHKERRQ(ierr);
365     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
366     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
367     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
368     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
369     ierr = MPI_Reduce(&allocatedmax,&gallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
370     ierr = MPI_Reduce(&allocatedmax,&maxgallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
371     ierr = MPI_Reduce(&allocatedmax,&mingallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
372     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) space PetscMalloc()ed: total %5.4e max %5.4e min %5.4e\n",gallocatedmax,maxgallocatedmax,mingallocatedmax);CHKERRQ(ierr);
373     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
374     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
375     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
376     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
377   } else if (resident && residentmax) {
378     ierr = MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
379     ierr = MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
380     ierr = MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
381     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);CHKERRQ(ierr);
382     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
383     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
384     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
385     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
386   } else if (resident && allocated) {
387     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
388     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
389     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
390     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
391     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
392     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
393     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
394     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
395     ierr = PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");CHKERRQ(ierr);
396   } else if (allocated) {
397     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
398     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
399     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
400     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
401     ierr = PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");CHKERRQ(ierr);
402     ierr = PetscViewerASCIIPrintf(viewer,"OS cannot compute process memory\n");CHKERRQ(ierr);
403   } else {
404     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
405   }
406   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
407   PetscFunctionReturn(0);
408 }
409 
410 #undef __FUNCT__
411 #define __FUNCT__ "PetscMallocGetCurrentUsage"
412 /*@C
413     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
414 
415     Not Collective
416 
417     Output Parameters:
418 .   space - number of bytes currently allocated
419 
420     Level: intermediate
421 
422     Concepts: memory usage
423 
424 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
425           PetscMemoryGetMaximumUsage()
426  @*/
427 PetscErrorCode  PetscMallocGetCurrentUsage(PetscLogDouble *space)
428 {
429   PetscFunctionBegin;
430   *space = (PetscLogDouble) TRallocated;
431   PetscFunctionReturn(0);
432 }
433 
434 #undef __FUNCT__
435 #define __FUNCT__ "PetscMallocGetMaximumUsage"
436 /*@C
437     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
438         during this run.
439 
440     Not Collective
441 
442     Output Parameters:
443 .   space - maximum number of bytes ever allocated at one time
444 
445     Level: intermediate
446 
447     Concepts: memory usage
448 
449 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
450           PetscMemoryGetCurrentUsage()
451  @*/
452 PetscErrorCode  PetscMallocGetMaximumUsage(PetscLogDouble *space)
453 {
454   PetscFunctionBegin;
455   *space = (PetscLogDouble) TRMaxMem;
456   PetscFunctionReturn(0);
457 }
458 
459 #if defined(PETSC_USE_DEBUG)
460 #undef __FUNCT__
461 #define __FUNCT__ "PetscMallocGetStack"
462 /*@C
463    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to PetscMalloc() was used to obtain that memory
464 
465    Collective on PETSC_COMM_WORLD
466 
467    Input Parameter:
468 .    ptr - the memory location
469 
470    Output Paramter:
471 .    stack - the stack indicating where the program allocated this memory
472 
473    Level: intermediate
474 
475 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
476 @*/
477 PetscErrorCode  PetscMallocGetStack(void *ptr,PetscStack **stack)
478 {
479   TRSPACE *head;
480 
481   PetscFunctionBegin;
482   head   = (TRSPACE*) (((char*)ptr) - HEADER_BYTES);
483   *stack = &head->stack;
484   PetscFunctionReturn(0);
485 }
486 #else
487 #undef __FUNCT__
488 #define __FUNCT__ "PetscMallocGetStack"
489 PetscErrorCode  PetscMallocGetStack(void *ptr,void **stack)
490 {
491   PetscFunctionBegin;
492   *stack = NULL;
493   PetscFunctionReturn(0);
494 }
495 #endif
496 
497 #undef __FUNCT__
498 #define __FUNCT__ "PetscMallocDump"
499 /*@C
500    PetscMallocDump - Dumps the allocated memory blocks to a file. The information
501    printed is: size of space (in bytes), address of space, id of space,
502    file in which space was allocated, and line number at which it was
503    allocated.
504 
505    Collective on PETSC_COMM_WORLD
506 
507    Input Parameter:
508 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
509 
510    Options Database Key:
511 .  -malloc_dump - Dumps unfreed memory during call to PetscFinalize()
512 
513    Level: intermediate
514 
515    Fortran Note:
516    The calling sequence in Fortran is PetscMallocDump(integer ierr)
517    The fp defaults to stdout.
518 
519    Notes: uses MPI_COMM_WORLD, because this may be called in PetscFinalize() after PETSC_COMM_WORLD
520           has been freed.
521 
522    Concepts: memory usage
523    Concepts: memory bleeding
524    Concepts: bleeding memory
525 
526 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocDumpLog()
527 @*/
528 PetscErrorCode  PetscMallocDump(FILE *fp)
529 {
530   TRSPACE        *head;
531   PetscInt       libAlloc = 0;
532   PetscErrorCode ierr;
533   PetscMPIInt    rank;
534 
535   PetscFunctionBegin;
536   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
537   if (!fp) fp = PETSC_STDOUT;
538   head = TRhead;
539   while (head) {
540     PetscBool isLib;
541 
542     ierr = PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib);CHKERRQ(ierr);
543     libAlloc += head->size;
544     head = head->next;
545   }
546   if (TRallocated - libAlloc > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
547   head = TRhead;
548   while (head) {
549     PetscBool isLib;
550 
551     ierr = PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib);CHKERRQ(ierr);
552     if (!isLib) {
553       fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->filename);
554 #if defined(PETSC_USE_DEBUG)
555       ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
556 #endif
557     }
558     head = head->next;
559   }
560   PetscFunctionReturn(0);
561 }
562 
563 /* ---------------------------------------------------------------------------- */
564 
565 #undef __FUNCT__
566 #define __FUNCT__ "PetscMallocSetDumpLog"
567 /*@C
568     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
569 
570     Not Collective
571 
572     Options Database Key:
573 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
574 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
575 
576     Level: advanced
577 
578 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLogThreshold()
579 @*/
580 PetscErrorCode PetscMallocSetDumpLog(void)
581 {
582   PetscErrorCode ierr;
583 
584   PetscFunctionBegin;
585   PetscLogMalloc = 0;
586 
587   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
588   PetscFunctionReturn(0);
589 }
590 
591 #undef __FUNCT__
592 #define __FUNCT__ "PetscMallocSetDumpLogThreshold"
593 /*@C
594     PetscMallocSetDumpLogThreshold - Activates logging of all calls to PetscMalloc().
595 
596     Not Collective
597 
598     Input Arguments:
599 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
600 
601     Options Database Key:
602 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
603 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
604 
605     Level: advanced
606 
607 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLog()
608 @*/
609 PetscErrorCode PetscMallocSetDumpLogThreshold(PetscLogDouble logmin)
610 {
611   PetscErrorCode ierr;
612 
613   PetscFunctionBegin;
614   ierr = PetscMallocSetDumpLog();CHKERRQ(ierr);
615   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
616   PetscLogMallocThreshold = (size_t)logmin;
617   PetscFunctionReturn(0);
618 }
619 
620 #undef __FUNCT__
621 #define __FUNCT__ "PetscMallocGetDumpLog"
622 /*@C
623     PetscMallocGetDumpLog - Determine whether all calls to PetscMalloc() are being logged
624 
625     Not Collective
626 
627     Output Arguments
628 .   logging - PETSC_TRUE if logging is active
629 
630     Options Database Key:
631 .  -malloc_log - Activates PetscMallocDumpLog()
632 
633     Level: advanced
634 
635 .seealso: PetscMallocDump(), PetscMallocDumpLog()
636 @*/
637 PetscErrorCode PetscMallocGetDumpLog(PetscBool *logging)
638 {
639 
640   PetscFunctionBegin;
641   *logging = (PetscBool)(PetscLogMalloc >= 0);
642   PetscFunctionReturn(0);
643 }
644 
645 #undef __FUNCT__
646 #define __FUNCT__ "PetscMallocDumpLog"
647 /*@C
648     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
649        PetscMemoryGetMaximumUsage()
650 
651     Collective on PETSC_COMM_WORLD
652 
653     Input Parameter:
654 .   fp - file pointer; or NULL
655 
656     Options Database Key:
657 .  -malloc_log - Activates PetscMallocDumpLog()
658 
659     Level: advanced
660 
661    Fortran Note:
662    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
663    The fp defaults to stdout.
664 
665 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
666 @*/
667 PetscErrorCode  PetscMallocDumpLog(FILE *fp)
668 {
669   PetscInt       i,j,n,dummy,*perm;
670   size_t         *shortlength;
671   int            *shortcount,err;
672   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
673   PetscBool      match;
674   const char     **shortfunction;
675   PetscLogDouble rss;
676   MPI_Status     status;
677   PetscErrorCode ierr;
678 
679   PetscFunctionBegin;
680   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
681   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
682   /*
683        Try to get the data printed in order by processor. This will only sometimes work
684   */
685   err = fflush(fp);
686   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
687 
688   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
689   if (rank) {
690     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
691   }
692 
693   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()");
694 
695   if (!fp) fp = PETSC_STDOUT;
696   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
697   if (rss) {
698     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);
699   } else {
700     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);
701   }
702   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
703   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
704   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
705   for (i=0,n=0; i<PetscLogMalloc; i++) {
706     for (j=0; j<n; j++) {
707       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
708       if (match) {
709         shortlength[j] += PetscLogMallocLength[i];
710         shortcount[j]++;
711         goto foundit;
712       }
713     }
714     shortfunction[n] = PetscLogMallocFunction[i];
715     shortlength[n]   = PetscLogMallocLength[i];
716     shortcount[n]    = 1;
717     n++;
718 foundit:;
719   }
720 
721   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
722   for (i=0; i<n; i++) perm[i] = i;
723   ierr = PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);CHKERRQ(ierr);
724 
725   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
726   for (i=0; i<n; i++) {
727     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
728   }
729   free(perm);
730   free(shortlength);
731   free(shortcount);
732   free((char**)shortfunction);
733   err = fflush(fp);
734   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
735   if (rank != size-1) {
736     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
737   }
738   PetscFunctionReturn(0);
739 }
740 
741 /* ---------------------------------------------------------------------------- */
742 
743 #undef __FUNCT__
744 #define __FUNCT__ "PetscMallocDebug"
745 /*@C
746     PetscMallocDebug - Turns on/off debugging for the memory management routines.
747 
748     Not Collective
749 
750     Input Parameter:
751 .   level - PETSC_TRUE or PETSC_FALSE
752 
753    Level: intermediate
754 
755 .seealso: CHKMEMQ(), PetscMallocValidate()
756 @*/
757 PetscErrorCode  PetscMallocDebug(PetscBool level)
758 {
759   PetscFunctionBegin;
760   TRdebugLevel = level;
761   PetscFunctionReturn(0);
762 }
763 
764 #undef __FUNCT__
765 #define __FUNCT__ "PetscMallocGetDebug"
766 /*@C
767     PetscMallocGetDebug - Indicates if any PETSc is doing ANY memory debugging.
768 
769     Not Collective
770 
771     Output Parameter:
772 .    flg - PETSC_TRUE if any debugger
773 
774    Level: intermediate
775 
776     Note that by default, the debug version always does some debugging unless you run with -malloc no
777 
778 
779 .seealso: CHKMEMQ(), PetscMallocValidate()
780 @*/
781 PetscErrorCode  PetscMallocGetDebug(PetscBool *flg)
782 {
783   PetscFunctionBegin;
784   if (PetscTrMalloc == PetscTrMallocDefault) *flg = PETSC_TRUE;
785   else *flg = PETSC_FALSE;
786   PetscFunctionReturn(0);
787 }
788