Actual source code: ex33.c
1: static char help[] = "Tests bounded stack storage and unwinding.\n\n";
3: // PetscStackCopy() is declared in this private header.
4: #include <petsc/private/petscimpl.h>
5: #if PetscDefined(HAVE_THREADSAFETY) && PetscDefined(HAVE_OPENMP)
6: #include <omp.h>
7: #endif
9: static PetscErrorCode CheckStack(int depth, int remaining, PetscBool check)
10: {
11: PetscStack copy = {{NULL}, {NULL}, {0}, {0}, 0, 0, PETSC_BOOL3_FALSE};
13: PetscFunctionBeginUser;
14: PetscCheck(petscstack.currentsize == depth, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected stack depth %d, got %d", depth, petscstack.currentsize);
15: PetscCheck(petscstack.check == PetscBoolToBool3(check), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect stack checking policy");
16: PetscStackUpdateLine;
17: PetscCheck(depth > PETSCSTACKSIZE || petscstack.line[depth - 1] == __LINE__ - 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect stack line number");
18: PetscCall(PetscStackCopy(&petscstack, ©));
19: PetscCheck(copy.currentsize == depth, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect stack copy depth");
20: for (int i = 0; i < PetscMin(depth, PETSCSTACKSIZE); ++i) {
21: PetscCheck(copy.function[i] == petscstack.function[i] && copy.file[i] == petscstack.file[i] && copy.line[i] == petscstack.line[i] && copy.petscroutine[i] == petscstack.petscroutine[i], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect copied frame %d", i);
22: }
23: if (remaining) PetscCall(CheckStack(depth + 1, remaining - 1, check));
24: else {
25: PetscStack *stack;
26: FILE *file;
27: char line[1024];
28: char *ptr;
29: int frames = 0;
30: PetscBool mdebug, truncated = PETSC_FALSE;
32: file = tmpfile();
33: PetscCheck(file, PETSC_COMM_SELF, PETSC_ERR_SYS, "Cannot create temporary stack output file");
34: PetscCall(PetscStackView(file));
35: rewind(file);
36: while (fgets(line, sizeof(line), file)) {
37: if (line[0] == '[') ++frames;
38: if (strstr(line, "Only the first")) truncated = PETSC_TRUE;
39: }
40: PetscCheck(frames == PetscMin(depth, PETSCSTACKSIZE), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect number of viewed frames: %d", frames);
41: PetscCheck(truncated == (depth > PETSCSTACKSIZE ? PETSC_TRUE : PETSC_FALSE), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect stack truncation diagnostic");
42: PetscCall(PetscMallocGetDebug(&mdebug, NULL, NULL));
43: PetscCall(PetscMalloc1(8, &ptr));
44: PetscCall(PetscMallocGetStack(ptr, &stack));
45: PetscCheck(mdebug ? stack && stack->currentsize == depth + 1 : !stack, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect allocation stack");
46: PetscCall(PetscRealloc(16, &ptr));
47: PetscCall(PetscMallocGetStack(ptr, &stack));
48: PetscCheck(mdebug ? stack && stack->currentsize == depth : !stack, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect reallocation stack");
49: PetscCall(PetscMallocDump(file));
50: PetscCall(PetscFree(ptr));
51: PetscCallExternal(fclose, file);
52: }
53: PetscStackPushExternal("external");
54: PetscCheck(petscstack.currentsize == depth + 1 && petscstack.hotdepth == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrect external stack frame");
55: PetscStackPop;
56: PetscCheck(petscstack.currentsize == depth && !petscstack.hotdepth, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stack was not restored");
57: PetscFunctionReturn(PETSC_SUCCESS);
58: }
60: int main(int argc, char **argv)
61: {
62: PetscBool check = PETSC_TRUE;
63: const int depths[] = {2, PETSCSTACKSIZE - 1, PETSCSTACKSIZE, PETSCSTACKSIZE + 1, 2 * PETSCSTACKSIZE};
64: #if PetscDefined(HAVE_THREADSAFETY) && PetscDefined(HAVE_OPENMP)
65: PetscStack *stacks[2];
66: #endif
68: PetscFunctionBeginUser;
69: #if PetscDefined(HAVE_THREADSAFETY) && PetscDefined(HAVE_OPENMP)
70: PetscCall(PetscSetMPIThreadRequiredType(MPI_THREAD_MULTIPLE));
71: #endif
72: PetscCall(PetscInitialize(&argc, &argv, NULL, help));
73: PetscCall(PetscOptionsGetBool(NULL, NULL, "-checkstack", &check, NULL));
74: /* Use private push/pop macros to test an empty local stack. The public macros operate on petscstack
75: and cannot target this local stack. */
76: for (int i = 0; i < 2; ++i) {
77: PetscStack stack = {{NULL}, {NULL}, {0}, {0}, 0, 0, PETSC_BOOL3_FALSE};
79: stack.check = i ? PETSC_BOOL3_UNKNOWN : PETSC_BOOL3_FALSE;
80: PetscStackPop_Private(stack, PETSC_FUNCTION_NAME);
81: PetscStackPop_Private(stack, PETSC_FUNCTION_NAME);
82: PetscCheck(!stack.currentsize && !stack.hotdepth, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Empty stack was not preserved");
83: PetscStackPush_Private(stack, __FILE__, PETSC_FUNCTION_NAME, __LINE__, 1, PETSC_TRUE);
84: PetscCheck(stack.currentsize == 1 && stack.hotdepth == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stack could not be reused after an empty pop");
85: PetscStackPop_Private(stack, PETSC_FUNCTION_NAME);
86: PetscCheck(!stack.currentsize && !stack.hotdepth, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Stack was not restored");
87: }
88: for (int i = 0; i < (int)PETSC_STATIC_ARRAY_LENGTH(depths); ++i) PetscCall(CheckStack(2, depths[i] - 2, check));
89: petscstack.check = PetscBoolToBool3(PetscNot(check));
90: PetscCall(CheckStack(2, 1, PetscNot(check)));
91: petscstack.check = PetscBoolToBool3(check);
92: #if PetscDefined(HAVE_THREADSAFETY) && PetscDefined(HAVE_OPENMP)
93: omp_set_dynamic(0);
94: PetscPragmaOMP(parallel num_threads(2))
95: {
96: const int thread = omp_get_thread_num(), depth = petscstack.currentsize;
97: const PetscBool localcheck = thread ? PetscNot(check) : check;
99: stacks[thread] = &petscstack;
100: PetscCheckAbort(!thread || petscstack.check == PETSC_BOOL3_UNKNOWN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Worker stack checking was already initialized");
101: PetscPragmaOMP(barrier)
102: for (int i = 0; i < (int)PETSC_STATIC_ARRAY_LENGTH(depths); ++i) PetscCallAbort(PETSC_COMM_SELF, CheckStack(depth + 1, depths[i] - 2, check));
103: petscstack.check = PetscBoolToBool3(localcheck);
104: PetscPragmaOMP(barrier)
105: PetscCallAbort(PETSC_COMM_SELF, CheckStack(depth + 1, 1, localcheck));
106: PetscCheckAbort(petscstackcheck == check, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Thread changed the process-wide default");
107: }
108: PetscCheck(stacks[0] != stacks[1], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Threads share a stack");
109: #endif
110: PetscCheck(petscstack.currentsize == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Main stack was not restored");
111: PetscCall(PetscFinalize());
112: return 0;
113: }
115: /*TEST
117: build:
118: requires: debug
120: test:
121: suffix: serial
122: requires: !threadsafety
123: args: -checkstack {{0 1}}
124: output_file: output/empty.out
126: test:
127: suffix: serial_no_malloc_debug
128: requires: !threadsafety
129: args: -malloc_debug 0
130: output_file: output/empty.out
132: test:
133: suffix: threads
134: requires: threadsafety openmp
135: args: -checkstack {{0 1}}
136: output_file: output/empty.out
138: TEST*/