xref: /petsc/src/sys/memory/mtr.c (revision c8c5c547f526914c69472d8cade615559dc64129)
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) && !defined(PETSC_HAVE_THREADSAFETY)
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 PETSC_SUCCESS;
114   head     = TRhead;
115   lasthead = NULL;
116   if (head && head->prev) {
117     PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
118     PetscCall((*PetscErrorPrintf)("Root memory header %p has invalid back pointer %p\n", (void *)head, (void *)head->prev));
119     return PETSC_ERR_MEMC;
120   }
121   while (head) {
122     if (head->classid != CLASSID_VALUE) {
123       PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
124       PetscCall((*PetscErrorPrintf)("Memory at address %p is corrupted\n", (void *)head));
125       PetscCall((*PetscErrorPrintf)("Probably write before beginning of or past end of array\n"));
126       if (lasthead) {
127         a = (char *)(((TrSPACE *)head) + 1);
128         PetscCall((*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       PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
137       if (*nend == ALREADY_FREED) {
138         PetscCall((*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         PetscCall((*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a));
142         PetscCall((*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       PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
148       PetscCall((*PetscErrorPrintf)("Backpointer %p is invalid, should be %p\n", (void *)head->prev, (void *)lasthead));
149       PetscCall((*PetscErrorPrintf)("Previous memory originally allocated in %s() at %s:%d\n", lasthead->functionname, lasthead->filename, lasthead->lineno));
150       PetscCall((*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 PETSC_SUCCESS;
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(PETSC_SUCCESS);
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) && !defined(PETSC_HAVE_THREADSAFETY)
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
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     PetscCall((*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno));
286     PetscCall((*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       PetscCall((*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno));
293       PetscCall((*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         PetscCall((*PetscErrorPrintf)("Block freed in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
296       } else {
297         PetscCall((*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       PetscCall((*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno));
303       PetscCall((*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a));
304       PetscCall((*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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
363   }
364   /* If the original space was NULL just use the regular malloc() */
365   if (!*result) {
366     PetscCall(PetscTrMallocDefault(len, PETSC_FALSE, lineno, function, filename, result));
367     PetscFunctionReturn(PETSC_SUCCESS);
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     PetscCall((*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno));
379     PetscCall((*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       PetscCall((*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno));
386       PetscCall((*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         PetscCall((*PetscErrorPrintf)("Block freed in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
389       } else {
390         PetscCall((*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       PetscCall((*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno));
396       PetscCall((*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a));
397       PetscCall((*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) && !defined(PETSC_HAVE_THREADSAFETY)
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(PETSC_SUCCESS);
466 }
467 
468 /*@C
469     PetscMemoryView - Shows the amount of memory currently being used in a communicator.
470 
471     Collective
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
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(PETSC_SUCCESS);
609   TRMaxMems[NumTRMaxMems - 1]       = TRallocated;
610   TRMaxMemsEvents[NumTRMaxMems - 1] = event;
611   PetscFunctionReturn(PETSC_SUCCESS);
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(PETSC_SUCCESS);
635   PetscCheck(TRMaxMemsEvents[NumTRMaxMems] == event, PETSC_COMM_SELF, PETSC_ERR_MEMC, "PetscMallocPush/PopMaximumUsage() are not nested");
636   *mu = TRMaxMems[NumTRMaxMems];
637   PetscFunctionReturn(PETSC_SUCCESS);
638 }
639 
640 /*@C
641    PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to `PetscMalloc()` was used to obtain that memory
642 
643    Collective on `PETSC_COMM_WORLD`
644 
645    Input Parameter:
646 .    ptr - the memory location
647 
648    Output Parameter:
649 .    stack - the stack indicating where the program allocated this memory
650 
651    Level: intermediate
652 
653 .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocView()`
654 @*/
655 PetscErrorCode PetscMallocGetStack(void *ptr, PetscStack **stack)
656 {
657 #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
658   TRSPACE *head;
659 
660   PetscFunctionBegin;
661   head   = (TRSPACE *)(((char *)ptr) - HEADER_BYTES);
662   *stack = &head->stack;
663   PetscFunctionReturn(PETSC_SUCCESS);
664 #else
665   *stack = NULL;
666   return PETSC_SUCCESS;
667 #endif
668 }
669 
670 /*@C
671    PetscMallocDump - Dumps the currently allocated memory blocks to a file. The information
672    printed is: size of space (in bytes), address of space, id of space,
673    file in which space was allocated, and line number at which it was
674    allocated.
675 
676    Not Collective
677 
678    Input Parameter:
679 .  fp  - file pointer.  If fp is NULL, stdout is assumed.
680 
681    Options Database Key:
682 .  -malloc_dump <optional filename> - Dumps unfreed memory during call to `PetscFinalize()`
683 
684    Level: intermediate
685 
686    Fortran Note:
687    The calling sequence in Fortran is PetscMallocDump(integer ierr)
688    The fp defaults to stdout.
689 
690    Notes:
691      Uses `MPI_COMM_WORLD` to display rank, because this may be called in `PetscFinalize()` after `PETSC_COMM_WORLD` has been freed.
692 
693      When called in `PetscFinalize()` dumps only the allocations that have not been properly freed
694 
695      `PetscMallocView()` prints a list of all memory ever allocated
696 
697 .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocView()`, `PetscMallocViewSet()`, `PetscMallocValidate()`
698 @*/
699 PetscErrorCode PetscMallocDump(FILE *fp)
700 {
701   TRSPACE    *head;
702   size_t      libAlloc = 0;
703   PetscMPIInt rank;
704 
705   PetscFunctionBegin;
706   PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
707   if (!fp) fp = PETSC_STDOUT;
708   head = TRhead;
709   while (head) {
710     libAlloc += TRrequestedSize ? head->rsize : head->size;
711     head = head->next;
712   }
713   if (TRallocated - libAlloc > 0) fprintf(fp, "[%d]Total space allocated %.0f bytes\n", rank, (PetscLogDouble)TRallocated);
714   head = TRhead;
715   while (head) {
716     PetscBool isLib;
717 
718     PetscCall(PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib));
719     if (!isLib) {
720       fprintf(fp, "[%2d] %.0f bytes %s() at %s:%d\n", rank, (PetscLogDouble)(TRrequestedSize ? head->rsize : head->size), head->functionname, head->filename, head->lineno);
721 #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
722       PetscCall(PetscStackPrint(&head->stack, fp));
723 #endif
724     }
725     head = head->next;
726   }
727   PetscFunctionReturn(PETSC_SUCCESS);
728 }
729 
730 /*@
731     PetscMallocViewSet - Activates logging of all calls to `PetscMalloc()` with a minimum size to view
732 
733     Not Collective
734 
735     Input Parameter:
736 .   logmin - minimum allocation size to log, or `PETSC_DEFAULT`
737 
738     Options Database Key:
739 +  -malloc_view <optional filename> - Activates `PetscMallocView()` in `PetscFinalize()`
740 .  -malloc_view_threshold <min> - Sets a minimum size if -malloc_view is used
741 -  -log_view_memory - view the memory usage also with the -log_view option
742 
743     Level: advanced
744 
745     Notes:
746     Must be called after `PetscMallocSetDebug()`
747 
748     Uses `MPI_COMM_WORLD` to determine rank because PETSc communicators may not be available
749 
750 .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocViewSet()`, `PetscMallocTraceSet()`, `PetscMallocValidate()`
751 @*/
752 PetscErrorCode PetscMallocViewSet(PetscLogDouble logmin)
753 {
754   PetscFunctionBegin;
755   PetscLogMalloc = 0;
756   PetscCall(PetscMemorySetGetMaximumUsage());
757   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
758   PetscLogMallocThreshold = (size_t)logmin;
759   PetscFunctionReturn(PETSC_SUCCESS);
760 }
761 
762 /*@
763     PetscMallocViewGet - Determine whether calls to `PetscMalloc()` are being logged
764 
765     Not Collective
766 
767     Output Parameter
768 .   logging - `PETSC_TRUE` if logging is active
769 
770     Options Database Key:
771 .  -malloc_view <optional filename> - Activates `PetscMallocView()`
772 
773     Level: advanced
774 
775 .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocTraceGet()`
776 @*/
777 PetscErrorCode PetscMallocViewGet(PetscBool *logging)
778 {
779   PetscFunctionBegin;
780   *logging = (PetscBool)(PetscLogMalloc >= 0);
781   PetscFunctionReturn(PETSC_SUCCESS);
782 }
783 
784 /*@
785   PetscMallocTraceSet - Trace all calls to `PetscMalloc()`
786 
787   Not Collective
788 
789   Input Parameters:
790 + viewer - The viewer to use for tracing, or NULL to use stdout
791 . active - Flag to activate or deactivate tracing
792 - logmin - The smallest memory size that will be logged
793 
794   Note:
795   The viewer should not be collective.
796 
797   Level: advanced
798 
799 .seealso: `PetscMallocTraceGet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`
800 @*/
801 PetscErrorCode PetscMallocTraceSet(PetscViewer viewer, PetscBool active, PetscLogDouble logmin)
802 {
803   PetscFunctionBegin;
804   if (!active) {
805     PetscLogMallocTrace = -1;
806     PetscFunctionReturn(PETSC_SUCCESS);
807   }
808   PetscLogMallocTraceViewer = !viewer ? PETSC_VIEWER_STDOUT_SELF : viewer;
809   PetscLogMallocTrace       = 0;
810   PetscCall(PetscMemorySetGetMaximumUsage());
811   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
812   PetscLogMallocTraceThreshold = (size_t)logmin;
813   PetscFunctionReturn(PETSC_SUCCESS);
814 }
815 
816 /*@
817   PetscMallocTraceGet - Determine whether all calls to `PetscMalloc()` are being traced
818 
819   Not Collective
820 
821   Output Parameter:
822 . logging - `PETSC_TRUE` if logging is active
823 
824   Options Database Key:
825 . -malloc_view <optional filename> - Activates PetscMallocView()
826 
827   Level: advanced
828 
829 .seealso: `PetscMallocTraceSet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`
830 @*/
831 PetscErrorCode PetscMallocTraceGet(PetscBool *logging)
832 {
833   PetscFunctionBegin;
834   *logging = (PetscBool)(PetscLogMallocTrace >= 0);
835   PetscFunctionReturn(PETSC_SUCCESS);
836 }
837 
838 /*@C
839     PetscMallocView - Saves the log of all calls to `PetscMalloc()`; also calls
840        `PetscMemoryGetMaximumUsage()`
841 
842     Not Collective
843 
844     Input Parameter:
845 .   fp - file pointer; or NULL
846 
847     Options Database Key:
848 .  -malloc_view <optional filename> - Activates `PetscMallocView()` in `PetscFinalize()`
849 
850     Level: advanced
851 
852    Fortran Note:
853    The calling sequence in Fortran is PetscMallocView(integer ierr)
854    The fp defaults to stdout.
855 
856    Notes:
857      `PetscMallocDump()` dumps only the currently unfreed memory, this dumps all memory ever allocated
858 
859      `PetscMemoryView()` gives a brief summary of current memory usage
860 
861 .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocDump()`, `PetscMallocViewSet()`, `PetscMemoryView()`
862 @*/
863 PetscErrorCode PetscMallocView(FILE *fp)
864 {
865   PetscInt       i, j, n, *perm;
866   size_t        *shortlength;
867   int           *shortcount;
868   PetscMPIInt    rank;
869   PetscBool      match;
870   const char   **shortfunction;
871   PetscLogDouble rss;
872 
873   PetscFunctionBegin;
874   PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
875   PetscCall(PetscFFlush(fp));
876 
877   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()");
878 
879   if (!fp) fp = PETSC_STDOUT;
880   PetscCall(PetscMemoryGetMaximumUsage(&rss));
881   if (rss) {
882     (void)fprintf(fp, "[%d] Maximum memory PetscMalloc()ed %.0f maximum size of entire process %.0f\n", rank, (PetscLogDouble)TRMaxMem, rss);
883   } else {
884     (void)fprintf(fp, "[%d] Maximum memory PetscMalloc()ed %.0f OS cannot compute size of entire process\n", rank, (PetscLogDouble)TRMaxMem);
885   }
886   if (PetscLogMalloc > 0) {
887     shortcount = (int *)malloc(PetscLogMalloc * sizeof(int));
888     PetscCheck(shortcount, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
889     shortlength = (size_t *)malloc(PetscLogMalloc * sizeof(size_t));
890     PetscCheck(shortlength, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
891     shortfunction = (const char **)malloc(PetscLogMalloc * sizeof(char *));
892     PetscCheck(shortfunction, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
893     for (i = 0, n = 0; i < PetscLogMalloc; i++) {
894       for (j = 0; j < n; j++) {
895         PetscCall(PetscStrcmp(shortfunction[j], PetscLogMallocFunction[i], &match));
896         if (match) {
897           shortlength[j] += PetscLogMallocLength[i];
898           shortcount[j]++;
899           goto foundit;
900         }
901       }
902       shortfunction[n] = PetscLogMallocFunction[i];
903       shortlength[n]   = PetscLogMallocLength[i];
904       shortcount[n]    = 1;
905       n++;
906     foundit:;
907     }
908 
909     perm = (PetscInt *)malloc(n * sizeof(PetscInt));
910     PetscCheck(perm, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
911     for (i = 0; i < n; i++) perm[i] = i;
912     PetscCall(PetscSortStrWithPermutation(n, (const char **)shortfunction, perm));
913 
914     (void)fprintf(fp, "[%d] Memory usage sorted by function\n", rank);
915     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]]);
916     free(perm);
917     free(shortlength);
918     free(shortcount);
919     free((char **)shortfunction);
920   }
921   PetscCall(PetscFFlush(fp));
922   PetscFunctionReturn(PETSC_SUCCESS);
923 }
924 
925 /* ---------------------------------------------------------------------------- */
926 
927 /*@
928     PetscMallocSetDebug - Set's PETSc memory debugging
929 
930     Not Collective
931 
932     Input Parameters:
933 +   eachcall - checks the entire heap of allocated memory for issues on each call to `PetscMalloc()` and `PetscFree()`, slow
934 -   initializenan - initializes all memory with NaN to catch use of uninitialized floating point arrays
935 
936     Options Database Keys:
937 +   -malloc_debug <true or false> - turns on or off debugging
938 .   -malloc_test - turns on all debugging if PETSc was configured with debugging including -malloc_dump, otherwise ignored
939 .   -malloc_view_threshold t - log only allocations larger than t
940 .   -malloc_dump <filename> - print a list of all memory that has not been freed
941 .   -malloc no - (deprecated) same as -malloc_debug no
942 -   -malloc_log - (deprecated) same as -malloc_view
943 
944    Level: developer
945 
946     Note:
947     This is called in `PetscInitialize()` and should not be called elsewhere
948 
949 .seealso: `CHKMEMQ()`, `PetscMallocValidate()`, `PetscMallocGetDebug()`
950 @*/
951 PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan)
952 {
953   PetscFunctionBegin;
954   PetscCheck(PetscTrMalloc != PetscTrMallocDefault, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call this routine more than once, it can only be called in PetscInitialize()");
955   PetscCall(PetscMallocSet(PetscTrMallocDefault, PetscTrFreeDefault, PetscTrReallocDefault));
956 
957   TRallocated           = 0;
958   TRfrags               = 0;
959   TRhead                = NULL;
960   TRid                  = 0;
961   TRdebugLevel          = eachcall;
962   TRMaxMem              = 0;
963   PetscLogMallocMax     = 10000;
964   PetscLogMalloc        = -1;
965   TRdebugIinitializenan = initializenan;
966   PetscFunctionReturn(PETSC_SUCCESS);
967 }
968 
969 /*@
970     PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.
971 
972     Not Collective
973 
974     Output Parameters:
975 +    basic - doing basic debugging
976 .    eachcall - checks the entire memory heap at each `PetscMalloc()`/`PetscFree()`
977 -    initializenan - initializes memory with NaN
978 
979    Level: intermediate
980 
981    Note:
982      By default, the debug version always does some debugging unless you run with -malloc_debug no
983 
984 .seealso: `CHKMEMQ()`, `PetscMallocValidate()`, `PetscMallocSetDebug()`
985 @*/
986 PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan)
987 {
988   PetscFunctionBegin;
989   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
990   if (eachcall) *eachcall = TRdebugLevel;
991   if (initializenan) *initializenan = TRdebugIinitializenan;
992   PetscFunctionReturn(PETSC_SUCCESS);
993 }
994 
995 /*@
996   PetscMallocLogRequestedSizeSet - Whether to log the requested or aligned memory size
997 
998   Not Collective
999 
1000   Input Parameter:
1001 . flg - `PETSC_TRUE` to log the requested memory size
1002 
1003   Options Database Key:
1004 . -malloc_requested_size <bool> - Sets this flag
1005 
1006   Level: developer
1007 
1008 .seealso: `PetscMallocLogRequestedSizeGet()`, `PetscMallocViewSet()`
1009 @*/
1010 PetscErrorCode PetscMallocLogRequestedSizeSet(PetscBool flg)
1011 {
1012   PetscFunctionBegin;
1013   TRrequestedSize = flg;
1014   PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016 
1017 /*@
1018   PetscMallocLogRequestedSizeGet - Whether to log the requested or aligned memory size
1019 
1020   Not Collective
1021 
1022   Output Parameter:
1023 . flg - `PETSC_TRUE` if we log the requested memory size
1024 
1025   Level: developer
1026 
1027 .seealso: `PetscMallocLogRequestedSizeSetinalSizeSet()`, `PetscMallocViewSet()`
1028 @*/
1029 PetscErrorCode PetscMallocLogRequestedSizeGet(PetscBool *flg)
1030 {
1031   PetscFunctionBegin;
1032   *flg = TRrequestedSize;
1033   PetscFunctionReturn(PETSC_SUCCESS);
1034 }
1035