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 defined(PETSC_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 CLASSID_VALUE ((PetscClassId)0xf0e0d0c9)
 18: #define ALREADY_FREED ((PetscClassId)0x0f0e0d9c)

 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:   PetscClassId classid;
 28: #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
 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 int       TRfrags               = 0;
 51: static TRSPACE  *TRhead                = NULL;
 52: static int       TRid                  = 0;
 53: static PetscBool TRdebug               = PETSC_FALSE;
 54: static PetscBool TRdebugIinitializenan = PETSC_FALSE;
 55: static PetscBool TRrequestedSize       = PETSC_FALSE;
 56: static size_t    TRMaxMem              = 0;
 57: static int       NumTRMaxMems          = 0;
 58: static size_t    TRMaxMems[MAXTRMAXMEMS];
 59: static int       TRMaxMemsEvents[MAXTRMAXMEMS];
 60: /*
 61:       Arrays to log information on mallocs for PetscMallocView()
 62: */
 63: static int          PetscLogMallocMax       = 10000;
 64: static int          PetscLogMalloc          = -1;
 65: static size_t       PetscLogMallocThreshold = 0;
 66: static size_t      *PetscLogMallocLength;
 67: static const char **PetscLogMallocFile, **PetscLogMallocFunction;
 68: static int          PetscLogMallocTrace          = -1;
 69: static size_t       PetscLogMallocTraceThreshold = 0;
 70: static PetscViewer  PetscLogMallocTraceViewer    = NULL;

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

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

 80:   Options Database Keys:
 81: + -malloc_test  - turns this feature on when PETSc was not configured with `--with-debugging=0`
 82: - -malloc_debug - turns this feature on anytime

 84:   Level: advanced

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

 89:   Error messages are written to `stdout`.

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

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

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

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

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

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

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

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

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

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

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

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

189:   head->filename                  = filename;
190:   head->functionname              = function;
191:   head->classid                   = CLASSID_VALUE;
192:   *(PetscClassId *)(inew + nsize) = CLASSID_VALUE;

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

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

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

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

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

247: /*
248:    PetscTrFreeDefault - Free with logging and error checking

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

259:   PetscFunctionBegin;
260:   if (!a) PetscFunctionReturn(PETSC_SUCCESS);

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

264:   ahead = a;
265:   a     = a - sizeof(TrSPACE);
266:   head  = (TRSPACE *)a;

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

313:   if (head->next) head->next->prev = head->prev;
314:   PetscCall(PetscFreeAlign(a, lineno, function, filename));
315:   PetscFunctionReturn(PETSC_SUCCESS);
316: }

318: /*
319:   PetscTrReallocDefault - Realloc with logging and error checking

321: */
322: static PetscErrorCode PetscTrReallocDefault(size_t len, int lineno, const char function[], const char filename[], void **result)
323: {
324:   char         *a = (char *)*result;
325:   TRSPACE      *head;
326:   char         *ahead, *inew;
327:   PetscClassId *nend;
328:   size_t        nsize;

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

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

345:   ahead = a;
346:   a     = a - sizeof(TrSPACE);
347:   head  = (TRSPACE *)a;
348:   inew  = a;

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

377:   /* remove original reference to the memory allocated from the PETSc debugging heap */
378:   TRallocated -= TRrequestedSize ? head->rsize : head->size;
379:   TRfrags--;
380:   if (head->prev) head->prev->next = head->next;
381:   else TRhead = head->next;
382:   if (head->next) head->next->prev = head->prev;

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

387:   head = (TRSPACE *)inew;
388:   inew += sizeof(TrSPACE);

390:   if (TRhead) TRhead->prev = head;
391:   head->next   = TRhead;
392:   TRhead       = head;
393:   head->prev   = NULL;
394:   head->size   = nsize;
395:   head->rsize  = len;
396:   head->id     = TRid++;
397:   head->lineno = lineno;

399:   head->filename                  = filename;
400:   head->functionname              = function;
401:   head->classid                   = CLASSID_VALUE;
402:   *(PetscClassId *)(inew + nsize) = CLASSID_VALUE;

404:   TRallocated += TRrequestedSize ? head->rsize : head->size;
405:   if (TRallocated > TRMaxMem) TRMaxMem = TRallocated;
406:   if (PetscLogMemory) {
407:     for (PetscInt i = 0; i < NumTRMaxMems; i++) {
408:       if (TRallocated > TRMaxMems[i]) TRMaxMems[i] = TRallocated;
409:     }
410:   }
411:   TRfrags++;

413: #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
414:   PetscCall(PetscStackCopy(&petscstack, &head->stack));
415:   /* fix the line number to where the malloc() was called, not the PetscFunctionBegin; */
416:   head->stack.line[PetscMax(head->stack.currentsize - 2, 0)] = lineno;
417: #endif

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

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

431:       PetscLogMallocFunction = (const char **)malloc(PetscLogMallocMax * sizeof(char *));
432:       PetscCheck(PetscLogMallocFunction, PETSC_COMM_SELF, PETSC_ERR_MEM, " ");
433:     }
434:     PetscLogMallocLength[PetscLogMalloc]     = nsize;
435:     PetscLogMallocFile[PetscLogMalloc]       = filename;
436:     PetscLogMallocFunction[PetscLogMalloc++] = function;
437:   }
438:   *result = (void *)inew;
439:   PetscFunctionReturn(PETSC_SUCCESS);
440: }

442: /*@C
443:   PetscMemoryView - Shows the amount of memory currently being used in a communicator.

445:   Collective

447:   Input Parameters:
448: + viewer  - the viewer to output the information on
449: - message - string printed before values

451:   Options Database Keys:
452: + -malloc_debug    - have PETSc track how much memory it has allocated
453: . -log_view_memory - print memory usage per event when `-log_view` is used
454: - -memory_view     - during `PetscFinalize()` have this routine called

456:   Level: intermediate

458: .seealso: `PetscMallocDump()`, `PetscMemoryGetCurrentUsage()`, `PetscMemorySetGetMaximumUsage()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
459:  @*/
460: PetscErrorCode PetscMemoryView(PetscViewer viewer, const char message[])
461: {
462:   PetscLogDouble allocated, allocatedmax, resident, residentmax, gallocated, gallocatedmax, gresident, gresidentmax, maxgallocated, maxgallocatedmax;
463:   PetscLogDouble mingallocated, mingallocatedmax, mingresident, mingresidentmax, maxgresident, maxgresidentmax;
464:   MPI_Comm       comm;

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

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

528:   Not Collective

530:   Output Parameter:
531: . space - number of bytes currently allocated

533:   Level: intermediate

535:   Note:
536:   This only works if `-memory_view` or `-log_view_memory` have been used

538: .seealso: `PetscMallocDump()`, `PetscMallocGetMaximumUsage()`, `PetscMemoryGetCurrentUsage()`, `PetscMalloc()`, `PetscFree()`,
539:           `PetscMemoryGetMaximumUsage()`
540:  @*/
541: PetscErrorCode PetscMallocGetCurrentUsage(PetscLogDouble *space)
542: {
543:   PetscFunctionBegin;
544:   *space = (PetscLogDouble)TRallocated;
545:   PetscFunctionReturn(PETSC_SUCCESS);
546: }

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

552:   Not Collective

554:   Output Parameter:
555: . space - maximum number of bytes ever allocated at one time

557:   Level: intermediate

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

562: .seealso: `PetscMallocDump()`, `PetscMallocView()`, `PetscMemoryGetCurrentUsage()`, `PetscMalloc()`, `PetscFree()`,
563:           `PetscMallocPushMaximumUsage()`
564:  @*/
565: PetscErrorCode PetscMallocGetMaximumUsage(PetscLogDouble *space)
566: {
567:   PetscFunctionBegin;
568:   *space = (PetscLogDouble)TRMaxMem;
569:   PetscFunctionReturn(PETSC_SUCCESS);
570: }

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

575:   Not Collective

577:   Input Parameter:
578: . event - an event id; this is just for error checking

580:   Level: developer

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

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

597: /*@
598:   PetscMallocPopMaximumUsage - collect the maximum memory usage over an event

600:   Not Collective

602:   Input Parameter:
603: . event - an event id; this is just for error checking

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

608:   Level: developer

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

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

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

629:   Not Collective

631:   Input Parameter:
632: . ptr - the memory location

634:   Output Parameter:
635: . stack - the stack indicating where the program allocated this memory

637:   Level: intermediate

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

642: .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
643: @*/
644: PetscErrorCode PetscMallocGetStack(void *ptr, PetscStack **stack)
645: {
646: #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
647:   TRSPACE *head;

649:   PetscFunctionBegin;
650:   head   = (TRSPACE *)(((char *)ptr) - HEADER_BYTES);
651:   *stack = &head->stack;
652:   PetscFunctionReturn(PETSC_SUCCESS);
653: #else
654:   *stack = NULL;
655:   return PETSC_SUCCESS;
656: #endif
657: }

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

665:   Not Collective

667:   Input Parameter:
668: . fp - file pointer.  If `fp` is `NULL`, `stdout` is assumed.

670:   Options Database Key:
671: . -malloc_dump <optional filename> - Print summary of unfreed memory during call to `PetscFinalize()`, writing to filename if given

673:   Level: intermediate

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

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

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

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

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

687:   Developer Notes:
688:   This should be absorbed into `PetscMallocView()`

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

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

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

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

728:   Not Collective

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

733:   Options Database Keys:
734: + -malloc_view <optional filename> - Activates `PetscMallocView()` in `PetscFinalize()`
735: . -malloc_view_threshold <min>     - Sets a minimum size if `-malloc_view` is used
736: - -log_view_memory                 - view the memory usage also with the -log_view option

738:   Level: advanced

740:   Note:
741:   Must be called after `PetscMallocSetDebug()`

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

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

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

761:   Not Collective

763:   Output Parameter:
764: . logging - `PETSC_TRUE` if logging is active

766:   Options Database Key:
767: . -malloc_view <optional filename> - Activates `PetscMallocView()`

769:   Level: advanced

771: .seealso: `PetscMallocViewSet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMallocTraceGet()`, `PetscMalloc()`, `PetscFree()`
772: @*/
773: PetscErrorCode PetscMallocViewGet(PetscBool *logging)
774: {
775:   PetscFunctionBegin;
776:   *logging = (PetscBool)(PetscLogMalloc >= 0);
777:   PetscFunctionReturn(PETSC_SUCCESS);
778: }

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

783:   Not Collective

785:   Input Parameters:
786: + viewer - The viewer to use for tracing, or `NULL` to use `PETSC_VIEWER_STDOUT_SELF`
787: . active - Flag to activate or deactivate tracing
788: - logmin - The smallest memory size that will be logged

790:   Level: advanced

792:   Note:
793:   The viewer should not be collective.

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

797: .seealso: `PetscMallocTraceGet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
798: @*/
799: PetscErrorCode PetscMallocTraceSet(PetscViewer viewer, PetscBool active, PetscLogDouble logmin)
800: {
801:   PetscFunctionBegin;
802:   if (!active) {
803:     PetscLogMallocTrace = -1;
804:     PetscFunctionReturn(PETSC_SUCCESS);
805:   }
806:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_SELF;
808:   PetscLogMallocTraceViewer = 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: }

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

819:   Not Collective

821:   Output Parameter:
822: . logging - `PETSC_TRUE` if logging is active

824:   Options Database Key:
825: . -malloc_view <optional filename> - Activates `PetscMallocView()`

827:   Level: advanced

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

831: .seealso: `PetscMallocTraceSet()`, `PetscMallocViewGet()`, `PetscMallocDump()`, `PetscMallocView()`, `PetscMalloc()`, `PetscFree()`
832: @*/
833: PetscErrorCode PetscMallocTraceGet(PetscBool *logging)
834: {
835:   PetscFunctionBegin;
836:   *logging = (PetscBool)(PetscLogMallocTrace >= 0);
837:   PetscFunctionReturn(PETSC_SUCCESS);
838: }

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

843:   Not Collective

845:   Input Parameter:
846: . fp - file pointer; or `NULL`

848:   Options Database Key:
849: . -malloc_view <optional filename> - Activates `PetscMallocView()` in `PetscFinalize()`

851:   Level: advanced

853:   Notes:
854:   `PetscMallocDump()` dumps only the currently unfreed memory, this dumps all memory ever allocated

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

858:   Fortran Notes:
859:   The calling sequence in Fortran is `PetscMallocView`(integer ierr)

861: .seealso: `PetscMallocGetCurrentUsage()`, `PetscMallocDump()`, `PetscMallocViewSet()`, `PetscMemoryView()`, `PetscMalloc()`, `PetscFree()`
862: @*/
863: PetscErrorCode PetscMallocView(FILE *fp)
864: {
865:   PetscInt       n, *perm;
866:   size_t        *shortlength;
867:   int           *shortcount;
868:   PetscMPIInt    rank;
869:   PetscBool      match;
870:   const char   **shortfunction;
871:   PetscLogDouble rss;

873:   PetscFunctionBegin;
874:   PetscCallMPI(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
875:   PetscCall(PetscFFlush(fp));

877:   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()");

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:     n = 0;
894:     for (PetscInt i = 0; i < PetscLogMalloc; i++) {
895:       for (PetscInt j = 0; j < n; j++) {
896:         PetscCall(PetscStrcmp(shortfunction[j], PetscLogMallocFunction[i], &match));
897:         if (match) {
898:           shortlength[j] += PetscLogMallocLength[i];
899:           shortcount[j]++;
900:           goto foundit;
901:         }
902:       }
903:       shortfunction[n] = PetscLogMallocFunction[i];
904:       shortlength[n]   = PetscLogMallocLength[i];
905:       shortcount[n]    = 1;
906:       n++;
907:     foundit:;
908:     }

910:     perm = (PetscInt *)malloc(n * sizeof(PetscInt));
911:     PetscCheck(perm, PETSC_COMM_SELF, PETSC_ERR_MEM, "Out of memory");
912:     for (PetscInt i = 0; i < n; i++) perm[i] = i;
913:     PetscCall(PetscSortStrWithPermutation(n, (const char **)shortfunction, perm));

915:     (void)fprintf(fp, "[%d] Memory usage sorted by function\n", rank);
916:     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]]);
917:     free(perm);
918:     free(shortlength);
919:     free(shortcount);
920:     free((char **)shortfunction);
921:   }
922:   PetscCall(PetscFFlush(fp));
923:   PetscFunctionReturn(PETSC_SUCCESS);
924: }

926: /*@
927:   PetscMallocSetDebug - Set's PETSc memory debugging

929:   Not Collective

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

935:   Options Database Keys:
936: + -malloc_debug <true or false> - turns on or off debugging
937: . -malloc_test                  - turns on all debugging if PETSc was configured with debugging including `-malloc_dump`, otherwise ignored
938: . -malloc_view_threshold t      - log only allocations larger than t
939: - -malloc_dump <filename>       - print a list of all memory that has not been freed, in `PetscFinalize()`

941:   Level: developer

943:   Note:
944:   This is called in `PetscInitialize()` and should not be called elsewhere

946: .seealso: `CHKMEMQ`, `PetscMallocValidate()`, `PetscMallocGetDebug()`, `PetscMalloc()`, `PetscFree()`
947: @*/
948: PetscErrorCode PetscMallocSetDebug(PetscBool eachcall, PetscBool initializenan)
949: {
950:   PetscFunctionBegin;
951:   PetscCheck(PetscTrMalloc != PetscTrMallocDefault, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cannot call this routine more than once, it can only be called in PetscInitialize()");
952:   PetscCall(PetscMallocSet(PetscTrMallocDefault, PetscTrFreeDefault, PetscTrReallocDefault));

954:   TRallocated           = 0;
955:   TRfrags               = 0;
956:   TRhead                = NULL;
957:   TRid                  = 0;
958:   TRdebug               = eachcall;
959:   TRMaxMem              = 0;
960:   PetscLogMallocMax     = 10000;
961:   PetscLogMalloc        = -1;
962:   TRdebugIinitializenan = initializenan;
963:   PetscFunctionReturn(PETSC_SUCCESS);
964: }

966: /*@
967:   PetscMallocGetDebug - Indicates what PETSc memory debugging it is doing.

969:   Not Collective

971:   Output Parameters:
972: + basic         - doing basic debugging
973: . eachcall      - checks the entire memory heap at each `PetscMalloc()`/`PetscFree()`
974: - initializenan - initializes memory with `NaN`

976:   Level: intermediate

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

981: .seealso: `CHKMEMQ`, `PetscMallocValidate()`, `PetscMallocSetDebug()`, `PetscMalloc()`, `PetscFree()`
982: @*/
983: PetscErrorCode PetscMallocGetDebug(PetscBool *basic, PetscBool *eachcall, PetscBool *initializenan)
984: {
985:   PetscFunctionBegin;
986:   if (basic) *basic = (PetscTrMalloc == PetscTrMallocDefault) ? PETSC_TRUE : PETSC_FALSE;
987:   if (eachcall) *eachcall = TRdebug;
988:   if (initializenan) *initializenan = TRdebugIinitializenan;
989:   PetscFunctionReturn(PETSC_SUCCESS);
990: }

992: /*@
993:   PetscMallocLogRequestedSizeSet - Whether to log the requested or aligned memory size

995:   Not Collective

997:   Input Parameter:
998: . flg - `PETSC_TRUE` to log the requested memory size

1000:   Options Database Key:
1001: . -malloc_requested_size <bool> - Sets this flag

1003:   Level: developer

1005: .seealso: `PetscMallocLogRequestedSizeGet()`, `PetscMallocViewSet()`, `PetscMalloc()`, `PetscFree()`
1006: @*/
1007: PetscErrorCode PetscMallocLogRequestedSizeSet(PetscBool flg)
1008: {
1009:   PetscFunctionBegin;
1010:   TRrequestedSize = flg;
1011:   PetscFunctionReturn(PETSC_SUCCESS);
1012: }

1014: /*@
1015:   PetscMallocLogRequestedSizeGet - Whether to log the requested or aligned memory size

1017:   Not Collective

1019:   Output Parameter:
1020: . flg - `PETSC_TRUE` if we log the requested memory size

1022:   Level: developer

1024: .seealso: `PetscMallocLogRequestedSizeSet()`, `PetscMallocViewSet()`, `PetscMalloc()`, `PetscFree()`
1025: @*/
1026: PetscErrorCode PetscMallocLogRequestedSizeGet(PetscBool *flg)
1027: {
1028:   PetscFunctionBegin;
1029:   *flg = TRrequestedSize;
1030:   PetscFunctionReturn(PETSC_SUCCESS);
1031: }