Skip to content

Commit

Permalink
Fix team reuse with foreign threads
Browse files Browse the repository at this point in the history
After hot teams were enabled by default, the library started using levels kept
in the team structure. The levels are broken in case foreign thread exits and
puts its team into the pool which is then re-used by another foreign thread.
The broken behavior observed is when printing the levels for each new team, one
gets 1, 2, 1, 2, 1, 2, etc. This makes the library believe that every other
team is nested which is incorrect. What is wanted is for the levels to be
1, 1, 1, etc.

Differential Revision: http://reviews.llvm.org/D19980

llvm-svn: 269363
  • Loading branch information
jpeyton52 committed May 12, 2016
1 parent 01f1636 commit 2b749b3
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
2 changes: 2 additions & 0 deletions openmp/runtime/src/kmp_runtime.c
Expand Up @@ -5219,6 +5219,8 @@ __kmp_free_team( kmp_root_t *root, kmp_team_t *team USE_NESTED_HOT_ARG(kmp_info

// Reset pointer to parent team only for non-hot teams.
team->t.t_parent = NULL;
team->t.t_level = 0;
team->t.t_active_level = 0;

/* free the worker threads */
for ( f = 1; f < team->t.t_nproc; ++ f ) {
Expand Down
82 changes: 82 additions & 0 deletions openmp/runtime/test/misc_bugs/omp_foreign_thread_team_reuse.c
@@ -0,0 +1,82 @@
// RUN: %libomp-compile-and-run
#include <stdio.h>
#include <pthread.h>
#include "omp_testsuite.h"

#define NUM_THREADS 10

/*
After hot teams were enabled by default, the library started using levels
kept in the team structure. The levels are broken in case foreign thread
exits and puts its team into the pool which is then re-used by another foreign
thread. The broken behavior observed is when printing the levels for each
new team, one gets 1, 2, 1, 2, 1, 2, etc. This makes the library believe that
every other team is nested which is incorrect. What is wanted is for the
levels to be 1, 1, 1, etc.
*/

int a = 0;
int level;

typedef struct thread_arg_t {
int iterations;
} thread_arg_t;

void* thread_function(void* arg) {
int i;
thread_arg_t* targ = (thread_arg_t*)arg;
int iterations = targ->iterations;
#pragma omp parallel private(i)
{
// level should always be 1
#pragma omp single
level = omp_get_level();

#pragma omp for
for(i = 0; i < iterations; i++) {
#pragma omp atomic
a++;
}
}
}

int test_omp_team_reuse()
{
int i;
int success = 1;
pthread_t thread[NUM_THREADS];
thread_arg_t thread_arg[NUM_THREADS];
// launch NUM_THREADS threads, one at a time to perform thread_function()
for(i = 0; i < NUM_THREADS; i++) {
thread_arg[i].iterations = i + 1;
pthread_create(thread+i, NULL, thread_function, thread_arg+i);
pthread_join(*(thread+i), NULL);
// level read in thread_function()'s parallel region should be 1
if(level != 1) {
fprintf(stderr, "error: for pthread %d level should be 1 but "
"instead equals %d\n", i, level);
success = 0;
}
}
// make sure the for loop works
int known_sum = (NUM_THREADS * (NUM_THREADS+1)) / 2;
if(a != known_sum) {
fprintf(stderr, "a should be %d but instead equals %d\n", known_sum, a);
success = 0;
}
return success;
}

int main()
{
int i;
int num_failed=0;

for(i = 0; i < REPETITIONS; i++) {
a = 0;
if(!test_omp_team_reuse()) {
num_failed++;
}
}
return num_failed;
}

0 comments on commit 2b749b3

Please sign in to comment.