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