#include /*I "petscsys.h" I*/ #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY) PetscStack petscstack; #endif #if defined(PETSC_HAVE_SAWS) #include static PetscBool amsmemstack = PETSC_FALSE; /*@ PetscStackSAWsGrantAccess - Grants access of the PETSc stack frames to the SAWs publisher Collective on `PETSC_COMM_WORLD`? Level: developer Developer Notes: Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be used within those routines .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsTakeAccess()` @*/ void PetscStackSAWsGrantAccess(void) { if (amsmemstack) { /* ignore any errors from SAWs */ (void)SAWs_Unlock(); } } /*@ PetscStackSAWsTakeAccess - Takes access of the PETSc stack frames from the SAWs publisher Collective on `PETSC_COMM_WORLD`? Level: developer Developer Notes: Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be used within those routines .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsGrantAccess()` @*/ void PetscStackSAWsTakeAccess(void) { if (amsmemstack) { /* ignore any errors from SAWs */ (void)SAWs_Lock(); } } PetscErrorCode PetscStackViewSAWs(void) { PetscMPIInt rank; PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank)); if (rank) return PETSC_SUCCESS; #if PetscDefined(USE_DEBUG) PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/functions", petscstack.function, 20, SAWs_READ, SAWs_STRING)); PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/__current_size", &petscstack.currentsize, 1, SAWs_READ, SAWs_INT)); #endif amsmemstack = PETSC_TRUE; return PETSC_SUCCESS; } PetscErrorCode PetscStackSAWsViewOff(void) { PetscFunctionBegin; if (!amsmemstack) PetscFunctionReturn(PETSC_SUCCESS); PetscCallSAWs(SAWs_Delete, ("/PETSc/Stack")); amsmemstack = PETSC_FALSE; PetscFunctionReturn(PETSC_SUCCESS); } #endif /* PETSC_HAVE_SAWS */ #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY) PetscErrorCode PetscStackSetCheck(PetscBool check) { petscstack.check = check; return PETSC_SUCCESS; } PetscErrorCode PetscStackReset(void) { memset(&petscstack, 0, sizeof(petscstack)); return PETSC_SUCCESS; } // PetscClangLinter pragma disable: -fdoc-sowing-chars /* PetscStackView - Print the current (default) PETSc stack to an ASCII file Not Collective Input Parameter: . file - the file pointer, or `NULL` to use `PETSC_STDOUT` Level: developer Notes: In debug mode PETSc maintains a stack of the current function calls that can be used to help to quickly see where a problem has occurred, for example, when a signal is received. It is recommended to use the debugger if extensive information is needed to help debug the problem. The default stack is a global variable called `petscstack`. .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackPrint()`, `PetscStackSAWsGrantAccess()`, `PetscStackSAWsTakeAccess()` */ PetscErrorCode PetscStackView(FILE *file) { if (!file) file = PETSC_STDOUT; if (petscstack.currentsize < 0) { /* < 0 is absolutely a corrupted stack, but this function is usually called in an error * handler, which are not capable of recovering from errors so best we can do is print * this warning */ fprintf(file, "PetscStack is definitely corrupted with stack size %d\n", petscstack.currentsize); } else if (petscstack.currentsize == 0) { if (file == PETSC_STDOUT) { PetscCall((*PetscErrorPrintf)("No error traceback is available, the problem could be in the main program. \n")); } else { fprintf(file, "No error traceback is available, the problem could be in the main program. \n"); } } else { char *ptr = NULL; if (file == PETSC_STDOUT) { PetscCall((*PetscErrorPrintf)("The line numbers in the error traceback may not be exact.\n")); for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) { if (petscstack.file[i]) PetscCall((*PetscErrorPrintf)("#%d %s() at %s:%d\n", j, petscstack.function[i], PetscCIFilename(petscstack.file[i]), PetscCILinenumber(petscstack.line[i]))); else { PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr)); if (!ptr) PetscCall((*PetscErrorPrintf)("#%d %s()\n", j, petscstack.function[i])); else PetscCall((*PetscErrorPrintf)("#%d %s\n", j, petscstack.function[i])); } } } else { fprintf(file, "The line numbers in the error traceback are not always exact.\n"); for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) { if (petscstack.file[i]) fprintf(file, "[%d] #%d %s() at %s:%d\n", PetscGlobalRank, j, petscstack.function[i], PetscCIFilename(petscstack.file[i]), PetscCILinenumber(petscstack.line[i])); else { PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr)); if (!ptr) fprintf(file, "[%d] #%d %s()\n", PetscGlobalRank, j, petscstack.function[i]); else fprintf(file, "[%d] #%d %s\n", PetscGlobalRank, j, petscstack.function[i]); } } } } return PETSC_SUCCESS; } /* PetscStackCopy - Copy the information from one PETSc stack to another Not Collective Input Parameter: . sint - the stack to be copied from Output Parameter: . sout - the stack to be copied to, this stack must already exist Level: developer Note: In debug mode PETSc maintains a stack of the current function calls that can be used to help to quickly see where a problem has occurred, for example, when a signal is received. It is recommended to use the debugger if extensive information is needed to help debug the problem. .seealso: `PetscAttachDebugger()`, `PetscStackView()` */ PetscErrorCode PetscStackCopy(PetscStack *sint, PetscStack *sout) { if (sint) { for (int i = 0; i < sint->currentsize; ++i) { sout->function[i] = sint->function[i]; sout->file[i] = sint->file[i]; sout->line[i] = sint->line[i]; sout->petscroutine[i] = sint->petscroutine[i]; } sout->currentsize = sint->currentsize; } else { sout->currentsize = 0; } return PETSC_SUCCESS; } // PetscClangLinter pragma disable: -fdoc-sowing-chars /* PetscStackPrint - Prints a given PETSc stack to an ASCII file Not Collective Input Parameters: + sint - the PETSc stack to print - fp - the file pointer Level: developer Notes: In debug mode PETSc maintains a stack of the current function calls that can be used to help to quickly see where a problem has occurred, for example, when a signal is received. It is recommended to use the debugger if extensive information is needed to help debug the problem. The default stack is a global variable called `petscstack`. Developer Note: `PetscStackPrint()` and `PetscStackView()` should be merged into a single API. .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackView()` */ PetscErrorCode PetscStackPrint(PetscStack *sint, FILE *fp) { if (sint) { for (int i = sint->currentsize; i >= 0; --i) { if (sint->file[i]) fprintf(fp, " [%d] %s() at %s:%d\n", PetscGlobalRank, sint->function[i], PetscCIFilename(sint->file[i]), PetscCILinenumber(sint->line[i])); else fprintf(fp, " [%d] %s()\n", PetscGlobalRank, sint->function[i]); } } return PETSC_SUCCESS; } #endif /* PetscDefined(USE_DEBUG) */