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