xref: /petsc/src/sys/memory/mtr.c (revision 00d931fe9835bef04c3bcd2a9a1bf118d64cc4c2)
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   PetscErrorCode ierr;
530   PetscMPIInt    rank;
531 
532   PetscFunctionBegin;
533   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
534   if (!fp) fp = PETSC_STDOUT;
535   if (TRallocated > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
536   head = TRhead;
537   while (head) {
538     fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->filename);
539 #if defined(PETSC_USE_DEBUG)
540     ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
541 #endif
542     head = head->next;
543   }
544   PetscFunctionReturn(0);
545 }
546 
547 /* ---------------------------------------------------------------------------- */
548 
549 #undef __FUNCT__
550 #define __FUNCT__ "PetscMallocSetDumpLog"
551 /*@C
552     PetscMallocSetDumpLog - Activates logging of all calls to PetscMalloc().
553 
554     Not Collective
555 
556     Options Database Key:
557 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
558 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
559 
560     Level: advanced
561 
562 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLogThreshold()
563 @*/
564 PetscErrorCode PetscMallocSetDumpLog(void)
565 {
566   PetscErrorCode ierr;
567 
568   PetscFunctionBegin;
569   PetscLogMalloc = 0;
570 
571   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
572   PetscFunctionReturn(0);
573 }
574 
575 #undef __FUNCT__
576 #define __FUNCT__ "PetscMallocSetDumpLogThreshold"
577 /*@C
578     PetscMallocSetDumpLogThreshold - Activates logging of all calls to PetscMalloc().
579 
580     Not Collective
581 
582     Input Arguments:
583 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
584 
585     Options Database Key:
586 +  -malloc_log <filename> - Activates PetscMallocDumpLog()
587 -  -malloc_log_threshold <min> - Activates logging and sets a minimum size
588 
589     Level: advanced
590 
591 .seealso: PetscMallocDump(), PetscMallocDumpLog(), PetscMallocSetDumpLog()
592 @*/
593 PetscErrorCode PetscMallocSetDumpLogThreshold(PetscLogDouble logmin)
594 {
595   PetscErrorCode ierr;
596 
597   PetscFunctionBegin;
598   ierr = PetscMallocSetDumpLog();CHKERRQ(ierr);
599   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
600   PetscLogMallocThreshold = (size_t)logmin;
601   PetscFunctionReturn(0);
602 }
603 
604 #undef __FUNCT__
605 #define __FUNCT__ "PetscMallocGetDumpLog"
606 /*@C
607     PetscMallocGetDumpLog - Determine whether all calls to PetscMalloc() are being logged
608 
609     Not Collective
610 
611     Output Arguments
612 .   logging - PETSC_TRUE if logging is active
613 
614     Options Database Key:
615 .  -malloc_log - Activates PetscMallocDumpLog()
616 
617     Level: advanced
618 
619 .seealso: PetscMallocDump(), PetscMallocDumpLog()
620 @*/
621 PetscErrorCode PetscMallocGetDumpLog(PetscBool *logging)
622 {
623 
624   PetscFunctionBegin;
625   *logging = (PetscBool)(PetscLogMalloc >= 0);
626   PetscFunctionReturn(0);
627 }
628 
629 #undef __FUNCT__
630 #define __FUNCT__ "PetscMallocDumpLog"
631 /*@C
632     PetscMallocDumpLog - Dumps the log of all calls to PetscMalloc(); also calls
633        PetscMemoryGetMaximumUsage()
634 
635     Collective on PETSC_COMM_WORLD
636 
637     Input Parameter:
638 .   fp - file pointer; or NULL
639 
640     Options Database Key:
641 .  -malloc_log - Activates PetscMallocDumpLog()
642 
643     Level: advanced
644 
645    Fortran Note:
646    The calling sequence in Fortran is PetscMallocDumpLog(integer ierr)
647    The fp defaults to stdout.
648 
649 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocSetDumpLog()
650 @*/
651 PetscErrorCode  PetscMallocDumpLog(FILE *fp)
652 {
653   PetscInt       i,j,n,dummy,*perm;
654   size_t         *shortlength;
655   int            *shortcount,err;
656   PetscMPIInt    rank,size,tag = 1212 /* very bad programming */;
657   PetscBool      match;
658   const char     **shortfunction;
659   PetscLogDouble rss;
660   MPI_Status     status;
661   PetscErrorCode ierr;
662 
663   PetscFunctionBegin;
664   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
665   ierr = MPI_Comm_size(MPI_COMM_WORLD,&size);CHKERRQ(ierr);
666   /*
667        Try to get the data printed in order by processor. This will only sometimes work
668   */
669   err = fflush(fp);
670   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
671 
672   ierr = MPI_Barrier(MPI_COMM_WORLD);CHKERRQ(ierr);
673   if (rank) {
674     ierr = MPI_Recv(&dummy,1,MPIU_INT,rank-1,tag,MPI_COMM_WORLD,&status);CHKERRQ(ierr);
675   }
676 
677   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()");
678 
679   if (!fp) fp = PETSC_STDOUT;
680   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
681   if (rss) {
682     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);
683   } else {
684     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);
685   }
686   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
687   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
688   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
689   for (i=0,n=0; i<PetscLogMalloc; i++) {
690     for (j=0; j<n; j++) {
691       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
692       if (match) {
693         shortlength[j] += PetscLogMallocLength[i];
694         shortcount[j]++;
695         goto foundit;
696       }
697     }
698     shortfunction[n] = PetscLogMallocFunction[i];
699     shortlength[n]   = PetscLogMallocLength[i];
700     shortcount[n]    = 1;
701     n++;
702 foundit:;
703   }
704 
705   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
706   for (i=0; i<n; i++) perm[i] = i;
707   ierr = PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);CHKERRQ(ierr);
708 
709   ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] Memory usage sorted by function\n",rank);CHKERRQ(ierr);
710   for (i=0; i<n; i++) {
711     ierr = PetscFPrintf(MPI_COMM_WORLD,fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);CHKERRQ(ierr);
712   }
713   free(perm);
714   free(shortlength);
715   free(shortcount);
716   free((char**)shortfunction);
717   err = fflush(fp);
718   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
719   if (rank != size-1) {
720     ierr = MPI_Send(&dummy,1,MPIU_INT,rank+1,tag,MPI_COMM_WORLD);CHKERRQ(ierr);
721   }
722   PetscFunctionReturn(0);
723 }
724 
725 /* ---------------------------------------------------------------------------- */
726 
727 #undef __FUNCT__
728 #define __FUNCT__ "PetscMallocDebug"
729 /*@C
730     PetscMallocDebug - Turns on/off debugging for the memory management routines.
731 
732     Not Collective
733 
734     Input Parameter:
735 .   level - PETSC_TRUE or PETSC_FALSE
736 
737    Level: intermediate
738 
739 .seealso: CHKMEMQ(), PetscMallocValidate()
740 @*/
741 PetscErrorCode  PetscMallocDebug(PetscBool level)
742 {
743   PetscFunctionBegin;
744   TRdebugLevel = level;
745   PetscFunctionReturn(0);
746 }
747 
748 #undef __FUNCT__
749 #define __FUNCT__ "PetscMallocGetDebug"
750 /*@C
751     PetscMallocGetDebug - Indicates if any PETSc is doing ANY memory debugging.
752 
753     Not Collective
754 
755     Output Parameter:
756 .    flg - PETSC_TRUE if any debugger
757 
758    Level: intermediate
759 
760     Note that by default, the debug version always does some debugging unless you run with -malloc no
761 
762 
763 .seealso: CHKMEMQ(), PetscMallocValidate()
764 @*/
765 PetscErrorCode  PetscMallocGetDebug(PetscBool *flg)
766 {
767   PetscFunctionBegin;
768   if (PetscTrMalloc == PetscTrMallocDefault) *flg = PETSC_TRUE;
769   else *flg = PETSC_FALSE;
770   PetscFunctionReturn(0);
771 }
772