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) */