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, &copy));
 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*/