--- /dev/null
+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 *~
--- /dev/null
+#ifndef ___MEMPOOL_H__
+#define ___MEMPOOL_H__
+
+#include <stdlib.h>
+#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__
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+
+#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;
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <pthread.h>
+
+
+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;
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <pthread.h>
+
+
+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;
+}
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <pthread.h>
+
+#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;
+}