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