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