Actual source code: mtr.c

  1: /*
  2:      Logging of memory usage and some error checking
  3: */
  4: #include <petsc/private/petscimpl.h>
  5: #include <petscviewer.h>
  6: #if PetscDefined(HAVE_MALLOC_H)
  7:   #include <malloc.h>
  8: #endif

 10: /*
 11:      These are defined in mal.c and ensure that malloced space is PetscScalar aligned
 12: */
 13: PETSC_EXTERN PetscErrorCode PetscMallocAlign(size_t, PetscBool, int, const char[], const char[], void **);
 14: PETSC_EXTERN PetscErrorCode PetscFreeAlign(void *, int, const char[], const char[]);
 15: PETSC_EXTERN PetscErrorCode PetscReallocAlign(size_t, int, const char[], const char[], void **);

 17: #define COOKIE_VALUE  -253701943
 18: #define ALREADY_FREED 252579228

 20: /*  this is the header put at the beginning of each PetscTrMallocDefault() for tracking allocated space and checking of allocated space heap */
 21: typedef struct _trSPACE {
 22:   size_t      size, rsize; /* Aligned size and requested size */
 23:   int         id;
 24:   int         lineno;
 25:   const char *filename;
 26:   const char *functionname;
 27:   PetscInt    specialcookie;
 28: #if PetscDefined(USE_DEBUG)
 29:   PetscStack stack;
 30: #endif
 31:   struct _trSPACE *next, *prev;
 32: } TRSPACE;

 34: /* HEADER_BYTES is the number of bytes in a PetscTrMallocDefault() header.
 35:    It is sizeof(trSPACE) padded to be a multiple of PETSC_MEMALIGN.
 36: */
 37: #define HEADER_BYTES ((sizeof(TRSPACE) + (PETSC_MEMALIGN - 1)) & ~(PETSC_MEMALIGN - 1))

 39: /* This union is used to insure that the block passed to the user retains
 40:    a minimum alignment of PETSC_MEMALIGN.
 41: */
 42: typedef union
 43: {
 44:   TRSPACE sp;
 45:   char    v[HEADER_BYTES];
 46: } TrSPACE;

 48: #define MAXTRMAXMEMS 50
 49: static size_t    TRallocated           = 0;
 50: static TRSPACE  *TRhead                = NULL;
 51: static int       TRid                  = 0;
 52: static PetscBool TRdebug               = PETSC_FALSE;
 53: static PetscBool TRdebugIinitializenan = PETSC_FALSE;
 54: static PetscBool TRrequestedSize       = PETSC_FALSE;
 55: static size_t    TRMaxMem              = 0;
 56: static int       NumTRMaxMems          = 0;
 57: static size_t    TRMaxMems[MAXTRMAXMEMS];
 58: static int       TRMaxMemsEvents[MAXTRMAXMEMS];
 59: /*
 60:       Arrays to log information on mallocs for PetscMallocView()
 61: */
 62: static int          PetscLogMallocMax       = 10000;
 63: static int          PetscLogMalloc          = -1;
 64: static size_t       PetscLogMallocThreshold = 0;
 65: static size_t      *PetscLogMallocLength;
 66: static const char **PetscLogMallocFile, **PetscLogMallocFunction;
 67: static int          PetscLogMallocTrace          = -1;
 68: static size_t       PetscLogMallocTraceThreshold = 0;
 69: static PetscViewer  PetscLogMallocTraceViewer    = NULL;

 71: /*@
 72:   PetscMallocValidate - Test the memory for corruption.  This can be called at any time between `PetscInitialize()` and `PetscFinalize()`

 74:   Input Parameters:
 75: + line     - line number where call originated.
 76: . function - name of function calling
 77: - file     - file where function is

 79:   Options Database Keys:
 80: + -malloc_test               - turns this feature on when PETSc was not configured with `--with-debugging=0`
 81: - -malloc_debug (true|false) - turns this feature on anytime

 83:   Level: advanced

 85:   Notes:
 86:   You should generally use `CHKMEMQ` as a short cut for calling this routine.

 88:   Error messages are written to `stdout`.

 90:   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)

 92:   No output is generated if there are no problems detected.

 94:   Fortran Notes:
 95:   The Fortran calling sequence is simply `PetscMallocValidate(ierr)`

 97: .seealso: `CHKMEMQ`, `PetscMalloc()`, `PetscFree()`, `PetscMallocSetDebug()`
 98: @*/
 99: PetscErrorCode PetscMallocValidate(int line, const char function[], const char file[])
100: {
101:   TRSPACE  *head, *lasthead;
102:   char     *a;
103:   PetscInt *nend;

105:   if (!TRdebug) return PETSC_SUCCESS;
106:   head     = TRhead;
107:   lasthead = NULL;
108:   if (head && head->prev) {
109:     TRdebug = PETSC_FALSE;
110:     PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
111:     PetscCall((*PetscErrorPrintf)("Root memory header %p has invalid back pointer %p\n", (void *)head, (void *)head->prev));
112:     return PETSC_ERR_MEMC;
113:   }
114:   while (head) {
115:     if (head->specialcookie != COOKIE_VALUE) {
116:       TRdebug = PETSC_FALSE;
117:       PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
118:       PetscCall((*PetscErrorPrintf)("Memory at address %p is corrupted\n", (void *)head));
119:       PetscCall((*PetscErrorPrintf)("Probably write before beginning of or past end of array\n"));
120:       if (lasthead) {
121:         a = (char *)(((TrSPACE *)head) + 1);
122:         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));
123:       }
124:       abort();
125:       return PETSC_ERR_MEMC;
126:     }
127:     a    = (char *)(((TrSPACE *)head) + 1);
128:     nend = (PetscInt *)(a + head->size);
129:     if (*nend != COOKIE_VALUE) {
130:       TRdebug = PETSC_FALSE;
131:       PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
132:       if (*nend == ALREADY_FREED) {
133:         PetscCall((*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p already freed\n", head->id, (PetscLogDouble)head->size, a));
134:         return PETSC_ERR_MEMC;
135:       } else {
136:         PetscCall((*PetscErrorPrintf)("Memory [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a));
137:         PetscCall((*PetscErrorPrintf)("Memory originally allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
138:         return PETSC_ERR_MEMC;
139:       }
140:     }
141:     if (head->prev && head->prev != lasthead) {
142:       TRdebug = PETSC_FALSE;
143:       PetscCall((*PetscErrorPrintf)("PetscMallocValidate: error detected in %s() at %s:%d\n", function, file, line));
144:       PetscCall((*PetscErrorPrintf)("Backpointer %p is invalid, should be %p\n", (void *)head->prev, (void *)lasthead));
145:       PetscCall((*PetscErrorPrintf)("Previous memory originally allocated in %s() at %s:%d\n", lasthead->functionname, lasthead->filename, lasthead->lineno));
146:       PetscCall((*PetscErrorPrintf)("Memory originally allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
147:       return PETSC_ERR_MEMC;
148:     }
149:     lasthead = head;
150:     head     = head->next;
151:   }
152:   return PETSC_SUCCESS;
153: }

155: /*
156:     PetscTrMallocDefault - Malloc with logging and error checking

158: */
159: static PetscErrorCode PetscTrMallocDefault(size_t a, PetscBool clear, int lineno, const char function[], const char filename[], void **result)
160: {
161:   TRSPACE *head;
162:   char    *inew;
163:   size_t   nsize;

165:   PetscFunctionBegin;
166:   if (!a) {
167:     *result = NULL;
168:     PetscFunctionReturn(PETSC_SUCCESS);
169:   }

171:   PetscCall(PetscMallocValidate(lineno, function, filename));

173:   nsize = (a + (PETSC_MEMALIGN - 1)) & ~(PETSC_MEMALIGN - 1);
174:   PetscCall(PetscMallocAlign(nsize + sizeof(TrSPACE) + sizeof(PetscInt), clear, lineno, function, filename, (void **)&inew));

176:   head = (TRSPACE *)inew;
177:   inew += sizeof(TrSPACE);

179:   if (TRhead) TRhead->prev = head;
180:   head->next   = TRhead;
181:   TRhead       = head;
182:   head->prev   = NULL;
183:   head->size   = nsize;
184:   head->rsize  = a;
185:   head->id     = TRid++;
186:   head->lineno = lineno;

188:   head->filename              = filename;
189:   head->functionname          = function;
190:   head->specialcookie         = COOKIE_VALUE;
191:   *(PetscInt *)(inew + nsize) = COOKIE_VALUE;

193:   TRallocated += TRrequestedSize ? head->rsize : head->size;
194:   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
195:   if (PetscLogMemory) {
196:     for (PetscInt i = 0; i < NumTRMaxMems; i++) {
197:       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
198:     }
199:   }

201: #if PetscDefined(USE_DEBUG)
202:   PetscCall(PetscStackCopy(&petscstack, &head->stack));
203:   /* fix the line number to where PetscTrMallocDefault() was called, not the PetscFunctionBegin; */
204:   if (head->stack.currentsize > 1 && head->stack.currentsize - 2 < PETSCSTACKSIZE) head->stack.line[head->stack.currentsize - 2] = lineno;
205:   head->stack.currentsize--;
206:   #if PetscDefined(USE_REAL_SINGLE) || PetscDefined(USE_REAL_DOUBLE)
207:   if (!clear && TRdebugIinitializenan) {
208:     size_t     n = a / sizeof(PetscReal);
209:     PetscReal *s = (PetscReal *)inew;
210:       /* from https://www.doc.ic.ac.uk/~eedwards/compsys/float/nan.html */
211:     #if PetscDefined(USE_REAL_SINGLE)
212:     int nas = 0x7F800002;
213:     #else
214:     PetscInt64 nas = 0x7FF0000000000002;
215:     #endif
216:     for (size_t i = 0; i < n; i++) memcpy(s + i, &nas, sizeof(PetscReal));
217:   }
218:   #endif
219: #endif

221:   /*
222:          Allow logging of all mallocs made.
223:          TODO: Currently this memory is never freed, it should be freed during PetscFinalize()
224:   */
225:   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && a >= PetscLogMallocThreshold) {
226:     if (!PetscLogMalloc) {
227:       PetscLogMallocLength = (size_t *)malloc(PetscLogMallocMax * sizeof(size_t));
228:       PetscCheck(PetscLogMallocLength, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");

230:       PetscLogMallocFile = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
231:       PetscCheck(PetscLogMallocFile, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");

233:       PetscLogMallocFunction = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
234:       PetscCheck(PetscLogMallocFunction, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
235:     }
236:     PetscLogMallocLength[PetscLogMalloc]     = nsize;
237:     PetscLogMallocFile[PetscLogMalloc]       = filename;
238:     PetscLogMallocFunction[PetscLogMalloc++] = function;
239:   }
240:   if (PetscLogMallocTrace > -1 && a >= PetscLogMallocTraceThreshold) PetscCall(PetscViewerASCIIPrintf(PetscLogMallocTraceViewer, "Alloc %zu %s:%d (%s)\n", a, filename ? filename : "null", lineno, function ? function : "null"));
241:   *result = (void *)inew;
242:   PetscFunctionReturn(PETSC_SUCCESS);
243: }

245: /*
246:    PetscTrFreeDefault - Free with logging and error checking

248: */
249: static PetscErrorCode PetscTrFreeDefault(void *aa, int lineno, const char function[], const char filename[])
250: {
251:   char     *a = (char *)aa;
252:   TRSPACE  *head;
253:   char     *ahead;
254:   size_t    asize;
255:   PetscInt *nend;

257:   PetscFunctionBegin;
258:   if (!a) PetscFunctionReturn(PETSC_SUCCESS);

260:   PetscCall(PetscMallocValidate(lineno, function, filename));

262:   ahead = a;
263:   a     = a - sizeof(TrSPACE);
264:   head  = (TRSPACE *)a;

266:   if (head->specialcookie != COOKIE_VALUE) {
267:     TRdebug = PETSC_FALSE;
268:     PetscCall((*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno));
269:     PetscCall((*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n", a));
270:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Bad location or corrupted memory");
271:   }
272:   nend = (PetscInt *)(ahead + head->size);
273:   if (*nend != COOKIE_VALUE) {
274:     TRdebug = PETSC_FALSE;
275:     if (*nend == ALREADY_FREED) {
276:       PetscCall((*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno));
277:       PetscCall((*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n", head->id, (PetscLogDouble)head->size, a + sizeof(TrSPACE)));
278:       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
279:         PetscCall((*PetscErrorPrintf)("Block freed in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
280:       } else {
281:         PetscCall((*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, -head->lineno));
282:       }
283:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Memory already freed");
284:     } else {
285:       /* Damaged tail */
286:       PetscCall((*PetscErrorPrintf)("PetscTrFreeDefault() called from %s() at %s:%d\n", function, filename, lineno));
287:       PetscCall((*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a));
288:       PetscCall((*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
289:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Corrupted memory");
290:     }
291:   }
292:   if (PetscLogMallocTrace > -1 && head->rsize >= PetscLogMallocTraceThreshold) PetscCall(PetscViewerASCIIPrintf(PetscLogMallocTraceViewer, "Free  %zu %s:%d (%s)\n", head->rsize, filename ? filename : "null", lineno, function ? function : "null"));
293:   *nend = ALREADY_FREED;
294:   /* Save location where freed.  If we suspect the line number, mark as allocated location */
295:   if (lineno > 0 && lineno < 50000) {
296:     head->lineno       = lineno;
297:     head->filename     = filename;
298:     head->functionname = function;
299:   } else {
300:     head->lineno = -head->lineno;
301:   }
302:   asize = TRrequestedSize ? head->rsize : head->size;
303:   PetscCheck(TRallocated >= asize, PETSC_COMM_SELF, PETSC_ERR_MEMC, "TRallocate is smaller than memory just freed");
304:   TRallocated -= asize;
305:   if (head->prev) head->prev->next = head->next;
306:   else TRhead = head->next;

308:   if (head->next) head->next->prev = head->prev;
309:   PetscCall(PetscFreeAlign(a, lineno, function, filename));
310:   PetscFunctionReturn(PETSC_SUCCESS);
311: }

313: /*
314:   PetscTrReallocDefault - Realloc with logging and error checking

316: */
317: static PetscErrorCode PetscTrReallocDefault(size_t len, int lineno, const char function[], const char filename[], void **result)
318: {
319:   char     *a = (char *)*result;
320:   TRSPACE  *head;
321:   char     *ahead, *inew;
322:   PetscInt *nend;
323:   size_t    nsize;

325:   PetscFunctionBegin;
326:   /* Realloc requests zero space so just free the current space */
327:   if (!len) {
328:     PetscCall(PetscTrFreeDefault(*result, lineno, function, filename));
329:     *result = NULL;
330:     PetscFunctionReturn(PETSC_SUCCESS);
331:   }
332:   /* If the original space was NULL just use the regular malloc() */
333:   if (!*result) {
334:     PetscCall(PetscTrMallocDefault(len, PETSC_FALSE, lineno, function, filename, result));
335:     PetscFunctionReturn(PETSC_SUCCESS);
336:   }

338:   PetscCall(PetscMallocValidate(lineno, function, filename));

340:   ahead = a;
341:   a     = a - sizeof(TrSPACE);
342:   head  = (TRSPACE *)a;
343:   inew  = a;

345:   if (head->specialcookie != COOKIE_VALUE) {
346:     TRdebug = PETSC_FALSE;
347:     PetscCall((*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno));
348:     PetscCall((*PetscErrorPrintf)("Block at address %p is corrupted; cannot free;\nmay be block not allocated with PetscMalloc()\n", a));
349:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Bad location or corrupted memory");
350:   }
351:   nend = (PetscInt *)(ahead + head->size);
352:   if (*nend != COOKIE_VALUE) {
353:     TRdebug = PETSC_FALSE;
354:     if (*nend == ALREADY_FREED) {
355:       PetscCall((*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno));
356:       PetscCall((*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p was already freed\n", head->id, (PetscLogDouble)head->size, a + sizeof(TrSPACE)));
357:       if (head->lineno > 0 && head->lineno < 50000 /* sanity check */) {
358:         PetscCall((*PetscErrorPrintf)("Block freed in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
359:       } else {
360:         PetscCall((*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, -head->lineno));
361:       }
362:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Memory already freed");
363:     } else {
364:       /* Damaged tail */
365:       PetscCall((*PetscErrorPrintf)("PetscTrReallocDefault() called from %s() at %s:%d\n", function, filename, lineno));
366:       PetscCall((*PetscErrorPrintf)("Block [id=%d(%.0f)] at address %p is corrupted (probably write past end of array)\n", head->id, (PetscLogDouble)head->size, a));
367:       PetscCall((*PetscErrorPrintf)("Block allocated in %s() at %s:%d\n", head->functionname, head->filename, head->lineno));
368:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MEMC, "Corrupted memory");
369:     }
370:   }

372:   /* remove original reference to the memory allocated from the PETSc debugging heap */
373:   TRallocated -= TRrequestedSize ? head->rsize : head->size;
374:   if (head->prev) head->prev->next = head->next;
375:   else TRhead = head->next;
376:   if (head->next) head->next->prev = head->prev;

378:   nsize = (len + (PETSC_MEMALIGN - 1)) & ~(PETSC_MEMALIGN - 1);
379:   PetscCall(PetscReallocAlign(nsize + sizeof(TrSPACE) + sizeof(PetscInt), lineno, function, filename, (void **)&inew));

381:   head = (TRSPACE *)inew;
382:   inew += sizeof(TrSPACE);

384:   if (TRhead) TRhead->prev = head;
385:   head->next   = TRhead;
386:   TRhead       = head;
387:   head->prev   = NULL;
388:   head->size   = nsize;
389:   head->rsize  = len;
390:   head->id     = TRid++;
391:   head->lineno = lineno;

393:   head->filename              = filename;
394:   head->functionname          = function;
395:   head->specialcookie         = COOKIE_VALUE;
396:   *(PetscInt *)(inew + nsize) = COOKIE_VALUE;

398:   TRallocated += TRrequestedSize ? head->rsize : head->size;
399:   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
400:   if (PetscLogMemory) {
401:     for (PetscInt i = 0; i < NumTRMaxMems; i++) {
402:       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
403:     }
404:   }

406: #if PetscDefined(USE_DEBUG)
407:   PetscCall(PetscStackCopy(&petscstack, &head->stack));
408:   /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
409:   if (head->stack.currentsize > 1 && head->stack.currentsize - 2 < PETSCSTACKSIZE) head->stack.line[head->stack.currentsize - 2] = lineno;
410:   head->stack.currentsize--;
411: #endif

413:   /*
414:          Allow logging of all mallocs made. This adds a new entry to the list of allocated memory
415:          and does not remove the previous entry to the list hence this memory is "double counted" in PetscMallocView()
416:   */
417:   if (PetscLogMalloc > -1 && PetscLogMalloc < PetscLogMallocMax && len >= PetscLogMallocThreshold) {
418:     if (!PetscLogMalloc) {
419:       PetscLogMallocLength = (size_t *)malloc(PetscLogMallocMax * sizeof(size_t));
420:       PetscCheck(PetscLogMallocLength, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");

422:       PetscLogMallocFile = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
423:       PetscCheck(PetscLogMallocFile, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");

425:       PetscLogMallocFunction = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
426:       PetscCheck(PetscLogMallocFunction, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
427:     }
428:     PetscLogMallocLength[PetscLogMalloc]     = nsize;
429:     PetscLogMallocFile[PetscLogMalloc]       = filename;
430:     PetscLogMallocFunction[PetscLogMalloc++] = function;
431:   }
432:   *result = (void *)inew;
433:   PetscFunctionReturn(PETSC_SUCCESS);
434: }

436: /*@
437:   PetscMemoryView - Shows the amount of memory currently being used in a communicator.

439:   Collective

441:   Input Parameters:
442: + viewer  - the viewer to output the information on
443: - message - string printed before values

445:   Options Database Keys:
446: + -malloc_debug (true|false)    - have PETSc track how much memory it has allocated
447: . -log_view_memory (true|false) - print memory usage per event when `-log_view` is used
448: - -memory_view (true|false)     - during `PetscFinalize()` have this routine called with `PETSC_VIEWER_STDOUT_WORLD`

450:   Level: intermediate

452: .seealso: `PetscMallocDump()`, `PetscMemoryGetCurrentUsage()`, `PetscMemorySetGetMaximumUsage()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
453:  @*/
454: PetscErrorCode PetscMemoryView(PetscViewer viewer, const char message[])
455: {
456:   PetscLogDouble allocated, allocatedmax, resident, residentmax, gallocated, gallocatedmax, gresident, gresidentmax, maxgallocated, maxgallocatedmax;
457:   PetscLogDouble mingallocated, mingallocatedmax, mingresident, mingresidentmax, maxgresident, maxgresidentmax;
458:   MPI_Comm       comm;

460:   PetscFunctionBegin;
461:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_WORLD;
462:   PetscCall(PetscMallocGetCurrentUsage(&allocated));
463:   PetscCall(PetscMallocGetMaximumUsage(&allocatedmax));
464:   PetscCall(PetscMemoryGetCurrentUsage(&resident));
465:   PetscCall(PetscMemoryGetMaximumUsage(&residentmax));
466:   if (residentmax > 0) residentmax = PetscMax(resident, residentmax);
467:   PetscCall(PetscObjectGetComm((PetscObject)viewer, &comm));
468:   PetscCall(PetscViewerASCIIPrintf(viewer, "%s", message));
469:   if (resident && residentmax && allocated) {
470:     PetscCallMPI(MPI_Reduce(&residentmax, &gresidentmax, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
471:     PetscCallMPI(MPI_Reduce(&residentmax, &maxgresidentmax, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
472:     PetscCallMPI(MPI_Reduce(&residentmax, &mingresidentmax, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
473:     PetscCall(PetscViewerASCIIPrintf(viewer, "Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n", gresidentmax, maxgresidentmax, mingresidentmax));
474:     PetscCallMPI(MPI_Reduce(&resident, &gresident, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
475:     PetscCallMPI(MPI_Reduce(&resident, &maxgresident, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
476:     PetscCallMPI(MPI_Reduce(&resident, &mingresident, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
477:     PetscCall(PetscViewerASCIIPrintf(viewer, "Current process memory:                                  total %5.4e max %5.4e min %5.4e\n", gresident, maxgresident, mingresident));
478:     PetscCallMPI(MPI_Reduce(&allocatedmax, &gallocatedmax, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
479:     PetscCallMPI(MPI_Reduce(&allocatedmax, &maxgallocatedmax, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
480:     PetscCallMPI(MPI_Reduce(&allocatedmax, &mingallocatedmax, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
481:     PetscCall(PetscViewerASCIIPrintf(viewer, "Maximum (over computational time) space PetscMalloc()ed: total %5.4e max %5.4e min %5.4e\n", gallocatedmax, maxgallocatedmax, mingallocatedmax));
482:     PetscCallMPI(MPI_Reduce(&allocated, &gallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
483:     PetscCallMPI(MPI_Reduce(&allocated, &maxgallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
484:     PetscCallMPI(MPI_Reduce(&allocated, &mingallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
485:     PetscCall(PetscViewerASCIIPrintf(viewer, "Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n", gallocated, maxgallocated, mingallocated));
486:   } else if (resident && residentmax) {
487:     PetscCallMPI(MPI_Reduce(&residentmax, &gresidentmax, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
488:     PetscCallMPI(MPI_Reduce(&residentmax, &maxgresidentmax, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
489:     PetscCallMPI(MPI_Reduce(&residentmax, &mingresidentmax, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
490:     PetscCall(PetscViewerASCIIPrintf(viewer, "Maximum (over computational time) process memory:        total %5.4e max %5.4e min %5.4e\n", gresidentmax, maxgresidentmax, mingresidentmax));
491:     PetscCallMPI(MPI_Reduce(&resident, &gresident, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
492:     PetscCallMPI(MPI_Reduce(&resident, &maxgresident, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
493:     PetscCallMPI(MPI_Reduce(&resident, &mingresident, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
494:     PetscCall(PetscViewerASCIIPrintf(viewer, "Current process memory:                                  total %5.4e max %5.4e min %5.4e\n", gresident, maxgresident, mingresident));
495:   } else if (resident && allocated) {
496:     PetscCallMPI(MPI_Reduce(&resident, &gresident, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
497:     PetscCallMPI(MPI_Reduce(&resident, &maxgresident, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
498:     PetscCallMPI(MPI_Reduce(&resident, &mingresident, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
499:     PetscCall(PetscViewerASCIIPrintf(viewer, "Current process memory:                                  total %5.4e max %5.4e min %5.4e\n", gresident, maxgresident, mingresident));
500:     PetscCallMPI(MPI_Reduce(&allocated, &gallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
501:     PetscCallMPI(MPI_Reduce(&allocated, &maxgallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
502:     PetscCallMPI(MPI_Reduce(&allocated, &mingallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
503:     PetscCall(PetscViewerASCIIPrintf(viewer, "Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n", gallocated, maxgallocated, mingallocated));
504:     PetscCall(PetscViewerASCIIPrintf(viewer, "Run with -memory_view to get maximum memory usage\n"));
505:   } else if (allocated) {
506:     PetscCallMPI(MPI_Reduce(&allocated, &gallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_SUM, 0, comm));
507:     PetscCallMPI(MPI_Reduce(&allocated, &maxgallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_MAX, 0, comm));
508:     PetscCallMPI(MPI_Reduce(&allocated, &mingallocated, 1, MPIU_PETSCLOGDOUBLE, MPI_MIN, 0, comm));
509:     PetscCall(PetscViewerASCIIPrintf(viewer, "Current space PetscMalloc()ed:                           total %5.4e max %5.4e min %5.4e\n", gallocated, maxgallocated, mingallocated));
510:     PetscCall(PetscViewerASCIIPrintf(viewer, "Run with -memory_view to get maximum memory usage\n"));
511:     PetscCall(PetscViewerASCIIPrintf(viewer, "OS cannot compute process memory\n"));
512:   } else {
513:     PetscCall(PetscViewerASCIIPrintf(viewer, "Run with -malloc_debug to get statistics on PetscMalloc() calls\nOS cannot compute process memory\n"));
514:   }
515:   PetscCall(PetscViewerFlush(viewer));
516:   PetscFunctionReturn(PETSC_SUCCESS);
517: }

519: /*@
520:   PetscMallocGetCurrentUsage - gets the current amount of memory used that was allocated with `PetscMalloc()`

522:   Not Collective

524:   Output Parameter:
525: . space - number of bytes currently allocated

527:   Level: intermediate

529:   Note:
530:   This only works if `-memory_view` or `-log_view_memory` have been used

532: .seealso: `PetscMallocDump()`, `PetscMallocGetMaximumUsage()`, `PetscMemoryGetCurrentUsage()`, `PetscMalloc()`, `PetscFree()`,
533:           `PetscMemoryGetMaximumUsage()`
534:  @*/
535: PetscErrorCode PetscMallocGetCurrentUsage(PetscLogDouble *space)
536: {
537:   PetscFunctionBegin;
538:   *space = (PetscLogDouble)TRallocated;
539:   PetscFunctionReturn(PETSC_SUCCESS);
540: }

542: /*@
543:   PetscMallocGetMaximumUsage - gets the maximum amount of memory used that was obtained with `PetscMalloc()` at any time
544:   during this run, the high water mark.

546:   Not Collective

548:   Output Parameter:
549: . space - maximum number of bytes ever allocated at one time

551:   Level: intermediate

553:   Note:
554:   This only works if `PetscMemorySetGetMaximumUsage()`, `-memory_view`, or `-log_view_memory` have been used

556: .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMemoryGetCurrentUsage()`, `PetscMalloc()`, `PetscFree()`,
557:           `PetscMallocPushMaximumUsage()`
558:  @*/
559: PetscErrorCode PetscMallocGetMaximumUsage(PetscLogDouble *space)
560: {
561:   PetscFunctionBegin;
562:   *space = (PetscLogDouble)TRMaxMem;
563:   PetscFunctionReturn(PETSC_SUCCESS);
564: }

566: /*@
567:   PetscMallocPushMaximumUsage - Adds another event to collect the maximum memory usage over an event

569:   Not Collective

571:   Input Parameter:
572: . event - an event id; this is just for error checking

574:   Level: developer

576:   Note:
577:   This only does anything if `PetscMemorySetGetMaximumUsage()`, `-memory_view`, or `-log_view_memory` have been used

579: .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocGetMaximumUsage()`, `PetscMemoryGetCurrentUsage()`, `PetscMalloc()`, `PetscFree()`,
580:           `PetscMallocPopMaximumUsage()`
581:  @*/
582: PetscErrorCode PetscMallocPushMaximumUsage(int event)
583: {
584:   PetscFunctionBegin;
585:   if (event < 0 || ++NumTRMaxMems > MAXTRMAXMEMS) PetscFunctionReturn(PETSC_SUCCESS);
586:   TRMaxMems[NumTRMaxMems - 1]       = TRallocated;
587:   TRMaxMemsEvents[NumTRMaxMems - 1] = event;
588:   PetscFunctionReturn(PETSC_SUCCESS);
589: }

591: /*@
592:   PetscMallocPopMaximumUsage - collect the maximum memory usage over an event

594:   Not Collective

596:   Input Parameter:
597: . event - an event id; this is just for error checking

599:   Output Parameter:
600: . mu - maximum amount of memory malloced during this event; high water mark relative to the beginning of the event

602:   Level: developer

604:   Note:
605:   This only does anything if `PetscMemorySetGetMaximumUsage()`, `-memory_view`, or `-log_view_memory` have been used

607: .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocGetMaximumUsage()`, `PetscMemoryGetCurrentUsage()`, `PetscMalloc()`, `PetscFree()`,
608:           `PetscMallocPushMaximumUsage()`
609:  @*/
610: PetscErrorCode PetscMallocPopMaximumUsage(int event, PetscLogDouble *mu)
611: {
612:   PetscFunctionBegin;
613:   *mu = 0;
614:   if (event < 0 || NumTRMaxMems-- > MAXTRMAXMEMS) PetscFunctionReturn(PETSC_SUCCESS);
615:   PetscCheck(TRMaxMemsEvents[NumTRMaxMems] == event, PETSC_COMM_SELF, PETSC_ERR_MEMC, "PetscMallocPush/PopMaximumUsage() are not nested");
616:   *mu = (PetscLogDouble)TRMaxMems[NumTRMaxMems];
617:   PetscFunctionReturn(PETSC_SUCCESS);
618: }

620: /*@
621:   PetscMallocGetStack - returns a pointer to the stack for the location in the program a call to `PetscMalloc()` was used to obtain that memory

623:   Not Collective, No Fortran Support

625:   Input Parameter:
626: . ptr - the memory location

628:   Output Parameter:
629: . stack - the stack indicating where the program allocated this memory, or `NULL` if unavailable

631:   Level: intermediate

633:   Note:
634:   This only does anything if `-malloc_debug` (or `-malloc_test` if PETSc was configured with debugging) has been used

636: .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
637: @*/
638: PetscErrorCode PetscMallocGetStack(void *ptr, PetscStack **stack)
639: {
640: #if PetscDefined(USE_DEBUG)
641:   TRSPACE *head;

643:   PetscFunctionBegin;
644:   *stack = NULL;
645:   if (PetscTrMalloc != PetscTrMallocDefault) PetscFunctionReturn(PETSC_SUCCESS);
646:   head   = (TRSPACE *)((char *)ptr - HEADER_BYTES);
647:   *stack = &head->stack;
648:   PetscFunctionReturn(PETSC_SUCCESS);
649: #else
650:   *stack = NULL;
651:   return PETSC_SUCCESS;
652: #endif
653: }

655: /*@
656:   PetscMallocDump - Dumps the currently allocated memory blocks to a file. The information
657:   printed is: size of space (in bytes), address of space, id of space,
658:   file in which space was allocated, and line number at which it was
659:   allocated.

661:   Not Collective

663:   Input Parameter:
664: . fp - file pointer.  If `fp` is `NULL`, `stdout` is assumed.

666:   Options Database Key:
667: . -malloc_dump [filename] - Print summary of unfreed memory during call to `PetscFinalize()`, writing to `filename` if given otherwise `stdout`

669:   Level: intermediate

671:   Notes:
672:   Uses `MPI_COMM_WORLD` to display the MPI rank, because this may be called in `PetscFinalize()` after `PETSC_COMM_WORLD` has been freed.

674:   When called in `PetscFinalize()` dumps only the allocations that have not been properly freed

676:   `PetscMallocView()` prints a list of all memory ever allocated

678:   This only does anything if `-malloc_debug` (or `-malloc_test` if PETSc was configured with debugging) has been used

680:   Fortran Notes:
681:   The calling sequence is `PetscMallocDump`(PetscErrorCode ierr). A `fp` parameter is not supported.

683:   Developer Notes:
684:   This should be absorbed into `PetscMallocView()`

686: .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocView()`, `PetscMallocViewSet()`, `PetscMallocValidate()`, `PetscMalloc()`, `PetscFree()`
687: @*/
688: PetscErrorCode PetscMallocDump(FILE *fp)
689: {
690:   TRSPACE    *head;
691:   size_t      libAlloc = 0;
692:   PetscMPIInt rank;

694:   PetscFunctionBegin;
695:   PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
696:   if (!fp) fp = PETSC_STDOUT;
697:   head = TRhead;
698:   while (head) {
699:     libAlloc += TRrequestedSize ? head->rsize : head->size;
700:     head = head->next;
701:   }
702:   if (TRallocated - libAlloc > 0) fprintf(fp, "[%d]Total space allocated %.0f bytes\n", rank, (PetscLogDouble)TRallocated);
703:   head = TRhead;
704:   while (head) {
705:     PetscBool isLib;

707:     PetscCall(PetscStrcmp(head->functionname, "PetscDLLibraryOpen", &isLib));
708:     if (!isLib) {
709: #if PetscDefined(USE_DEBUG)
710:       fprintf(fp, "[%2d] %.0f bytes\n", rank, (PetscLogDouble)(TRrequestedSize ? head->rsize : head->size));
711:       PetscCall(PetscStackPrint(&head->stack, fp));
712: #else
713:       fprintf(fp, "[%2d] %.0f bytes %s() at %s:%d\n", rank, (PetscLogDouble)(TRrequestedSize ? head->rsize : head->size), head->functionname, head->filename, head->lineno);
714: #endif
715:     }
716:     head = head->next;
717:   }
718:   PetscFunctionReturn(PETSC_SUCCESS);
719: }

721: /*@
722:   PetscMallocViewSet - Activates logging of all calls to `PetscMalloc()` with a minimum size to view

724:   Not Collective

726:   Input Parameter:
727: . logmin - minimum allocation size to log, or `PETSC_DEFAULT` to log all memory allocations

729:   Options Database Keys:
730: + -malloc_view [filename]       - Activates `PetscMallocView()` in `PetscFinalize()`
731: . -malloc_view_threshold logmin - Sets a minimum size if `-malloc_view` is used
732: - -log_view_memory (true|false) - View the memory usage also with the `-log_view` option

734:   Level: advanced

736:   Note:
737:   Must be called after `PetscMallocSetDebug()`

739:   Developer Notes:
740:   Uses `MPI_COMM_WORLD` to determine rank because PETSc communicators may not be available

742: .seealso: `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocTraceSet()`, `PetscMallocValidate()`, `PetscMalloc()`, `PetscFree()`
743: @*/
744: PetscErrorCode PetscMallocViewSet(PetscLogDouble logmin)
745: {
746:   PetscFunctionBegin;
747:   PetscLogMalloc = 0;
748:   PetscCall(PetscMemorySetGetMaximumUsage());
749:   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
750:   PetscLogMallocThreshold = (size_t)logmin;
751:   PetscFunctionReturn(PETSC_SUCCESS);
752: }

754: /*@
755:   PetscMallocViewGet - Determine whether calls to `PetscMalloc()` are being logged

757:   Not Collective

759:   Output Parameter:
760: . logging - `PETSC_TRUE` if logging is active

762:   Level: advanced

764: .seealso: `PetscMallocViewSet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocTraceGet()`, `PetscMalloc()`, `PetscFree()`
765: @*/
766: PetscErrorCode PetscMallocViewGet(PetscBool *logging)
767: {
768:   PetscFunctionBegin;
769:   *logging = (PetscBool)(PetscLogMalloc >= 0);
770:   PetscFunctionReturn(PETSC_SUCCESS);
771: }

773: /*@
774:   PetscMallocTraceSet - Trace all calls to `PetscMalloc()`. That is print each `PetscMalloc()` and `PetscFree()` call to a viewer.

776:   Not Collective

778:   Input Parameters:
779: + viewer - The viewer to use for tracing, or `NULL` to use `PETSC_VIEWER_STDOUT_SELF`
780: . active - Flag to activate or deactivate tracing
781: - logmin - The smallest memory size that will be logged

783:   Level: advanced

785:   Note:
786:   The viewer should not be collective.

788:   This only does anything if `-malloc_debug` (or `-malloc_test` if PETSc was configured with debugging) has been used

790: .seealso: `PetscMallocTraceGet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
791: @*/
792: PetscErrorCode PetscMallocTraceSet(PetscViewer viewer, PetscBool active, PetscLogDouble logmin)
793: {
794:   PetscFunctionBegin;
795:   if (!active) {
796:     PetscLogMallocTrace = -1;
797:     PetscFunctionReturn(PETSC_SUCCESS);
798:   }
799:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
801:   PetscLogMallocTraceViewer = viewer;
802:   PetscLogMallocTrace       = 0;
803:   PetscCall(PetscMemorySetGetMaximumUsage());
804:   if (logmin < 0) logmin = 0.0; /* PETSC_DEFAULT or PETSC_DECIDE */
805:   PetscLogMallocTraceThreshold = (size_t)logmin;
806:   PetscFunctionReturn(PETSC_SUCCESS);
807: }

809: /*@
810:   PetscMallocTraceGet - Determine whether all calls to `PetscMalloc()` are being traced

812:   Not Collective

814:   Output Parameter:
815: . logging - `PETSC_TRUE` if logging is active

817:   Level: advanced

819:   This only does anything if `-malloc_debug` (or `-malloc_test` if PETSc was configured with debugging) has been used

821: .seealso: `PetscMallocTraceSet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
822: @*/
823: PetscErrorCode PetscMallocTraceGet(PetscBool *logging)
824: {
825:   PetscFunctionBegin;
826:   *logging = (PetscBool)(PetscLogMallocTrace >= 0);
827:   PetscFunctionReturn(PETSC_SUCCESS);
828: }

830: /*@
831:   PetscMallocView - Saves the log of all calls to `PetscMalloc()`; also calls `PetscMemoryGetMaximumUsage()`

833:   Not Collective

835:   Input Parameter:
836: . fp - file pointer; or `NULL`

838:   Options Database Key:
839: . -malloc_view [filename] - Activates `PetscMallocView()` in `PetscFinalize()`

841:   Level: advanced

843:   Notes:
844:   `PetscMallocDump()` dumps only the currently unfreed memory, this routine dumps all memory ever allocated

846:   `PetscMemoryView()` gives a brief summary of current memory usage

848:   Fortran Notes:
849:   The calling sequence in Fortran is `PetscMallocView`(integer ierr) and can only write to `stdout`

851: .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocDump()`, `PetscMallocViewSet()`, `PetscMemoryView()`, `PetscMalloc()`, `PetscFree()`
852: @*/
853: PetscErrorCode PetscMallocView(FILE *fp)
854: {
855:   PetscInt       n, *perm;
856:   size_t        *shortlength;
857:   int           *shortcount;
858:   PetscMPIInt    rank;
859:   PetscBool      match;
860:   const char   **shortfunction;
861:   PetscLogDouble rss;

863:   PetscFunctionBegin;
864:   PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
865:   PetscCall(PetscFFlush(fp));

867:   PetscCheck(PetscLogMalloc >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscMallocView() called without call to PetscMallocViewSet() this is often due to setting the option -malloc_view AFTER PetscInitialize() with PetscOptionsInsert() or PetscOptionsInsertFile()");

869:   if (!fp) fp = PETSC_STDOUT;
870:   PetscCall(PetscMemoryGetMaximumUsage(&rss));
871:   if (rss) {
872:     (void)fprintf(fp, "[%d] Maximum memory PetscMalloc()ed %.0f maximum size of entire process %.0f\n", rank, (PetscLogDouble)TRMaxMem, rss);
873:   } else {
874:     (void)fprintf(fp, "[%d] Maximum memory PetscMalloc()ed %.0f OS cannot compute size of entire process\n", rank, (PetscLogDouble)TRMaxMem);
875:   }
876:   if (PetscLogMalloc > 0) {
877:     shortcount = (int *)malloc(PetscLogMalloc * sizeof(int));
878:     PetscCheck(shortcount, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
879:     shortlength = (size_t *)malloc(PetscLogMalloc * sizeof(size_t));
880:     PetscCheck(shortlength, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
881:     shortfunction = (const char **)malloc(PetscLogMalloc * sizeof(char *));
882:     PetscCheck(shortfunction, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
883:     n = 0;
884:     for (PetscInt i = 0; i < PetscLogMalloc; i++) {
885:       for (PetscInt j = 0; j < n; j++) {
886:         PetscCall(PetscStrcmp(shortfunction[j], PetscLogMallocFunction[i], &match));
887:         if (match) {
888:           shortlength[j] += PetscLogMallocLength[i];
889:           shortcount[j]++;
890:           goto foundit;
891:         }
892:       }
893:       shortfunction[n] = PetscLogMallocFunction[i];
894:       shortlength[n]   = PetscLogMallocLength[i];
895:       shortcount[n]    = 1;
896:       n++;
897:     foundit:;
898:     }

900:     perm = (PetscInt *)malloc(n * sizeof(PetscInt));
901:     PetscCheck(perm, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
902:     for (PetscInt i = 0; i < n; i++) perm[i] = i;
903:     PetscCall(PetscSortStrWithPermutation(n, shortfunction, perm));

905:     (void)fprintf(fp, "[%d] Memory usage sorted by function\n", rank);
906:     for (PetscInt i = 0; i < n; i++) (void)fprintf(fp, "[%d] %d %.0f %s()\n", rank, shortcount[perm[i]], (PetscLogDouble)shortlength[perm[i]], shortfunction[perm[i]]);
907:     free(perm);
908:     free(shortlength);
909:     free(shortcount);
910:     free((char **)shortfunction);
911:   }
912:   PetscCall(PetscFFlush(fp));
913:   PetscFunctionReturn(PETSC_SUCCESS);
914: }

916: /*@
917:   PetscMallocSetDebug - Set's PETSc memory debugging

919:   Not Collective

921:   Input Parameters:
922: + eachcall      - checks the entire heap of allocated memory for issues on each call to `PetscMalloc()` and `PetscFree()`, slow
923: - initializenan - initializes all memory with `NaN` to catch use of uninitialized floating point arrays

925:   Options Database Keys:
926: + -malloc_debug (true|false)    - turns on or off debugging
927: . -malloc_test                  - turns on all debugging if PETSc was configured with debugging including `-malloc_dump`, otherwise ignored
928: . -malloc_view_threshold logmin - log only allocations larger than `logmin`
929: - -malloc_dump [filename]       - print a list of all memory that has not been freed, in `PetscFinalize()`

931:   Level: developer

933:   Note:
934:   This is called in `PetscInitialize()` and should not be called elsewhere

936: .seealso: `CHKMEMQ`, `PetscMallocValidate()`, `PetscMallocGetDebug()`, `PetscMalloc()`, `PetscFree()`
937: @*/
938: PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan)
939: {
940:   PetscFunctionBegin;
941:   PetscCheck(PetscTrMalloc != PetscTrMallocDefault, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call this routine more than once, it can only be called in PetscInitialize()");
942:   PetscCall(PetscMallocSet(PetscTrMallocDefault, PetscTrFreeDefault, PetscTrReallocDefault));

944:   TRallocated           = 0;
945:   TRhead                = NULL;
946:   TRid                  = 0;
947:   TRdebug               = eachcall;
948:   TRMaxMem              = 0;
949:   PetscLogMallocMax     = 10000;
950:   PetscLogMalloc        = -1;
951:   TRdebugIinitializenan = initializenan;
952:   PetscFunctionReturn(PETSC_SUCCESS);
953: }

955: /*@
956:   PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.

958:   Not Collective

960:   Output Parameters:
961: + basic         - doing basic debugging
962: . eachcall      - checks the entire memory heap at each `PetscMalloc()`/`PetscFree()`
963: - initializenan - initializes memory with `NaN`

965:   Level: intermediate

967:   Note:
968:   By default, the debug configuration of PETSc always does some debugging unless you run with `-malloc_debug no`

970: .seealso: `CHKMEMQ`, `PetscMallocValidate()`, `PetscMallocSetDebug()`, `PetscMalloc()`, `PetscFree()`
971: @*/
972: PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan)
973: {
974:   PetscFunctionBegin;
975:   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
976:   if (eachcall) *eachcall = TRdebug;
977:   if (initializenan) *initializenan = TRdebugIinitializenan;
978:   PetscFunctionReturn(PETSC_SUCCESS);
979: }

981: /*@
982:   PetscMallocLogRequestedSizeSet - Whether to log the requested or aligned memory size

984:   Not Collective

986:   Input Parameter:
987: . flg - `PETSC_TRUE` to log the requested memory size

989:   Options Database Key:
990: . -malloc_requested_size (true|false) - Sets this flag

992:   Level: developer

994: .seealso: `PetscMallocLogRequestedSizeGet()`, `PetscMallocViewSet()`, `PetscMalloc()`, `PetscFree()`
995: @*/
996: PetscErrorCode PetscMallocLogRequestedSizeSet(PetscBool flg)
997: {
998:   PetscFunctionBegin;
999:   TRrequestedSize = flg;
1000:   PetscFunctionReturn(PETSC_SUCCESS);
1001: }

1003: /*@
1004:   PetscMallocLogRequestedSizeGet - Whether to log the requested or aligned memory size

1006:   Not Collective

1008:   Output Parameter:
1009: . flg - `PETSC_TRUE` if we log the requested memory size

1011:   Level: developer

1013: .seealso: `PetscMallocLogRequestedSizeSet()`, `PetscMallocViewSet()`, `PetscMalloc()`, `PetscFree()`
1014: @*/
1015: PetscErrorCode PetscMallocLogRequestedSizeGet(PetscBool *flg)
1016: {
1017:   PetscFunctionBegin;
1018:   *flg = TRrequestedSize;
1019:   PetscFunctionReturn(PETSC_SUCCESS);
1020: }