示例#1
0
void
ck_barrier_mcs(struct ck_barrier_mcs *barrier,
               struct ck_barrier_mcs_state *state)
{

	/*
	 * Wait until all children have reached the barrier and are done waiting
	 * for their children.
	 */
	while (ck_barrier_mcs_check_children(barrier[state->vpid].childnotready) == false)
		ck_pr_stall();

	/* Reinitialize for next barrier. */
	ck_barrier_mcs_reinitialize_children(&barrier[state->vpid]);

	/* Inform parent thread and its children have arrived at the barrier. */
	ck_pr_store_uint(barrier[state->vpid].parent, 0);

	/* Wait until parent indicates all threads have arrived at the barrier. */
	if (state->vpid != 0) {
		while (ck_pr_load_uint(&barrier[state->vpid].parentsense) != state->sense)
			ck_pr_stall();
	}

	/* Inform children of successful barrier. */
	ck_pr_store_uint(barrier[state->vpid].children[0], state->sense);
	ck_pr_store_uint(barrier[state->vpid].children[1], state->sense);
	state->sense = ~state->sense;
	return;
}
示例#2
0
void
ck_barrier_centralized(struct ck_barrier_centralized *barrier,
    struct ck_barrier_centralized_state *state,
    unsigned int n_threads)
{
	unsigned int sense, value;

	/*
	 * Every execution context has a sense associated with it.
	 * This sense is reversed when the barrier is entered. Every
	 * thread will spin on the global sense until the last thread
	 * reverses it.
	 */
	sense = state->sense = ~state->sense;
	value = ck_pr_faa_uint(&barrier->value, 1);
	if (value == n_threads - 1) {
		ck_pr_store_uint(&barrier->value, 0);
		ck_pr_fence_memory();
		ck_pr_store_uint(&barrier->sense, sense);
		return;
	}

	ck_pr_fence_load();
	while (sense != ck_pr_load_uint(&barrier->sense))
		ck_pr_stall();

	ck_pr_fence_memory();
	return;
}
示例#3
0
static void
rwlock_test(pthread_t *p, int d, uint64_t *latency, void *(*f)(void *), const char *label)
{
	int t;

	ck_pr_store_int(&barrier, 0);
	ck_pr_store_uint(&flag, 0);

	affinity.delta = d;
	affinity.request = 0;

	fprintf(stderr, "Creating threads (%s)...", label);
	for (t = 0; t < threads; t++) {
		if (pthread_create(&p[t], NULL, f, latency + t) != 0) {
			ck_error("ERROR: Could not create thread %d\n", t);
		}
	}
	fprintf(stderr, "done\n");

	common_sleep(10);
	ck_pr_store_uint(&flag, 1);

	fprintf(stderr, "Waiting for threads to finish acquisition regression...");
	for (t = 0; t < threads; t++)
		pthread_join(p[t], NULL);
	fprintf(stderr, "done\n\n");

	for (t = 1; t <= threads; t++)
		printf("%10u %20" PRIu64 "\n", t, latency[t - 1]);

	fprintf(stderr, "\n");
	return;
}
示例#4
0
CK_CC_INLINE static void
ck_barrier_mcs_reinitialize_children(struct ck_barrier_mcs *node)
{

	ck_pr_store_uint(&node->childnotready[0], node->havechild[0]);
	ck_pr_store_uint(&node->childnotready[1], node->havechild[1]);
	ck_pr_store_uint(&node->childnotready[2], node->havechild[2]);
	ck_pr_store_uint(&node->childnotready[3], node->havechild[3]);
	return;
}
示例#5
0
文件: counter.c 项目: kunth/libphenom
// want to verify that we can observe the correct end counter value
// in the face of concurrent updates
static void concurrentCounters(void)
{
  int i, num_threads = 4;
  struct counter_data data = { 0, 100000, 0, NULL };
  pthread_t threads[num_threads];

  data.scope = ph_counter_scope_define(NULL, "testConcurrentCounters", 1);
  is_true(data.scope != NULL);

  data.slot = ph_counter_scope_register_counter(data.scope, "dummy");
  is(0, data.slot);

  for (i = 0; i < num_threads; i++) {
    pthread_create(&threads[i], NULL, spin_and_count, &data);
  }

  /* unleash the threads on the data */
  ck_pr_store_uint(&data.barrier, 1);

  for (i = 0; i < num_threads; i++) {
    void *unused;
    pthread_join(threads[i], &unused);
  }

  is(num_threads * data.iters,
      ph_counter_scope_get(data.scope, data.slot));
}
示例#6
0
void
ck_barrier_dissemination(struct ck_barrier_dissemination *barrier,
			 struct ck_barrier_dissemination_state *state)
{
	unsigned int i;
	unsigned int size = barrier->size;

	for (i = 0; i < size; ++i) {
		/* Unblock current partner. */
		ck_pr_store_uint(barrier[state->tid].flags[state->parity][i].pflag, state->sense);

		/* Wait until some other thread unblocks this one. */
		while (ck_pr_load_uint(&barrier[state->tid].flags[state->parity][i].tflag) != state->sense)
			ck_pr_stall();
	}

	/*
	 * Dissemination barriers use two sets of flags to prevent race conditions
	 * between successive calls to the barrier. Parity indicates which set will
	 * be used for the next barrier. They also use a sense reversal technique 
	 * to avoid re-initialization of the flags for every two calls to the barrier.
	 */
	if (state->parity == 1)
		state->sense = ~state->sense;

	state->parity = 1 - state->parity;
	return;
}
示例#7
0
文件: latency.c 项目: msparks/ck
static CK_CC_INLINE void
rwlock_init(rwlock_t *rw)
{

        ck_pr_store_uint(&rw->readers, 0);
        ck_spinlock_fas_init(&rw->writer);
        return;
}
示例#8
0
int
main(int argc, char *argv[])
{
	int t;
	pthread_t *p;
	uint64_t *latency;

	if (argc != 3) {
		fprintf(stderr, "Usage: throughput <delta> <threads>\n");
		exit(EXIT_FAILURE);
	}

	threads = atoi(argv[2]);
	if (threads <= 0) {
		fprintf(stderr, "ERROR: Threads must be a value > 0.\n");
		exit(EXIT_FAILURE);
	}

	p = malloc(sizeof(pthread_t) * threads);
	if (p == NULL) {
		fprintf(stderr, "ERROR: Failed to initialize thread.\n");
		exit(EXIT_FAILURE);
	}

	latency = malloc(sizeof(uint64_t) * threads);
	if (latency == NULL) {
		fprintf(stderr, "ERROR: Failed to create latency buffer.\n");
		exit(EXIT_FAILURE);
	}

	affinity.delta = atoi(argv[1]);
	affinity.request = 0;

	fprintf(stderr, "Creating threads (brlock)...");
	for (t = 0; t < threads; t++) {
		if (pthread_create(&p[t], NULL, thread_brlock, latency + t) != 0) {
			fprintf(stderr, "ERROR: Could not create thread %d\n", t);
			exit(EXIT_FAILURE);
		}
	}
	fprintf(stderr, "done\n");

	sleep(10);
	ck_pr_store_uint(&flag, 1);

	fprintf(stderr, "Waiting for threads to finish acquisition regression...");
	for (t = 0; t < threads; t++)
		pthread_join(p[t], NULL);
	fprintf(stderr, "done\n\n");

	for (t = 1; t <= threads; t++)
		printf("%10u %20" PRIu64 "\n", t, latency[t - 1]);

	return (0);
}
示例#9
0
bool
ck_array_put(struct ck_array *array, void *value)
{
	struct _ck_array *target;
	unsigned int size;

	/*
	 * If no transaction copy has been necessary, attempt to do in-place
	 * modification of the array.
	 */
	if (array->transaction == NULL) {
		target = array->active;

		if (array->n_entries == target->length) {
			size = target->length << 1;

			target = array->allocator->realloc(target,
			    sizeof(struct _ck_array) + sizeof(void *) * array->n_entries,
			    sizeof(struct _ck_array) + sizeof(void *) * size,
			    true);

			if (target == NULL)
				return false;

			ck_pr_store_uint(&target->length, size);

			/* Serialize with respect to contents. */
			ck_pr_fence_store();
			ck_pr_store_ptr(&array->active, target);
		}

		target->values[array->n_entries++] = value;
		return true;
	}

	target = array->transaction;
	if (array->n_entries == target->length) {
		size = target->length << 1;

		target = array->allocator->realloc(target,
		    sizeof(struct _ck_array) + sizeof(void *) * array->n_entries,
		    sizeof(struct _ck_array) + sizeof(void *) * size,
		    true);

		if (target == NULL)
			return false;

		target->length = size;
		array->transaction = target;
	}

	target->values[array->n_entries++] = value;
	return false;
}
示例#10
0
static void
ck_barrier_combining_aux(struct ck_barrier_combining *barrier,
    struct ck_barrier_combining_group *tnode,
    unsigned int sense)
{

	/*
	 * If this is the last thread in the group, it moves on to the parent group.
	 * Otherwise, it spins on this group's sense.
	 */
	if (ck_pr_faa_uint(&tnode->count, 1) == tnode->k - 1) {
		/*
		 * If we are and will be the last thread entering the barrier for the
		 * current group then signal the parent group if one exists.
		 */
		if (tnode->parent != NULL)
			ck_barrier_combining_aux(barrier, tnode->parent, sense);

		/*
		 * Once the thread returns from its parent(s), it reinitializes the group's
		 * arrival count and signals other threads to continue by flipping the group
		 * sense. Order of these operations is not important since we assume a static
		 * number of threads are members of a barrier for the lifetime of the barrier.
		 * Since count is explicitly reinitialized, it is guaranteed that at any point
		 * tnode->count is equivalent to tnode->k if and only if that many threads
		 * are at the barrier.
		 */
		ck_pr_store_uint(&tnode->count, 0);
		ck_pr_fence_store();
		ck_pr_store_uint(&tnode->sense, ~tnode->sense);
	} else {
		ck_pr_fence_memory();
		while (sense != ck_pr_load_uint(&tnode->sense))
			ck_pr_stall();
	}

	return;
}
示例#11
0
void
ck_barrier_dissemination_init(struct ck_barrier_dissemination *barrier,
			      struct ck_barrier_dissemination_flag **barrier_internal,
			      unsigned int nthr)
{
	unsigned int i, j, k, size, offset;
	bool p = nthr & (nthr - 1);

	barrier->nthr = nthr;
	barrier->size = size = ck_internal_log(ck_internal_power_2(nthr));
	ck_pr_store_uint(&barrier->tid, 0);

	for (i = 0; i < nthr; ++i) {
		barrier[i].flags[0] = barrier_internal[i];
		barrier[i].flags[1] = barrier_internal[i] + size;
	}

	for (i = 0; i < nthr; ++i) {
		for (k = 0, offset = 1; k < size; ++k, offset <<= 1) {
			/* 
			 * Determine the thread's partner, j, for the current round, k.
			 * Partners are chosen such that by the completion of the barrier,
			 * every thread has been directly (having one of its flag set) or
			 * indirectly (having one of its partners's flags set) signaled
			 * by every other thread in the barrier. 
			 */
			if (p == false)
				j = (i + offset) & (nthr - 1);
			else
				j = (i + offset) % nthr;

			/* Set the thread's partner for round k. */
			barrier[i].flags[0][k].pflag = &barrier[j].flags[0][k].tflag;
			barrier[i].flags[1][k].pflag = &barrier[j].flags[1][k].tflag;

			/* Set the thread's flags to false. */
			barrier[i].flags[0][k].tflag = barrier[i].flags[1][k].tflag = 0;
		}
	}

	return;
}
示例#12
0
void
ck_barrier_mcs_init(struct ck_barrier_mcs *barrier,
                    unsigned int nthr)
{
	unsigned int i, j;

	ck_pr_store_uint(&barrier->tid, 0);

	for (i = 0; i < nthr; ++i) {
		for (j = 0; j < 4; ++j) {
			/*
			 * If there are still threads that don't have parents,
			 * add it as a child.
			 */
			barrier[i].havechild[j] = ((i << 2) + j < nthr - 1) ? ~0 : 0;

			/*
			 * childnotready is initialized to havechild to ensure
			 * a thread does not wait for a child that does not exist.
			 */
			barrier[i].childnotready[j] = barrier[i].havechild[j];
		}

		/* The root thread does not have a parent. */
		barrier[i].parent = (i == 0) ?
					    &barrier[i].dummy :
					    &barrier[(i - 1) >> 2].childnotready[(i - 1) & 3];

		/* Leaf threads do not have any children. */
		barrier[i].children[0] = ((i << 1) + 1 >= nthr)	?
						 &barrier[i].dummy :
						 &barrier[(i << 1) + 1].parentsense;

		barrier[i].children[1] = ((i << 1) + 2 >= nthr)	?
						 &barrier[i].dummy :
						 &barrier[(i << 1) + 2].parentsense;

		barrier[i].parentsense = 0;
	}

	return;
}
示例#13
0
void
ck_barrier_tournament_init(struct ck_barrier_tournament *barrier,
			   struct ck_barrier_tournament_round **rounds,
			   unsigned int nthr)
{
	unsigned int i, k, size, twok, twokm1, imod2k;

	ck_pr_store_uint(&barrier->tid, 0);
	size = ck_barrier_tournament_size(nthr);

	for (i = 0; i < nthr; ++i) {
		/* The first role is always CK_BARRIER_TOURNAMENT_DROPOUT. */
		rounds[i][0].flag = 0;
		rounds[i][0].role = CK_BARRIER_TOURNAMENT_DROPOUT;
		for (k = 1, twok = 2, twokm1 = 1; k < size; ++k, twokm1 = twok, twok <<= 1) {
			rounds[i][k].flag = 0;

			imod2k = i & (twok - 1);
			if (imod2k == 0) {
				if ((i + twokm1 < nthr) && (twok < nthr))
					rounds[i][k].role = CK_BARRIER_TOURNAMENT_WINNER;
				else if (i + twokm1 >= nthr)
					rounds[i][k].role = CK_BARRIER_TOURNAMENT_BYE;
			}

			if (imod2k == twokm1)
				rounds[i][k].role = CK_BARRIER_TOURNAMENT_LOSER;
			else if ((i == 0) && (twok >= nthr))
				rounds[i][k].role = CK_BARRIER_TOURNAMENT_CHAMPION;

			if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_LOSER)
				rounds[i][k].opponent = &rounds[i - twokm1][k].flag;
			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;  
		}
	}

	ck_pr_store_ptr(&barrier->rounds, rounds);
	return;
}
示例#14
0
bool
ck_array_commit(ck_array_t *array)
{
	struct _ck_array *m = array->transaction;

	if (m != NULL) {
		struct _ck_array *p;

		m->n_committed = array->n_entries;
		ck_pr_fence_store();
		p = array->active;
		ck_pr_store_ptr(&array->active, m);
		array->allocator->free(p, sizeof(struct _ck_array) +
		    p->length * sizeof(void *), true);
		array->transaction = NULL;

		return true;
	}

	ck_pr_fence_store();
	ck_pr_store_uint(&array->active->n_committed, array->n_entries);
	return true;
}
示例#15
0
文件: ck_rhs.c 项目: RaHus/ck
static inline void
ck_rhs_map_bound_set(struct ck_rhs_map *m,
    unsigned long h,
    unsigned long n_probes)
{
	unsigned long offset = h & m->mask;
	struct ck_rhs_entry_desc *desc;

	if (n_probes > m->probe_maximum)
		ck_pr_store_uint(&m->probe_maximum, n_probes);
	if (!(m->read_mostly)) {
		desc = &m->entries.descs[offset];

		if (desc->probe_bound < n_probes) {
			if (n_probes > CK_RHS_WORD_MAX)
				n_probes = CK_RHS_WORD_MAX;

			CK_RHS_STORE(&desc->probe_bound, n_probes);
			ck_pr_fence_store();
		}
	}

	return;
}
示例#16
0
void
ck_barrier_tournament(struct ck_barrier_tournament *barrier,
                      struct ck_barrier_tournament_state *state)
{
	struct ck_barrier_tournament_round **rounds = ck_pr_load_ptr(&barrier->rounds);
	int round = 1;

	for (;; ++round) {
		switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD***
		case CK_BARRIER_TOURNAMENT_BYE:
			break;
		case CK_BARRIER_TOURNAMENT_CHAMPION:
			/*
			 * The CK_BARRIER_TOURNAMENT_CHAMPION waits until it wins the tournament; it then
			 * sets the final flag before the wakeup phase of the barrier.
			 */
			while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)
				ck_pr_stall();

			ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);
			goto wakeup;
		case CK_BARRIER_TOURNAMENT_DROPOUT:
			/* NOTREACHED */
			break;
		case CK_BARRIER_TOURNAMENT_LOSER:
			/*
			 * CK_BARRIER_TOURNAMENT_LOSERs set the flags of their opponents and wait until
			 * their opponents release them after the tournament is over.
			 */
			ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);
			while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)
				ck_pr_stall();

			goto wakeup;
		case CK_BARRIER_TOURNAMENT_WINNER:
			/*
			 * CK_BARRIER_TOURNAMENT_WINNERs wait until their current opponent sets their flag; they then
			 * continue to the next round of the tournament.
			 */
			while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)
				ck_pr_stall();
			break;
		}
	}

wakeup:
	for (round -= 1 ;; --round) {
		switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD***
		case CK_BARRIER_TOURNAMENT_BYE:
			break;
		case CK_BARRIER_TOURNAMENT_CHAMPION:
			/* NOTREACHED */
			break;
		case CK_BARRIER_TOURNAMENT_DROPOUT:
			goto leave;
			break;
		case CK_BARRIER_TOURNAMENT_LOSER:
			/* NOTREACHED */
			break;
		case CK_BARRIER_TOURNAMENT_WINNER:
			/* 
			 * Winners inform their old opponents the tournament is over
			 * by setting their flags.
			 */
			ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);
			break;
		}
	}

leave:
	state->sense = ~state->sense;
	return;
}
示例#17
0
bool
ck_bag_put_spmc(struct ck_bag *bag, void *entry)
{
	struct ck_bag_block *cursor, *new_block, *new_block_prev, *new_tail;
	uint16_t n_entries_block;
	size_t blocks_alloc, i;
	uintptr_t next = 0;

	new_block = new_block_prev = new_tail = NULL;

	/*
	 * Blocks with available entries are stored in
	 * the bag's available list.
	 */
	cursor = bag->avail_head;
	if (cursor != NULL) {
		n_entries_block = ck_bag_block_count(cursor);
	} else {
		/* The bag is full, allocate a new set of blocks */
		if (bag->alloc_strat == CK_BAG_ALLOCATE_GEOMETRIC)
			blocks_alloc = (bag->n_blocks + 1) << 1;
		else
			blocks_alloc = 1;

		for (i = 0; i < blocks_alloc-1; i++) {
			new_block = allocator.malloc(bag->info.bytes);

			if (new_block == NULL)
				return false;

			/*
			 * First node is the tail of the Bag.
			 * Second node is the new tail of the Available list.
			 */
			if (i == 0)
				new_tail = new_block;

#ifndef __x86_64__
			new_block->next.n_entries = 0;
#endif

			new_block->next.ptr = new_block_prev;
			new_block->avail_next = new_block_prev;
			if (new_block_prev != NULL)
				new_block_prev->avail_prev = new_block;

			new_block_prev = new_block;
		}

		/*
		 * Insert entry into last allocated block.
		 * cursor is new head of available list.
		 */
		cursor = allocator.malloc(bag->info.bytes);
		cursor->avail_next = new_block;
		cursor->avail_prev = NULL;
		new_block->avail_prev = cursor;
		n_entries_block = 0;
		bag->n_blocks += blocks_alloc; /* n_blocks and n_avail_blocks? */
	}

	/* Update the available list */
	if (new_block != NULL) {
		if (bag->avail_tail != NULL) {
			cursor->avail_prev = bag->avail_tail;
			bag->avail_tail->avail_next = cursor;
		} else {
			/* Available list was previously empty */
			bag->avail_head = cursor;
		}

		bag->avail_tail = new_tail;
	} else if (n_entries_block == bag->info.max-1) {
	    /* New entry will fill up block, remove from avail list */
		    if (cursor->avail_prev != NULL)
			    cursor->avail_prev->avail_next = cursor->avail_next;

		    if (cursor->avail_next != NULL)
			    cursor->avail_next->avail_prev = cursor->avail_prev;

		    if (bag->avail_head == cursor)
			    bag->avail_head = cursor->avail_next;

		    if (bag->avail_tail == cursor)
			    bag->avail_tail = cursor->avail_prev;

		    /* For debugging purposes */
		    cursor->avail_next = NULL;
		    cursor->avail_prev = NULL;
	}

	/* Update array and block->n_entries */
	cursor->array[n_entries_block++] = entry;
	ck_pr_fence_store();

#ifdef __x86_64__
	next = ((uintptr_t)n_entries_block << 48);
#endif

	/* Update bag's list */
	if (n_entries_block == 1) {

		if (bag->head != NULL) {
#ifdef __x86_64__
			next += ((uintptr_t)(void *)ck_bag_block_next(bag->head));
#else
			next = (uintptr_t)(void *)ck_bag_block_next(bag->head);
#endif
		}

#ifndef __x86_64__
		ck_pr_store_ptr(&cursor->next.n_entries, (void *)(uintptr_t)n_entries_block);
#endif

		ck_pr_store_ptr(&cursor->next.ptr, (void *)next);
		ck_pr_store_ptr(&bag->head, cursor);
	} else {

#ifdef __x86_64__
		next += ((uintptr_t)(void *)ck_bag_block_next(cursor->next.ptr));
		ck_pr_store_ptr(&cursor->next, (void *)next);
#else
		ck_pr_store_ptr(&cursor->next.n_entries, (void *)(uintptr_t)n_entries_block);
#endif

	}

	ck_pr_store_uint(&bag->n_entries, bag->n_entries + 1);
	return true;
}
示例#18
0
bool
ck_bag_remove_spmc(struct ck_bag *bag, void *entry)
{
	struct ck_bag_block *cursor, *copy, *prev;
	uint16_t block_index, n_entries;

	cursor = bag->head;
	prev = NULL;
	while (cursor != NULL) {
		n_entries = ck_bag_block_count(cursor);

		for (block_index = 0; block_index < n_entries; block_index++) {
			if (cursor->array[block_index] == entry)
				goto found;

		}

		prev = cursor;
		cursor = ck_bag_block_next(cursor->next.ptr);
	}

	return true;

found:
	/* Cursor points to containing block, block_index is index of deletion */
	if (n_entries == 1) {
		/* If a block's single entry is being removed, remove the block. */
		if (prev == NULL) {
			struct ck_bag_block *new_head = ck_bag_block_next(cursor->next.ptr);
			ck_pr_store_ptr(&bag->head, new_head);
		} else {
			uintptr_t next;
#ifdef __x86_64__
			next = ((uintptr_t)prev->next.ptr & (CK_BAG_BLOCK_ENTRIES_MASK)) |
				(uintptr_t)(void *)ck_bag_block_next(cursor->next.ptr);
#else
			next = (uintptr_t)(void *)cursor->next.ptr;
#endif
			ck_pr_store_ptr(&prev->next.ptr, (struct ck_bag_block *)next);
		}

		/* Remove block from available list */
		if (cursor->avail_prev != NULL)
			cursor->avail_prev->avail_next = cursor->avail_next;

		if (cursor->avail_next != NULL)
			cursor->avail_next->avail_prev = cursor->avail_prev;

		bag->n_blocks--;
		copy = cursor->avail_next;
	} else {
		uintptr_t next_ptr;

		copy = allocator.malloc(bag->info.bytes);
		if (copy == NULL)
			return false;

		memcpy(copy, cursor, bag->info.bytes);
		copy->array[block_index] = copy->array[--n_entries];

		next_ptr = (uintptr_t)(void *)ck_bag_block_next(copy->next.ptr);
#ifdef __x86_64__
		copy->next.ptr = (void *)(((uintptr_t)n_entries << 48) | next_ptr);
#else
		copy->next.n_entries = n_entries;
		copy->next.ptr = (struct ck_bag_block *)next_ptr;
#endif

		ck_pr_fence_store();

		if (prev == NULL) {
			ck_pr_store_ptr(&bag->head, copy);
		} else {
#ifdef __x86_64__
			uintptr_t next = ((uintptr_t)prev->next.ptr & (CK_BAG_BLOCK_ENTRIES_MASK)) |
				(uintptr_t)(void *)ck_bag_block_next(copy);
			ck_pr_store_ptr(&prev->next.ptr, (struct ck_bag_block *)next);
#else
			ck_pr_store_ptr(&prev->next.ptr, copy);
#endif
		}

		if (n_entries == bag->info.max - 1) {
			/* Block was previously fully, add to head of avail. list */
			copy->avail_next = bag->avail_head;
			copy->avail_prev = NULL;
			bag->avail_head = copy;
		}

	}

	/* Update available list. */
	if (bag->avail_head == cursor)
		bag->avail_head = copy;

	if (bag->avail_tail == cursor)
		bag->avail_tail = copy;

	allocator.free(cursor, sizeof(struct ck_bag_block), true);
	ck_pr_store_uint(&bag->n_entries, bag->n_entries - 1);
	return true;
}
示例#19
0
int
main(int argc, char *argv[])
{
	uint64_t v, d;
	unsigned int i;
	pthread_t *threads;
	struct block *context;
	ck_spinlock_t *local_lock;

	if (argc != 5) {
		ck_error("Usage: ck_cohort <number of cohorts> <threads per cohort> "
			"<affinity delta> <critical section>\n");
	}

	n_cohorts = atoi(argv[1]);
	if (n_cohorts <= 0) {
		ck_error("ERROR: Number of cohorts must be greater than 0\n");
	}

	nthr = n_cohorts * atoi(argv[2]);
	if (nthr <= 0) {
		ck_error("ERROR: Number of threads must be greater than 0\n");
	}

	critical = atoi(argv[4]);
	if (critical < 0) {
		ck_error("ERROR: critical section cannot be negative\n");
	}

	threads = malloc(sizeof(pthread_t) * nthr);
	if (threads == NULL) {
		ck_error("ERROR: Could not allocate thread structures\n");
	}

	cohorts = malloc(sizeof(struct cohort_record) * n_cohorts);
	if (cohorts == NULL) {
		ck_error("ERROR: Could not allocate cohort structures\n");
	}

	context = malloc(sizeof(struct block) * nthr);
	if (context == NULL) {
		ck_error("ERROR: Could not allocate thread contexts\n");
	}

	a.delta = atoi(argv[2]);
	a.request = 0;

	count = malloc(sizeof(*count) * nthr);
	if (count == NULL) {
		ck_error("ERROR: Could not create acquisition buffer\n");
	}
	memset(count, 0, sizeof(*count) * nthr);

	fprintf(stderr, "Creating cohorts...");
	for (i = 0 ; i < n_cohorts ; i++) {
		local_lock = malloc(max(CK_MD_CACHELINE, sizeof(ck_spinlock_t)));
		if (local_lock == NULL) {
			ck_error("ERROR: Could not allocate local lock\n");
		}
		CK_COHORT_INIT(basic, &((cohorts + i)->cohort), &global_lock, local_lock,
		    CK_COHORT_DEFAULT_LOCAL_PASS_LIMIT);
		local_lock = NULL;
	}
	fprintf(stderr, "done\n");

	fprintf(stderr, "Creating threads (fairness)...");
	for (i = 0; i < nthr; i++) {
		context[i].tid = i;
		if (pthread_create(&threads[i], NULL, fairness, context + i)) {
			ck_error("ERROR: Could not create thread %d\n", i);
		}
	}
	fprintf(stderr, "done\n");

	ck_pr_store_uint(&ready, 1);
	common_sleep(10);
	ck_pr_store_uint(&ready, 0);

	fprintf(stderr, "Waiting for threads to finish acquisition regression...");
	for (i = 0; i < nthr; i++)
		pthread_join(threads[i], NULL);
	fprintf(stderr, "done\n\n");

	for (i = 0, v = 0; i < nthr; i++) {
		printf("%d %15" PRIu64 "\n", i, count[i].value);
		v += count[i].value;
	}

	printf("\n# total       : %15" PRIu64 "\n", v);
	printf("# throughput  : %15" PRIu64 " a/s\n", (v /= nthr) / 10);

	for (i = 0, d = 0; i < nthr; i++)
		d += (count[i].value - v) * (count[i].value - v);

	printf("# average     : %15" PRIu64 "\n", v);
	printf("# deviation   : %.2f (%.2f%%)\n\n", sqrt(d / nthr), (sqrt(d / nthr) / v) * 100.00);

	return 0;
}