ck_barrier: Clean up tournament barriers.

ck_pring
Samy Al Bahra 14 years ago
parent 8b4f72057c
commit fb25458121

@ -115,22 +115,28 @@ void ck_barrier_dissemination(ck_barrier_dissemination_t *,
ck_barrier_dissemination_state_t *); ck_barrier_dissemination_state_t *);
struct ck_barrier_tournament_round { struct ck_barrier_tournament_round {
enum {BYE, CHAMPION, DROPOUT, LOSER, WINNER} role; int role;
unsigned int *opponent; unsigned int *opponent;
unsigned int flag; unsigned int flag;
}; };
typedef struct ck_barrier_tournament_round ck_barrier_tournament_round_t; typedef struct ck_barrier_tournament_round ck_barrier_tournament_round_t;
struct ck_barrier_tournament {
unsigned int tid;
struct ck_barrier_tournament_round **rounds;
};
typedef struct ck_barrier_tournament ck_barrier_tournament_t;
struct ck_barrier_tournament_state { struct ck_barrier_tournament_state {
unsigned int sense; unsigned int sense;
unsigned int vpid; unsigned int vpid;
}; };
typedef struct ck_barrier_tournament_state ck_barrier_tournament_state_t; typedef struct ck_barrier_tournament_state ck_barrier_tournament_state_t;
void ck_barrier_tournament_state_init(ck_barrier_tournament_state_t *); void ck_barrier_tournament_subscribe(ck_barrier_tournament_t *, ck_barrier_tournament_state_t *);
void ck_barrier_tournament_round_init(ck_barrier_tournament_round_t **, unsigned int); void ck_barrier_tournament_init(ck_barrier_tournament_t *, ck_barrier_tournament_round_t **, unsigned int);
unsigned int ck_barrier_tournament_size(unsigned int); unsigned int ck_barrier_tournament_size(unsigned int);
void ck_barrier_tournament(ck_barrier_tournament_round_t **, ck_barrier_tournament_state_t *); void ck_barrier_tournament(ck_barrier_tournament_t *, ck_barrier_tournament_state_t *);
struct ck_barrier_mcs { struct ck_barrier_mcs {
unsigned int tid; unsigned int tid;

@ -23,4 +23,4 @@ clean:
rm -rf *.dSYM *~ *.o $(OBJECTS) rm -rf *.dSYM *~ *.o $(OBJECTS)
include ../../../build/regressions.build include ../../../build/regressions.build
CFLAGS+=-D_GNU_SOURCE -lpthread CFLAGS+=-D_GNU_SOURCE -lpthread -ggdb -O0

@ -53,17 +53,17 @@ static struct affinity a;
static int nthr; static int nthr;
static int counters[ENTRIES]; static int counters[ENTRIES];
static int barrier_wait; static int barrier_wait;
static ck_barrier_tournament_t barrier;
static void * static void *
thread(void *rounds) thread(CK_CC_UNUSED void *unused)
{ {
ck_barrier_tournament_state_t state; ck_barrier_tournament_state_t state;
int j, counter; int j, counter;
int i = 0; int i = 0;
aff_iterate(&a); aff_iterate(&a);
ck_barrier_tournament_subscribe(&barrier, &state);
ck_barrier_tournament_state_init(&state);
ck_pr_inc_int(&barrier_wait); ck_pr_inc_int(&barrier_wait);
while (ck_pr_load_int(&barrier_wait) != nthr) while (ck_pr_load_int(&barrier_wait) != nthr)
@ -72,7 +72,7 @@ thread(void *rounds)
for (j = 0; j < ITERATE; j++) { for (j = 0; j < ITERATE; j++) {
i = j++ & (ENTRIES - 1); i = j++ & (ENTRIES - 1);
ck_pr_inc_int(&counters[i]); ck_pr_inc_int(&counters[i]);
ck_barrier_tournament(rounds, &state); ck_barrier_tournament(&barrier, &state);
counter = ck_pr_load_int(&counters[i]); counter = ck_pr_load_int(&counters[i]);
if (counter != nthr * (j / ENTRIES + 1)) { if (counter != nthr * (j / ENTRIES + 1)) {
fprintf(stderr, "FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr); fprintf(stderr, "FAILED [%d:%d]: %d != %d\n", i, j - 1, counter, nthr);
@ -80,6 +80,10 @@ thread(void *rounds)
} }
} }
ck_pr_inc_int(&barrier_wait);
while (ck_pr_load_int(&barrier_wait) != nthr * 2)
ck_pr_stall();
return (NULL); return (NULL);
} }
@ -101,6 +105,7 @@ main(int argc, char *argv[])
fprintf(stderr, "ERROR: Number of threads must be greater than 0\n"); fprintf(stderr, "ERROR: Number of threads must be greater than 0\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
a.delta = atoi(argv[2]);
threads = malloc(sizeof(pthread_t) * nthr); threads = malloc(sizeof(pthread_t) * nthr);
if (threads == NULL) { if (threads == NULL) {
@ -122,13 +127,12 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
ck_barrier_tournament_round_init(rounds, nthr);
a.delta = atoi(argv[2]); ck_barrier_tournament_init(&barrier, rounds, nthr);
fprintf(stderr, "Creating threads (barrier)..."); fprintf(stderr, "Creating threads (barrier)...");
for (i = 0; i < nthr; i++) { for (i = 0; i < nthr; i++) {
if (pthread_create(&threads[i], NULL, thread, rounds)) { if (pthread_create(&threads[i], NULL, thread, NULL)) {
fprintf(stderr, "ERROR: Could not create thread %d\n", i); fprintf(stderr, "ERROR: Could not create thread %d\n", i);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -140,7 +144,6 @@ main(int argc, char *argv[])
pthread_join(threads[i], NULL); pthread_join(threads[i], NULL);
fprintf(stderr, "done (passed)\n"); fprintf(stderr, "done (passed)\n");
return (0); return (0);
} }

@ -37,52 +37,64 @@
* on their own flags. During the last round, the champion of the tournament * on their own flags. During the last round, the champion of the tournament
* sets the last flag that begins the wakeup process. * sets the last flag that begins the wakeup process.
*/ */
static unsigned int ck_barrier_tournament_tid;
enum {
CK_BARRIER_TOURNAMENT_BYE,
CK_BARRIER_TOURNAMENT_CHAMPION,
CK_BARRIER_TOURNAMENT_DROPOUT,
CK_BARRIER_TOURNAMENT_LOSER,
CK_BARRIER_TOURNAMENT_WINNER
};
void void
ck_barrier_tournament_state_init(ck_barrier_tournament_state_t *state) ck_barrier_tournament_subscribe(struct ck_barrier_tournament *barrier,
struct ck_barrier_tournament_state *state)
{ {
state->sense = ~0; state->sense = ~0;
state->vpid = ck_pr_faa_uint(&ck_barrier_tournament_tid, 1); state->vpid = ck_pr_faa_uint(&barrier->tid, 1);
return; return;
} }
void void
ck_barrier_tournament_round_init(struct ck_barrier_tournament_round **rounds, ck_barrier_tournament_init(struct ck_barrier_tournament *barrier,
struct ck_barrier_tournament_round **rounds,
unsigned int nthr) unsigned int nthr)
{ {
unsigned int i, k, size, twok, twokm1, imod2k; unsigned int i, k, size, twok, twokm1, imod2k;
ck_pr_store_uint(&barrier->tid, 0);
size = ck_barrier_tournament_size(nthr); size = ck_barrier_tournament_size(nthr);
for (i = 0; i < nthr; ++i) { for (i = 0; i < nthr; ++i) {
/* The first role is always DROPOUT. */ /* The first role is always CK_BARRIER_TOURNAMENT_DROPOUT. */
rounds[i][0].flag = 0; rounds[i][0].flag = 0;
rounds[i][0].role = DROPOUT; rounds[i][0].role = CK_BARRIER_TOURNAMENT_DROPOUT;
for (k = 1, twok = 2, twokm1 = 1; k < size; ++k, twokm1 = twok, twok <<= 1) { for (k = 1, twok = 2, twokm1 = 1; k < size; ++k, twokm1 = twok, twok <<= 1) {
rounds[i][k].flag = 0; rounds[i][k].flag = 0;
imod2k = i & (twok - 1); imod2k = i & (twok - 1);
if (imod2k == 0) { if (imod2k == 0) {
if ((i + twokm1 < nthr) && (twok < nthr)) if ((i + twokm1 < nthr) && (twok < nthr))
rounds[i][k].role = WINNER; rounds[i][k].role = CK_BARRIER_TOURNAMENT_WINNER;
else if (i + twokm1 >= nthr) else if (i + twokm1 >= nthr)
rounds[i][k].role = BYE; rounds[i][k].role = CK_BARRIER_TOURNAMENT_BYE;
} }
if (imod2k == twokm1)
rounds[i][k].role = LOSER;
/* There is exactly one champion in a tournament barrier. */ if (imod2k == twokm1)
rounds[i][k].role = CK_BARRIER_TOURNAMENT_LOSER;
else if ((i == 0) && (twok >= nthr)) else if ((i == 0) && (twok >= nthr))
rounds[i][k].role = CHAMPION; rounds[i][k].role = CK_BARRIER_TOURNAMENT_CHAMPION;
if (rounds[i][k].role == LOSER) if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_LOSER)
rounds[i][k].opponent = &rounds[i - twokm1][k].flag; rounds[i][k].opponent = &rounds[i - twokm1][k].flag;
else if (rounds[i][k].role == WINNER || rounds[i][k].role == CHAMPION) else if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_WINNER ||
rounds[i][k].role == CK_BARRIER_TOURNAMENT_CHAMPION)
rounds[i][k].opponent = &rounds[i + twokm1][k].flag; rounds[i][k].opponent = &rounds[i + twokm1][k].flag;
} }
} }
ck_pr_store_ptr(&barrier->rounds, rounds);
return; return;
} }
@ -94,41 +106,42 @@ ck_barrier_tournament_size(unsigned int nthr)
} }
void void
ck_barrier_tournament(struct ck_barrier_tournament_round **rounds, ck_barrier_tournament(struct ck_barrier_tournament *barrier,
struct ck_barrier_tournament_state *state) struct ck_barrier_tournament_state *state)
{ {
struct ck_barrier_tournament_round **rounds = ck_pr_load_ptr(&barrier->rounds);
int round = 1; int round = 1;
for (;; ++round) { for (;; ++round) {
switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD*** switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD***
case BYE: case CK_BARRIER_TOURNAMENT_BYE:
break; break;
case CHAMPION: case CK_BARRIER_TOURNAMENT_CHAMPION:
/* /*
* The CHAMPION waits until it wins the tournament; it then * The CK_BARRIER_TOURNAMENT_CHAMPION waits until it wins the tournament; it then
* sets the final flag before the wakeup phase of the barrier. * sets the final flag before the wakeup phase of the barrier.
*/ */
while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)
ck_pr_stall(); ck_pr_stall();
ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);
goto wakeup; goto wakeup;
break; case CK_BARRIER_TOURNAMENT_DROPOUT:
case DROPOUT:
/* NOTREACHED */ /* NOTREACHED */
break; break;
case LOSER: case CK_BARRIER_TOURNAMENT_LOSER:
/* /*
* LOSERs set the flags of their opponents and wait until * CK_BARRIER_TOURNAMENT_LOSERs set the flags of their opponents and wait until
* their opponents release them after the tournament is over. * their opponents release them after the tournament is over.
*/ */
ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);
while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)
ck_pr_stall(); ck_pr_stall();
goto wakeup; goto wakeup;
break; case CK_BARRIER_TOURNAMENT_WINNER:
case WINNER:
/* /*
* WINNERs wait until their current opponent sets their flag; they then * CK_BARRIER_TOURNAMENT_WINNERs wait until their current opponent sets their flag; they then
* continue to the next round of the tournament. * continue to the next round of the tournament.
*/ */
while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)
@ -136,21 +149,22 @@ ck_barrier_tournament(struct ck_barrier_tournament_round **rounds,
break; break;
} }
} }
wakeup: wakeup:
for (round -= 1;; --round) { for (round -= 1 ;; --round) {
switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD*** switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD***
case BYE: case CK_BARRIER_TOURNAMENT_BYE:
break; break;
case CHAMPION: case CK_BARRIER_TOURNAMENT_CHAMPION:
/* NOTREACHED */ /* NOTREACHED */
break; break;
case DROPOUT: case CK_BARRIER_TOURNAMENT_DROPOUT:
goto leave; goto leave;
break; break;
case LOSER: case CK_BARRIER_TOURNAMENT_LOSER:
/* NOTREACHED */ /* NOTREACHED */
break; break;
case WINNER: case CK_BARRIER_TOURNAMENT_WINNER:
/* /*
* Winners inform their old opponents the tournament is over * Winners inform their old opponents the tournament is over
* by setting their flags. * by setting their flags.

Loading…
Cancel
Save