Actual source code: pstack.c

  1: #include <petsc/private/petscimpl.h>

  3: #if defined(PETSC_USE_DEBUG) && !defined(PETSC_HAVE_THREADSAFETY)
  4: PetscStack petscstack;
  5: #endif

  7: #if defined(PETSC_HAVE_SAWS)
  8: #include <petscviewersaws.h>

 10: static PetscBool amsmemstack = PETSC_FALSE;

 12: /*@
 13:   PetscStackSAWsGrantAccess - Grants access of the PETSc stack frames to the SAWs publisher

 15:   Collective on `PETSC_COMM_WORLD`?

 17:   Level: developer

 19:   Developer Notes:
 20:   Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be
 21:   used within those routines

 23: .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsTakeAccess()`
 24: @*/
 25: void PetscStackSAWsGrantAccess(void)
 26: {
 27:   if (amsmemstack) {
 28:     /* ignore any errors from SAWs */
 29:     (void)SAWs_Unlock();
 30:   }
 31: }

 33: /*@
 34:   PetscStackSAWsTakeAccess - Takes access of the PETSc stack frames from the SAWs publisher

 36:   Collective on `PETSC_COMM_WORLD`?

 38:   Level: developer

 40:   Developer Notes:
 41:   Cannot use `PetscFunctionBegin`/`PetscFunctionReturn()` or `PetscCallSAWs()` since it may be
 42:   used within those routines

 44: .seealso: `PetscObjectSetName()`, `PetscObjectSAWsViewOff()`, `PetscObjectSAWsGrantAccess()`
 45: @*/
 46: void PetscStackSAWsTakeAccess(void)
 47: {
 48:   if (amsmemstack) {
 49:     /* ignore any errors from SAWs */
 50:     (void)SAWs_Lock();
 51:   }
 52: }

 54: /*@C
 55:   PetscStackViewSAWs - Publish PETSc's current debug call stack through the SAWs (Scientific Application Web server) so it can be inspected from a remote browser

 57:   Logically Collective on `PETSC_COMM_WORLD`

 59:   Level: developer

 61:   Note:
 62:   Only MPI rank 0 publishes; other ranks immediately return success. In non-debug builds the stack contents are not published but the call still succeeds.

 64: .seealso: `PetscStackView()`, `PetscStackSAWsViewOff()`, `PetscObjectSAWsViewOff()`
 65: @*/
 66: PetscErrorCode PetscStackViewSAWs(void)
 67: {
 68:   PetscMPIInt rank;

 70:   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
 71:   if (rank) return PETSC_SUCCESS;
 72:   #if PetscDefined(USE_DEBUG)
 73:   PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/functions", petscstack.function, 20, SAWs_READ, SAWs_STRING));
 74:   PetscCallSAWs(SAWs_Register, ("/PETSc/Stack/__current_size", &petscstack.currentsize, 1, SAWs_READ, SAWs_INT));
 75:   #endif
 76:   amsmemstack = PETSC_TRUE;
 77:   return PETSC_SUCCESS;
 78: }

 80: /*@C
 81:   PetscStackSAWsViewOff - Stop publishing the PETSc debug call stack through SAWs (Scientific Application Web server)

 83:   Logically Collective

 85:   Level: developer

 87:   Note:
 88:   No-op when `PetscStackViewSAWs()` was never called.

 90: .seealso: `PetscStackViewSAWs()`, `PetscStackView()`, `PetscObjectSAWsViewOff()`
 91: @*/
 92: PetscErrorCode PetscStackSAWsViewOff(void)
 93: {
 94:   PetscFunctionBegin;
 95:   if (!amsmemstack) PetscFunctionReturn(PETSC_SUCCESS);
 96:   PetscCallSAWs(SAWs_Delete, ("/PETSc/Stack"));
 97:   amsmemstack = PETSC_FALSE;
 98:   PetscFunctionReturn(PETSC_SUCCESS);
 99: }
100: #endif /* PETSC_HAVE_SAWS */

102: #if PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)
103: PetscErrorCode PetscStackSetCheck(PetscBool check)
104: {
105:   petscstack.check = check;
106:   return PETSC_SUCCESS;
107: }

109: PetscErrorCode PetscStackReset(void)
110: {
111:   memset(&petscstack, 0, sizeof(petscstack));
112:   return PETSC_SUCCESS;
113: }

115: // PetscClangLinter pragma disable: -fdoc-sowing-chars
116: /*@
117:   PetscStackView - Print the current (default) PETSc stack to an ASCII file

119:   Not Collective

121:   Input Parameter:
122: . file - the file pointer, or `NULL` to use `PETSC_STDERR`

124:   Level: developer

126:   Notes:
127:   In debug mode PETSc maintains a stack of the current function calls that can be used to help
128:   to quickly see where a problem has occurred, for example, when a signal is received. It is
129:   recommended to use the debugger if extensive information is needed to help debug the problem.

131:   If `file` is `PETSC_STDERR` (or `NULL`) then `PetscErrorPrintf()` is used to print the stack, otherwise `fprintf()` is used.

133:   Developer Note:
134:   The default stack is a global variable called `petscstack`.

136: .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackPrint()`, `PetscStackSAWsGrantAccess()`, `PetscStackSAWsTakeAccess()`
137: @*/
138: PetscErrorCode PetscStackView(FILE *file)
139: {
140:   if (!file) file = PETSC_STDERR;
141:   if (petscstack.currentsize < 0) {
142:     /* < 0 is absolutely a corrupted stack, but this function is usually called in an error
143:      * handler, which are not capable of recovering from errors so best we can do is print
144:      * this warning */
145:     fprintf(file, "PetscStack is definitely corrupted with stack size %d\n", petscstack.currentsize);
146:   } else if (petscstack.currentsize == 0) {
147:     if (file == PETSC_STDERR) {
148:       PetscCall((*PetscErrorPrintf)("No error traceback is available, the problem could be in the main program. \n"));
149:     } else {
150:       fprintf(file, "No error traceback is available, the problem could be in the main program. \n");
151:     }
152:   } else {
153:     char *ptr = NULL;

155:     if (file == PETSC_STDERR) {
156:       PetscCall((*PetscErrorPrintf)("The line numbers in the error traceback may not be exact.\n"));
157:       for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) {
158:         if (petscstack.file[i]) PetscCall((*PetscErrorPrintf)("#%d %s() at %s:%d\n", j, petscstack.function[i], PetscCIFilename(petscstack.file[i]), PetscCILinenumber(petscstack.line[i])));
159:         else {
160:           PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr));
161:           if (!ptr) PetscCall((*PetscErrorPrintf)("#%d %s()\n", j, petscstack.function[i]));
162:           else PetscCall((*PetscErrorPrintf)("#%d %s\n", j, petscstack.function[i]));
163:         }
164:       }
165:     } else {
166:       fprintf(file, "The line numbers in the error traceback are not always exact.\n");
167:       for (int i = petscstack.currentsize - 1, j = 1; i >= 0; --i, ++j) {
168:         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]));
169:         else {
170:           PetscCall(PetscStrstr(petscstack.function[i], " ", &ptr));
171:           if (!ptr) fprintf(file, "[%d] #%d %s()\n", PetscGlobalRank, j, petscstack.function[i]);
172:           else fprintf(file, "[%d] #%d %s\n", PetscGlobalRank, j, petscstack.function[i]);
173:         }
174:       }
175:     }
176:   }
177:   return PETSC_SUCCESS;
178: }

180: /*@
181:   PetscStackCopy - Copy the information from one PETSc stack to another

183:   Not Collective

185:   Input Parameter:
186: . sint - the stack to be copied from

188:   Output Parameter:
189: . sout - the stack to be copied to, this stack must already exist

191:   Level: developer

193:   Note:
194:   In debug mode PETSc maintains a stack of the current function calls that can be used to help
195:   to quickly see where a problem has occurred, for example, when a signal is received. It is
196:   recommended to use the debugger if extensive information is needed to help debug the problem.

198: .seealso: `PetscAttachDebugger()`, `PetscStackView()`
199: @*/
200: PetscErrorCode PetscStackCopy(PetscStack *sint, PetscStack *sout)
201: {
202:   if (sint) {
203:     for (int i = 0; i < sint->currentsize; ++i) {
204:       sout->function[i]     = sint->function[i];
205:       sout->file[i]         = sint->file[i];
206:       sout->line[i]         = sint->line[i];
207:       sout->petscroutine[i] = sint->petscroutine[i];
208:     }
209:     sout->currentsize = sint->currentsize;
210:   } else {
211:     sout->currentsize = 0;
212:   }
213:   return PETSC_SUCCESS;
214: }

216: // PetscClangLinter pragma disable: -fdoc-sowing-chars
217: /*@
218:   PetscStackPrint - Prints a given PETSc stack to an ASCII file

220:   Not Collective

222:   Input Parameters:
223: + sint - the PETSc stack to print
224: - fp   - the file pointer

226:   Level: developer

228:   Notes:
229:   In debug mode PETSc maintains a stack of the current function calls that can be used to help
230:   to quickly see where a problem has occurred, for example, when a signal is received. It is
231:   recommended to use the debugger if extensive information is needed to help debug the problem.

233:   The default stack is a global variable called `petscstack`.

235:   Developer Note:
236:   `PetscStackPrint()` and `PetscStackView()` should be merged into a single API.

238: .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackView()`
239: @*/
240: PetscErrorCode PetscStackPrint(PetscStack *sint, FILE *fp)
241: {
242:   if (sint) {
243:     for (int i = sint->currentsize; i >= 0; --i) {
244:       if (sint->file[i]) fprintf(fp, "      [%d]  %s() at %s:%d\n", PetscGlobalRank, sint->function[i], PetscCIFilename(sint->file[i]), PetscCILinenumber(sint->line[i]));
245:       else fprintf(fp, "      [%d]  %s()\n", PetscGlobalRank, sint->function[i]);
246:     }
247:   }
248:   return PETSC_SUCCESS;
249: }
250: #endif /* PetscDefined(USE_DEBUG) */