add feature to memPool for detecting misuse of records by clients, also added a funct...
authorjjenista <jjenista>
Wed, 27 Oct 2010 23:48:17 +0000 (23:48 +0000)
committerjjenista <jjenista>
Wed, 27 Oct 2010 23:48:17 +0000 (23:48 +0000)
Robust/src/Benchmarks/oooJava/micro-master-makefile
Robust/src/IR/Flat/BuildCode.java
Robust/src/Runtime/memPool.h
Robust/src/Runtime/mlp_runtime.c
Robust/src/Runtime/mlp_runtime.h
Robust/src/Runtime/squeue.h
Robust/src/buildscript

index 7048a2aaf7cada85e5acf318db310fd65fb6c3ed..0107d28de4a799ffbfd6008a6b25d971a463885a 100644 (file)
@@ -32,7 +32,7 @@ USECOREPROF= #-coreprof $(COREPROFOVERFLOW) \
        -coreprof-enable cpe_taskstallmem
 
 
-USEOOO= -ooojava 24 2 -squeue -ooodebug-disable-task-mem-pool #-ooodebug 
+USEOOO= -ooojava 24 2 -squeue -mempool-detect-misuse #-ooodebug-disable-task-mem-pool #-ooodebug 
 BSFLAGS= -64bit -mainclass $(PROGRAM)  -heapsize-mb 50 -garbagestats -joptimize -noloop -debug -debug-deque # -optimize src-after-pp
 
 DRELEASEMODE=-disjoint-release-mode -disjoint-dvisit-stack-callees-on-top -disjoint-alias-file aliases.txt tabbed
index 9beb1239038108203da824186b1e122597f38884..eb1b1bb77a0b8baa45f78ef7a87b499accd17533 100644 (file)
@@ -2548,8 +2548,8 @@ public class BuildCode {
     // don't bother if the task never has children (a leaf task)
     output.println( "#ifndef OOO_DISABLE_TASKMEMPOOL" );
     if( !fsen.getIsLeafSESE() ) {
-      output.println("   runningSESE->taskRecordMemPool = taskpoolcreate( "+
-                     maxTaskRecSizeStr+" );");
+      output.println("   runningSESE->taskRecordMemPool = poolcreate( "+
+                     maxTaskRecSizeStr+", freshTaskRecordInitializer );");
     } else {
       // make it clear we purposefully did not initialize this
       output.println("   runningSESE->taskRecordMemPool = (MemPool*)0x7;");
@@ -3928,7 +3928,7 @@ public class BuildCode {
         ) {
       output.println("     "+
                      fsen.getSESErecordName()+"* seseToIssue = ("+
-                     fsen.getSESErecordName()+"*) taskpoolalloc( runningSESE->taskRecordMemPool );");
+                     fsen.getSESErecordName()+"*) poolalloc( runningSESE->taskRecordMemPool );");
     } else {
       output.println("     "+
                      fsen.getSESErecordName()+"* seseToIssue = ("+
index 900e8fd5b2542d5661ad8161551189b128f68645..8724b19136a67f5fd4e47e1732e4220bb02acad3 100644 (file)
 //////////////////////////////////////////////////////////
 
 #include <stdlib.h>
+
+#ifdef MEMPOOL_DETECT_MISUSE
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+static INTPTR pageSize;
+#endif
+
 #include "runtime.h"
 #include "mem.h"
 #include "mlp_lock.h"
 #define CACHELINESIZE 64
 
 
+
 typedef struct MemPoolItem_t {
   void* next;
 } MemPoolItem;
 
+
 typedef struct MemPool_t {
   int itemSize;
-  MemPoolItem* head;
 
-  // avoid cache line contention between producer/consumer...
-  char buffer[CACHELINESIZE - sizeof(void*)];
+  // only invoke this on items that are
+  // actually new, saves time for reused
+  // items
+  void(*initFreshlyAllocated)(void*);
 
+#ifdef MEMPOOL_DETECT_MISUSE
+  int allocSize;
+#else
+  //normal version
+  MemPoolItem* head;
+  // avoid cache line contention between producer/consumer...
+  char buffer[CACHELINESIZE];
   MemPoolItem* tail;
+#endif
 } MemPool;
 
 
 // the memory pool must always have at least one
 // item in it
-static MemPool* poolcreate( int itemSize ) {
-  MemPool* p    = RUNMALLOC( sizeof( MemPool ) );
-  p->itemSize   = itemSize;
-  p->head       = RUNMALLOC( itemSize );
+static MemPool* poolcreate( int itemSize, 
+                            void(*initializer)(void*) 
+                            ) {
+
+  MemPool* p  = RUNMALLOC( sizeof( MemPool ) );
+  p->itemSize = itemSize;
+  
+  p->initFreshlyAllocated = initializer;
+
+#ifdef MEMPOOL_DETECT_MISUSE
+  // when detecting misuse, round the item size
+  // up to a page and add a page, so whatever
+  // allocated memory you get, you can use a
+  // page-aligned subset as the record  
+  pageSize = sysconf( _SC_PAGESIZE );
+
+  if( itemSize % pageSize == 0 ) {
+    // if the item size is already an exact multiple
+    // of the page size, just increase by one page
+    p->allocSize = itemSize + pageSize;
+  } else {
+    // otherwise, round down to a page size, then add two
+    p->allocSize = (itemSize & ~(pageSize-1)) + 2*pageSize;
+  }
+#else
+
+  // normal version
+  p->head = RUNMALLOC( p->itemSize );
+
+  if( p->initFreshlyAllocated != NULL ) {
+    p->initFreshlyAllocated( p->head );
+  }
+
   p->head->next = NULL;
   p->tail       = p->head;
+#endif
+
   return p;
 }
 
 
-// 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.)
+
+#ifdef MEMPOOL_DETECT_MISUSE
 
+static inline void poolfreeinto( MemPool* p, void* ptr ) {
+  // don't actually return memory to the pool, just lock
+  // it up tight so first code to touch it badly gets caught
+  // also, mprotect automatically protects full pages
+  if( mprotect( ptr, p->itemSize, PROT_NONE ) != 0 ) {
+    printf( "mprotect failed, %s.\n", strerror( errno ) );
+    exit( -1 );
+  }
+}
+
+#else
+
+// normal version
 static inline void poolfreeinto( MemPool* p, void* ptr ) {
 
   MemPoolItem* tailCurrent;
@@ -95,7 +152,30 @@ static inline void poolfreeinto( MemPool* p, void* ptr ) {
     // if CAS failed, retry entire operation
   }
 }
+#endif
+
+
+
+#ifdef MEMPOOL_DETECT_MISUSE
 
+static inline void* poolalloc( MemPool* p ) {
+  // put the memory we intend to expose to client
+  // on a page-aligned boundary, always return
+  // new memory
+  INTPTR nonAligned = (INTPTR) RUNMALLOC( p->allocSize );
+
+  void* newRec = (void*)((nonAligned + pageSize-1) & ~(pageSize-1));
+
+  if( p->initFreshlyAllocated != NULL ) {
+    p->initFreshlyAllocated( newRec );
+  }
+
+  return newRec;
+}
+
+#else
+
+// normal version
 static inline void* poolalloc( MemPool* p ) {
 
   // to protect CAS in poolfree from dereferencing
@@ -108,32 +188,30 @@ static inline void* poolalloc( MemPool* p ) {
   int i;
   if(next == NULL) {
     // only one item, so don't take from pool
-    return (void*) RUNMALLOC( p->itemSize );
+    void* newRec = RUNMALLOC( p->itemSize );
+
+    if( p->initFreshlyAllocated != NULL ) {
+      p->initFreshlyAllocated( newRec );
+    }
+
+    return newRec;
   }
  
   p->head = next;
 
-  //////////////////////////////////////////////////////////
-  //
-  //
-  //  static inline void prefetch(void *x) 
-  //  { 
-  //    asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
-  //  } 
-  //
-  //
-  //  but this built-in gcc one seems the most portable:
-  //////////////////////////////////////////////////////////
-  //__builtin_prefetch( &(p->head->next) );
   asm volatile( "prefetcht0 (%0)" :: "r" (next));
   next=(MemPoolItem*)(((char *)next)+CACHELINESIZE);
   asm volatile( "prefetcht0 (%0)" :: "r" (next));
 
   return (void*)headCurrent;
 }
+#endif
+
 
 
 static void pooldestroy( MemPool* p ) {
+
+#ifndef MEMPOOL_DETECT_MISUSE
   MemPoolItem* i = p->head;
   MemPoolItem* n;
 
@@ -142,6 +220,7 @@ static void pooldestroy( MemPool* p ) {
     free( i );
     i = n;
   }
+#endif
 
   free( p );
 }
index f138f9246ec63e4737ff00bd4453c19338e421b0..79be46fbd700e36e4d19f1a96a38725fbdf127ae 100644 (file)
@@ -17,6 +17,22 @@ __thread psemaphore runningSESEstallSem;
 
 
 
+// this is for using a memPool to allocate task records,
+// pass this into the poolcreate so it will run your
+// custom init code ONLY for fresh records, reused records
+// can be returned as is
+void freshTaskRecordInitializer( void* seseRecord ) {
+  SESEcommon* c = (SESEcommon*) seseRecord;
+  pthread_cond_init( &(c->runningChildrenCond), NULL );
+  pthread_mutex_init( &(c->lock), NULL );
+
+  // no need to use return value yet, future maybe
+  //return NULL;
+}
+
+
+
+
 void* mlpAllocSESErecord( int size ) {
   void* newrec = RUNMALLOC( size );  
   if( newrec == 0 ) {
@@ -202,7 +218,7 @@ MemoryQueue* createMemoryQueue(){
   queue->head = dummy;
   queue->tail = dummy;
 #ifndef OOO_DISABLE_TASKMEMPOOL
-  queue->rentrypool = poolcreate(sizeof(REntry));
+  queue->rentrypool = poolcreate( sizeof(REntry), NULL );
 #endif
   return queue;
 }
index da272560fd954170791d2b7cc033d650511d097c..8af7cfbe1e15c524177a0ff70e8e8805b4b82992 100644 (file)
@@ -272,61 +272,12 @@ static inline void RELEASE_REFERENCE_TO( SESEcommon* seseRec ) {
   }
 }
 
-static MemPool* taskpoolcreate( int itemSize ) {
-  MemPool* p    = RUNMALLOC( sizeof( MemPool ) );
-  SESEcommon *c = (SESEcommon *) RUNMALLOC(itemSize);
-  pthread_cond_init( &(c->runningChildrenCond), NULL );
-  pthread_mutex_init( &(c->lock), NULL );
-
-  p->itemSize   = itemSize;
-  p->head       = (void *)c;
-  p->head->next = NULL;
-  p->tail       = p->head;
-  return p;
-}
-
 
-static inline void* taskpoolalloc( MemPool* p ) {
-
-  // to protect CAS in poolfree from dereferencing
-  // null, treat the queue as empty when there is
-  // only one item.  The dequeue operation is only
-  // executed by the thread that owns the pool, so
-  // it doesn't require an atomic op
-  MemPoolItem* headCurrent = p->head;
-  MemPoolItem* next=headCurrent->next;
-  int i;
-  if(next == NULL) {
-    // only one item, so don't take from pool
-    SESEcommon *c = (SESEcommon*) RUNMALLOC( p->itemSize );
-    pthread_cond_init( &(c->runningChildrenCond), NULL );
-    pthread_mutex_init( &(c->lock), NULL );
-    return c;
-  }
-  p->head = next;
-
-  //////////////////////////////////////////////////////////
-  //
-  //
-  //  static inline void prefetch(void *x) 
-  //  { 
-  //    asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x));
-  //  } 
-  //
-  //
-  //  but this built-in gcc one seems the most portable:
-  //////////////////////////////////////////////////////////
-  //__builtin_prefetch( &(p->head->next) );
-  asm volatile( "prefetcht0 (%0)" :: "r" (next));
-  next=(MemPoolItem*)(((char *)next)+CACHELINESIZE);
-  asm volatile( "prefetcht0 (%0)" :: "r" (next));
-  next=(MemPoolItem*)(((char *)next)+CACHELINESIZE);
-  asm volatile( "prefetcht0 (%0)" :: "r" (next));
-  next=(MemPoolItem*)(((char *)next)+CACHELINESIZE);
-  asm volatile( "prefetcht0 (%0)" :: "r" (next));
-
-  return (void*)headCurrent;
-}
+// this is for using a memPool to allocate task records,
+// pass this into the poolcreate so it will run your
+// custom init code ONLY for fresh records, reused records
+// can be returned as is
+void freshTaskRecordInitializer( void* seseRecord );
+  
 
 #endif /* __MLP_RUNTIME__ */
index 38325e029d49ccf336c649d4a8145254f14c73d4..75782143227a7b349582b1753a7769a4c928f47d 100644 (file)
 #include "runtime.h"
 #include "mem.h"
 #include "mlp_lock.h"
-#include "memPool.h"
+
 
 #define CACHELINESIZE 64
 #define DQ_POP_EMPTY NULL
 #define DQ_POP_ABORT NULL
 
 
+typedef struct sqMemPoolItem_t {
+  void* next;
+} sqMemPoolItem;
+
+
+typedef struct sqMemPool_t {
+  int itemSize;
+
+  sqMemPoolItem* head;
+
+  // avoid cache line contention between producer/consumer...
+  char buffer[CACHELINESIZE];
+
+  sqMemPoolItem* tail;
+
+} sqMemPool;
+
+
+
 typedef struct dequeItem_t {
   void *otherqueue;
   struct dequeItem_t * next;
@@ -43,7 +62,7 @@ typedef struct deque_t {
 
   dequeItem* tail;
   
-  MemPool objret;
+  sqMemPool objret;
 } deque;
 
 #define EXTRACTPTR(x) (x&0x0000ffffffffffff)
@@ -61,13 +80,13 @@ static void dqInit(deque *q) {
   q->objret.tail=q->objret.head;
 }
 
-static inline void tagpoolfreeinto( MemPool* p, void* ptr, void *realptr ) {
-  MemPoolItem* tailCurrent;
-  MemPoolItem* tailActual;
+static inline void tagpoolfreeinto( sqMemPool* p, void* ptr, void *realptr ) {
+  sqMemPoolItem* tailCurrent;
+  sqMemPoolItem* tailActual;
   
   // set up the now unneeded record to as the tail of the
   // free list by treating its first bytes as next pointer,
-  MemPoolItem* tailNew = (MemPoolItem*) realptr;
+  sqMemPoolItem* tailNew = (sqMemPoolItem*) realptr;
   tailNew->next = NULL;
 
   while( 1 ) {
@@ -76,14 +95,14 @@ static inline void tagpoolfreeinto( MemPool* p, void* ptr, void *realptr ) {
     BARRIER();
 
     tailCurrent = p->tail;
-    tailActual = (MemPoolItem*)
+    tailActual = (sqMemPoolItem*)
       CAS( &(p->tail),         // ptr to set
            (INTPTR) tailCurrent, // current tail's next should be NULL
            (INTPTR) realptr);  // try set to our new tail
     
     if( tailActual == tailCurrent ) {
       // success, update tail
-      tailCurrent->next = (MemPoolItem *) ptr;
+      tailCurrent->next = (sqMemPoolItem *) ptr;
       return;
     }
 
@@ -91,16 +110,16 @@ static inline void tagpoolfreeinto( MemPool* p, void* ptr, void *realptr ) {
   }
 }
 
-static inline void* tagpoolalloc( MemPool* p ) {
+static inline void* tagpoolalloc( sqMemPool* p ) {
 
   // to protect CAS in poolfree from dereferencing
   // null, treat the queue as empty when there is
   // only one item.  The dequeue operation is only
   // executed by the thread that owns the pool, so
   // it doesn't require an atomic op
-  MemPoolItem* headCurrent = p->head;
-  MemPoolItem* realHead=(MemPoolItem *) EXTRACTPTR((INTPTR)headCurrent);
-  MemPoolItem* next=realHead->next;
+  sqMemPoolItem* headCurrent = p->head;
+  sqMemPoolItem* realHead=(sqMemPoolItem *) EXTRACTPTR((INTPTR)headCurrent);
+  sqMemPoolItem* next=realHead->next;
   int i;
   if(next == NULL) {
     // only one item, so don't take from pool
@@ -121,9 +140,9 @@ static inline void* tagpoolalloc( MemPool* p ) {
   //  but this built-in gcc one seems the most portable:
   //////////////////////////////////////////////////////////
   //__builtin_prefetch( &(p->head->next) );
-  MemPoolItem* realNext=(MemPoolItem *) EXTRACTPTR((INTPTR)next);
+  sqMemPoolItem* realNext=(sqMemPoolItem *) EXTRACTPTR((INTPTR)next);
   asm volatile( "prefetcht0 (%0)" :: "r" (realNext));
-  realNext=(MemPoolItem*)(((char *)realNext)+CACHELINESIZE);
+  realNext=(sqMemPoolItem*)(((char *)realNext)+CACHELINESIZE);
   asm volatile( "prefetcht0 (%0)" :: "r" (realNext));
 
   return (void*)headCurrent;
index 8578175d9780334ba0965d2bd4ef8c48ddabd533..9fc8b98bb3913703c1e940776d15923a98c98109 100755 (executable)
@@ -25,6 +25,7 @@ echo   EVENTNAME can be: cpe_main, cpe_runmalloc, cpe_runfree, cpe_poolalloc, cp
 echo "-ooojava <numberofcores> <maxseseage>"
 echo -ooodebug general OOOJava debugging messages
 echo -ooodebug-disable-task-mem-pool this is a tricky module, disable for simpler runtime
+echo -mempool-detect-misuse turn on to find code misusing pool-allocated records
 echo -rcr turn on runtime conflict resolver
 echo -squeue use single queue
 echo
@@ -565,6 +566,10 @@ elif [[ $1 = '-ooodebug-disable-task-mem-pool' ]]
 then
 EXTRAOPTIONS="$EXTRAOPTIONS -DOOO_DISABLE_TASKMEMPOOL"
 
+elif [[ $1 = '-mempool-detect-misuse' ]]
+then
+EXTRAOPTIONS="$EXTRAOPTIONS -DMEMPOOL_DETECT_MISUSE"
+
 elif [[ $1 = '-heapsize-mb' ]]
 then
 EXTRAOPTIONS="$EXTRAOPTIONS -DINITIALHEAPSIZE_MB=($2)"