xref: /petsc/src/sys/memory/mtr.c (revision 766cdfe255df005c0ccfe0a0cc165b52d3f16e52)
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:.
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 @*/
108 PetscErrorCode PetscMallocValidate(int line, const char function[], const char file[]) {
109   TRSPACE      *head, *lasthead;
110   char         *a;
111   PetscClassId *nend;
112 
113   if (!TRdebugLevel) return 0;
114   head     = TRhead;
115   lasthead = NULL;
116   if (head && head->prev) {
117     (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line);
118     (*PetscErrorPrintf)("Root memory header %p has invalid back pointer %p\n", head, head->prev);
119     return PETSC_ERR_MEMC;
120   }
121   while (head) {
122     if (head->classid != CLASSID_VALUE) {
123       (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line);
124       (*PetscErrorPrintf)("Memory at address %p is corrupted\n", head);
125       (*PetscErrorPrintf)("Probably write before beginning of or past end of array\n");
126       if (lasthead) {
127         a = (char *)(((TrSPACE *)head) + 1);
128         (*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);
129       }
130       abort();
131       return PETSC_ERR_MEMC;
132     }
133     a    = (char *)(((TrSPACE *)head) + 1);
134     nend = (PetscClassId *)(a + head->size);
135     if (*nend != CLASSID_VALUE) {
136       (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line);
137       if (*nend == ALREADY_FREED) {
138         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n", head->id, (PetscLogDouble)head->size, a);
139         return PETSC_ERR_MEMC;
140       } else {
141         (*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a);
142         (*PetscErrorPrintf)("Memory originally allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno);
143         return PETSC_ERR_MEMC;
144       }
145     }
146     if (head->prev && head->prev != lasthead) {
147       (*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line);
148       (*PetscErrorPrintf)("Backpointer %p is invalid, should be %p\n", head->prev, lasthead);
149       (*PetscErrorPrintf)("Previous memory originally allocated in %s() at %s:%d\n", lasthead->functionname, lasthead->filename, lasthead->lineno);
150       (*PetscErrorPrintf)("Memory originally allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno);
151       return PETSC_ERR_MEMC;
152     }
153     lasthead = head;
154     head     = head->next;
155   }
156   return 0;
157 }
158 
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 -   filename  - file name where used.  Use __FILE__ for this
166 
167     Returns:
168     double aligned pointer to requested storage, or null if not  available.
169  */
170 PetscErrorCode PetscTrMallocDefault(size_t a, PetscBool clear, int lineno, const char function[], const char filename[], void **result) {
171   TRSPACE *head;
172   char    *inew;
173   size_t   nsize;
174 
175   PetscFunctionBegin;
176   /* Do not try to handle empty blocks */
177   if (!a) {
178     *result = NULL;
179     PetscFunctionReturn(0);
180   }
181 
182   PetscCall(PetscMallocValidate(lineno, function, filename));
183 
184   nsize = (a + (PETSC_MEMALIGN - 1)) & ~(PETSC_MEMALIGN - 1);
185   PetscCall(PetscMallocAlign(nsize + sizeof(TrSPACE) + sizeof(PetscClassId), clear, lineno, function, filename, (void **)&inew));
186 
187   head = (TRSPACE *)inew;
188   inew += sizeof(TrSPACE);
189 
190   if (TRhead) TRhead->prev = head;
191   head->next   = TRhead;
192   TRhead       = head;
193   head->prev   = NULL;
194   head->size   = nsize;
195   head->rsize  = a;
196   head->id     = TRid++;
197   head->lineno = lineno;
198 
199   head->filename                  = filename;
200   head->functionname              = function;
201   head->classid                   = CLASSID_VALUE;
202   *(PetscClassId *)(inew + nsize) = CLASSID_VALUE;
203 
204   TRallocated += TRrequestedSize ? head->rsize : head->size;
205   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
206   if (PetscLogMemory) {
207     PetscInt i;
208     for (i = 0; i < NumTRMaxMems; i++) {
209       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
210     }
211   }
212   TRfrags++;
213 
214 #if defined(PETSC_USE_DEBUG)
215   PetscCall(PetscStackCopy(&petscstack, &head->stack));
216   /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
217   head->stack.line[head->stack.currentsize - 2] = lineno;
218 #if defined(PETSC_USE_REAL_SINGLE) || defined(PETSC_USE_REAL_DOUBLE)
219   if (!clear && TRdebugIinitializenan) {
220     size_t     i, n = a / sizeof(PetscReal);
221     PetscReal *s = (PetscReal *)inew;
222     /* from https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html */
223 #if defined(PETSC_USE_REAL_SINGLE)
224     int nas = 0x7F800002;
225 #else
226     PetscInt64 nas = 0x7FF0000000000002;
227 #endif
228     for (i = 0; i < n; i++) memcpy(s + i, &nas, sizeof(PetscReal));
229   }
230 #endif
231 #endif
232 
233   /*
234          Allow logging of all mallocs made.
235          TODO: Currently this memory is never freed, it should be freed during PetscFinalize()
236   */
237   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && a >= PetscLogMallocThreshold) {
238     if (!PetscLogMalloc) {
239       PetscLogMallocLength = (size_t *)malloc(PetscLogMallocMax * sizeof(size_t));
240       PetscCheck(PetscLogMallocLength, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
241 
242       PetscLogMallocFile = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
243       PetscCheck(PetscLogMallocFile, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
244 
245       PetscLogMallocFunction = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
246       PetscCheck(PetscLogMallocFunction, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
247     }
248     PetscLogMallocLength[PetscLogMalloc]     = nsize;
249     PetscLogMallocFile[PetscLogMalloc]       = filename;
250     PetscLogMallocFunction[PetscLogMalloc++] = function;
251   }
252   if (PetscLogMallocTrace > -1 && a >= PetscLogMallocTraceThreshold) PetscCall(PetscViewerASCIIPrintf(PetscLogMallocTraceViewer, "Alloc %zu %s:%d (%s)\n", a, filename ? filename : "null", lineno, function ? function : "null"));
253   *result = (void *)inew;
254   PetscFunctionReturn(0);
255 }
256 
257 /*
258    PetscTrFreeDefault - Free with tracing.
259 
260    Input Parameters:
261 .   a    - pointer to a block allocated with PetscTrMalloc
262 .   lineno - line number where used.  Use __LINE__ for this
263 .   filename  - file name where used.  Use __FILE__ for this
264  */
265 PetscErrorCode PetscTrFreeDefault(void *aa, int lineno, const char function[], const char filename[]) {
266   char         *a = (char *)aa;
267   TRSPACE      *head;
268   char         *ahead;
269   size_t        asize;
270   PetscClassId *nend;
271 
272   PetscFunctionBegin;
273   /* Do not try to handle empty blocks */
274   if (!a) PetscFunctionReturn(0);
275 
276   PetscCall(PetscMallocValidate(lineno, function, filename));
277 
278   ahead = a;
279   a     = a - sizeof(TrSPACE);
280   head  = (TRSPACE *)a;
281 
282   if (head->classid != CLASSID_VALUE) {
283     (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno);
284     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n", a);
285     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Bad location or corrupted memory");
286   }
287   nend = (PetscClassId *)(ahead + head->size);
288   if (*nend != CLASSID_VALUE) {
289     if (*nend == ALREADY_FREED) {
290       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno);
291       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n", head->id, (PetscLogDouble)head->size, a + sizeof(TrSPACE));
292       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
293         (*PetscErrorPrintf)("Block freed in %s() at %s:%d\n", head->functionname, head->filename, head->lineno);
294       } else {
295         (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, -head->lineno);
296       }
297       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Memory already freed");
298     } else {
299       /* Damaged tail */
300       (*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno);
301       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a);
302       (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno);
303       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Corrupted memory");
304     }
305   }
306   if (PetscLogMallocTrace > -1 && head->rsize >= PetscLogMallocTraceThreshold) {
307     PetscCall(PetscViewerASCIIPrintf(PetscLogMallocTraceViewer, "Free  %zu %s:%d (%s)\n", head->rsize, filename ? filename : "null", lineno, function ? function : "null"));
308   }
309   /* Mark the location freed */
310   *nend = ALREADY_FREED;
311   /* Save location where freed.  If we suspect the line number, mark as  allocated location */
312   if (lineno > 0 && lineno < 50000) {
313     head->lineno       = lineno;
314     head->filename     = filename;
315     head->functionname = function;
316   } else {
317     head->lineno = -head->lineno;
318   }
319   asize = TRrequestedSize ? head->rsize : head->size;
320   PetscCheck(TRallocated >= asize, PETSC_COMM_SELF, PETSC_ERR_MEMC, "TRallocate is smaller than memory just freed");
321   TRallocated -= asize;
322   TRfrags--;
323   if (head->prev) head->prev->next = head->next;
324   else TRhead = head->next;
325 
326   if (head->next) head->next->prev = head->prev;
327   PetscCall(PetscFreeAlign(a, lineno, function, filename));
328   PetscFunctionReturn(0);
329 }
330 
331 /*
332   PetscTrReallocDefault - Realloc with tracing.
333 
334   Input Parameters:
335 + len      - number of bytes to allocate
336 . lineno   - line number where used.  Use __LINE__ for this
337 . filename - file name where used.  Use __FILE__ for this
338 - result - original memory
339 
340   Output Parameter:
341 . result - double aligned pointer to requested storage, or null if not available.
342 
343   Level: developer
344 
345 .seealso: `PetscTrMallocDefault()`, `PetscTrFreeDefault()`
346 */
347 PetscErrorCode PetscTrReallocDefault(size_t len, int lineno, const char function[], const char filename[], void **result) {
348   char         *a = (char *)*result;
349   TRSPACE      *head;
350   char         *ahead, *inew;
351   PetscClassId *nend;
352   size_t        nsize;
353 
354   PetscFunctionBegin;
355   /* Realloc requests zero space so just free the current space */
356   if (!len) {
357     PetscCall(PetscTrFreeDefault(*result, lineno, function, filename));
358     *result = NULL;
359     PetscFunctionReturn(0);
360   }
361   /* If the orginal space was NULL just use the regular malloc() */
362   if (!*result) {
363     PetscCall(PetscTrMallocDefault(len, PETSC_FALSE, lineno, function, filename, result));
364     PetscFunctionReturn(0);
365   }
366 
367   PetscCall(PetscMallocValidate(lineno, function, filename));
368 
369   ahead = a;
370   a     = a - sizeof(TrSPACE);
371   head  = (TRSPACE *)a;
372   inew  = a;
373 
374   if (head->classid != CLASSID_VALUE) {
375     (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno);
376     (*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n", a);
377     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Bad location or corrupted memory");
378   }
379   nend = (PetscClassId *)(ahead + head->size);
380   if (*nend != CLASSID_VALUE) {
381     if (*nend == ALREADY_FREED) {
382       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno);
383       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n", head->id, (PetscLogDouble)head->size, a + sizeof(TrSPACE));
384       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
385         (*PetscErrorPrintf)("Block freed in %s() at %s:%d\n", head->functionname, head->filename, head->lineno);
386       } else {
387         (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, -head->lineno);
388       }
389       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Memory already freed");
390     } else {
391       /* Damaged tail */
392       (*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno);
393       (*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a);
394       (*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno);
395       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Corrupted memory");
396     }
397   }
398 
399   /* remove original reference to the memory allocated from the PETSc debugging heap */
400   TRallocated -= TRrequestedSize ? head->rsize : head->size;
401   TRfrags--;
402   if (head->prev) head->prev->next = head->next;
403   else TRhead = head->next;
404   if (head->next) head->next->prev = head->prev;
405 
406   nsize = (len + (PETSC_MEMALIGN - 1)) & ~(PETSC_MEMALIGN - 1);
407   PetscCall(PetscReallocAlign(nsize + sizeof(TrSPACE) + sizeof(PetscClassId), lineno, function, filename, (void **)&inew));
408 
409   head = (TRSPACE *)inew;
410   inew += sizeof(TrSPACE);
411 
412   if (TRhead) TRhead->prev = head;
413   head->next   = TRhead;
414   TRhead       = head;
415   head->prev   = NULL;
416   head->size   = nsize;
417   head->rsize  = len;
418   head->id     = TRid++;
419   head->lineno = lineno;
420 
421   head->filename                  = filename;
422   head->functionname              = function;
423   head->classid                   = CLASSID_VALUE;
424   *(PetscClassId *)(inew + nsize) = CLASSID_VALUE;
425 
426   TRallocated += TRrequestedSize ? head->rsize : head->size;
427   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
428   if (PetscLogMemory) {
429     PetscInt i;
430     for (i = 0; i < NumTRMaxMems; i++) {
431       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
432     }
433   }
434   TRfrags++;
435 
436 #if defined(PETSC_USE_DEBUG)
437   PetscCall(PetscStackCopy(&petscstack, &head->stack));
438   /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
439   head->stack.line[head->stack.currentsize - 2] = lineno;
440 #endif
441 
442   /*
443          Allow logging of all mallocs made. This adds a new entry to the list of allocated memory
444          and does not remove the previous entry to the list hence this memory is "double counted" in PetscMallocView()
445   */
446   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && len >= PetscLogMallocThreshold) {
447     if (!PetscLogMalloc) {
448       PetscLogMallocLength = (size_t *)malloc(PetscLogMallocMax * sizeof(size_t));
449       PetscCheck(PetscLogMallocLength, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
450 
451       PetscLogMallocFile = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
452       PetscCheck(PetscLogMallocFile, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
453 
454       PetscLogMallocFunction = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
455       PetscCheck(PetscLogMallocFunction, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
456     }
457     PetscLogMallocLength[PetscLogMalloc]     = nsize;
458     PetscLogMallocFile[PetscLogMalloc]       = filename;
459     PetscLogMallocFunction[PetscLogMalloc++] = function;
460   }
461   *result = (void *)inew;
462   PetscFunctionReturn(0);
463 }
464 
465 /*@C
466     PetscMemoryView - Shows the amount of memory currently being used in a communicator.
467 
468     Collective on PetscViewer
469 
470     Input Parameters:
471 +    viewer - the viewer that defines the communicator
472 -    message - string printed before values
473 
474     Options Database:
475 +    -malloc_debug - have PETSc track how much memory it has allocated
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 PetscMalloc()ed
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 PetscMalloc()ed at any time
567         during this run.
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: Must be called after PetscMallocSetDebug()
738 
739     Uses MPI_COMM_WORLD to determine rank because PETSc communicators may not be available
740 
741 .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocViewSet()`, `PetscMallocTraceSet()`, `PetscMallocValidate()`
742 @*/
743 PetscErrorCode PetscMallocViewSet(PetscLogDouble logmin) {
744   PetscFunctionBegin;
745   PetscLogMalloc = 0;
746   PetscCall(PetscMemorySetGetMaximumUsage());
747   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
748   PetscLogMallocThreshold = (size_t)logmin;
749   PetscFunctionReturn(0);
750 }
751 
752 /*@
753     PetscMallocViewGet - Determine whether all calls to PetscMalloc() are being logged
754 
755     Not Collective
756 
757     Output Parameter
758 .   logging - PETSC_TRUE if logging is active
759 
760     Options Database Key:
761 .  -malloc_view <optional filename> - Activates PetscMallocView()
762 
763     Level: advanced
764 
765 .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocTraceGet()`
766 @*/
767 PetscErrorCode PetscMallocViewGet(PetscBool *logging) {
768   PetscFunctionBegin;
769   *logging = (PetscBool)(PetscLogMalloc >= 0);
770   PetscFunctionReturn(0);
771 }
772 
773 /*@
774   PetscMallocTraceSet - Trace all calls to PetscMalloc()
775 
776   Not Collective
777 
778   Input Parameters:
779 + viewer - The viewer to use for tracing, or NULL to use stdout
780 . active - Flag to activate or deactivate tracing
781 - logmin - The smallest memory size that will be logged
782 
783   Note:
784   The viewer should not be collective.
785 
786   Level: advanced
787 
788 .seealso: `PetscMallocTraceGet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`
789 @*/
790 PetscErrorCode PetscMallocTraceSet(PetscViewer viewer, PetscBool active, PetscLogDouble logmin) {
791   PetscFunctionBegin;
792   if (!active) {
793     PetscLogMallocTrace = -1;
794     PetscFunctionReturn(0);
795   }
796   PetscLogMallocTraceViewer = !viewer ? PETSC_VIEWER_STDOUT_SELF : viewer;
797   PetscLogMallocTrace       = 0;
798   PetscCall(PetscMemorySetGetMaximumUsage());
799   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
800   PetscLogMallocTraceThreshold = (size_t)logmin;
801   PetscFunctionReturn(0);
802 }
803 
804 /*@
805   PetscMallocTraceGet - Determine whether all calls to PetscMalloc() are being traced
806 
807   Not Collective
808 
809   Output Parameter:
810 . logging - PETSC_TRUE if logging is active
811 
812   Options Database Key:
813 . -malloc_view <optional filename> - Activates PetscMallocView()
814 
815   Level: advanced
816 
817 .seealso: `PetscMallocTraceSet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`
818 @*/
819 PetscErrorCode PetscMallocTraceGet(PetscBool *logging) {
820   PetscFunctionBegin;
821   *logging = (PetscBool)(PetscLogMallocTrace >= 0);
822   PetscFunctionReturn(0);
823 }
824 
825 /*@C
826     PetscMallocView - Saves the log of all calls to PetscMalloc(); also calls
827        PetscMemoryGetMaximumUsage()
828 
829     Not Collective
830 
831     Input Parameter:
832 .   fp - file pointer; or NULL
833 
834     Options Database Key:
835 .  -malloc_view <optional filename> - Activates PetscMallocView() in PetscFinalize()
836 
837     Level: advanced
838 
839    Fortran Note:
840    The calling sequence in Fortran is PetscMallocView(integer ierr)
841    The fp defaults to stdout.
842 
843    Notes:
844      PetscMallocDump() dumps only the currently unfreed memory, this dumps all memory ever allocated
845 
846      PetscMemoryView() gives a brief summary of current memory usage
847 
848 .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocDump()`, `PetscMallocViewSet()`, `PetscMemoryView()`
849 @*/
850 PetscErrorCode PetscMallocView(FILE *fp) {
851   PetscInt       i, j, n, *perm;
852   size_t        *shortlength;
853   int           *shortcount, err;
854   PetscMPIInt    rank;
855   PetscBool      match;
856   const char   **shortfunction;
857   PetscLogDouble rss;
858 
859   PetscFunctionBegin;
860   PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
861   err = fflush(fp);
862   PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
863 
864   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()");
865 
866   if (!fp) fp = PETSC_STDOUT;
867   PetscCall(PetscMemoryGetMaximumUsage(&rss));
868   if (rss) {
869     (void)fprintf(fp, "[%d] Maximum memory PetscMalloc()ed %.0f maximum size of entire process %.0f\n", rank, (PetscLogDouble)TRMaxMem, rss);
870   } else {
871     (void)fprintf(fp, "[%d] Maximum memory PetscMalloc()ed %.0f OS cannot compute size of entire process\n", rank, (PetscLogDouble)TRMaxMem);
872   }
873   shortcount = (int *)malloc(PetscLogMalloc * sizeof(int));
874   PetscCheck(shortcount, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
875   shortlength = (size_t *)malloc(PetscLogMalloc * sizeof(size_t));
876   PetscCheck(shortlength, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
877   shortfunction = (const char **)malloc(PetscLogMalloc * sizeof(char *));
878   PetscCheck(shortfunction, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
879   for (i = 0, n = 0; i < PetscLogMalloc; i++) {
880     for (j = 0; j < n; j++) {
881       PetscCall(PetscStrcmp(shortfunction[j], PetscLogMallocFunction[i], &match));
882       if (match) {
883         shortlength[j] += PetscLogMallocLength[i];
884         shortcount[j]++;
885         goto foundit;
886       }
887     }
888     shortfunction[n] = PetscLogMallocFunction[i];
889     shortlength[n]   = PetscLogMallocLength[i];
890     shortcount[n]    = 1;
891     n++;
892   foundit:;
893   }
894 
895   perm = (PetscInt *)malloc(n * sizeof(PetscInt));
896   PetscCheck(perm, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
897   for (i = 0; i < n; i++) perm[i] = i;
898   PetscCall(PetscSortStrWithPermutation(n, (const char **)shortfunction, perm));
899 
900   (void)fprintf(fp, "[%d] Memory usage sorted by function\n", rank);
901   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]]);
902   free(perm);
903   free(shortlength);
904   free(shortcount);
905   free((char **)shortfunction);
906   err = fflush(fp);
907   PetscCheck(!err, PETSC_COMM_SELF, PETSC_ERR_SYS, "fflush() failed on file");
908   PetscFunctionReturn(0);
909 }
910 
911 /* ---------------------------------------------------------------------------- */
912 
913 /*@
914     PetscMallocSetDebug - Set's PETSc memory debugging
915 
916     Not Collective
917 
918     Input Parameters:
919 +   eachcall - checks the entire heap of allocated memory for issues on each call to PetscMalloc() and PetscFree()
920 -   initializenan - initializes all memory with NaN to catch use of uninitialized floating point arrays
921 
922     Options Database:
923 +   -malloc_debug <true or false> - turns on or off debugging
924 .   -malloc_test - turns on all debugging if PETSc was configured with debugging including -malloc_dump, otherwise ignored
925 .   -malloc_view_threshold t - log only allocations larger than t
926 .   -malloc_dump <filename> - print a list of all memory that has not been freed
927 .   -malloc no - (deprecated) same as -malloc_debug no
928 -   -malloc_log - (deprecated) same as -malloc_view
929 
930    Level: developer
931 
932     Notes: This is called in PetscInitialize() and should not be called elsewhere
933 
934 .seealso: `CHKMEMQ()`, `PetscMallocValidate()`, `PetscMallocGetDebug()`
935 @*/
936 PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan) {
937   PetscFunctionBegin;
938   PetscCheck(PetscTrMalloc != PetscTrMallocDefault, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call this routine more than once, it can only be called in PetscInitialize()");
939   PetscCall(PetscMallocSet(PetscTrMallocDefault, PetscTrFreeDefault, PetscTrReallocDefault));
940 
941   TRallocated           = 0;
942   TRfrags               = 0;
943   TRhead                = NULL;
944   TRid                  = 0;
945   TRdebugLevel          = eachcall;
946   TRMaxMem              = 0;
947   PetscLogMallocMax     = 10000;
948   PetscLogMalloc        = -1;
949   TRdebugIinitializenan = initializenan;
950   PetscFunctionReturn(0);
951 }
952 
953 /*@
954     PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.
955 
956     Not Collective
957 
958     Output Parameters:
959 +    basic - doing basic debugging
960 .    eachcall - checks the entire memory heap at each PetscMalloc()/PetscFree()
961 -    initializenan - initializes memory with NaN
962 
963    Level: intermediate
964 
965    Notes:
966      By default, the debug version always does some debugging unless you run with -malloc_debug no
967 
968 .seealso: `CHKMEMQ()`, `PetscMallocValidate()`, `PetscMallocSetDebug()`
969 @*/
970 PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan) {
971   PetscFunctionBegin;
972   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
973   if (eachcall) *eachcall = TRdebugLevel;
974   if (initializenan) *initializenan = TRdebugIinitializenan;
975   PetscFunctionReturn(0);
976 }
977 
978 /*@
979   PetscMallocLogRequestedSizeSet - Whether to log the requested or aligned memory size
980 
981   Not Collective
982 
983   Input Parameter:
984 . flg - PETSC_TRUE to log the requested memory size
985 
986   Options Database:
987 . -malloc_requested_size <bool> - Sets this flag
988 
989   Level: developer
990 
991 .seealso: `PetscMallocLogRequestedSizeGet()`, `PetscMallocViewSet()`
992 @*/
993 PetscErrorCode PetscMallocLogRequestedSizeSet(PetscBool flg) {
994   PetscFunctionBegin;
995   TRrequestedSize = flg;
996   PetscFunctionReturn(0);
997 }
998 
999 /*@
1000   PetscMallocLogRequestedSizeGet - Whether to log the requested or aligned memory size
1001 
1002   Not Collective
1003 
1004   Output Parameter:
1005 . flg - PETSC_TRUE if we log the requested memory size
1006 
1007   Level: developer
1008 
1009 .seealso: `PetscMallocLogRequestedSizeSetinalSizeSet()`, `PetscMallocViewSet()`
1010 @*/
1011 PetscErrorCode PetscMallocLogRequestedSizeGet(PetscBool *flg) {
1012   PetscFunctionBegin;
1013   *flg = TRrequestedSize;
1014   PetscFunctionReturn(0);
1015 }
1016