Actual source code: mtr.c

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

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

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

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

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

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

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

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

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

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

 82:   Level: advanced

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

 87:   Error messages are written to `stdout`.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

438:   Collective

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

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

449:   Level: intermediate

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

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

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

521:   Not Collective

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

526:   Level: intermediate

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

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

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

545:   Not Collective

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

550:   Level: intermediate

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

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

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

568:   Not Collective

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

573:   Level: developer

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

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

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

593:   Not Collective

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

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

601:   Level: developer

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

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

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

622:   Not Collective, No Fortran Support

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

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

630:   Level: intermediate

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

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

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

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

660:   Not Collective

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

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

668:   Level: intermediate

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

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

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

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

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

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

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

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

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

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

723:   Not Collective

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

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

733:   Level: advanced

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

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

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

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

756:   Not Collective

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

761:   Level: advanced

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

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

775:   Not Collective

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

782:   Level: advanced

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

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

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

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

811:   Not Collective

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

816:   Level: advanced

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

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

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

832:   Not Collective

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

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

840:   Level: advanced

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

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

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

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

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

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

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

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

904:     (void)fprintf(fp, "[%d] Memory usage sorted by function\n", rank);
905:     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]]);
906:     free(perm);
907:     free(shortlength);
908:     free(shortcount);
909:     free((char **)shortfunction);
910:   }
911:   PetscCall(PetscFFlush(fp));
912:   PetscFunctionReturn(PETSC_SUCCESS);
913: }

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

918:   Not Collective

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

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

930:   Level: developer

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

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

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

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

957:   Not Collective

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

964:   Level: intermediate

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

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

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

983:   Not Collective

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

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

991:   Level: developer

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

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

1005:   Not Collective

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

1010:   Level: developer

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