From: jjenista Date: Sun, 12 Sep 2010 21:23:31 +0000 (+0000) Subject: a self-contained test of the mempool strategy, doesnt seem promising yet X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=f44e190056cdc663752fee124ca46ff62eb27314;p=IRC.git a self-contained test of the mempool strategy, doesnt seem promising yet --- diff --git a/Robust/src/Tests/memPool/makefile b/Robust/src/Tests/memPool/makefile new file mode 100644 index 00000000..848dc4f4 --- /dev/null +++ b/Robust/src/Tests/memPool/makefile @@ -0,0 +1,24 @@ +PROGRAM1=testMemPool-calloc +PROGRAM2=testMemPool-malloc +PROGRAM3=testMemPool-poolalloc + +FLAGS=-O3 + +all: $(PROGRAM1) $(PROGRAM2) $(PROGRAM3) + + +$(PROGRAM1): $(PROGRAM1).c + gcc $(FLAGS) $(PROGRAM1).c -lpthread -o $(PROGRAM1) + +$(PROGRAM2): $(PROGRAM2).c + gcc $(FLAGS) $(PROGRAM2).c -lpthread -o $(PROGRAM2) + +$(PROGRAM3): $(PROGRAM3).c + gcc $(FLAGS) $(PROGRAM3).c -lpthread -o $(PROGRAM3) + + +clean: + rm -f $(PROGRAM1) + rm -f $(PROGRAM2) + rm -f $(PROGRAM3) + rm -f *~ diff --git a/Robust/src/Tests/memPool/memPool.h b/Robust/src/Tests/memPool/memPool.h new file mode 100644 index 00000000..9a729976 --- /dev/null +++ b/Robust/src/Tests/memPool/memPool.h @@ -0,0 +1,129 @@ +#ifndef ___MEMPOOL_H__ +#define ___MEMPOOL_H__ + +#include +#include "mlp_lock.h" + + +// A memory pool implements POOLALLOCATE and POOLFREE +// to improve memory allocation by reusing records. +// + + +typedef struct MemPool_t { + int itemSize; + + int poolSize; + INTPTR* ringBuffer; + + int head; + int tail; +} MemPool; + + + +MemPool* poolcreate( int itemSize, int poolSize ) { + MemPool* p = malloc( sizeof( MemPool ) ); + p->itemSize = itemSize; + p->poolSize = poolSize; + p->ringBuffer = malloc( poolSize * sizeof( INTPTR ) ); + p->head = 0; + p->tail = 0; +} + + +// CAS +// in: a ptr, expected old, desired new +// return: actual old +// +// Pass in a ptr, what you expect the old value is and +// what you want the new value to be. +// The CAS returns what the value is actually: if it matches +// your proposed old value then you assume the update was successful, +// otherwise someone did CAS before you, so try again (the return +// value is the old value you will pass next time.) + + +static inline void* poolalloc( MemPool* p ) { + int headNow; + int headNext; + int headActual; + + while( 1 ) { + // if there are no free items available, just do regular + // allocation and move on--ok to use unnsynched reads + // for this test, its conservative + if( p->head == p->tail ) { + return calloc( 1, p->itemSize ); + } + + // otherwise, attempt to grab a free item from the + // front of the free list + headNow = p->head; + headNext = headNow + 1; + if( headNext == p->poolSize ) { + headNext = 0; + } + + headActual = CAS( &(p->head), headNow, headNext ); + if( headActual == headNow ) { + // can't some other pool accesses happen during + // this time, before return??? + return (void*) p->ringBuffer[headActual]; + } + + // if CAS failed, retry entire operation + } +} + + +static inline void poolfree( MemPool* p, void* ptr ) { + int tailNow; + int tailNext; + int tailActual; + + while( 1 ) { + // if the ring buffer is full, just do regular free, ok to + // use unsyhcronized reads for this test, its conservative + if( p->tail + 1 == p->head || + ( p->tail == p->poolSize - 1 && + p->head == 0 + ) + ) { + free( ptr ); + return; + } + + // otherwise, attempt to grab add the free item to the + // end of the free list + tailNow = p->tail; + tailNext = tailNow + 1; + if( tailNext == p->poolSize ) { + tailNext = 0; + } + + tailActual = CAS( &(p->tail), tailNow, tailNext ); + if( tailActual == tailNow ) { + // can't some other pool accesses happen during + // this time, before return??? + p->ringBuffer[tailActual] = (INTPTR)ptr; + return; + } + + // if CAS failed, retry entire operation + } +} + + + +#endif // ___MEMPOOL_H__ + + + + + + + + + + diff --git a/Robust/src/Tests/memPool/mlp_lock.h b/Robust/src/Tests/memPool/mlp_lock.h new file mode 100644 index 00000000..650e3048 --- /dev/null +++ b/Robust/src/Tests/memPool/mlp_lock.h @@ -0,0 +1,98 @@ +#include +#include +#include + + +#define INTPTR long + + +#define __xg(x) ((volatile INTPTR *)(x)) + +#define CFENCE asm volatile("":::"memory"); + +#define LOCK_PREFIX \ + ".section .smp_locks,\"a\"\n" \ + " .align 4\n" \ + " .long 661f\n" /* address */\ + ".previous\n" \ + "661:\n\tlock; " + + +static inline void atomic_dec(volatile int *v) { + __asm__ __volatile__ (LOCK_PREFIX "decl %0" + : "+m" (*v)); +} + +static inline void atomic_inc(volatile int *v) { + __asm__ __volatile__ (LOCK_PREFIX "incl %0" + : "+m" (*v)); +} + +static inline int atomic_sub_and_test(int i, volatile int *v) { + unsigned char c; + + __asm__ __volatile__ (LOCK_PREFIX "subl %2,%0; sete %1" + : "+m" (*v), "=qm" (c) + : "ir" (i) : "memory"); + return c; +} + +#ifdef BIT64 +static inline INTPTR LOCKXCHG(volatile INTPTR * ptr, INTPTR val){ + INTPTR retval; + //note: xchgl always implies lock + __asm__ __volatile__("xchgq %0,%1" + : "=r"(retval) + : "m"(*ptr), "0"(val) + : "memory"); + return retval; + +} +#else +static inline int LOCKXCHG(volatile int* ptr, int val){ + int retval; + //note: xchgl always implies lock + __asm__ __volatile__("xchgl %0,%1" + : "=r"(retval) + : "m"(*ptr), "0"(val) + : "memory"); + return retval; + +} +#endif + +/* +static inline int write_trylock(volatile int *lock) { + int retval=0; + __asm__ __volatile__("xchgl %0,%1" + : "=r"(retval) + : "m"(*lock), "0"(retval) + : "memory"); + return retval; +} +*/ + +#ifdef BIT64 +static inline INTPTR CAS(volatile void *ptr, unsigned INTPTR old, unsigned INTPTR new){ + unsigned INTPTR prev; + __asm__ __volatile__("lock; cmpxchgq %1,%2" + : "=a"(prev) + : "r"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; +} +#else +static inline long CAS(volatile void *ptr, unsigned long old, unsigned long new){ + unsigned long prev; + __asm__ __volatile__("lock; cmpxchgl %k1,%2" + : "=a"(prev) + : "r"(new), "m"(*__xg(ptr)), "0"(old) + : "memory"); + return prev; +} +#endif + +static inline int BARRIER(){ + CFENCE; + return 1; +} diff --git a/Robust/src/Tests/memPool/testMemPool-calloc.c b/Robust/src/Tests/memPool/testMemPool-calloc.c new file mode 100644 index 00000000..e4a74644 --- /dev/null +++ b/Robust/src/Tests/memPool/testMemPool-calloc.c @@ -0,0 +1,103 @@ +#include +#include + +#include + + +struct bar { + int x; + char takeSpace[1000]; +}; + +struct baz { + int y; + char takeSpace[1000]; +}; + +struct foo { + struct bar* br; + struct baz* bz; + int z; + char takeSpace[1000]; +}; + + +void* workerMain( void* arg ) { + + struct foo* f = (struct foo*)arg; + + f->z = f->br->x + f->bz->y; + + free( f->br ); + free( f->bz ); + + pthread_exit( arg ); +} + + +int main() { + + int i; + + struct bar* br; + struct baz* bz; + struct foo* f; + + int numThreads = 10000; + pthread_t threads[numThreads]; + pthread_attr_t attr; + + int total = 0; + + + pthread_attr_init( &attr ); + pthread_attr_setdetachstate( &attr, + PTHREAD_CREATE_JOINABLE ); + + + for( i = 0; i < numThreads; ++i ) { + + br = calloc( 1, sizeof( struct bar ) ); + bz = calloc( 1, sizeof( struct baz ) ); + f = calloc( 1, sizeof( struct foo ) ); + + br->x = i; + bz->y = -4321; + + f->br = br; + f->bz = bz; + + pthread_create( &(threads[i]), + &attr, + workerMain, + (void*)f ); + + if( i % 1000 == 0 ) { + printf( "." ); + } + + if( i % 100 == 0 ) { + sched_yield(); + } + } + + printf( "\n" ); + + for( i = 0; i < numThreads; ++i ) { + + f = NULL; + pthread_join( threads[i], + (void**)&f ); + + total += f->z; + free( f ); + + if( i % 1000 == 0 ) { + printf( "+" ); + } + } + + printf( "\nTotal=%d\n", total ); + + return 0; +} diff --git a/Robust/src/Tests/memPool/testMemPool-malloc.c b/Robust/src/Tests/memPool/testMemPool-malloc.c new file mode 100644 index 00000000..2c08e4a4 --- /dev/null +++ b/Robust/src/Tests/memPool/testMemPool-malloc.c @@ -0,0 +1,103 @@ +#include +#include + +#include + + +struct bar { + int x; + char takeSpace[1000]; +}; + +struct baz { + int y; + char takeSpace[1000]; +}; + +struct foo { + struct bar* br; + struct baz* bz; + int z; + char takeSpace[1000]; +}; + + +void* workerMain( void* arg ) { + + struct foo* f = (struct foo*)arg; + + f->z = f->br->x + f->bz->y; + + free( f->br ); + free( f->bz ); + + pthread_exit( arg ); +} + + +int main() { + + int i; + + struct bar* br; + struct baz* bz; + struct foo* f; + + int numThreads = 10000; + pthread_t threads[numThreads]; + pthread_attr_t attr; + + int total = 0; + + + pthread_attr_init( &attr ); + pthread_attr_setdetachstate( &attr, + PTHREAD_CREATE_JOINABLE ); + + + for( i = 0; i < numThreads; ++i ) { + + br = malloc( sizeof( struct bar ) ); + bz = malloc( sizeof( struct baz ) ); + f = malloc( sizeof( struct foo ) ); + + br->x = i; + bz->y = -4321; + + f->br = br; + f->bz = bz; + + pthread_create( &(threads[i]), + &attr, + workerMain, + (void*)f ); + + if( i % 1000 == 0 ) { + printf( "." ); + } + + if( i % 100 == 0 ) { + sched_yield(); + } + } + + printf( "\n" ); + + for( i = 0; i < numThreads; ++i ) { + + f = NULL; + pthread_join( threads[i], + (void**)&f ); + + total += f->z; + free( f ); + + if( i % 1000 == 0 ) { + printf( "+" ); + } + } + + printf( "\nTotal=%d\n", total ); + + return 0; +} diff --git a/Robust/src/Tests/memPool/testMemPool-poolalloc.c b/Robust/src/Tests/memPool/testMemPool-poolalloc.c new file mode 100644 index 00000000..659805ed --- /dev/null +++ b/Robust/src/Tests/memPool/testMemPool-poolalloc.c @@ -0,0 +1,115 @@ +#include +#include + +#include + +#include "memPool.h" + + +static const int POOLSIZE = 100; + +static MemPool* barPool; +static MemPool* bazPool; +static MemPool* fooPool; + + +struct bar { + int x; + char takeSpace[1000]; +}; + +struct baz { + int y; + char takeSpace[1000]; +}; + +struct foo { + struct bar* br; + struct baz* bz; + int z; + char takeSpace[1000]; +}; + + +void* workerMain( void* arg ) { + + struct foo* f = (struct foo*)arg; + + f->z = f->br->x + f->bz->y; + + poolfree( barPool, f->br ); + poolfree( bazPool, f->bz ); + + pthread_exit( arg ); +} + + +int main() { + + int i; + + struct bar* br; + struct baz* bz; + struct foo* f; + + int numThreads = 10000; + pthread_t threads[numThreads]; + pthread_attr_t attr; + + int total = 0; + + barPool = poolcreate( sizeof( struct bar ), POOLSIZE ); + bazPool = poolcreate( sizeof( struct baz ), POOLSIZE ); + fooPool = poolcreate( sizeof( struct foo ), POOLSIZE ); + + pthread_attr_init( &attr ); + pthread_attr_setdetachstate( &attr, + PTHREAD_CREATE_JOINABLE ); + + + for( i = 0; i < numThreads; ++i ) { + + br = poolalloc( barPool ); + bz = poolalloc( bazPool ); + f = poolalloc( fooPool ); + + br->x = i; + bz->y = -4321; + + f->br = br; + f->bz = bz; + + pthread_create( &(threads[i]), + &attr, + workerMain, + (void*)f ); + + if( i % 1000 == 0 ) { + printf( "." ); + } + + if( i % 100 == 0 ) { + sched_yield(); + } + } + + printf( "\n" ); + + for( i = 0; i < numThreads; ++i ) { + + f = NULL; + pthread_join( threads[i], + (void**)&f ); + + total += f->z; + poolfree( fooPool, f ); + + if( i % 1000 == 0 ) { + printf( "+" ); + } + } + + printf( "\nTotal=%d\n", total ); + + return 0; +}