reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
// RUN: %libomp-compile-and-run

// The test checks OMP 5.0 monotonic/nonmonotonic scheduling API
//   1. initial schedule should be (static,0)
//   2. omp_get_schedule() should return the schedule set by omp_set_schedule()
//   3. schedules set inside parallel should not impact outer tasks' schedules

#include <stdio.h>
#ifndef __INTEL_COMPILER
#define _OMPIMP
#endif

#define NO_MODIFIERS ((omp_sched_t)0)

#include "omp.h"

int global = 0;
int err = 0;

omp_sched_t sched_append_modifiers(omp_sched_t sched, omp_sched_t modifiers) {
  return (omp_sched_t)((int)sched | (int)modifiers);
}

omp_sched_t sched_without_modifiers(omp_sched_t sched) {
  return (omp_sched_t)((int)sched & ~((int)omp_sched_monotonic));
}

int sched_has_modifiers(omp_sched_t sched, omp_sched_t modifiers) {
  return (((int)sched & ((int)omp_sched_monotonic)) > 0);
}

// check that sched = hope | modifiers
void check_schedule(const char *extra, const omp_sched_t sched, int chunk,
                    omp_sched_t hope_sched, int hope_chunk) {

  if (sched != hope_sched || chunk != hope_chunk) {
#pragma omp atomic
    ++err;
    printf("Error: %s: schedule: (%d, %d) is not equal to (%d, %d)\n", extra,
           (int)hope_sched, hope_chunk, (int)sched, chunk);
  }
}

int main() {
  int i;
  int chunk;
  omp_sched_t sched0;

  omp_set_dynamic(0);
  omp_set_nested(1);

  // check serial region
  omp_get_schedule(&sched0, &chunk);
#ifdef DEBUG
  printf("initial: (%d, %d)\n", sched0, chunk);
#endif
  check_schedule("initial", omp_sched_static, 0, sched0, chunk);
  // set schedule before the parallel, check it after the parallel
  omp_set_schedule(
      sched_append_modifiers(omp_sched_dynamic, omp_sched_monotonic), 3);

#pragma omp parallel num_threads(3) private(i)
  {
    omp_sched_t n_outer_set, n_outer_get;
    int c_outer;
    int tid = omp_get_thread_num();

    n_outer_set = sched_append_modifiers((omp_sched_t)(tid + 1),
                                         omp_sched_monotonic); // 1, 2, 3

    // check outer parallel region
    // master sets (static, unchunked), others - (dynamic, 1), (guided, 2)
    // set schedule before inner parallel, check it after the parallel
    omp_set_schedule(n_outer_set, tid);

// Make sure this schedule doesn't crash the runtime
#pragma omp for
    for (i = 0; i < 100; ++i) {
#pragma omp atomic
      global++;
    }

#pragma omp parallel num_threads(3) private(i) shared(n_outer_set)
    {
      omp_sched_t n_inner_set, n_inner_get;
      int c_inner_set, c_inner_get;
      int tid = omp_get_thread_num();

      n_inner_set = (omp_sched_t)(tid + 1); // 1, 2, 3
      c_inner_set = (int)(n_outer_set)*10 +
                    (int)n_inner_set; // 11, 12, 13, 21, 22, 23, 31, 32, 33
      n_inner_set = sched_append_modifiers(n_inner_set, omp_sched_monotonic);
      // schedules set inside parallel should not impact outer schedules
      omp_set_schedule(n_inner_set, c_inner_set);

// Make sure this schedule doesn't crash the runtime
#pragma omp for
      for (i = 0; i < 100; ++i) {
#pragma omp atomic
        global++;
      }

#pragma omp barrier
      omp_get_schedule(&n_inner_get, &c_inner_get);
#ifdef DEBUG
      printf("inner parallel: o_th %d, i_th %d, (%d, %d)\n", n_outer_set - 1,
             tid, n_inner_get, c_inner_get);
#endif
      check_schedule("inner", n_inner_set, c_inner_set, n_inner_get,
                     c_inner_get);
    }

    omp_get_schedule(&n_outer_get, &c_outer);
#ifdef DEBUG
    printf("outer parallel: thread %d, (%d, %d)\n", tid, n_outer_get, c_outer);
#endif
    check_schedule("outer", n_outer_set, tid, n_outer_get, c_outer);
  }

  omp_get_schedule(&sched0, &chunk);
#ifdef DEBUG
  printf("after parallels: (%d, %d)\n", sched0, chunk);
#endif
  check_schedule("after parallels",
                 sched_append_modifiers(omp_sched_dynamic, omp_sched_monotonic),
                 3, sched0, chunk);

  if (err > 0) {
    printf("Failed\n");
    return 1;
  }
  printf("Passed\n");
  return 0;
}