Merge branch 'histolines'
Conflicts: communication_techniques/src/main.c
This commit is contained in:
commit
0c81f6323c
|
@ -1 +1,2 @@
|
|||
include/specific_comm.h
|
||||
logs/*
|
||||
|
|
|
@ -1,60 +1,83 @@
|
|||
# Directories
|
||||
OBJDIR=obj
|
||||
BINDIR=bin
|
||||
SRCDIR=src
|
||||
INCDIR=include
|
||||
LIBDIR=lib
|
||||
LOCALDIR=$(HOME)/local
|
||||
PAPIHIGHLEVELLIBDIR=lib
|
||||
PAPIHIGHLEVELINCDIR=include
|
||||
OBJDIR:=obj
|
||||
BINDIR:=bin
|
||||
SRCDIR:=src
|
||||
INCDIR:=include
|
||||
LIBDIR:=lib
|
||||
LOGDIR:=logs
|
||||
LOCALDIR:=$(HOME)/local
|
||||
|
||||
# PHL stands for PAPI High Level
|
||||
PHL_LIB_INSTALLDIR:=lib
|
||||
PHL_INC_INSTALLDIR:=lib
|
||||
PHL_LIBDIR:=lib
|
||||
PHL_INCDIR:=include
|
||||
PHLDIR:=../papihighlevel
|
||||
PAPI_LIB_INSTALLDIR:=lib
|
||||
PAPIDIR:=$(PHLDIR)/papi
|
||||
PAPI_LIBDIR:=src
|
||||
PAPI_PFMDIR:=$(PAPI_LIBDIR)/libpfm-3.y/lib
|
||||
CALCDIR:=calculation
|
||||
COMMDIR:=communication
|
||||
|
||||
# Compilation flags
|
||||
# I know -finline-functions and -finline-functions-called-once are enabled by
|
||||
# -O3 but I did this in case gcc behaviour change one day
|
||||
CFLAGS=-g -O3 -finline-functions -finline-functions-called-once -Wall -Werror
|
||||
LDFLAGS=-L$(LIBDIR) -L$(LOCALDIR)/$(PAPIHIGHLEVELLIBDIR) -Wl,-rpath-link,$(HOME)/local/lib -lpthread -lpapihighlevel
|
||||
CFLAGS:=-c -O3 -finline-functions -finline-functions-called-once -Wall -Werror
|
||||
LDFLAGS:=-L$(LIBDIR) -L$(LOCALDIR)/$(PHL_LIB_INSTALLDIR) -L$(PHLDIR)/$(PHL_LIBDIR)
|
||||
LDFLAGS:=$(LDFLAGS) -Wl,-rpath-link,$(LOCALDIR)/$(PAPI_LIB_INSTALLDIR):$(PAPIDIR)/$(PAPI_LIBDIR):$(PAPIDIR)/$(PAPI_PFMDIR)
|
||||
LDFLAGS:=$(LDFLAGS) -lpthread -lpapihighlevel -ldl
|
||||
|
||||
# Executables
|
||||
CC=gcc
|
||||
|
||||
# Files
|
||||
BINNAMES=asm_cache_comm c_cache_comm pipe_comm shared_mem_comm shared_mem_opt_comm jikes_barrier_comm fake_comm
|
||||
BINS=$(patsubst %, $(BINDIR)/%, $(BINNAMES))
|
||||
MAIN_OBJS=main.o common.o
|
||||
COMMON_LIB_OBJS=common.o
|
||||
BINNAMES:=asm_cache_comm c_cache_comm pipe_comm shared_mem_comm shared_mem_opt_comm jikes_barrier_comm fake_comm
|
||||
CALCLIBSNAMES:=calc_mat calc_useless_loop
|
||||
BINS:=$(patsubst %,$(BINDIR)/%,$(BINNAMES))
|
||||
CALCLIBS:=$(patsubst %,$(LIBDIR)/$(CALCDIR)/lib%.so.1,$(CALCLIBSNAMES))
|
||||
MAIN_OBJS:=main.o
|
||||
COMMON_LIB_OBJS:=common.o
|
||||
|
||||
.PHONY: all tidy clean distclean symlink
|
||||
.PHONY: all tidy clean distclean
|
||||
.SECONDARY:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
default: $(BINS)
|
||||
|
||||
ifneq (,$(findstring $(MAKECMDGOALS),$(BINS)))
|
||||
BASE_TARGET=$(patsubst $(BINDIR)/%_comm,%,$(MAKECMDGOALS))
|
||||
default: $(BINS) $(CALCLIBS)
|
||||
|
||||
# Compilation of binary
|
||||
$(BINDIR)/$(BASE_TARGET)_comm: $(patsubst %,$(OBJDIR)/$(BASE_TARGET)_%,$(MAIN_OBJS)) $(LIBDIR)/lib$(BASE_TARGET).a
|
||||
$(BINDIR)/%_comm: $(patsubst %,$(OBJDIR)/\%/%,$(MAIN_OBJS)) $(LIBDIR)/$(COMMDIR)/lib%.a
|
||||
if [ ! -d $(BINDIR) ] ; then mkdir $(BINDIR) ; fi
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
# Compilation of library
|
||||
$(LIBDIR)/lib$(BASE_TARGET).a: $(OBJDIR)/$(BASE_TARGET).o $(patsubst %,$(OBJDIR)/$(BASE_TARGET)_%,$(COMMON_LIB_OBJS))
|
||||
# Creation of comm library
|
||||
$(LIBDIR)/$(COMMDIR)/lib%.a: $(OBJDIR)/$(COMMDIR)/%.o $(patsubst %,$(OBJDIR)/$(COMMDIR)/\%/%,$(COMMON_LIB_OBJS))
|
||||
if [ ! -d $(LIBDIR) ] ; then mkdir $(LIBDIR) ; fi
|
||||
if [ ! -d $(LIBDIR)/$(COMMDIR) ] ; then mkdir $(LIBDIR)/$(COMMDIR) ; fi
|
||||
$(AR) -rcus $@ $^
|
||||
|
||||
# Compile common source files
|
||||
$(OBJDIR)/$(BASE_TARGET)_%.o: $(SRCDIR)/%.c symlink
|
||||
if [ ! -d $(OBJDIR) ] ; then mkdir $(OBJDIR) ; fi
|
||||
$(CC) $(CFLAGS) -I$(INCDIR) -I$(LOCALDIR)/$(PAPIHIGHLEVELINCDIR) -c $< -o $@
|
||||
endif
|
||||
# Creation of calc library
|
||||
$(LIBDIR)/$(CALCDIR)/libcalc_%.so.1: $(OBJDIR)/$(CALCDIR)/calc_%.o
|
||||
if [ ! -d $(LIBDIR) ] ; then mkdir $(LIBDIR) ; fi
|
||||
if [ ! -d $(LIBDIR)/$(CALCDIR) ] ; then mkdir $(LIBDIR)/$(CALCDIR) ; fi
|
||||
$(CC) -shared -Wl,-soname,libcalc_$*.so.1 -o $@ $<
|
||||
cd $(@D) ; ln -sf libcalc_$*.so.1 libcalc_$*.so
|
||||
|
||||
# Compile non common source files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c symlink
|
||||
# Compile lib specific source files
|
||||
$(OBJDIR)/$(COMMDIR)/%.o: $(SRCDIR)/$(COMMDIR)/%.c $(INCDIR)/%_comm.h $(INCDIR)/commtech.h
|
||||
if [ ! -d $(OBJDIR) ] ; then mkdir $(OBJDIR) ; fi
|
||||
$(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@
|
||||
if [ ! -d $(OBJDIR)/$(COMMDIR) ] ; then mkdir $(OBJDIR)/$(COMMDIR) ; fi
|
||||
cd $(INCDIR) ; ln -sfT $*_comm.h specific_comm.h
|
||||
$(CC) $(CFLAGS) -I$(INCDIR) $< -o $@
|
||||
|
||||
symlink:
|
||||
ln -sfT $(BASE_TARGET)_comm.h $(INCDIR)/specific_comm.h
|
||||
# Rule for compiling common source files using libcomm is at the end of
|
||||
# this file, after the .SECONDEXPANSION target
|
||||
|
||||
# Compile source files not using libcomm
|
||||
$(OBJDIR)/$(CALCDIR)/%.o: $(SRCDIR)/$(CALCDIR)/%.c
|
||||
if [ ! -d $(OBJDIR) ] ; then mkdir $(OBJDIR) ; fi
|
||||
if [ ! -d $(OBJDIR)/$(CALCDIR) ] ; then mkdir $(OBJDIR)/$(CALCDIR) ; fi
|
||||
$(CC) $(CFLAGS) -I$(INCDIR) $< -o $@
|
||||
|
||||
#.%.d: %.c
|
||||
# gcc $(CFLAGS) -MM $^ | sed -e 's/\([^:]*\):\(.*\)/\1 $@: \2 Makefile/' > $@
|
||||
|
@ -66,6 +89,9 @@ clean:
|
|||
rm -f $(INCDIR)/specific_comm.h
|
||||
rm -rf $(OBJDIR)
|
||||
|
||||
logclean:
|
||||
rm -rf $(LOGDIR)
|
||||
|
||||
distclean: clean
|
||||
rm -rf $(BINDIR) $(LIBDIR)
|
||||
|
||||
|
@ -78,3 +104,19 @@ distclean: clean
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
.SECONDEXPANSION:
|
||||
|
||||
# Compile common source files using libcomm
|
||||
$(OBJDIR)/$(COMMDIR)/%.o: $(SRCDIR)/$(COMMDIR)/$$(*F).c $(INCDIR)/$$(*D)_comm.h $(INCDIR)/commtech.h
|
||||
if [ ! -d $(OBJDIR) ] ; then mkdir $(OBJDIR) ; fi
|
||||
if [ ! -d $(OBJDIR)/$(COMMDIR) ] ; then mkdir $(OBJDIR)/$(COMMDIR) ; fi
|
||||
if [ ! -d $(OBJDIR)/$(COMMDIR)/$(*D) ] ; then mkdir $(OBJDIR)/$(COMMDIR)/$(*D) ; fi
|
||||
cd $(INCDIR) ; ln -sfT $(*D)_comm.h specific_comm.h
|
||||
$(CC) $(CFLAGS) -I$(INCDIR) $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/$$(*F).c $(INCDIR)/$$(*D)_comm.h $(INCDIR)/commtech.h
|
||||
if [ ! -d $(OBJDIR) ] ; then mkdir $(OBJDIR) ; fi
|
||||
if [ ! -d $(OBJDIR)/$(*D) ] ; then mkdir $(OBJDIR)/$(*D) ; fi
|
||||
cd $(INCDIR) ; ln -sfT $(*D)_comm.h specific_comm.h
|
||||
$(CC) $(CFLAGS) -I$(INCDIR) -I$(LOCALDIR)/$(PHL_INCDIR) -I../$(PHLDIR)/$(PHL_INCDIR) $< -o $@
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
- move init_thread_library in papihighlevel.c in init_library (the constructor is only called once)
|
|
@ -1,37 +1,36 @@
|
|||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <commtech.h>
|
||||
|
||||
/* This is not an error, we need this two-macro system */
|
||||
#define toString(x) doStringification(x)
|
||||
#define doStringification(x) #x
|
||||
|
||||
struct communication_channel
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct comm_channel
|
||||
{
|
||||
void *buf[2 * BUF_SIZE / sizeof(void *)] __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
int state __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
volatile void *buf[2 * BUF_SIZE / sizeof(void *)] __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
volatile int state __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
int idx __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
};
|
||||
|
||||
struct communication_assoc
|
||||
struct thread_comm
|
||||
{
|
||||
struct communication_assoc *next;
|
||||
struct communication_assoc *prev;
|
||||
pthread_t tid;
|
||||
struct communication_channel *channel;
|
||||
struct comm_channel *channel;
|
||||
int receiver_idx;
|
||||
int unused;
|
||||
};
|
||||
|
||||
extern struct communication_assoc assoc_root;
|
||||
extern struct thread_comm *tcomms;
|
||||
extern int swap_buffer;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void);
|
||||
static inline void send(void **addr) {
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
static inline void send(void **addr)
|
||||
{
|
||||
asm volatile("mov %%gs:channel@NTPOFF + 2 *" toString(BUF_SIZE) " + " toString(CACHE_LINE_SIZE) ", %%eax\n\t"
|
||||
"mov %0, %%gs:channel@NTPOFF(%%eax)\n\t"
|
||||
"addl $4, %%eax\n\t"
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
/* Non standard include */
|
||||
#include <commtech.h>
|
||||
|
||||
/* This is not an error, we need this two-macro system */
|
||||
#define toString(x) doStringification(x)
|
||||
#define doStringification(x) #x
|
||||
|
||||
struct comm_channel
|
||||
{
|
||||
volatile void *buf[2 * BUF_SIZE / sizeof(void *)] __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
volatile int state __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
int idx __attribute__ ((aligned (CACHE_LINE_SIZE)));
|
||||
};
|
||||
|
||||
struct thread_comm
|
||||
{
|
||||
struct comm_channel *channel;
|
||||
int receiver_idx;
|
||||
};
|
||||
|
||||
extern struct thread_comm *tcomms;
|
||||
extern __thread struct comm_channel channel;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
static inline void send(void **addr)
|
||||
{
|
||||
channel.buf[channel.idx++] = addr;
|
||||
channel.idx %= 2 * BUF_SIZE / sizeof(void *);
|
||||
if (!(channel.idx % (BUF_SIZE / sizeof(void *))))
|
||||
{
|
||||
while (channel.state);
|
||||
channel.state = 1;
|
||||
}
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -1,7 +1,5 @@
|
|||
#ifndef _COMMON_COMM_H_
|
||||
#define _COMMON_COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef _COMMTECH_H_
|
||||
#define _COMMTECH_H_ 1
|
||||
|
||||
#define CACHE_LINE_SIZE 128
|
||||
#define BUF_SIZE CACHE_LINE_SIZE
|
||||
|
@ -10,16 +8,15 @@
|
|||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
extern volatile int cont;
|
||||
extern long nb_prod;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void add_sender(void);
|
||||
void remove_sender(void);
|
||||
volatile int *init_comm(void);
|
||||
int init_library(void);
|
||||
int end_library(void);
|
||||
int init_producer_thread(void);
|
||||
int end_producer_thread(void);
|
||||
void reception(void (*)(void *));
|
||||
extern int swap_buffer;
|
||||
void wait_initialization(void);
|
||||
void discover_new_producers(void);
|
||||
|
||||
__END_DECLS
|
||||
|
|
@ -1,27 +1,21 @@
|
|||
#ifndef __COMM_H_
|
||||
#define __COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
#define FAKE_NURSERY_START 1
|
||||
|
||||
struct communication_assoc
|
||||
struct thread_comm
|
||||
{
|
||||
struct communication_assoc *next;
|
||||
struct communication_assoc *prev;
|
||||
pthread_t tid;
|
||||
int unused;
|
||||
};
|
||||
|
||||
extern struct communication_assoc assoc_root;
|
||||
extern struct thread_comm *tcomms;
|
||||
extern __thread void ** volatile store_var;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void);
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
static inline void send(void **addr) {
|
||||
static __thread void **store_var = NULL;
|
||||
store_var = addr;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +1,29 @@
|
|||
#ifndef __COMM_H_
|
||||
#define __COMM_H_ 1
|
||||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
|
||||
#define FAKE_NURSERY_START 1
|
||||
#define REALLY_FAKE_NURSERY_START ((uintptr_t) -1)
|
||||
#define ANOTHER_FAKE_NURSERY_START ((uintptr_t) -1)
|
||||
|
||||
struct communication_assoc
|
||||
struct thread_comm
|
||||
{
|
||||
struct communication_assoc *next;
|
||||
struct communication_assoc *prev;
|
||||
pthread_t tid;
|
||||
int unused;
|
||||
};
|
||||
|
||||
extern struct communication_assoc assoc_root;
|
||||
extern struct thread_comm *tcomms;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void);
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
void insert(void *);
|
||||
static inline void send(void **addr) {
|
||||
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))
|
||||
if (!((uintptr_t) addr >= ANOTHER_FAKE_NURSERY_START) && ((uintptr_t) ptd_addr >= FAKE_NURSERY_START))
|
||||
insert(addr);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +1,23 @@
|
|||
#ifndef __COMM_H_
|
||||
#define __COMM_H_ 1
|
||||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standart include */
|
||||
#include <specific_comm.h>
|
||||
|
||||
#define READ_IDX 0
|
||||
#define WRITE_IDX 1
|
||||
|
||||
struct communication_assoc
|
||||
struct thread_comm
|
||||
{
|
||||
struct communication_assoc *next;
|
||||
struct communication_assoc *prev;
|
||||
pthread_t tid;
|
||||
int *pipefd;
|
||||
struct communication_channel *channel;
|
||||
int receiver_idx;
|
||||
};
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern __thread int pipefd[];
|
||||
extern struct communication_assoc assoc_root;
|
||||
extern struct thread_comm *tcomms;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void);
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
static inline void send(void **addr) {
|
||||
write(pipefd[WRITE_IDX], &addr, sizeof(void *));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef _PRIVATE_COMMON_H_
|
||||
#define _PRIVATE_COMMON_H_ 1
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void wait_initialization(void);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -1,33 +1,29 @@
|
|||
#ifndef __COMM_H_
|
||||
#define __COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <commtech.h>
|
||||
|
||||
#define SHARED_SPACE_SIZE (2 * BUF_SIZE)
|
||||
#define SHARED_SPACE_VOIDPTR (SHARED_SPACE_SIZE / sizeof(void *))
|
||||
|
||||
struct communication_assoc
|
||||
struct thread_comm
|
||||
{
|
||||
struct communication_assoc *next;
|
||||
struct communication_assoc *prev;
|
||||
pthread_t tid;
|
||||
void **shared_space;
|
||||
volatile void **shared_space;
|
||||
volatile int *cons_idx;
|
||||
volatile int *prod_idx;
|
||||
};
|
||||
|
||||
extern struct communication_assoc assoc_root;
|
||||
extern struct thread_comm *tcomms;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern __thread void **shared_space;
|
||||
extern __thread volatile void **shared_space;
|
||||
extern __thread volatile int prod_idx;
|
||||
extern __thread volatile int cons_idx;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void);
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
static inline void send(void **addr) {
|
||||
while ((prod_idx + 1) % SHARED_SPACE_VOIDPTR == cons_idx);
|
||||
shared_space[prod_idx] = addr;
|
||||
|
|
|
@ -1,33 +1,29 @@
|
|||
#ifndef __COMM_H_
|
||||
#define __COMM_H_ 1
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef _SPECIFIC_COMM_H_
|
||||
#define _SPECIFIC_COMM_H_ 1
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <commtech.h>
|
||||
|
||||
#define SHARED_SPACE_SIZE (2 * BUF_SIZE)
|
||||
#define SHARED_SPACE_VOIDPTR (SHARED_SPACE_SIZE / sizeof(void *))
|
||||
|
||||
struct communication_assoc
|
||||
struct thread_comm
|
||||
{
|
||||
struct communication_assoc *next;
|
||||
struct communication_assoc *prev;
|
||||
pthread_t tid;
|
||||
void **shared_space;
|
||||
volatile void **shared_space;
|
||||
volatile int *cons_idx;
|
||||
volatile int *prod_idx;
|
||||
};
|
||||
|
||||
extern struct communication_assoc assoc_root;
|
||||
extern struct thread_comm *tcomms;
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
extern __thread void **shared_space;
|
||||
extern __thread volatile void **shared_space;
|
||||
extern __thread volatile int prod_idx;
|
||||
extern __thread volatile int cons_idx;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void);
|
||||
int init_thread_comm(struct thread_comm *);
|
||||
int end_thread_comm(void);
|
||||
static inline void send(void **addr) {
|
||||
static __thread int local_cons_idx = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
#! /bin/bash
|
||||
|
||||
set -u
|
||||
|
||||
# Files and directories
|
||||
binDir="bin"
|
||||
calcDir="calculation"
|
||||
PHLDir="../papihighlevel"
|
||||
PHLLibDir="lib"
|
||||
PAPIDir="${PHLDir}/papi"
|
||||
PAPILibDir="src"
|
||||
PAPIPFMDir="libpfm-3.y/lib"
|
||||
|
||||
# Param
|
||||
binList="asm_cache_comm c_cache_comm pipe_comm shared_mem_comm shared_mem_opt_comm jikes_barrier_comm fake_comm" # Type de communication
|
||||
nbProdList="1" # Nombre de cores producteurs
|
||||
typeProdList="none matrice useless_loop" # Methode pour produire les valeurs
|
||||
typeCacheList="L2 Memory" # Niveau de cache partage
|
||||
|
||||
# Const
|
||||
nbIter="5000000" # Nb de lignes produites
|
||||
sizeBuf="1" # En nombre de lignes de cache
|
||||
|
||||
# Nom generique des fichiers de log
|
||||
logFileName="\$perfDirName/cache_\$typeCache-nbProd_\$nbProd-typeProd_\$typeProd-argTypeProd_\$argTypeProd-nbIter_\$nbIter-\$bin.log"
|
||||
expDirName="logs"
|
||||
perfDirName="$expDirName/perfCommMulti-`date +'%F-%Hh%Mm%S'`"
|
||||
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}${LD_LIBRARY_PATH:+:}${PHLDir}/${PHLLibDir}:${PAPIDir}/${PAPILibDir}:${PAPIDir}/${PAPILibDir}/${PAPIPFMDir}"
|
||||
|
||||
PAPILibPresent=""
|
||||
PFMLibPresent=""
|
||||
papiHighLevelLibPresent=""
|
||||
LD_LIBRARY_PATH_LEFT="${LD_LIBRARY_PATH}:"
|
||||
while [ -n "${LD_LIBRARY_PATH_LEFT}" ]
|
||||
do
|
||||
aLibDir="${LD_LIBRARY_PATH_LEFT%%:*}"
|
||||
if [ -x ${aLibDir}/libpapi.so.3 ]
|
||||
then
|
||||
PAPILibPresent="1";
|
||||
fi
|
||||
if [ -x ${aLibDir}/libpfm.so.3 ]
|
||||
then
|
||||
PHLLibPresent="1";
|
||||
fi
|
||||
if [ -x ${aLibDir}/libpapihighlevel.so ]
|
||||
then
|
||||
PHLLibPresent="1";
|
||||
fi
|
||||
if [ -n "${PAPILibPresent}" -a -n "${PHLLibPresent}" -a -n "${PFMLibPresent}" ]
|
||||
then
|
||||
break
|
||||
fi
|
||||
LD_LIBRARY_PATH_LEFT="${LD_LIBRARY_PATH_LEFT#*:}"
|
||||
done
|
||||
if [ -z "${PAPILibPresent}" -o -z "${PHLLibPresent}" ]
|
||||
then
|
||||
echo "Libraries needed for this bench not accessible by \$LD_LIBRARY_PATH" > /dev/stderr # Is there a better way to display something on stderr ?
|
||||
exit 1
|
||||
fi
|
||||
|
||||
unset PAPILibPresent
|
||||
unset PHLLibPresent
|
||||
unset LD_LIBRARY_PATH_LEFT
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
[ -d "$expDirName" ] || mkdir "$expDirName"
|
||||
[ -d "$perfDirName" ] || mkdir "$perfDirName"
|
||||
|
||||
function_run () {
|
||||
case $typeProd in
|
||||
"none" ) optTypeProd="" ;;
|
||||
"matrice" ) optTypeProd="-c lib/${calcDir}/libcalc_mat.so 16" ;;
|
||||
"useless_loop" ) optTypeProd="-c lib/${calcDir}/libcalc_useless_loop.so ${argTypeProd}" ;;
|
||||
* ) exit 1 ;;
|
||||
esac
|
||||
case $typeCache in
|
||||
"Memory" ) optTypeCache="" ;;
|
||||
"L2" ) optTypeCache="-s" ;;
|
||||
* ) exit 1 ;;
|
||||
esac
|
||||
|
||||
make $binDir/$bin
|
||||
echo "On lance : \"${bin##*/} $optTypeCache $optTypeProd -p $nbProd -n $nbIter\""
|
||||
beginingDate=`date +%s`
|
||||
|
||||
( $binDir/$bin $optTypeCache $optTypeProd -p $nbProd -n $nbIter || echo "echec experience" ) | eval tee $logFileName
|
||||
endDate=`date +%s`
|
||||
duration_sec=`expr \( $endDate - $beginingDate \) % 60`
|
||||
duration_min=`expr \( $endDate - $beginingDate \) / 60`
|
||||
duration_hrs=`expr $duration_min / 60`
|
||||
duration_min=`expr $duration_min % 60`
|
||||
|
||||
echo "Fin de l'experience : `date +'%H:%M:%S (%d/%m/%y)'`"
|
||||
echo "La duree est de : ${duration_hrs}hrs ${duration_min}min ${duration_sec}sec"
|
||||
echo ""
|
||||
}
|
||||
|
||||
|
||||
|
||||
echo -e "On commence les perfs\n"
|
||||
globalBeginingDate=`date +%s`
|
||||
|
||||
for nbProd in $nbProdList ; do
|
||||
for typeProd in $typeProdList; do
|
||||
for typeCache in $typeCacheList ; do
|
||||
for bin in $binList ; do
|
||||
case $typeProd in
|
||||
"useless_loop" )
|
||||
case $bin in
|
||||
"jikes_barrier_comm" | "asm_cache_comm" | "c_cache_comm" )
|
||||
for argTypeProd in 1 `seq 5 5 50` ; do
|
||||
function_run ;
|
||||
done ;;
|
||||
* )
|
||||
argTypeProd=1 ;
|
||||
function_run ;;
|
||||
esac ;;
|
||||
"matrice" )
|
||||
argTypeProd=16 ;
|
||||
function_run ;;
|
||||
* )
|
||||
argTypeProd=1 ;
|
||||
function_run ;;
|
||||
esac
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
globalEndDate=`date +%s`
|
||||
globalDuration_sec=`expr \( $globalEndDate - $globalBeginingDate \) % 60`
|
||||
globalDuration_min=`expr \( $globalEndDate - $globalBeginingDate \) / 60`
|
||||
globalDuration_hrs=`expr $globalDuration_min / 60`
|
||||
globalDuration_min=`expr $globalDuration_min % 60`
|
||||
|
||||
echo "Fin de la serie d'experience : `date +'%H:%M:%S (%d/%m/%y)'`"
|
||||
echo "La duree totale est de : ${globalDuration_hrs}hrs ${globalDuration_min}min ${globalDuration_sec}sec"
|
||||
|
|
@ -0,0 +1,330 @@
|
|||
#! /bin/bash
|
||||
|
||||
set -u
|
||||
|
||||
#barriereList="jikes_barrier asm_cache c_cache fake"
|
||||
barriereList="jikes_barrier asm_cache c_cache"
|
||||
communicationList="asm_cache c_cache shared_mem shared_mem_opt pipe"
|
||||
comList=`ls *.log | perl -ni -e '/-([^-]+)_comm/; $a{$1}=""; END { foreach ( sort keys %a ) {print "$_ "}}'`
|
||||
cacheList=`ls *log | perl -ni -e '/cache_([^-]+)-/; $a{$1}=""; END { foreach ( sort keys %a ) {print "$_ "}}'`
|
||||
prodList=`ls *.log | perl -ni -e '/typeProd_([^-]+)-/; $a{$1}=""; END { foreach ( sort keys %a ) {print "$_ "}}'`
|
||||
barriereCommaList=`echo $barriereList | sed "s/ /,/g"`
|
||||
argTypeProdList=`eval ls *typeProd_useless_loop*{$barriereCommaList}_comm.log | perl -ni -e '/argTypeProd_([\d]+)-/; $a{$1}=""; END { foreach ( sort { $a <=> $b } keys %a ) {print "$_ "}}'`
|
||||
|
||||
metriqueList="cache_hits cache_miss cycles total_time"
|
||||
|
||||
echo "set style data histogram" > multicores.gnuplot
|
||||
echo "set style histogram cluster gap 1" >> multicores.gnuplot
|
||||
echo "set style fill solid border -1" >> multicores.gnuplot
|
||||
echo "set boxwidth 0.9" >> multicores.gnuplot
|
||||
echo "set xtic rotate by -45" >> multicores.gnuplot
|
||||
echo "set bmargin 5" >> multicores.gnuplot
|
||||
echo "set terminal postscript landscape color" >> multicores.gnuplot
|
||||
|
||||
use_histo ()
|
||||
{
|
||||
local prod bench
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
|
||||
[ "$bench" = "communication" -o "$prod" != "useless_loop" ]
|
||||
return $?
|
||||
}
|
||||
|
||||
create_dat_header ()
|
||||
{
|
||||
local prod bench metrique
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
metrique="$3"
|
||||
|
||||
# Create file
|
||||
> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
|
||||
# Only one point per com and cache
|
||||
if use_histo "$prod" "$bench"
|
||||
then
|
||||
for i in 1 2 3 # 1: total, 2: by loop, 3: by write
|
||||
do
|
||||
if [ $i -ne 1 ]
|
||||
then
|
||||
echo >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
fi
|
||||
echo -ne "Method\t\t" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
for cache in $cacheList
|
||||
do
|
||||
echo -ne "\t$cache" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
done
|
||||
done
|
||||
# Several points per com and cache (one per calc argument)
|
||||
else
|
||||
for i in 1 2
|
||||
do
|
||||
if [ $i -ne 1 ]
|
||||
then
|
||||
echo >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
fi
|
||||
for j in 1 2 3 # 1: total, 2: by loop, 3: by write
|
||||
do
|
||||
echo -ne "argTypeProd\t\t" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
for com in $barriereList
|
||||
do
|
||||
echo -ne "\t$com" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
done
|
||||
echo >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
done
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
get_metric_values ()
|
||||
{
|
||||
local prod com cache argTypeProd logFile
|
||||
prod="$1"
|
||||
com="$2"
|
||||
cache="$3"
|
||||
argTypeProd="$4"
|
||||
metriquePattern="$5"
|
||||
|
||||
logFile=cache_$cache-*-typeProd_$prod-argTypeProd_$argTypeProd-*-${com}_comm.log
|
||||
perl -n -e "print \"\$1 \$2 \$3 \" if /$metriquePattern.* (\S+) \/ (\S+) \/ (\S+)/" $logFile
|
||||
}
|
||||
|
||||
create_simple_dat_body ()
|
||||
{
|
||||
local prod bench metrique argTypeProd
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
metrique="$3"
|
||||
argTypeProd="$4"
|
||||
|
||||
for com in `eval echo \\\$\${bench}List`
|
||||
do
|
||||
for i in 1 2 3 # 1: total, 2: by loop, 3: by write
|
||||
do
|
||||
echo -ne "\n$com\t\t" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
for cache in $cacheList
|
||||
do
|
||||
if [ $i -eq 1 ]
|
||||
then
|
||||
valuetmp=`get_metric_values "$prod" "$com" "$cache" "$argTypeProd" "$metriquePattern"`
|
||||
eval value$cache=\"$valuetmp\"
|
||||
fi
|
||||
eval echo -ne "\${value$cache}" | sed -r "s/^([^ ]+ ){$((i-1))}([^ ]+).*/\t\2/" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
done
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
create_complex_dat_body ()
|
||||
{
|
||||
local prod bench metrique
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
metrique="$3"
|
||||
|
||||
for argTypeProd in $argTypeProdList
|
||||
do
|
||||
for cache in $cacheList
|
||||
do
|
||||
if [ $cache != ${cacheList%% *} -o $argTypeProd != ${argTypeProdList%% *} ]
|
||||
then
|
||||
echo "" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
fi
|
||||
for i in 1 2 3 # 1: total, 2: by loop, 3: by write
|
||||
do
|
||||
echo -ne "\n$argTypeProd\t\t" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
for com in `eval echo \\\$\${bench}List`
|
||||
do
|
||||
if [ $i -eq 1 ]
|
||||
then
|
||||
valuetmp=`get_metric_values "$prod" "$com" "$cache" "$argTypeProd" "$metriquePattern"`
|
||||
eval value$com=\"$valuetmp\"
|
||||
fi
|
||||
eval echo -ne "\${value$com}" | sed -r "s/^([^ ]+ ){$((i-1))}([^ ]+).*/\t\2/" >> bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
done
|
||||
done
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
create_dat_body ()
|
||||
{
|
||||
local prod bench metrique argTypeProd
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
metrique="$3"
|
||||
argTypeProd="$4"
|
||||
|
||||
if use_histo "$prod" "$bench"
|
||||
then
|
||||
create_simple_dat_body "$prod" "$bench" "$metrique" "$argTypeProd" "$metriquePattern"
|
||||
else
|
||||
create_complex_dat_body "$prod" "$bench" "$metrique" "$argTypeProd" "$metriquePattern"
|
||||
fi
|
||||
}
|
||||
|
||||
create_gnuplot_header ()
|
||||
{
|
||||
local prod bench gnuplotFile
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
gnuplotFile="$3"
|
||||
|
||||
echo "set style fill solid border -1" > $gnuplotFile
|
||||
echo "set boxwidth 0.9" >> $gnuplotFile
|
||||
echo "set xtic rotate by -45" >> $gnuplotFile
|
||||
echo "set bmargin 5" >> $gnuplotFile
|
||||
echo "set terminal postscript landscape color" >> $gnuplotFile
|
||||
if use_histo "$prod" "$bench"
|
||||
then
|
||||
echo "set style data histogram" >> $gnuplotFile
|
||||
echo "set style histogram cluster gap 1" >> $gnuplotFile
|
||||
else
|
||||
echo "set style data linespoints" >> $gnuplotFile
|
||||
fi
|
||||
}
|
||||
|
||||
create_simple_gnuplot_body ()
|
||||
{
|
||||
local metrique ylabel yscale patternPlotFile datFile
|
||||
ylabel="$1"
|
||||
lineNum="$2"
|
||||
datFile="$3"
|
||||
patternPlotFile="$4"
|
||||
|
||||
echo "set ylabel \"$ylabel\"" >> $patternPlotFile.gnuplot
|
||||
echo "set output '$patternPlotFile.ps'" >> $patternPlotFile.gnuplot
|
||||
echo "plot '$datFile' every 3::$lineNum using 2:xtic(1) title 2 , '' every 3::$lineNum u 3 ti 3" >> $patternPlotFile.gnuplot
|
||||
}
|
||||
|
||||
create_complex_gnuplot_body ()
|
||||
{
|
||||
local bench ylabel lineNum datFile patternPlotFile columnNo baseTitle
|
||||
bench="$1"
|
||||
ylabel="$2"
|
||||
lineNum="$3"
|
||||
datFile="$4"
|
||||
patternPlotFile="$5"
|
||||
columnNo=2
|
||||
|
||||
echo "set ylabel \"$ylabel\"" >> $patternPlotFile.gnuplot
|
||||
echo "set output '$patternPlotFile.ps'" >> $patternPlotFile.gnuplot
|
||||
for com in `eval echo \\\$\${bench}List` ; do
|
||||
baseTitle=`head -1 $datFile | cut -f $((columnNo + 2))`
|
||||
if [ $columnNo -ne 2 ]
|
||||
then
|
||||
echo -n ", '' " >> $patternPlotFile.gnuplot
|
||||
else
|
||||
echo -n "plot '$datFile' " >> $patternPlotFile.gnuplot
|
||||
fi
|
||||
echo -n "every :2:$lineNum:0:$lineNum using 1:$columnNo:xtic(1) title '$baseTitle (L2)'" >> $patternPlotFile.gnuplot
|
||||
echo -n ", '' every :2:$lineNum:1:$lineNum using 1:$columnNo:xtic(1) title '$baseTitle (mem)'" >> $patternPlotFile.gnuplot
|
||||
columnNo=$((columnNo + 1))
|
||||
done
|
||||
echo >> $patternPlotFile.gnuplot
|
||||
}
|
||||
|
||||
create_gnuplot_body ()
|
||||
{
|
||||
local prod bench yscale ylabel lineNum datFile patternPlotFile
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
yscale="$3"
|
||||
ylabel="$4"
|
||||
lineNum="$5"
|
||||
datFile="$6"
|
||||
patternPlotFile="$7"
|
||||
|
||||
echo "set $yscale y" >> $patternPlotFile.gnuplot
|
||||
if [ "$yscale" = "nologscale" ]
|
||||
then
|
||||
echo "set yrange [0:*]" >> $patternPlotFile.gnuplot
|
||||
else
|
||||
echo "set yrange [*:*]" >> $patternPlotFile.gnuplot
|
||||
fi
|
||||
echo "set title \"Producteur : $prod\"" >> $patternPlotFile.gnuplot
|
||||
if use_histo "$prod" "$bench"
|
||||
then
|
||||
create_simple_gnuplot_body "$ylabel" "$lineNum" "$datFile" "$patternPlotFile"
|
||||
else
|
||||
create_complex_gnuplot_body "$bench" "$ylabel" "$lineNum" "$datFile" "$patternPlotFile"
|
||||
fi
|
||||
}
|
||||
|
||||
create_gnuplot_file ()
|
||||
{
|
||||
local prod bench metrique ylabel yscale avg lineNum
|
||||
prod="$1"
|
||||
bench="$2"
|
||||
metrique="$3"
|
||||
baseYlabel="$4"
|
||||
|
||||
for yscale in "nologscale" "logscale"
|
||||
do
|
||||
for avg in total byLoop byWrite
|
||||
do
|
||||
case $avg in
|
||||
total)
|
||||
lineNum=0
|
||||
ylabel="$baseYlabel" ;;
|
||||
byLoop)
|
||||
lineNum=1
|
||||
ylabel="$baseYlabel par boucle" ;;
|
||||
byWrite)
|
||||
lineNum=2
|
||||
ylabel="$baseYlabel par ecriture" ;;
|
||||
esac
|
||||
datFile=bench_$bench-prod_$prod-metrique_$metrique.dat
|
||||
patternPlotFile="bench_$bench-prod_$prod-$metrique-$avg-$yscale" # Name without extension of plot and ps files
|
||||
create_gnuplot_header "$prod" "$bench" "$patternPlotFile.gnuplot"
|
||||
if [ $metrique != "total_time" -o $yscale != "logscale" ]
|
||||
then
|
||||
create_gnuplot_body "$prod" "$bench" "$yscale" "$ylabel" "$lineNum" "$datFile" "$patternPlotFile"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
for prod in $prodList ; do
|
||||
case "$prod" in
|
||||
matrice) argTypeProd=16 ;;
|
||||
*) argTypeProd=1 ;;
|
||||
esac
|
||||
for bench in "communication" "barriere" ; do
|
||||
# Create dat headers
|
||||
for metrique in $metriqueList ; do
|
||||
case "$metrique" in
|
||||
cache_hits)
|
||||
metriquePattern="cache hits"
|
||||
ylabel="Nb cache hit" ;;
|
||||
cache_miss)
|
||||
metriquePattern="cache miss"
|
||||
ylabel="Nb cache miss" ;;
|
||||
cycles)
|
||||
metriquePattern="cycles"
|
||||
ylabel="Nb cycles" ;;
|
||||
total_time)
|
||||
metriquePattern="total_time"
|
||||
ylabel="Secondes" ;;
|
||||
*)
|
||||
echo "Pas de pattern pour cette métrique : $metrique"
|
||||
echo "Pas de label pour cette métrique : $metrique"
|
||||
exit 1 ;;
|
||||
esac
|
||||
create_dat_header "$prod" "$bench" "$metrique"
|
||||
create_dat_body "$prod" "$bench" "$metrique" "$argTypeProd" "$metriquePattern"
|
||||
create_gnuplot_file "$prod" "$bench" "$metrique" "$ylabel"
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
for gnuplotFile in *.gnuplot
|
||||
do
|
||||
gnuplot "$gnuplotFile"
|
||||
done
|
||||
|
||||
for psFile in *.ps
|
||||
do
|
||||
ps2pdf $psFile
|
||||
done
|
|
@ -0,0 +1,58 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
|
||||
static int *mat, *vect;
|
||||
static int li;
|
||||
static int n, m; /* Size of the matrice: n lines, m columns */
|
||||
static int *mat_cell_ptr;
|
||||
|
||||
int init_calc(int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
n = size;
|
||||
m = size;
|
||||
srand(42);
|
||||
mat = (int *) malloc(n * m * sizeof(int));
|
||||
if (mat == NULL)
|
||||
{
|
||||
fprintf(stderr, "calc_mat: Unable to allocate memory for matrice calculation\n");
|
||||
return -1;
|
||||
}
|
||||
vect = (int *) malloc(m * sizeof(int));
|
||||
if (vect == NULL)
|
||||
{
|
||||
free(mat);
|
||||
fprintf(stderr, "calc_mat: Unable to allocate memory for matrice calculation\n");
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < n * m; i++)
|
||||
mat[i] = rand();
|
||||
li = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void **do_calc(void)
|
||||
{
|
||||
int co, p = 0;
|
||||
|
||||
for (co = 0; co < m; co++)
|
||||
p += mat[li * m + co] * vect[li];
|
||||
mat[li * m] = p;
|
||||
if (unlikely(++li >= n))
|
||||
li = 0;
|
||||
mat_cell_ptr = &mat[li * m];
|
||||
return (void **) &mat_cell_ptr;
|
||||
}
|
||||
|
||||
int end_calc(void)
|
||||
{
|
||||
free(mat);
|
||||
free(vect);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static int nb_loop = 0, prod = 0, *prod_ptr = ∏
|
||||
volatile int fourty_two = 42;
|
||||
unsigned int seedp;
|
||||
|
||||
int init_calc(int param_nb_loop)
|
||||
{
|
||||
nb_loop = param_nb_loop;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void **do_calc(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < nb_loop; i++)
|
||||
prod += fourty_two;
|
||||
return (void **) &prod_ptr;
|
||||
}
|
||||
|
||||
int end_calc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
struct communication_assoc assoc_root;
|
||||
static pthread_mutex_t assoc_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static struct communication_assoc assoc_tmp;
|
||||
static volatile int init = 0;
|
||||
volatile int cont = 1;
|
||||
|
||||
void initialize_library(void)
|
||||
{
|
||||
assoc_tmp.prev = &assoc_tmp;
|
||||
assoc_tmp.next = &assoc_tmp;
|
||||
assoc_root.prev = &assoc_root;
|
||||
assoc_root.next = &assoc_root;
|
||||
}
|
||||
|
||||
volatile int *init_comm(void)
|
||||
{
|
||||
return &cont;
|
||||
}
|
||||
|
||||
void wait_initialization(void)
|
||||
{
|
||||
while (!init);
|
||||
}
|
||||
|
||||
void add_sender(void)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
|
||||
assoc = create_comm_assoc();
|
||||
pthread_mutex_lock(&assoc_lock);
|
||||
if (!init)
|
||||
{
|
||||
initialize_library();
|
||||
init = 1;
|
||||
}
|
||||
assoc->next = assoc_tmp.next;
|
||||
assoc_tmp.next->prev = assoc;
|
||||
assoc->prev = &assoc_tmp;
|
||||
assoc_tmp.next = assoc;
|
||||
pthread_mutex_unlock(&assoc_lock);
|
||||
}
|
||||
|
||||
void remove_sender()
|
||||
{
|
||||
printf("remove_communication_channel: Not yet implemented\n");
|
||||
}
|
||||
|
||||
void discover_new_producers(void)
|
||||
{
|
||||
/* If there is some new thread for the write barrier */
|
||||
if(&assoc_tmp != assoc_tmp.next)
|
||||
{
|
||||
/* printf("Adding a new set of producers\n"); */
|
||||
pthread_mutex_lock(&assoc_lock);
|
||||
/*
|
||||
* list in assoc_tmp is inserted between assoc_root
|
||||
* and the first elements of assoc_root list
|
||||
*/
|
||||
assoc_root.next->prev = assoc_tmp.prev;
|
||||
assoc_tmp.prev->next = assoc_root.next;
|
||||
assoc_root.next = assoc_tmp.next;
|
||||
assoc_root.next->prev = &assoc_root;
|
||||
/*
|
||||
* assoc_tmp temporary list has been copied in
|
||||
* assoc_root list. assoc_tmp is now alone and so
|
||||
* double linked to itself
|
||||
*/
|
||||
assoc_tmp.prev = &assoc_tmp;
|
||||
assoc_tmp.next = &assoc_tmp;
|
||||
pthread_mutex_unlock(&assoc_lock);
|
||||
}
|
||||
}
|
|
@ -3,21 +3,25 @@
|
|||
#include <pthread.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread struct communication_channel channel;
|
||||
__thread struct comm_channel channel;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void)
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
comm->receiver_idx = 0;
|
||||
comm->channel = &channel;
|
||||
comm->channel->state = 0;
|
||||
comm->channel->idx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assoc = (struct communication_assoc *) malloc(sizeof(struct communication_assoc));
|
||||
assoc->tid = pthread_self();
|
||||
assoc->receiver_idx = 0;
|
||||
assoc->channel = &channel;
|
||||
return assoc;
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *dstr="buffer transition\n";
|
||||
|
@ -39,17 +43,15 @@ void reception(void (*on_receive)(void *))
|
|||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
while (cont)
|
||||
{
|
||||
struct communication_assoc *cur;
|
||||
int i;
|
||||
|
||||
discover_new_producers();
|
||||
cur = assoc_root.next;
|
||||
while(cur != &assoc_root)
|
||||
for (i = 0; i < nb_prod; i++)
|
||||
{
|
||||
struct communication_channel *channel = cur->channel;
|
||||
if(channel->state)
|
||||
if(tcomms[i].channel->state)
|
||||
{
|
||||
int j, n;
|
||||
/*
|
||||
* cur->receiver_idx point to the last cache
|
||||
* line we have read. We go to the next cache
|
||||
|
@ -59,14 +61,19 @@ void reception(void (*on_receive)(void *))
|
|||
* line we correct the pointer to point to
|
||||
* the first one (this is done by the modulo)
|
||||
*/
|
||||
int i = cur->receiver_idx;
|
||||
int n = cur->receiver_idx + (BUF_SIZE / sizeof(void *));
|
||||
cur->receiver_idx = n % ((2 * BUF_SIZE) / sizeof(void *));
|
||||
for(; i<n; i++)
|
||||
on_receive(channel->buf[i]);
|
||||
channel->state = 0;
|
||||
j = tcomms[i].receiver_idx;
|
||||
n = tcomms[i].receiver_idx + (BUF_SIZE / sizeof(void *));
|
||||
tcomms[i].receiver_idx = n % ((2 * BUF_SIZE) / sizeof(void *));
|
||||
for(; j<n; j++)
|
||||
{
|
||||
/*
|
||||
* The behaviour of this is not documented but we know
|
||||
* the values inside buf won't change during this affectation
|
||||
*/
|
||||
on_receive((void *) tcomms[i].channel->buf[j]);
|
||||
}
|
||||
tcomms[i].channel->state = 0;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread struct comm_channel channel;
|
||||
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
comm->receiver_idx = 0;
|
||||
comm->channel = &channel;
|
||||
comm->channel->state = 0;
|
||||
comm->channel->idx = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *dstr="buffer transition\n";
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while (cont)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_prod; i++)
|
||||
{
|
||||
if(tcomms[i].channel->state)
|
||||
{
|
||||
int j, n;
|
||||
/*
|
||||
* cur->receiver_idx point to the last cache
|
||||
* line we have read. We go to the next cache
|
||||
* line "+ (CACHE_LINE_SIZE >> 2)" (because
|
||||
* the line is full of integer (2^2 octets)
|
||||
* and then if we are after the second cache
|
||||
* line we correct the pointer to point to
|
||||
* the first one (this is done by the modulo)
|
||||
*/
|
||||
j = tcomms[i].receiver_idx;
|
||||
n = tcomms[i].receiver_idx + (BUF_SIZE / sizeof(void *));
|
||||
tcomms[i].receiver_idx = n % ((2 * BUF_SIZE) / sizeof(void *));
|
||||
for(; j<n; j++)
|
||||
{
|
||||
/*
|
||||
* The behaviour of this is not documented but we know
|
||||
* the values inside buf won't change during this affectation
|
||||
*/
|
||||
on_receive((void *) tcomms[i].channel->buf[j]);
|
||||
}
|
||||
tcomms[i].channel->state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <specific_comm.h>
|
||||
#include <commtech.h>
|
||||
|
||||
|
||||
struct thread_comm *tcomms;
|
||||
volatile int cont = 1;
|
||||
static int init = 0;
|
||||
static int error = 0;
|
||||
static pthread_mutex_t init_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
int init_library(void)
|
||||
{
|
||||
tcomms = (struct thread_comm *) malloc(nb_prod * sizeof(struct thread_comm));
|
||||
if (tcomms == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate %lu bytes needed by the library to work\n", nb_prod * sizeof(struct thread_comm));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_library(void)
|
||||
{
|
||||
free(tcomms);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_thread_number(void)
|
||||
{
|
||||
static int i = 0;
|
||||
static pthread_mutex_t i_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
int i_local;
|
||||
|
||||
pthread_mutex_lock(&i_lock);
|
||||
i_local = i;
|
||||
i++;
|
||||
pthread_mutex_unlock(&i_lock);
|
||||
return i_local;
|
||||
}
|
||||
|
||||
int init_producer_thread(void)
|
||||
{
|
||||
int thread_num;
|
||||
|
||||
thread_num = get_thread_number();
|
||||
if (init_thread_comm(&tcomms[thread_num]))
|
||||
{
|
||||
pthread_mutex_lock(&init_lock);
|
||||
error = 1;
|
||||
pthread_cond_signal(&init_cond);
|
||||
pthread_mutex_unlock(&init_lock);
|
||||
return -1;
|
||||
}
|
||||
if (thread_num == nb_prod - 1)
|
||||
{
|
||||
pthread_mutex_lock(&init_lock);
|
||||
init = 1;
|
||||
pthread_cond_signal(&init_cond);
|
||||
pthread_mutex_unlock(&init_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_producer_thread(void)
|
||||
{
|
||||
return end_thread_comm();
|
||||
}
|
||||
|
||||
int wait_initialization(void)
|
||||
{
|
||||
pthread_mutex_lock(&init_lock);
|
||||
if (!init && !error)
|
||||
pthread_cond_wait(&init_cond, &init_lock);
|
||||
pthread_mutex_unlock(&init_lock);
|
||||
if (error)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread void ** volatile store_var = NULL;
|
||||
|
||||
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization(); /* Not needed but here for equity with others techniques */
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while (cont);
|
||||
}
|
|
@ -4,7 +4,8 @@
|
|||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
|
@ -32,18 +33,24 @@ static struct double_linked_list *global_head = NULL;
|
|||
static int bufsenqueued = 0;
|
||||
static unsigned int lock = 0;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void)
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
void **new_buffer;
|
||||
|
||||
new_buffer = (void **) malloc(BUFFER_SIZE);
|
||||
if (posix_memalign((void *) &new_buffer, CACHE_LINE_SIZE, BUFFER_SIZE))
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate a new buffer for the thread\n");
|
||||
return -1;
|
||||
}
|
||||
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
|
||||
(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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_next(struct double_linked_list *list, struct double_linked_list *next)
|
||||
|
@ -85,7 +92,7 @@ static void spin_unlock(unsigned int *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
|
||||
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)
|
||||
|
@ -127,34 +134,39 @@ void **normalizeTail(int arity)
|
|||
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]
|
||||
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
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (bufsenqueued >= 262144) /* We use more than 1 Go */
|
||||
{
|
||||
fprintf(stderr, "We use 1.5 Go. Program terminated before kernel panic\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void tailOverflow(int arity)
|
||||
{
|
||||
void *new_buffer;
|
||||
if (local_tail != NULL)
|
||||
closeAndEnqueueTail(arity); // Add the buffer to the tail of the shared buffer
|
||||
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
|
||||
(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()
|
||||
checkForAsyncCollection(); /* possible side-effect of posix_memalign() */
|
||||
}
|
||||
|
||||
void insert(void *addr)
|
||||
|
@ -167,9 +179,10 @@ void insert(void *addr)
|
|||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
struct double_linked_list *list_cur;
|
||||
void **buf_start, **buf_ptr;
|
||||
wait_initialization();
|
||||
struct double_linked_list *list_cur = NULL;
|
||||
|
||||
wait_initialization(); /* Not needed but here for equity with others techniques */
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while (cont && (global_head == NULL));
|
||||
if (!cont)
|
||||
|
@ -182,4 +195,12 @@ void reception(void (*on_receive)(void *))
|
|||
on_receive(*buf_ptr);
|
||||
while (cont && (list_cur->next == NULL));
|
||||
} while (cont);
|
||||
while (global_head != NULL)
|
||||
{
|
||||
void *tmp;
|
||||
|
||||
tmp = (void *) ((uintptr_t) global_head & ~BUFFER_MASK);
|
||||
global_head = global_head->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread int pipefd[2];
|
||||
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
int flags;
|
||||
|
||||
if (pipe(pipefd))
|
||||
{
|
||||
fprintf(stderr, "Unable to create a pipe for pipe communication\n");
|
||||
return -1;
|
||||
}
|
||||
flags = fcntl(pipefd[READ_IDX], F_GETFL);
|
||||
fcntl(pipefd[READ_IDX], F_SETFL, flags | O_NONBLOCK);
|
||||
comm->pipefd = pipefd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization(); /* Not needed but here for equity with others techniques */
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_prod; i++)
|
||||
{
|
||||
int nb_read;
|
||||
|
||||
for(nb_read = 0; nb_read < BUF_SIZE / sizeof(void *); nb_read++)
|
||||
{
|
||||
int j, n;
|
||||
void *tmp_buf[BUF_SIZE / sizeof(void *)];
|
||||
|
||||
j = nb_read / sizeof(void *);
|
||||
n = read(tcomms[i].pipefd[READ_IDX], (void *) ((uintptr_t) tmp_buf + nb_read), BUF_SIZE - nb_read);
|
||||
if (n > 0)
|
||||
{
|
||||
nb_read += n;
|
||||
for (; j + sizeof(void *) <= nb_read / sizeof(void *); j += sizeof(void *))
|
||||
on_receive(tmp_buf[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread volatile void **shared_space;
|
||||
__thread volatile int cons_idx = 0;
|
||||
__thread volatile int prod_idx = 0;
|
||||
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
if (posix_memalign((void *) &shared_space, CACHE_LINE_SIZE, SHARED_SPACE_SIZE))
|
||||
{
|
||||
fprintf(stderr, "Unable to allocate space for shared mem communication\n");
|
||||
return -1;
|
||||
}
|
||||
comm->shared_space = shared_space;
|
||||
comm->cons_idx = &cons_idx;
|
||||
comm->prod_idx = &prod_idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nb_prod; i++)
|
||||
{
|
||||
int cons_idx;
|
||||
|
||||
for(cons_idx = *tcomms[i].cons_idx; cons_idx != *tcomms[i].prod_idx; cons_idx = (cons_idx + 1) % SHARED_SPACE_VOIDPTR, *tcomms[i].cons_idx = cons_idx)
|
||||
{
|
||||
/*
|
||||
* The behaviour of this is not documented but we know
|
||||
* the values inside buf won't change during this affectation
|
||||
*/
|
||||
on_receive((void *) tcomms[i].shared_space[cons_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <commtech.h>
|
||||
#include <private_common.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread volatile void **shared_space;
|
||||
__thread volatile int cons_idx = 0;
|
||||
__thread volatile int prod_idx = 0;
|
||||
|
||||
int init_thread_comm(struct thread_comm *comm)
|
||||
{
|
||||
if (posix_memalign((void *) &shared_space, CACHE_LINE_SIZE, SHARED_SPACE_SIZE))
|
||||
{
|
||||
fprintf(stderr, "Unable to allocate space for shared mem communication\n");
|
||||
return -1;
|
||||
}
|
||||
comm->shared_space = shared_space;
|
||||
comm->cons_idx = &cons_idx;
|
||||
comm->prod_idx = &prod_idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int end_thread_comm(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < nb_prod; i++)
|
||||
{
|
||||
int cons_idx, prod_idx;
|
||||
|
||||
cons_idx = *tcomms[i].cons_idx;
|
||||
do
|
||||
{
|
||||
prod_idx = *tcomms[i].prod_idx;
|
||||
for(; cons_idx != prod_idx; cons_idx = (cons_idx + 1) % SHARED_SPACE_VOIDPTR)
|
||||
{
|
||||
/*
|
||||
* The behaviour of this is not documented but we know
|
||||
* the values inside buf won't change during this affectation
|
||||
*/
|
||||
on_receive((void *) tcomms[i].shared_space[cons_idx]);
|
||||
}
|
||||
} while (prod_idx != *tcomms[i].prod_idx);
|
||||
*tcomms[i].cons_idx = cons_idx;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
|
||||
assoc = (struct communication_assoc *) malloc(sizeof(struct communication_assoc));
|
||||
assoc->tid = pthread_self();
|
||||
return assoc;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while (cont);
|
||||
}
|
|
@ -9,72 +9,127 @@
|
|||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Non standards includes */
|
||||
#include <papihighlevel.h>
|
||||
#include <common_comm.h>
|
||||
#include <commtech.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
static long nb_cache_lines = 0;
|
||||
static long nb_prod = 0;
|
||||
static long size_buf = 1;
|
||||
static char *calculation_lib = NULL;
|
||||
static int shared = 0;
|
||||
|
||||
#define toString(x) doStringification(x)
|
||||
#define doStringification(x) #x
|
||||
#define WORDS_PER_BUF (BUF_SIZE / sizeof(uintptr_t))
|
||||
#define DIV_SEC(secs, div) ((unsigned ) (((unsigned) secs) / (unsigned long) (div)))
|
||||
#define DIV_USEC(nsecs, nusecs, div) ((unsigned) (((unsigned) (nusecs) + 1000000 * \
|
||||
((unsigned ) (nsecs) % (div))) / (unsigned long) (div)))
|
||||
|
||||
|
||||
static long nb_bufs_sent = 0;
|
||||
long nb_prod = 0;
|
||||
static int (*init_calc)(int) = NULL;
|
||||
static void **(*do_calc)(void) = NULL;
|
||||
static int (*end_calc)(void) = NULL;
|
||||
static int shared = 0; /* We are not shared by default */
|
||||
pthread_cond_t cond_cons_has_finished = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t mutex_cons_has_finished = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int consumer_has_finished = 0;
|
||||
static int producers_ended = 0;
|
||||
static int init_calc_arg = 0;
|
||||
|
||||
void usage(char *argv[])
|
||||
{
|
||||
char format[] = "-n [options]";
|
||||
char options[] = "Required options :\n"
|
||||
"-n nb_cache_lines\tNumber of cache lines to send to another core\n"
|
||||
"-p nb_producers\tNumber of producers which send data to another core\n"
|
||||
"-n nb_buffer_sent\t\tNumber of buffer to send to another core\n"
|
||||
"\t\t\t\tBuffer size is " toString(BUF_SIZE) " bytes\n"
|
||||
"-p nb_producers\t\t\tNumber of producers which send data to another core\n"
|
||||
"Facultative options :\n"
|
||||
"-h\t\t\tPrint this help\n"
|
||||
"-s\t\t\tShare the same L2 cache or not\n"
|
||||
"-c calculation_lib\tLibrary to use for calculation\n"
|
||||
"\t\t\tThis library must implement functions in calc.h\n";
|
||||
"-h\t\t\t\tPrint this help\n"
|
||||
"-s <level>\t\t\tShare the same L<level> cache or not\n"
|
||||
"\t\t\t\tIf level is:\n"
|
||||
"\t\t\t\t\t> 0, then the same L<level> must be shared\n"
|
||||
"\t\t\t\t\t< 0, then different L<level> must be used\n"
|
||||
"\t\t\t\t\t= 0, then no constraint is given, only main memory (RAM) is guaranteed to be shared\n"
|
||||
"-c calculation_libname arg\tLibrary to use for calculation with its argument\n"
|
||||
"\t\t\t\tThis library must implement functions in calc.h\n";
|
||||
printf("Usage : %s %s\n", argv[0], format);
|
||||
printf("Options :\n");
|
||||
printf("%s\n", options);
|
||||
}
|
||||
|
||||
int do_noinit(int unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void **do_nocalc(void)
|
||||
{
|
||||
static int an_int, *an_int_ptr = &an_int;
|
||||
|
||||
return (void **) &an_int_ptr;
|
||||
}
|
||||
|
||||
int do_noend(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int analyse_options(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
|
||||
opterr = 0;
|
||||
while ((opt = getopt(argc, argv, ":hsc:n:p:b:")) != -1)
|
||||
while ((opt = getopt(argc, argv, ":hs::c:n:p:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'b' :
|
||||
{
|
||||
char *inval;
|
||||
size_buf = strtol(optarg, &inval, 10);
|
||||
if ((*optarg == '\0') || (*inval != '\0'))
|
||||
{
|
||||
fprintf(stderr, "Option '-b' needs an integer argument\n");
|
||||
return -1;
|
||||
}
|
||||
if ((nb_cache_lines <= 0) || ((nb_cache_lines == LONG_MAX) && errno == ERANGE))
|
||||
{
|
||||
fprintf(stderr, "Number of cache lines for each buffer must be between 1 and %ld, both inclusive\n", LONG_MAX);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'c' :
|
||||
calculation_lib = optarg;
|
||||
{
|
||||
struct stat file_stat;
|
||||
if (stat(calculation_lib, &file_stat))
|
||||
void *dl_descriptor;
|
||||
|
||||
if (stat(optarg, &file_stat))
|
||||
{
|
||||
printf("%s: %s\n", optarg, strerror(errno));
|
||||
fprintf(stderr, "%s: %s\n", optarg, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
dl_descriptor = dlopen(optarg, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (dl_descriptor == NULL)
|
||||
{
|
||||
fprintf(stderr, "dlopen error: %s\n", dlerror());
|
||||
return -1;
|
||||
}
|
||||
init_calc = (int (*)(int)) dlsym(dl_descriptor, "init_calc");
|
||||
do_calc = (void ** (*)(void)) dlsym(dl_descriptor, "do_calc");
|
||||
end_calc = (int (*)(void)) dlsym(dl_descriptor, "end_calc");
|
||||
if ((init_calc == NULL) || (do_calc == NULL) || (end_calc == NULL))
|
||||
{
|
||||
fprintf(stderr, "A symbol cannot be loaded: %s\n", dlerror());
|
||||
return -1;
|
||||
}
|
||||
if ((optind == argc) || (*argv[optind] == '-'))
|
||||
{
|
||||
fprintf(stderr, "Missing argument for -c option\n");
|
||||
return -1;
|
||||
}
|
||||
{
|
||||
char *inval;
|
||||
init_calc_arg = strtol(argv[optind], &inval, 10);
|
||||
if ((*argv[optind] == '\0') || (*inval != '\0'))
|
||||
{
|
||||
fprintf(stderr, "Option '-c' needs also an integer argument\n");
|
||||
return -1;
|
||||
}
|
||||
if ((init_calc_arg <= 0) || ((init_calc_arg == LONG_MAX) && errno == ERANGE))
|
||||
{
|
||||
fprintf(stderr, "Number of useless loop to be done between 2 send must be"
|
||||
" between 1 and %ld, both inclusive\n", LONG_MAX);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
break;
|
||||
case 'h' :
|
||||
|
@ -83,13 +138,13 @@ int analyse_options(int argc, char *argv[])
|
|||
case 'n' :
|
||||
{
|
||||
char *inval;
|
||||
nb_cache_lines = strtol(optarg, &inval, 10);
|
||||
nb_bufs_sent = strtol(optarg, &inval, 10);
|
||||
if ((*optarg == '\0') || (*inval != '\0'))
|
||||
{
|
||||
fprintf(stderr, "Option '-n' needs an integer argument\n");
|
||||
return -1;
|
||||
}
|
||||
if ((nb_cache_lines <= 0) || ((nb_cache_lines == LONG_MAX) && errno == ERANGE))
|
||||
if ((nb_bufs_sent <= 0) || ((nb_bufs_sent == LONG_MAX) && errno == ERANGE))
|
||||
{
|
||||
fprintf(stderr, "Number of cache lines to be sent must be between 1 and %ld, both inclusive\n", LONG_MAX);
|
||||
return -1;
|
||||
|
@ -105,7 +160,7 @@ int analyse_options(int argc, char *argv[])
|
|||
fprintf(stderr, "Option '-p' needs an integer argument\n");
|
||||
return -1;
|
||||
}
|
||||
if ((nb_cache_lines <= 0) || ((nb_cache_lines == LONG_MAX) && errno == ERANGE))
|
||||
if ((nb_prod <= 0) || ((nb_prod == LONG_MAX) && errno == ERANGE))
|
||||
{
|
||||
fprintf(stderr, "Number of producers must be between 1 and %ld, both inclusive\n", LONG_MAX);
|
||||
return -1;
|
||||
|
@ -113,8 +168,28 @@ int analyse_options(int argc, char *argv[])
|
|||
}
|
||||
break;
|
||||
case 's' :
|
||||
shared = 1;
|
||||
/* TODO: shared L2 cache */
|
||||
if ((optind != argc) && (*argv[optind] != '-'))
|
||||
{
|
||||
int share_level;
|
||||
char *inval;
|
||||
share_level = strtol(argv[optind], &inval, 10);
|
||||
if ((*argv[optind] == '\0') || (*inval != '\0'))
|
||||
{
|
||||
fprintf(stderr, "Option '-p' needs an integer argument\n");
|
||||
return -1;
|
||||
}
|
||||
if ((share_level == LONG_MIN) || ((share_level == LONG_MAX) && errno == ERANGE))
|
||||
{
|
||||
fprintf(stderr, "Shared memory level must be between %ld and %ld, both inclusive\n", LONG_MIN, LONG_MAX);
|
||||
return -1;
|
||||
}
|
||||
/* TODO: Real management of shared memory level */
|
||||
if (share_level <= 0) /* -x: We wan't level x not to be shared; 0 do as we want, only memory is guaranteed to be shared */
|
||||
shared = 0;
|
||||
else
|
||||
shared = 1;
|
||||
optind++;
|
||||
}
|
||||
break;
|
||||
case '?' :
|
||||
fprintf(stderr, "Option inconnue\n");
|
||||
|
@ -127,7 +202,7 @@ int analyse_options(int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
if (!nb_cache_lines)
|
||||
if (!nb_bufs_sent)
|
||||
{
|
||||
fprintf(stderr, "You must give the number of cache lines to be sent\n");
|
||||
return -1;
|
||||
|
@ -142,16 +217,36 @@ int analyse_options(int argc, char *argv[])
|
|||
fprintf(stderr, "Too many producers to fit with the consumer in processors which share a same cache\n");
|
||||
return -1;
|
||||
}
|
||||
if (do_calc == NULL)
|
||||
{
|
||||
init_calc = do_noinit;
|
||||
do_calc = do_nocalc;
|
||||
end_calc = do_noend;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *producer(void *cont_ptr_void)
|
||||
void wait_consumer(void)
|
||||
{
|
||||
pthread_mutex_lock(&mutex_cons_has_finished);
|
||||
if (++producers_ended == nb_prod)
|
||||
cont = 0;
|
||||
if (!consumer_has_finished)
|
||||
pthread_cond_wait(&cond_cons_has_finished, &mutex_cons_has_finished);
|
||||
pthread_mutex_unlock(&mutex_cons_has_finished);
|
||||
}
|
||||
|
||||
void *producer(void *unused)
|
||||
{
|
||||
int i, j;
|
||||
void *k;
|
||||
volatile int *cont;
|
||||
struct timeval tv1, tv2, tv_result;
|
||||
|
||||
cont = *((volatile int **) cont_ptr_void);
|
||||
if (init_producer_thread())
|
||||
{
|
||||
fprintf(stderr, "Initialization of thread has failed\n");
|
||||
wait_consumer();
|
||||
return &nb_prod; /* &nb_prod can't be NULL, whatever NULL is bound to */
|
||||
}
|
||||
if (shared)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
@ -163,7 +258,8 @@ void *producer(void *cont_ptr_void)
|
|||
if (pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpuset))
|
||||
{
|
||||
perror("pthread_setaffinity_np");
|
||||
return NULL;
|
||||
wait_consumer();
|
||||
return &nb_prod; /* &nb_prod can't be NULL, whatever NULL is bound to */
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -177,33 +273,58 @@ void *producer(void *cont_ptr_void)
|
|||
if (pthread_setaffinity_np(tid, sizeof(cpu_set_t), &cpuset))
|
||||
{
|
||||
perror("pthread_setaffinity_np");
|
||||
return NULL;
|
||||
wait_consumer();
|
||||
return &nb_prod; /* &nb_prod can't be NULL, whatever NULL is bound to */
|
||||
}
|
||||
}
|
||||
printf("Registering: %p !\n", (void*) pthread_self());
|
||||
add_sender();
|
||||
k = cont_ptr_void;
|
||||
if (init_calc(init_calc_arg))
|
||||
{
|
||||
fprintf(stderr, "Initialization of calculation has failed\n");
|
||||
wait_consumer();
|
||||
return &nb_prod; /* nb_prod can't be NULL, whatever NULL is bound to */
|
||||
}
|
||||
gettimeofday(&tv1, NULL);
|
||||
if (initialize_papi() != -1)
|
||||
{
|
||||
for(i = 0; i < nb_cache_lines; i++) {
|
||||
//printf("[%p] Send a new CACHE_LINE\n", (void *) pthread_self());
|
||||
for(j = 0; j < (CACHE_LINE_SIZE / sizeof(uintptr_t)); j++)
|
||||
send(&k);
|
||||
for(i = 0; i < nb_bufs_sent; i++) {
|
||||
//printf("[%p] Send %d new CACHE_LINE\n", (void *) pthread_self(), BUF_SIZE / CACHE_LINE_SIZE);
|
||||
for(j = 0; j < WORDS_PER_BUF; j++)
|
||||
send(do_calc());
|
||||
}
|
||||
print_results();
|
||||
print_results(WORDS_PER_BUF, nb_bufs_sent);
|
||||
}
|
||||
gettimeofday(&tv2, NULL);
|
||||
tv_result.tv_sec = tv2.tv_sec - tv1.tv_sec;
|
||||
if (tv2.tv_usec < tv1.tv_usec)
|
||||
{
|
||||
tv_result.tv_usec = tv1.tv_usec - tv2.tv_usec;
|
||||
tv_result.tv_sec--;
|
||||
}
|
||||
else
|
||||
tv_result.tv_usec = tv2.tv_usec - tv1.tv_usec;
|
||||
printf("total_time: %u.%06u / %u.%06u / %u.%06u\n", (unsigned) tv_result.tv_sec,
|
||||
(unsigned) tv_result.tv_usec,
|
||||
DIV_SEC(tv_result.tv_sec, nb_bufs_sent),
|
||||
DIV_USEC(tv_result.tv_sec, tv_result.tv_usec, nb_bufs_sent),
|
||||
DIV_SEC(tv_result.tv_sec, nb_bufs_sent * WORDS_PER_BUF),
|
||||
DIV_USEC(tv_result.tv_sec, tv_result.tv_usec, nb_bufs_sent * WORDS_PER_BUF));
|
||||
if (end_calc())
|
||||
{
|
||||
fprintf(stderr, "uninitialization of calculation has failed\n");
|
||||
wait_consumer();
|
||||
return &nb_prod; /* &nb_prod can't be NULL, whatever NULL is bound to */
|
||||
}
|
||||
printf("[%p] Producer finished !\n", (void*) pthread_self());
|
||||
remove_sender();
|
||||
/*
|
||||
* When a producer end its thread-local storage vanished. Thus,
|
||||
* producers must finish only after consumer has stopped using them
|
||||
*/
|
||||
pthread_mutex_lock(&mutex_cons_has_finished);
|
||||
if (++producers_ended == nb_prod)
|
||||
*cont = 0;
|
||||
if (!consumer_has_finished)
|
||||
pthread_cond_wait(&cond_cons_has_finished, &mutex_cons_has_finished);
|
||||
pthread_mutex_unlock(&mutex_cons_has_finished);
|
||||
wait_consumer();
|
||||
if (end_producer_thread())
|
||||
{
|
||||
fprintf(stderr, "Uninitialization of thread has failed\n");
|
||||
return &nb_prod; /* &nb_prod can't be NULL, whatever NULL is bound to */
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -238,21 +359,34 @@ void *receptor(void *a)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
volatile int *cont;
|
||||
int i, global_return_value = EXIT_SUCCESS;
|
||||
void *return_value;
|
||||
pthread_t *tid;
|
||||
|
||||
if (analyse_options(argc, argv))
|
||||
return EXIT_FAILURE;
|
||||
if (init_library())
|
||||
return EXIT_FAILURE;
|
||||
tid = (pthread_t *) malloc((nb_prod + 1) * sizeof(pthread_t));
|
||||
cont = init_comm();
|
||||
if (tid == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate %lu bytes needed for thread creation\n", (nb_prod + 1) * sizeof(pthread_t));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
for(i = 0; i < nb_prod; i++)
|
||||
pthread_create(&tid[i], NULL, producer, &cont);
|
||||
pthread_create(&tid[i], NULL, producer, NULL);
|
||||
pthread_create(&tid[i], NULL, receptor, NULL);
|
||||
for(i = 0; i < nb_prod; i++)
|
||||
{
|
||||
pthread_join(tid[i], &return_value);
|
||||
if (return_value != NULL)
|
||||
global_return_value = EXIT_FAILURE;
|
||||
}
|
||||
pthread_join(tid[i], &return_value);
|
||||
if (return_value != NULL)
|
||||
global_return_value = EXIT_FAILURE;
|
||||
free(tid);
|
||||
return EXIT_SUCCESS;
|
||||
if (end_library())
|
||||
return EXIT_FAILURE;
|
||||
return global_return_value;
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread int pipefd[2];
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
|
||||
pipe(pipefd);
|
||||
assoc = (struct communication_assoc *) malloc(sizeof(struct communication_assoc));
|
||||
assoc->tid = pthread_self();
|
||||
assoc->pipefd = pipefd;
|
||||
return assoc;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
{
|
||||
struct communication_assoc *cur;
|
||||
|
||||
discover_new_producers();
|
||||
cur = assoc_root.next;
|
||||
while(cur != &assoc_root)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < BUF_SIZE / sizeof(void *); i++)
|
||||
{
|
||||
void *tmp;
|
||||
read(cur->pipefd[READ_IDX], &tmp, sizeof(void *));
|
||||
on_receive(tmp);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread void **shared_space;
|
||||
__thread volatile int cons_idx = 0;
|
||||
__thread volatile int prod_idx = 0;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
|
||||
shared_space = (void **) malloc(SHARED_SPACE_SIZE);
|
||||
assoc = (struct communication_assoc *) malloc(sizeof(struct communication_assoc));
|
||||
assoc->tid = pthread_self();
|
||||
assoc->shared_space = shared_space;
|
||||
assoc->cons_idx = &cons_idx;
|
||||
assoc->prod_idx = &prod_idx;
|
||||
return assoc;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
{
|
||||
struct communication_assoc *cur;
|
||||
|
||||
discover_new_producers();
|
||||
cur = assoc_root.next;
|
||||
while(cur != &assoc_root)
|
||||
{
|
||||
int cons_idx;
|
||||
|
||||
for(cons_idx = *cur->cons_idx; cons_idx != *cur->prod_idx; cons_idx = (cons_idx + 1) % SHARED_SPACE_VOIDPTR, *cur->cons_idx = cons_idx)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = cur->shared_space[cons_idx];
|
||||
on_receive(tmp);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Non standard include */
|
||||
#include <common_comm.h>
|
||||
#include <specific_comm.h>
|
||||
|
||||
|
||||
__thread void **shared_space;
|
||||
__thread volatile int cons_idx = 0;
|
||||
__thread volatile int prod_idx = 0;
|
||||
|
||||
struct communication_assoc *create_comm_assoc(void)
|
||||
{
|
||||
struct communication_assoc *assoc;
|
||||
|
||||
shared_space = (void **) malloc(SHARED_SPACE_SIZE);
|
||||
assoc = (struct communication_assoc *) malloc(sizeof(struct communication_assoc));
|
||||
assoc->tid = pthread_self();
|
||||
assoc->shared_space = shared_space;
|
||||
assoc->cons_idx = &cons_idx;
|
||||
assoc->prod_idx = &prod_idx;
|
||||
return assoc;
|
||||
}
|
||||
|
||||
void reception(void (*on_receive)(void *))
|
||||
{
|
||||
wait_initialization();
|
||||
/* printf("Activate the consumer...\n"); */
|
||||
while(cont)
|
||||
{
|
||||
struct communication_assoc *cur;
|
||||
|
||||
discover_new_producers();
|
||||
cur = assoc_root.next;
|
||||
while(cur != &assoc_root)
|
||||
{
|
||||
int cons_idx, prod_idx;
|
||||
|
||||
cons_idx = *cur->cons_idx;
|
||||
do
|
||||
{
|
||||
prod_idx = *cur->prod_idx;
|
||||
for(; cons_idx != prod_idx; cons_idx = (cons_idx + 1) % SHARED_SPACE_VOIDPTR)
|
||||
{
|
||||
void *tmp;
|
||||
tmp = cur->shared_space[cons_idx];
|
||||
on_receive(tmp);
|
||||
}
|
||||
} while (prod_idx != *cur->prod_idx);
|
||||
*cur->cons_idx = cons_idx;
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1 @@
|
|||
Subproject commit 6d5117308f78e2ca984691d4440b6a1aa45857b9
|
||||
Subproject commit 16449c571f7363d0a6dc8293df8f0aaec40b492a
|
Loading…
Reference in New Issue