a self-contained test of the mempool strategy, doesnt seem promising yet
authorjjenista <jjenista>
Sun, 12 Sep 2010 21:23:31 +0000 (21:23 +0000)
committerjjenista <jjenista>
Sun, 12 Sep 2010 21:23:31 +0000 (21:23 +0000)
Robust/src/Tests/memPool/makefile [new file with mode: 0644]
Robust/src/Tests/memPool/memPool.h [new file with mode: 0644]
Robust/src/Tests/memPool/mlp_lock.h [new file with mode: 0644]
Robust/src/Tests/memPool/testMemPool-calloc.c [new file with mode: 0644]
Robust/src/Tests/memPool/testMemPool-malloc.c [new file with mode: 0644]
Robust/src/Tests/memPool/testMemPool-poolalloc.c [new file with mode: 0644]

diff --git a/Robust/src/Tests/memPool/makefile b/Robust/src/Tests/memPool/makefile
new file mode 100644 (file)
index 0000000..848dc4f
--- /dev/null
@@ -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 (file)
index 0000000..9a72997
--- /dev/null
@@ -0,0 +1,129 @@
+#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__
+
+
+
+
+
+
+
+
+
+
diff --git a/Robust/src/Tests/memPool/mlp_lock.h b/Robust/src/Tests/memPool/mlp_lock.h
new file mode 100644 (file)
index 0000000..650e304
--- /dev/null
@@ -0,0 +1,98 @@
+#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;
+}
diff --git a/Robust/src/Tests/memPool/testMemPool-calloc.c b/Robust/src/Tests/memPool/testMemPool-calloc.c
new file mode 100644 (file)
index 0000000..e4a7464
--- /dev/null
@@ -0,0 +1,103 @@
+#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;
+}
diff --git a/Robust/src/Tests/memPool/testMemPool-malloc.c b/Robust/src/Tests/memPool/testMemPool-malloc.c
new file mode 100644 (file)
index 0000000..2c08e4a
--- /dev/null
@@ -0,0 +1,103 @@
+#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;
+}
diff --git a/Robust/src/Tests/memPool/testMemPool-poolalloc.c b/Robust/src/Tests/memPool/testMemPool-poolalloc.c
new file mode 100644 (file)
index 0000000..659805e
--- /dev/null
@@ -0,0 +1,115 @@
+#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;
+}