xref: /petsc/src/sys/memory/mtr.c (revision 02c9f0b548ed2228330a66acd2df0a92dd2a8bb1)
1 
2 /*
3      Interface to malloc() and free(). This code allows for logging of memory usage and some error checking
4 */
5 #include <petscsys.h>           /*I "petscsys.h" I*/
6 #include <petscviewer.h>
7 #if defined(PETSC_HAVE_MALLOC_H)
8 #include <malloc.h>
9 #endif
10 
11 /*
12      These are defined in mal.c and ensure that malloced space is PetscScalar aligned
13 */
14 PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t,PetscBool,int,const char[],const char[],void**);
15 PETSC_EXTERN PetscErrorCode PetscFreeAlign(void*,int,const char[],const char[]);
16 PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t,int,const char[],const char[],void**);
17 
18 #define CLASSID_VALUE  ((PetscClassId) 0xf0e0d0c9)
19 #define ALREADY_FREED  ((PetscClassId) 0x0f0e0d9c)
20 
21 /*  this is the header put at the beginning of each malloc() using for tracking allocated space and checking of allocated space heap */
22 typedef struct _trSPACE {
23   size_t          size;
24   int             id;
25   int             lineno;
26   const char      *filename;
27   const char      *functionname;
28   PetscClassId    classid;
29 #if defined(PETSC_USE_DEBUG)
30   PetscStack      stack;
31 #endif
32   struct _trSPACE *next,*prev;
33 } TRSPACE;
34 
35 /* HEADER_BYTES is the number of bytes in a PetscMalloc() header.
36    It is sizeof(trSPACE) padded to be a multiple of PETSC_MEMALIGN.
37 */
38 #define HEADER_BYTES  ((sizeof(TRSPACE)+(PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1))
39 
40 /* This union is used to insure that the block passed to the user retains
41    a minimum alignment of PETSC_MEMALIGN.
42 */
43 typedef union {
44   TRSPACE sp;
45   char    v[HEADER_BYTES];
46 } TrSPACE;
47 
48 #define MAXTRMAXMEMS 50
49 static size_t    TRallocated          = 0;
50 static int       TRfrags              = 0;
51 static TRSPACE   *TRhead              = NULL;
52 static int       TRid                 = 0;
53 static PetscBool TRdebugLevel         = PETSC_FALSE;
54 static PetscBool TRdebugIintializenan = PETSC_FALSE;
55 static size_t    TRMaxMem             = 0;
56 static int       NumTRMaxMems         = 0;
57 static size_t    TRMaxMems[MAXTRMAXMEMS];
58 static int       TRMaxMemsEvents[MAXTRMAXMEMS];
59 /*
60       Arrays to log information on mallocs for PetscMallocView()
61 */
62 static int        PetscLogMallocMax       = 10000;
63 static int        PetscLogMalloc          = -1;
64 static size_t     PetscLogMallocThreshold = 0;
65 static size_t     *PetscLogMallocLength;
66 static const char **PetscLogMallocFile,**PetscLogMallocFunction;
67 
68 /*@C
69    PetscMallocValidate - Test the memory for corruption.  This can be called at any time between PetscInitialize() and PetscFinalize()
70 
71    Input Parameters:
72 +  line - line number where call originated.
73 .  function - name of function calling
74 -  file - file where function is
75 
76    Return value:
77    The number of errors detected.
78 
79    Options Database:.
80 +  -malloc_test - turns this feature on when PETSc was not configured with --with-debugging=0
81 -  -malloc_debug - turns this feature on anytime
82 
83    Output Effect:
84    Error messages are written to stdout.
85 
86    Level: advanced
87 
88    Notes:
89     This is only run if PetscMallocSetDebug() has been called which is set by -malloc_test (if debugging is turned on) or -malloc_debug (any time)
90 
91     You should generally use CHKMEMQ as a short cut for calling this  routine.
92 
93     The Fortran calling sequence is simply PetscMallocValidate(ierr)
94 
95    No output is generated if there are no problems detected.
96 
97    Developers Note:
98      Uses the flg TRdebugLevel (set as the first argument to PetscMallocSetDebug()) to determine if it should run
99 
100 .seealso: CHKMEMQ
101 
102 @*/
103 PetscErrorCode  PetscMallocValidate(int line,const char function[],const char file[])
104 {
105   TRSPACE      *head,*lasthead;
106   char         *a;
107   PetscClassId *nend;
108 
109   if (!TRdebugLevel) return 0;
110   PetscFunctionBegin;
111   head = TRhead; lasthead = NULL;
112   while (head) {
113     if (head->classid != CLASSID_VALUE) {
114       (*PetscErrorPrintf)("PetscMallocValidate: error detected at  %s() line %d in %s\n",function,line,file);
115       (*PetscErrorPrintf)("Memory at address %p is corrupted\n",head);
116       (*PetscErrorPrintf)("Probably write past beginning or end of array\n");
117       if (lasthead) (*PetscErrorPrintf)("Last intact block allocated in %s() line %d in %s\n",lasthead->functionname,lasthead->lineno,lasthead->filename);
118       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
119     }
120     a    = (char*)(((TrSPACE*)head) + 1);
121     nend = (PetscClassId*)(a + head->size);
122     if (*nend != CLASSID_VALUE) {
123       (*PetscErrorPrintf)("PetscMallocValidate: error detected at %s() line %d in %s\n",function,line,file);
124       if (*nend == ALREADY_FREED) {
125         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n",head->id,(PetscLogDouble)head->size,a);
126         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
127       } else {
128         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
129         (*PetscErrorPrintf)("Memory originally allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
130         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC," ");
131       }
132     }
133     lasthead = head;
134     head     = head->next;
135   }
136   PetscFunctionReturn(0);
137 }
138 
139 /*
140     PetscTrMallocDefault - Malloc with tracing.
141 
142     Input Parameters:
143 +   a   - number of bytes to allocate
144 .   lineno - line number where used.  Use __LINE__ for this
145 -   filename  - file name where used.  Use __FILE__ for this
146 
147     Returns:
148     double aligned pointer to requested storage, or null if not  available.
149  */
150 PetscErrorCode  PetscTrMallocDefault(size_t a,PetscBool clear,int lineno,const char function[],const char filename[],void **result)
151 {
152   TRSPACE        *head;
153   char           *inew;
154   size_t         nsize;
155   PetscErrorCode ierr;
156 
157   PetscFunctionBegin;
158   /* Do not try to handle empty blocks */
159   if (!a) { *result = NULL; PetscFunctionReturn(0); }
160 
161   ierr = PetscMallocValidate(lineno,function,filename); if (ierr) PetscFunctionReturn(ierr);
162 
163   nsize = (a + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
164   ierr  = PetscMallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),clear,lineno,function,filename,(void**)&inew);CHKERRQ(ierr);
165 
166   head  = (TRSPACE*)inew;
167   inew += sizeof(TrSPACE);
168 
169   if (TRhead) TRhead->prev = head;
170   head->next   = TRhead;
171   TRhead       = head;
172   head->prev   = NULL;
173   head->size   = nsize;
174   head->id     = TRid;
175   head->lineno = lineno;
176 
177   head->filename                 = filename;
178   head->functionname             = function;
179   head->classid                  = CLASSID_VALUE;
180   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;
181 
182   TRallocated += nsize;
183   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
184   if (PetscLogMemory) {
185     PetscInt i;
186     for (i=0; i<NumTRMaxMems; i++) {
187       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
188     }
189   }
190   TRfrags++;
191 
192 #if defined(PETSC_USE_DEBUG)
193   if (PetscStackActive()) {
194     ierr = PetscStackCopy(petscstack,&head->stack);CHKERRQ(ierr);
195     /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
196     head->stack.line[head->stack.currentsize-2] = lineno;
197   } else {
198     head->stack.currentsize = 0;
199   }
200 #if defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE)
201   if (!clear && TRdebugIintializenan) {
202     size_t     i, n = a/sizeof(PetscReal);
203     PetscReal *s = (PetscReal*) inew;
204     /* from https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html */
205 #if defined(PETSC_USE_REAL_SINGLE)
206     int        nas = 0x7F800002;
207 #else
208     PetscInt64 nas = 0x7FF0000000000002;
209 #endif
210     for (i=0; i<n; i++) {
211       memcpy(s+i,&nas,sizeof(PetscReal));
212     }
213   }
214 #endif
215 #endif
216 
217   /*
218          Allow logging of all mallocs made.
219          TODO: Currently this memory is never freed, it should be freed during PetscFinalize()
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    PetscTrFreeDefault - Free with tracing.
242 
243    Input Parameters:
244 .   a    - pointer to a block allocated with PetscTrMalloc
245 .   lineno - line number where used.  Use __LINE__ for this
246 .   file  - file name where used.  Use __FILE__ for this
247  */
248 PetscErrorCode  PetscTrFreeDefault(void *aa,int line,const char function[],const char file[])
249 {
250   char           *a = (char*)aa;
251   TRSPACE        *head;
252   char           *ahead;
253   PetscErrorCode ierr;
254   PetscClassId   *nend;
255 
256   PetscFunctionBegin;
257   /* Do not try to handle empty blocks */
258   if (!a) PetscFunctionReturn(0);
259 
260   ierr = PetscMallocValidate(line,function,file);CHKERRQ(ierr);
261 
262   ahead = a;
263   a     = a - sizeof(TrSPACE);
264   head  = (TRSPACE*)a;
265 
266   if (head->classid != CLASSID_VALUE) {
267     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
268     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
269     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
270   }
271   nend = (PetscClassId*)(ahead + head->size);
272   if (*nend != CLASSID_VALUE) {
273     if (*nend == ALREADY_FREED) {
274       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
275       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
276       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
277         (*PetscErrorPrintf)("Block freed in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
278       } else {
279         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,-head->lineno,head->filename);
280       }
281       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
282     } else {
283       /* Damaged tail */
284       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() line %d in %s\n",function,line,file);
285       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
286       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
287       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
288     }
289   }
290   /* Mark the location freed */
291   *nend = ALREADY_FREED;
292   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
293   if (line > 0 && line < 50000) {
294     head->lineno       = line;
295     head->filename     = file;
296     head->functionname = function;
297   } else {
298     head->lineno = -head->lineno;
299   }
300   if (TRallocated < head->size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"TRallocate is smaller than memory just freed");
301   TRallocated -= head->size;
302   TRfrags--;
303   if (head->prev) head->prev->next = head->next;
304   else TRhead = head->next;
305 
306   if (head->next) head->next->prev = head->prev;
307   ierr = PetscFreeAlign(a,line,function,file);CHKERRQ(ierr);
308   PetscFunctionReturn(0);
309 }
310 
311 /*
312   PetscTrReallocDefault - Realloc with tracing.
313 
314   Input Parameters:
315 + len      - number of bytes to allocate
316 . lineno   - line number where used.  Use __LINE__ for this
317 . filename - file name where used.  Use __FILE__ for this
318 - result - original memory
319 
320   Output Parameter:
321 . result - double aligned pointer to requested storage, or null if not available.
322 
323   Level: developer
324 
325 .seealso: PetscTrMallocDefault(), PetscTrFreeDefault()
326 */
327 PetscErrorCode PetscTrReallocDefault(size_t len, int lineno, const char function[], const char filename[], void **result)
328 {
329   char           *a = (char *) *result;
330   TRSPACE        *head;
331   char           *ahead, *inew;
332   PetscClassId   *nend;
333   size_t         nsize;
334   PetscErrorCode ierr;
335 
336   PetscFunctionBegin;
337   /* Realloc requests zero space so just free the current space */
338   if (!len) {
339     ierr = PetscTrFreeDefault(*result,lineno,function,filename);CHKERRQ(ierr);
340     *result = NULL;
341     PetscFunctionReturn(0);
342   }
343   /* If the orginal space was NULL just use the regular malloc() */
344   if (!*result) {
345     ierr = PetscTrMallocDefault(len,PETSC_FALSE,lineno,function,filename,result);CHKERRQ(ierr);
346     PetscFunctionReturn(0);
347   }
348 
349   ierr = PetscMallocValidate(lineno,function,filename); if (ierr) PetscFunctionReturn(ierr);
350 
351   ahead = a;
352   a     = a - sizeof(TrSPACE);
353   head  = (TRSPACE *) a;
354   inew  = a;
355 
356   if (head->classid != CLASSID_VALUE) {
357     (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() line %d in %s\n",function,lineno,filename);
358     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n",a);
359     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Bad location or corrupted memory");
360   }
361   nend = (PetscClassId *)(ahead + head->size);
362   if (*nend != CLASSID_VALUE) {
363     if (*nend == ALREADY_FREED) {
364       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() line %d in %s\n",function,lineno,filename);
365       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n",head->id,(PetscLogDouble)head->size,a + sizeof(TrSPACE));
366       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
367         (*PetscErrorPrintf)("Block freed in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
368       } else {
369         (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,-head->lineno,head->filename);
370       }
371       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Memory already freed");
372     } else {
373       /* Damaged tail */
374       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() line %d in %s\n",function,lineno,filename);
375       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n",head->id,(PetscLogDouble)head->size,a);
376       (*PetscErrorPrintf)("Block allocated in %s() line %d in %s\n",head->functionname,head->lineno,head->filename);
377       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"Corrupted memory");
378     }
379   }
380 
381   /* remove original reference to the memory allocated from the PETSc debugging heap */
382   TRallocated -= head->size;
383   TRfrags--;
384   if (head->prev) head->prev->next = head->next;
385   else TRhead = head->next;
386   if (head->next) head->next->prev = head->prev;
387 
388   nsize = (len + (PETSC_MEMALIGN-1)) & ~(PETSC_MEMALIGN-1);
389   ierr  = PetscReallocAlign(nsize+sizeof(TrSPACE)+sizeof(PetscClassId),lineno,function,filename,(void**)&inew);CHKERRQ(ierr);
390 
391   head  = (TRSPACE*)inew;
392   inew += sizeof(TrSPACE);
393 
394   if (TRhead) TRhead->prev = head;
395   head->next   = TRhead;
396   TRhead       = head;
397   head->prev   = NULL;
398   head->size   = nsize;
399   head->id     = TRid;
400   head->lineno = lineno;
401 
402   head->filename                 = filename;
403   head->functionname             = function;
404   head->classid                  = CLASSID_VALUE;
405   *(PetscClassId*)(inew + nsize) = CLASSID_VALUE;
406 
407   TRallocated += nsize;
408   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
409   if (PetscLogMemory) {
410     PetscInt i;
411     for (i=0; i<NumTRMaxMems; i++) {
412       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
413     }
414   }
415   TRfrags++;
416 
417 #if defined(PETSC_USE_DEBUG)
418   if (PetscStackActive()) {
419     ierr = PetscStackCopy(petscstack,&head->stack);CHKERRQ(ierr);
420     /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
421     head->stack.line[head->stack.currentsize-2] = lineno;
422   } else {
423     head->stack.currentsize = 0;
424   }
425 #endif
426 
427   /*
428          Allow logging of all mallocs made. This adds a new entry to the list of allocated memory
429          and does not remove the previous entry to the list hence this memory is "double counted" in PetscMallocView()
430   */
431   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && len >= PetscLogMallocThreshold) {
432     if (!PetscLogMalloc) {
433       PetscLogMallocLength = (size_t*)malloc(PetscLogMallocMax*sizeof(size_t));
434       if (!PetscLogMallocLength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
435 
436       PetscLogMallocFile = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
437       if (!PetscLogMallocFile) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
438 
439       PetscLogMallocFunction = (const char**)malloc(PetscLogMallocMax*sizeof(char*));
440       if (!PetscLogMallocFunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM," ");
441     }
442     PetscLogMallocLength[PetscLogMalloc]     = nsize;
443     PetscLogMallocFile[PetscLogMalloc]       = filename;
444     PetscLogMallocFunction[PetscLogMalloc++] = function;
445   }
446   *result = (void*)inew;
447   PetscFunctionReturn(0);
448 }
449 
450 /*@C
451     PetscMemoryView - Shows the amount of memory currently being used in a communicator.
452 
453     Collective on PetscViewer
454 
455     Input Parameter:
456 +    viewer - the viewer that defines the communicator
457 -    message - string printed before values
458 
459     Options Database:
460 +    -malloc_debug - have PETSc track how much memory it has allocated
461 -    -memory_view - during PetscFinalize() have this routine called
462 
463     Level: intermediate
464 
465 .seealso: PetscMallocDump(), PetscMemoryGetCurrentUsage(), PetscMemorySetGetMaximumUsage(), PetscMallocView()
466  @*/
467 PetscErrorCode  PetscMemoryView(PetscViewer viewer,const char message[])
468 {
469   PetscLogDouble allocated,allocatedmax,resident,residentmax,gallocated,gallocatedmax,gresident,gresidentmax,maxgallocated,maxgallocatedmax,maxgresident,maxgresidentmax;
470   PetscLogDouble mingallocated,mingallocatedmax,mingresident,mingresidentmax;
471   PetscErrorCode ierr;
472   MPI_Comm       comm;
473 
474   PetscFunctionBegin;
475   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
476   ierr = PetscMallocGetCurrentUsage(&allocated);CHKERRQ(ierr);
477   ierr = PetscMallocGetMaximumUsage(&allocatedmax);CHKERRQ(ierr);
478   ierr = PetscMemoryGetCurrentUsage(&resident);CHKERRQ(ierr);
479   ierr = PetscMemoryGetMaximumUsage(&residentmax);CHKERRQ(ierr);
480   if (residentmax > 0) residentmax = PetscMax(resident,residentmax);
481   ierr = PetscObjectGetComm((PetscObject)viewer,&comm);CHKERRQ(ierr);
482   ierr = PetscViewerASCIIPrintf(viewer,message);CHKERRQ(ierr);
483   if (resident && residentmax && allocated) {
484     ierr = MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
485     ierr = MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
486     ierr = MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
487     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);CHKERRQ(ierr);
488     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
489     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
490     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
491     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
492     ierr = MPI_Reduce(&allocatedmax,&gallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
493     ierr = MPI_Reduce(&allocatedmax,&maxgallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
494     ierr = MPI_Reduce(&allocatedmax,&mingallocatedmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
495     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);
496     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
497     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
498     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
499     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
500   } else if (resident && residentmax) {
501     ierr = MPI_Reduce(&residentmax,&gresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
502     ierr = MPI_Reduce(&residentmax,&maxgresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
503     ierr = MPI_Reduce(&residentmax,&mingresidentmax,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
504     ierr = PetscViewerASCIIPrintf(viewer,"Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n",gresidentmax,maxgresidentmax,mingresidentmax);CHKERRQ(ierr);
505     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
506     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
507     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
508     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
509   } else if (resident && allocated) {
510     ierr = MPI_Reduce(&resident,&gresident,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
511     ierr = MPI_Reduce(&resident,&maxgresident,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
512     ierr = MPI_Reduce(&resident,&mingresident,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
513     ierr = PetscViewerASCIIPrintf(viewer,"Current process memory:                                  total %5.4e max %5.4e min %5.4e\n",gresident,maxgresident,mingresident);CHKERRQ(ierr);
514     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
515     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
516     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
517     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
518     ierr = PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");CHKERRQ(ierr);
519   } else if (allocated) {
520     ierr = MPI_Reduce(&allocated,&gallocated,1,MPIU_PETSCLOGDOUBLE,MPI_SUM,0,comm);CHKERRQ(ierr);
521     ierr = MPI_Reduce(&allocated,&maxgallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MAX,0,comm);CHKERRQ(ierr);
522     ierr = MPI_Reduce(&allocated,&mingallocated,1,MPIU_PETSCLOGDOUBLE,MPI_MIN,0,comm);CHKERRQ(ierr);
523     ierr = PetscViewerASCIIPrintf(viewer,"Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n",gallocated,maxgallocated,mingallocated);CHKERRQ(ierr);
524     ierr = PetscViewerASCIIPrintf(viewer,"Run with -memory_view to get maximum memory usage\n");CHKERRQ(ierr);
525     ierr = PetscViewerASCIIPrintf(viewer,"OS cannot compute process memory\n");CHKERRQ(ierr);
526   } else {
527     ierr = PetscViewerASCIIPrintf(viewer,"Run with -malloc_debug to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n");CHKERRQ(ierr);
528   }
529   ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
530   PetscFunctionReturn(0);
531 }
532 
533 /*@
534     PetscMallocGetCurrentUsage - gets the current amount of memory used that was PetscMalloc()ed
535 
536     Not Collective
537 
538     Output Parameters:
539 .   space - number of bytes currently allocated
540 
541     Level: intermediate
542 
543 .seealso: PetscMallocDump(), PetscMallocLog(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
544           PetscMemoryGetMaximumUsage()
545  @*/
546 PetscErrorCode  PetscMallocGetCurrentUsage(PetscLogDouble *space)
547 {
548   PetscFunctionBegin;
549   *space = (PetscLogDouble) TRallocated;
550   PetscFunctionReturn(0);
551 }
552 
553 /*@
554     PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was PetscMalloc()ed at any time
555         during this run.
556 
557     Not Collective
558 
559     Output Parameters:
560 .   space - maximum number of bytes ever allocated at one time
561 
562     Level: intermediate
563 
564 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
565           PetscMallocPushMaximumUsage()
566  @*/
567 PetscErrorCode  PetscMallocGetMaximumUsage(PetscLogDouble *space)
568 {
569   PetscFunctionBegin;
570   *space = (PetscLogDouble) TRMaxMem;
571   PetscFunctionReturn(0);
572 }
573 
574 /*@
575     PetscMallocPushMaximumUsage - Adds another event to collect the maximum memory usage over an event
576 
577     Not Collective
578 
579     Input Parameter:
580 .   event - an event id; this is just for error checking
581 
582     Level: developer
583 
584 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
585           PetscMallocPopMaximumUsage()
586  @*/
587 PetscErrorCode  PetscMallocPushMaximumUsage(int event)
588 {
589   PetscFunctionBegin;
590   if (++NumTRMaxMems > MAXTRMAXMEMS) PetscFunctionReturn(0);
591   TRMaxMems[NumTRMaxMems-1]       = TRallocated;
592   TRMaxMemsEvents[NumTRMaxMems-1] = event;
593   PetscFunctionReturn(0);
594 }
595 
596 /*@
597     PetscMallocPopMaximumUsage - collect the maximum memory usage over an event
598 
599     Not Collective
600 
601     Input Parameter:
602 .   event - an event id; this is just for error checking
603 
604     Output Parameter:
605 .   mu - maximum amount of memory malloced during this event; high water mark relative to the beginning of the event
606 
607     Level: developer
608 
609 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocGetMaximumUsage(), PetscMemoryGetCurrentUsage(),
610           PetscMallocPushMaximumUsage()
611  @*/
612 PetscErrorCode  PetscMallocPopMaximumUsage(int event,PetscLogDouble *mu)
613 {
614   PetscFunctionBegin;
615   *mu = 0;
616   if (NumTRMaxMems-- > MAXTRMAXMEMS) PetscFunctionReturn(0);
617   if (TRMaxMemsEvents[NumTRMaxMems] != event) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEMC,"PetscMallocPush/PopMaximumUsage() are not nested");
618   *mu = TRMaxMems[NumTRMaxMems];
619   PetscFunctionReturn(0);
620 }
621 
622 #if defined(PETSC_USE_DEBUG)
623 /*@C
624    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to PetscMalloc() was used to obtain that memory
625 
626    Collective on PETSC_COMM_WORLD
627 
628    Input Parameter:
629 .    ptr - the memory location
630 
631    Output Paramter:
632 .    stack - the stack indicating where the program allocated this memory
633 
634    Level: intermediate
635 
636 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocView()
637 @*/
638 PetscErrorCode  PetscMallocGetStack(void *ptr,PetscStack **stack)
639 {
640   TRSPACE *head;
641 
642   PetscFunctionBegin;
643   head   = (TRSPACE*) (((char*)ptr) - HEADER_BYTES);
644   *stack = &head->stack;
645   PetscFunctionReturn(0);
646 }
647 #else
648 PetscErrorCode  PetscMallocGetStack(void *ptr,void **stack)
649 {
650   PetscFunctionBegin;
651   *stack = NULL;
652   PetscFunctionReturn(0);
653 }
654 #endif
655 
656 /*@C
657    PetscMallocDump - Dumps the currently allocated memory blocks to a file. The information
658    printed is: size of space (in bytes), address of space, id of space,
659    file in which space was allocated, and line number at which it was
660    allocated.
661 
662    Not Collective
663 
664    Input Parameter:
665 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
666 
667    Options Database Key:
668 .  -malloc_dump <optional filename> - Dumps unfreed memory during call to PetscFinalize()
669 
670    Level: intermediate
671 
672    Fortran Note:
673    The calling sequence in Fortran is PetscMallocDump(integer ierr)
674    The fp defaults to stdout.
675 
676    Notes:
677      Uses MPI_COMM_WORLD to display rank, because this may be called in PetscFinalize() after PETSC_COMM_WORLD has been freed.
678 
679      When called in PetscFinalize() dumps only the allocations that have not been properly freed
680 
681      PetscMallocView() prints a list of all memory ever allocated
682 
683 .seealso:  PetscMallocGetCurrentUsage(), PetscMallocView(), PetscMallocViewSet()
684 @*/
685 PetscErrorCode  PetscMallocDump(FILE *fp)
686 {
687   TRSPACE        *head;
688   size_t         libAlloc = 0;
689   PetscErrorCode ierr;
690   PetscMPIInt    rank;
691 
692   PetscFunctionBegin;
693   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
694   if (!fp) fp = PETSC_STDOUT;
695   head = TRhead;
696   while (head) {
697     libAlloc += head->size;
698     head = head->next;
699   }
700   if (TRallocated - libAlloc > 0) fprintf(fp,"[%d]Total space allocated %.0f bytes\n",rank,(PetscLogDouble)TRallocated);
701   head = TRhead;
702   while (head) {
703     PetscBool isLib;
704 
705     ierr = PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib);CHKERRQ(ierr);
706     if (!isLib) {
707       fprintf(fp,"[%2d]%.0f bytes %s() line %d in %s\n",rank,(PetscLogDouble)head->size,head->functionname,head->lineno,head->filename);
708 #if defined(PETSC_USE_DEBUG)
709       ierr = PetscStackPrint(&head->stack,fp);CHKERRQ(ierr);
710 #endif
711     }
712     head = head->next;
713   }
714   PetscFunctionReturn(0);
715 }
716 
717 /*@
718     PetscMallocViewSet - Activates logging of all calls to PetscMalloc() with a minimum size to view
719 
720     Not Collective
721 
722     Input Arguments:
723 .   logmin - minimum allocation size to log, or PETSC_DEFAULT
724 
725     Options Database Key:
726 +  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()
727 -  -malloc_view_threshold <min> - Sets a minimum size if -malloc_view is used
728 
729     Level: advanced
730 
731     Notes: Must be called after PetscMallocSetDebug()
732 
733     Uses MPI_COMM_WORLD to determine rank because PETSc communicators may not be available
734 
735 .seealso: PetscMallocDump(), PetscMallocView(), PetscMallocViewSet()
736 @*/
737 PetscErrorCode PetscMallocViewSet(PetscLogDouble logmin)
738 {
739   PetscErrorCode ierr;
740 
741   PetscFunctionBegin;
742   PetscLogMalloc = 0;
743   ierr = PetscMemorySetGetMaximumUsage();CHKERRQ(ierr);
744   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
745   PetscLogMallocThreshold = (size_t)logmin;
746   PetscFunctionReturn(0);
747 }
748 
749 /*@
750     PetscMallocViewGet - Determine whether all calls to PetscMalloc() are being logged
751 
752     Not Collective
753 
754     Output Arguments
755 .   logging - PETSC_TRUE if logging is active
756 
757     Options Database Key:
758 .  -malloc_view <optional filename> - Activates PetscMallocView()
759 
760     Level: advanced
761 
762 .seealso: PetscMallocDump(), PetscMallocView()
763 @*/
764 PetscErrorCode PetscMallocViewGet(PetscBool *logging)
765 {
766 
767   PetscFunctionBegin;
768   *logging = (PetscBool)(PetscLogMalloc >= 0);
769   PetscFunctionReturn(0);
770 }
771 
772 /*@C
773     PetscMallocView - Saves the log of all calls to PetscMalloc(); also calls
774        PetscMemoryGetMaximumUsage()
775 
776     Not Collective
777 
778     Input Parameter:
779 .   fp - file pointer; or NULL
780 
781     Options Database Key:
782 .  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()
783 
784     Level: advanced
785 
786    Fortran Note:
787    The calling sequence in Fortran is PetscMallocView(integer ierr)
788    The fp defaults to stdout.
789 
790    Notes:
791      PetscMallocDump() dumps only the currently unfreed memory, this dumps all memory ever allocated
792 
793      PetscMemoryView() gives a brief summary of current memory usage
794 
795 .seealso: PetscMallocGetCurrentUsage(), PetscMallocDump(), PetscMallocViewSet(), PetscMemoryView()
796 @*/
797 PetscErrorCode  PetscMallocView(FILE *fp)
798 {
799   PetscInt       i,j,n,*perm;
800   size_t         *shortlength;
801   int            *shortcount,err;
802   PetscMPIInt    rank;
803   PetscBool      match;
804   const char     **shortfunction;
805   PetscLogDouble rss;
806   PetscErrorCode ierr;
807 
808   PetscFunctionBegin;
809   ierr = MPI_Comm_rank(MPI_COMM_WORLD,&rank);CHKERRQ(ierr);
810   err = fflush(fp);
811   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
812 
813   if (PetscLogMalloc < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"PetscMallocView() called without call to PetscMallocViewSet() this is often due to\n                      setting the option -malloc_view AFTER PetscInitialize() with PetscOptionsInsert() or PetscOptionsInsertFile()");
814 
815   if (!fp) fp = PETSC_STDOUT;
816   ierr = PetscMemoryGetMaximumUsage(&rss);CHKERRQ(ierr);
817   if (rss) {
818     (void) fprintf(fp,"[%d] Maximum memory PetscMalloc()ed %.0f maximum size of entire process %.0f\n",rank,(PetscLogDouble)TRMaxMem,rss);
819   } else {
820     (void) fprintf(fp,"[%d] Maximum memory PetscMalloc()ed %.0f OS cannot compute size of entire process\n",rank,(PetscLogDouble)TRMaxMem);
821   }
822   shortcount    = (int*)malloc(PetscLogMalloc*sizeof(int));if (!shortcount) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
823   shortlength   = (size_t*)malloc(PetscLogMalloc*sizeof(size_t));if (!shortlength) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
824   shortfunction = (const char**)malloc(PetscLogMalloc*sizeof(char*));if (!shortfunction) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
825   for (i=0,n=0; i<PetscLogMalloc; i++) {
826     for (j=0; j<n; j++) {
827       ierr = PetscStrcmp(shortfunction[j],PetscLogMallocFunction[i],&match);CHKERRQ(ierr);
828       if (match) {
829         shortlength[j] += PetscLogMallocLength[i];
830         shortcount[j]++;
831         goto foundit;
832       }
833     }
834     shortfunction[n] = PetscLogMallocFunction[i];
835     shortlength[n]   = PetscLogMallocLength[i];
836     shortcount[n]    = 1;
837     n++;
838 foundit:;
839   }
840 
841   perm = (PetscInt*)malloc(n*sizeof(PetscInt));if (!perm) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_MEM,"Out of memory");
842   for (i=0; i<n; i++) perm[i] = i;
843   ierr = PetscSortStrWithPermutation(n,(const char**)shortfunction,perm);CHKERRQ(ierr);
844 
845   (void) fprintf(fp,"[%d] Memory usage sorted by function\n",rank);
846   for (i=0; i<n; i++) {
847     (void) fprintf(fp,"[%d] %d %.0f %s()\n",rank,shortcount[perm[i]],(PetscLogDouble)shortlength[perm[i]],shortfunction[perm[i]]);
848   }
849   free(perm);
850   free(shortlength);
851   free(shortcount);
852   free((char**)shortfunction);
853   err = fflush(fp);
854   if (err) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SYS,"fflush() failed on file");
855   PetscFunctionReturn(0);
856 }
857 
858 /* ---------------------------------------------------------------------------- */
859 
860 /*@
861     PetscMallocSetDebug - Set's PETSc memory debugging
862 
863     Not Collective
864 
865     Input Parameter:
866 +   eachcall - checks the entire heap of allocated memory for issues on each call to PetscMalloc() and PetscFree()
867 -   intializenan - initializes all memory with NaN to catch use of unintialized floating point arrays
868 
869     Options Database:
870 +   -malloc_debug <true or false> - turns on or off debugging
871 .   -malloc_test - turns on all debugging if PETSc was configured with debugging including -malloc_dump, otherwise ignored
872 .   -malloc_view_threshold t - log only allocations larger than t
873 .   -malloc_dump <filename> - print a list of all memory that has not been freed
874 .   -malloc no - (deprecated) same as -malloc_debug no
875 -   -malloc_log - (deprecated) same as -malloc_view
876 
877    Level: developer
878 
879     Notes: This is called in PetscInitialize() and should not be called elsewhere
880 
881 .seealso: CHKMEMQ(), PetscMallocValidate(), PetscMallocGetDebug()
882 @*/
883 PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan)
884 {
885   PetscErrorCode ierr;
886 
887   PetscFunctionBegin;
888   if (PetscTrMalloc == PetscTrMallocDefault) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Cannot call this routine more than once, it can only be called in PetscInitialize()");
889   ierr = PetscMallocSet(PetscTrMallocDefault,PetscTrFreeDefault,PetscTrReallocDefault);CHKERRQ(ierr);
890 
891   TRallocated         = 0;
892   TRfrags             = 0;
893   TRhead              = NULL;
894   TRid                = 0;
895   TRdebugLevel        = eachcall;
896   TRMaxMem            = 0;
897   PetscLogMallocMax   = 10000;
898   PetscLogMalloc      = -1;
899   TRdebugIintializenan = initializenan;
900   PetscFunctionReturn(0);
901 }
902 
903 /*@
904     PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.
905 
906     Not Collective
907 
908     Output Parameters:
909 +    basic - doing basic debugging
910 .    eachcall - checks the entire memory heap at each PetscMalloc()/PetscFree()
911 -    initializenan - initializes memory with NaN
912 
913    Level: intermediate
914 
915    Notes:
916      By default, the debug version always does some debugging unless you run with -malloc_debug no
917 
918 .seealso: CHKMEMQ(), PetscMallocValidate(), PetscMallocSetDebug()
919 @*/
920 PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan)
921 {
922   PetscFunctionBegin;
923   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
924   if (eachcall) *eachcall           = TRdebugLevel;
925   if (initializenan) *initializenan = TRdebugIintializenan;
926   PetscFunctionReturn(0);
927 }
928