Actual source code: pstack.c

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

  3: #if PetscDefined(USE_DEBUG)
  4: PETSC_TLS PetscStack petscstack = {{NULL}, {NULL}, {0}, {0}, 0, 0, PETSC_BOOL3_UNKNOWN};
  5: /* Set during initialization, before worker threads enter PETSc. */
  6: PetscBool petscstackcheck = PETSC_FALSE;
  7: #endif

  9: #if PetscDefined(HAVE_SAWS)
 10: #include <petscviewersaws.h>

 12: static PetscBool amsmemstack = PETSC_FALSE;

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

 17:   Collective on `PETSC_COMM_WORLD`?

 19:   Level: developer

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

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

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

 38:   Collective on `PETSC_COMM_WORLD`?

 40:   Level: developer

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

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

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

 59:   Logically Collective on `PETSC_COMM_WORLD`; No Fortran Support

 61:   Level: developer

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

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

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

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

 85:   Logically Collective

 87:   Level: developer

 89:   Note:
 90:   No-op when `PetscStackViewSAWs()` was never called. Compiled to a no-op when PETSc is not configured `--with-saws`.

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

104: #if PetscDefined(USE_DEBUG)
105: PetscErrorCode PetscStackSetCheck(PetscBool check)
106: {
107:   petscstack.check = PetscBoolToBool3(check);
108:   return PETSC_SUCCESS;
109: }

111: PetscErrorCode PetscStackReset(void)
112: {
113:   memset(&petscstack, 0, sizeof(petscstack));
114:   petscstack.check = PETSC_BOOL3_UNKNOWN;
115:   return PETSC_SUCCESS;
116: }

118: // PetscClangLinter pragma disable: -fdoc-sowing-chars
119: /*@
120:   PetscStackView - Print the calling thread's default PETSc stack to an ASCII file

122:   Not Collective, No Fortran Support

124:   Input Parameter:
125: . file - the file pointer, or `NULL` to use `PETSC_STDERR`

127:   Level: developer

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

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

136:   The stack is maintained only when PETSc is configured `--with-debugging`; otherwise this becomes a no-op that returns `PETSC_SUCCESS`.

138:   Developer Note:
139:   The default stack is a global variable called `petscstack`.
140:   With thread safety enabled, this variable has a separate instance for each thread.

142: .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackPrint()`, `PetscStackSAWsGrantAccess()`, `PetscStackSAWsTakeAccess()`
143: @*/
144: PetscErrorCode PetscStackView(FILE *file)
145: {
146:   if (!file) file = PETSC_STDERR;
147:   if (petscstack.currentsize < 0) {
148:     /* Error handlers cannot recover from a corrupted stack, so only report it here. */
149:     if (file == PETSC_STDERR) PetscCall((*PetscErrorPrintf)("PetscStack is corrupted with stack size %d. Check for missing or mismatched PetscFunctionBegin/PetscFunctionReturn.\n", petscstack.currentsize));
150:     else fprintf(file, "PetscStack is corrupted with stack size %d. Check for missing or mismatched PetscFunctionBegin/PetscFunctionReturn.\n", petscstack.currentsize);
151:   } else if (petscstack.currentsize == 0) {
152:     if (file == PETSC_STDERR) PetscCall((*PetscErrorPrintf)("No error traceback is available. Check for missing or mismatched PetscFunctionBegin/PetscFunctionReturn, including PetscFunctionBeginUser in main().\n"));
153:     else fprintf(file, "No error traceback is available. Check for missing or mismatched PetscFunctionBegin/PetscFunctionReturn, including PetscFunctionBeginUser in main().\n");
154:   } else {
155:     char *ptr = NULL;

157:     if (petscstack.currentsize > PETSCSTACKSIZE) {
158:       if (file == PETSC_STDERR) PetscCall((*PetscErrorPrintf)("Only the first %d of %d stack frames are available.\n", PETSCSTACKSIZE, petscstack.currentsize));
159:       else fprintf(file, "Only the first %d of %d stack frames are available.\n", PETSCSTACKSIZE, petscstack.currentsize);
160:     }

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

187: /*@
188:   PetscStackCopy - Copy the information from one PETSc stack to another

190:   Not Collective

192:   Input Parameter:
193: . sint - the stack to be copied from

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

198:   Level: developer

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

205: .seealso: `PetscAttachDebugger()`, `PetscStackView()`
206: @*/
207: PetscErrorCode PetscStackCopy(PetscStack *sint, PetscStack *sout)
208: {
209:   if (sint) {
210:     for (int i = 0; i < PetscStackGetSize_Private(sint); ++i) {
211:       sout->function[i]     = sint->function[i];
212:       sout->file[i]         = sint->file[i];
213:       sout->line[i]         = sint->line[i];
214:       sout->petscroutine[i] = sint->petscroutine[i];
215:     }
216:     sout->currentsize = sint->currentsize;
217:   } else {
218:     sout->currentsize = 0;
219:   }
220:   return PETSC_SUCCESS;
221: }

223: // PetscClangLinter pragma disable: -fdoc-sowing-chars
224: /*@
225:   PetscStackPrint - Prints a given PETSc stack to an ASCII file

227:   Not Collective

229:   Input Parameters:
230: + sint - the PETSc stack to print
231: - fp   - the file pointer

233:   Level: developer

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

240:   The default stack is a global variable called `petscstack`.
241:   With thread safety enabled, this variable has a separate instance for each thread.

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

246: .seealso: `PetscAttachDebugger()`, `PetscStackCopy()`, `PetscStackView()`
247: @*/
248: PetscErrorCode PetscStackPrint(PetscStack *sint, FILE *fp)
249: {
250:   if (sint) {
251:     if (sint->currentsize > PETSCSTACKSIZE) fprintf(fp, "Only the first %d of %d stack frames are available.\n", PETSCSTACKSIZE, sint->currentsize);
252:     for (int i = PetscStackGetSize_Private(sint) - 1; i >= 0; --i) {
253:       if (sint->file[i]) fprintf(fp, "      [%d]  %s() at %s:%d\n", PetscGlobalRank, sint->function[i], PetscCIFilename(sint->file[i]), PetscCILinenumber(sint->line[i]));
254:       else fprintf(fp, "      [%d]  %s()\n", PetscGlobalRank, sint->function[i]);
255:     }
256:   }
257:   return PETSC_SUCCESS;
258: }
259: #endif /* PetscDefined(USE_DEBUG) */