Date: 2025-03-29T05:58:44+00:00

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 COOKIE_VALUE  -253701943
     18: #define ALREADY_FREED 252579228

     20: /*  this is the header put at the beginning of each PetscTrMallocDefault() for tracking allocated space and checking of allocated space heap */
     21: typedef struct _trSPACE {
     22:   size_t      size, rsize; /* Aligned size and requested size */
     23:   int         id;
     24:   int         lineno;
     25:   const char *filename;
     26:   const char *functionname;
     27:   PetscInt    specialcookie;
     28: #if 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:   PetscInt *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->specialcookie != COOKIE_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 = (PetscInt *)(a + head->size);
    130:     if (*nend != COOKIE_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(PetscInt), 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->specialcookie         = COOKIE_VALUE;
    192:   *(PetscInt *)(inew + nsize) = COOKIE_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:   PetscInt *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->specialcookie != COOKIE_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 = (PetscInt *)(ahead + head->size);
    275:   if (*nend != COOKIE_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:   PetscInt *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->specialcookie != COOKIE_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 = (PetscInt *)(ahead + head->size);
    357:   if (*nend != COOKIE_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(PetscInt), 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->specialcookie         = COOKIE_VALUE;
    402:   *(PetscInt *)(inew + nsize) = COOKIE_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 = (PetscLogDouble)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, No Fortran Support

    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, 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: }