From 3059605ed4a2183d11e1f2ea99732f18ab11e637 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Wed, 17 Jun 2009 15:46:22 +0200 Subject: [PATCH] Communication techniques bench: add jikes barrier --- communication_techniques/Makefile | 2 +- .../include/jikes_barrier_comm.h | 35 ++++ communication_techniques/src/jikes_barrier.c | 185 ++++++++++++++++++ 3 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 communication_techniques/include/jikes_barrier_comm.h create mode 100644 communication_techniques/src/jikes_barrier.c diff --git a/communication_techniques/Makefile b/communication_techniques/Makefile index f2ba68f..e88ff57 100644 --- a/communication_techniques/Makefile +++ b/communication_techniques/Makefile @@ -18,7 +18,7 @@ LDFLAGS=-L$(LIBDIR) -L$(LOCALDIR)/$(PAPIHIGHLEVELLIBDIR) -Wl,-rpath-link,$(HOME) CC=gcc # Files -BINNAMES=asm_cache_comm c_cache_comm pipe_comm shared_mem_comm shared_mem_opt_comm +BINNAMES=asm_cache_comm c_cache_comm pipe_comm shared_mem_comm shared_mem_opt_comm jikes_barrier_comm BINS=$(patsubst %, $(BINDIR)/%, $(BINNAMES)) MAIN_OBJS=main.o common.o COMMON_LIB_OBJS=common.o diff --git a/communication_techniques/include/jikes_barrier_comm.h b/communication_techniques/include/jikes_barrier_comm.h new file mode 100644 index 0000000..536060e --- /dev/null +++ b/communication_techniques/include/jikes_barrier_comm.h @@ -0,0 +1,35 @@ +#ifndef __COMM_H_ +#define __COMM_H_ 1 + +#include + +/* Non standard include */ +#include + +#define FAKE_NURSERY_START 1 +#define REALLY_FAKE_NURSERY_START ((uintptr_t) -1) + +struct communication_assoc +{ + struct communication_assoc *next; + struct communication_assoc *prev; + pthread_t tid; +}; + +extern struct communication_assoc assoc_root; + +__BEGIN_DECLS + +struct communication_assoc *create_comm_assoc(void); +void insert(void *); +static inline void send(void **addr) { + void *ptd_addr; + + ptd_addr = *addr; /* NOTE: Not done in real jikes barrier */ + if (!((uintptr_t) addr >= REALLY_FAKE_NURSERY_START) && ((uintptr_t) ptd_addr >= FAKE_NURSERY_START)) + insert(addr); +} + +__END_DECLS + +#endif diff --git a/communication_techniques/src/jikes_barrier.c b/communication_techniques/src/jikes_barrier.c new file mode 100644 index 0000000..314b83e --- /dev/null +++ b/communication_techniques/src/jikes_barrier.c @@ -0,0 +1,185 @@ +#include +#include +#include +#include + +/* Non standard include */ +#include +#include + + +#define LOG_BYTES_IN_PAGE 12 +#define LOG_PAGES_PER_BUFFER 0 +#define LOG_BYTES_IN_ADDRESS ((sizeof(void *) == 8) ? 3 : 2) +#define LOG_BUFFER_SIZE (LOG_BYTES_IN_PAGE + LOG_PAGES_PER_BUFFER) +#define BYTES_IN_ADDRESS (1 << LOG_BYTES_IN_ADDRESS) +#define BUFFER_MASK ((1 << LOG_BUFFER_SIZE) - 1) +#define BUFFER_SIZE (1 << LOG_BUFFER_SIZE) +#define META_DATA_SIZE (2 * BYTES_IN_ADDRESS) +#define USABLE_BUFFER_BYTES (BUFFER_SIZE - META_DATA_SIZE) + + +struct double_linked_list +{ + struct double_linked_list *prev; + struct double_linked_list *next; +}; + +static __thread void **local_tail = NULL; +static __thread void **local_tail_buffer_end = NULL; +static struct double_linked_list *global_tail = NULL; +static struct double_linked_list *global_head = NULL; +static int bufsenqueued = 0; +static unsigned int lock = 0; + +struct communication_assoc *create_comm_assoc(void) +{ + struct communication_assoc *assoc; + void **new_buffer; + + new_buffer = (void **) malloc(BUFFER_SIZE); + local_tail = new_buffer + (USABLE_BUFFER_BYTES - BYTES_IN_ADDRESS - + (USABLE_BUFFER_BYTES % (1 << LOG_BYTES_IN_ADDRESS))) + BYTES_IN_ADDRESS; // The second parenthesis is equal to 0 + local_tail_buffer_end = local_tail; + assoc = (struct communication_assoc *) malloc(sizeof(struct communication_assoc)); + assoc->tid = pthread_self(); + return assoc; +} + +void set_next(struct double_linked_list *list, struct double_linked_list *next) +{ + list->next = next; +} + +void set_prev(struct double_linked_list *list, struct double_linked_list *prev) +{ + list->prev = prev; +} + +static void spin_lock(unsigned int *lock) +{ + int inc = 0x00010000; + int tmp; + + asm volatile("lock xaddl %0, %1\n" + "movzwl %w0, %2\n\t" + "shrl $16, %0\n\t" + "1:\t" + "cmpl %0, %2\n\t" + "je 2f\n\t" + "rep ; nop\n\t" + "movzwl %1, %2\n\t" + /* don't need lfence here, because loads are in-order */ + "jmp 1b\n" + "2:" + : "+r" (inc), "+m" (*lock), "=&r" (tmp) + : + : "memory", "cc"); +} + +static void spin_unlock(unsigned int *lock) +{ + asm volatile("incw %0" + : "+m" (*lock) + : + : "memory", "cc"); +} + +void enqueue(struct double_linked_list *list, int arity, int to_tail) // Insert in the shared buffer: tail here is the tail of the shared buffer +{ + spin_lock(&lock); + if (to_tail) + { + /* Add to the tail of the queue */ + set_next(list, NULL); + if (global_tail == NULL) + global_head = list; + else + set_next(global_tail, list); + set_prev(list, global_tail); + global_tail = list; + } + else + { + /* Add to the head of the queue */ + set_prev(list, NULL); + if (global_head == NULL) + global_tail = list; + else + set_prev(global_head, list); + set_next(list, global_head); + global_head = list; + } + bufsenqueued++; + spin_unlock(&lock); +} + +void **normalizeTail(int arity) +{ + void **src = local_tail; + void **buffer_start = (void **) ((uintptr_t) local_tail & ~BUFFER_MASK); + void **last = buffer_start + (USABLE_BUFFER_BYTES - BYTES_IN_ADDRESS - (USABLE_BUFFER_BYTES % (arity << LOG_BYTES_IN_ADDRESS))) - ((uintptr_t) local_tail & BUFFER_MASK); + /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ + /* point on the last address in the buffer */ + while (buffer_start <= last) /* copy the addresses in the buffer from the end to the beginning of the buffer */ + { + *buffer_start = *src; + src++; + buffer_start++; + } + return last; // Return the buffer address of the last address (if address goes from 0 to n then it's &buf[n] +} + +void closeAndEnqueueTail(int arity) +{ + void **last; + if ((((uintptr_t) local_tail) & BUFFER_MASK) != 0) // prematurely closed, won't pass here if it comes from insert + last = normalizeTail(arity); + else // a full tail buffer + last = local_tail_buffer_end - BYTES_IN_ADDRESS; // last space in the buffer before the 8/16 bytes of metadata of the buffer + enqueue((struct double_linked_list *) ((uintptr_t) last + BYTES_IN_ADDRESS), arity, 1); +} + +void checkForAsyncCollection(void) +{ +} + +void tailOverflow(int arity) +{ + void *new_buffer; + if (local_tail != NULL) + closeAndEnqueueTail(arity); // Add the buffer to the tail of the shared buffer + if (posix_memalign(&new_buffer, BUFFER_SIZE, BUFFER_SIZE)) + fprintf(stderr, "Failed to allocate space for queue. Is metadata virtual memory exhausted?"); + local_tail = (void **) ((uintptr_t) new_buffer + (USABLE_BUFFER_BYTES - BYTES_IN_ADDRESS - + (USABLE_BUFFER_BYTES % (arity << LOG_BYTES_IN_ADDRESS))) + BYTES_IN_ADDRESS); // The second parenthesis is equal to 0 + local_tail_buffer_end = local_tail; + checkForAsyncCollection(); // possible side-effect of alloc() +} + +void insert(void *addr) +{ + if ((((uintptr_t) local_tail) & BUFFER_MASK) == 0) + tailOverflow(1); + local_tail--; + *local_tail = addr; +} + +void reception(void (*on_receive)(void *)) +{ + struct double_linked_list *list_cur; + void **buf_start, **buf_ptr; + wait_initialization(); + /* printf("Activate the consumer...\n"); */ + while (cont && (global_head == NULL)); + if (!cont) + return; + list_cur = global_head; + do + { + buf_start = (void **) (((uintptr_t) &list_cur->prev) & ~BUFFER_MASK); + for (buf_ptr = buf_start; buf_ptr != (void **) &list_cur->prev; buf_ptr++) + on_receive(*buf_ptr); + while (cont && (list_cur->next == NULL)); + } while (cont); +}