Implementation of out-of-core emulation for bigsim emulator. The "+bgooc" option...
authorChao Mei <chaomei2@illinois.edu>
Tue, 30 Dec 2008 16:28:05 +0000 (16:28 +0000)
committerChao Mei <chaomei2@illinois.edu>
Tue, 30 Dec 2008 16:28:05 +0000 (16:28 +0000)
src/langs/bluegene/bigsim_debug.h [new file with mode: 0644]
src/langs/bluegene/bigsim_init.C
src/langs/bluegene/bigsim_node.C
src/langs/bluegene/bigsim_ooc.C [new file with mode: 0644]
src/langs/bluegene/bigsim_ooc.h [new file with mode: 0644]
src/langs/bluegene/bigsim_proc.C
src/langs/bluegene/blue.C
src/langs/bluegene/blue.h
src/langs/bluegene/blue_impl.h

diff --git a/src/langs/bluegene/bigsim_debug.h b/src/langs/bluegene/bigsim_debug.h
new file mode 100644 (file)
index 0000000..93831ee
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _BIGSIM_DEBUG_H_
+#define _BIGSIM_DEBUG_H_
+
+#ifdef TURNONDEBUG
+    #define DEBUGF(x) CmiPrintf x;
+#else
+    #define DEBUGF(x) //CmiPrintf x;
+#endif
+
+#define MAXDEBUGLEVEL 10
+
+//The higher the value is, the lower level the debug info is
+#define DEBUGLEVEL MAXDEBUGLEVEL
+
+#define DEBUGM(level, x) \
+    { if (level == DEBUGLEVEL) CmiPrintf x; }
+    
+#endif
index 232d3b4dd934a8998c12daa6248971c34bc4c5e8..11b86633e43a7c6b4b4e6e3f1c7695d04991c306 100644 (file)
    using namespace std;
 #endif
 
-#define  DEBUGF(x)      //CmiPrintf x;
+#include "bigsim_debug.h"
+#undef DEBUGLEVEL
+#define DEBUGLEVEL 10 
+//#define  DEBUGF(x)      //CmiPrintf x;
 
 #include "queueing.h"
 #include "blue.h"
 #include "blue_impl.h"         // implementation header file
 //#include "blue_timing.h"     // timing module
 
+#include "bigsim_ooc.h"
+
 extern CmiStartFn bgMain(int argc, char **argv);
 
 /* called by a AMPI thread of certan rank to attatch itself */
@@ -42,6 +47,20 @@ extern "C" void BgAttach(CthThread t)
   BgSetStrategyBigSimDefault(t);
 }
 
+extern "C" void BgSetStartOutOfCore(){
+    DEBUGM(4, ("Set startOutOfCore!(node: %d, gId: %d, id: %d)\n", tMYNODEID, tMYGLOBALID, tMYID));
+    if(cta(threadinfo)->startOutOfCore==0)
+       cta(threadinfo)->startOOCChanged=1;
+    cta(threadinfo)->startOutOfCore = 1;
+}
+
+extern "C" void BgUnsetStartOutOfCore(){
+    DEBUGM(4, ("UnSet startOutOfCore!(node: %d, gId: %d, id: %d)\n", tMYNODEID, tMYGLOBALID, tMYID));
+    if(cta(threadinfo)->startOutOfCore==1)
+       cta(threadinfo)->startOOCChanged=1;
+    cta(threadinfo)->startOutOfCore = 0;
+}
+
 // quiescence detection callback
 // only used when doing timing correction to wait for 
 static void BroadcastShutdown(void *null, double t)
@@ -83,6 +102,10 @@ void BgShutdown()
     /* don't return */
     // ConverseExit();
     CmiDeliverMsgs(-1);
+
+    if(bgUseOutOfCore)
+        deInitTblThreadInMem();
+
     CmiPrintf("\nBG> BlueGene emulator shutdown gracefully!\n");
     CmiPrintf("BG> Emulation took %f seconds!\n", CmiWallTimer()-cva(simState).simStartTime);
     ConverseExit();
@@ -221,6 +244,13 @@ int BGMach::read(char *file)
       procList.set(strdup(parameterValue));
       continue;
     }
+    /* Parameters related with out-of-core execution */
+//    if (!strcmp(parameterName, "bgooc")) {      
+//        bgUseOutOfCore = 1;
+//        bgOOCMaxMemSize = atof(parameterValue);
+//        continue;
+//    }           
+
     if (CmiMyPe() == 0)
       CmiPrintf("skip %s '%s'\n", parameterName, parameterValue);
   }
index 071c08b4ca6f7641c17865ad75efb2d38b306211..d09968b09ce052a01cc7b73f90b5bb7fcde0ff9f 100644 (file)
@@ -2,8 +2,8 @@
 #include "blue.h"
 #include "blue_impl.h"         // implementation header file
 //#include "blue_timing.h"     // timing module
-
-#define  DEBUGF(x)      //CmiPrintf x;
+#include "bigsim_debug.h"
+//#define  DEBUGF(x)      //CmiPrintf x;
 
 /**
   nodeInfo construtor
diff --git a/src/langs/bluegene/bigsim_ooc.C b/src/langs/bluegene/bigsim_ooc.C
new file mode 100644 (file)
index 0000000..b7eebe3
--- /dev/null
@@ -0,0 +1,474 @@
+#include "blue.h"
+#include "blue_types.h"
+#include "bigsim_ooc.h"
+#include <assert.h>
+#include "bigsim_debug.h"
+
+#undef DEBUGLEVEL
+#define DEBUGLEVEL 3
+
+
+//default values for out-of-core execution
+int bgUseOutOfCore = 0; //default is off
+
+double bgOOCMaxMemSize = 512.0; //default 512MB
+
+
+threadInMemEntry *tblThreadInMemHead;
+
+int TBLCAPACITY=2;
+
+#define OOOSIMPLEVER 1 
+
+#if OOOSIMPLEVER
+void initTblThreadInMem(){ 
+  
+  /* Initialize the table that tracks threads (workThread) in memory:
+   * First, accordin g to current memory usage, decide an appropriate table size
+   * which should be less than TBLTHDINMEMMAXSIZE.
+   * NOTE: This has not been implemented. The initial step is only set the table
+   * to a small constant!!!
+   * Second, initialize the table entries.
+   */  
+  tblThreadInMemHead = new threadInMemEntry[TBLCAPACITY];  
+  for(int i=1; i<TBLCAPACITY; i++){
+      tblThreadInMemHead[i].initSelf();
+  }
+}
+
+void deInitTblThreadInMem(){    
+    delete tblThreadInMemHead;
+}
+
+//if found return the entry of this thread, otherwise return NULL
+threadInMemEntry *checkThreadInCore(/*int threadID*/threadInfo *thd){
+    for(int i=0; i<TBLCAPACITY; i++){
+        if(tblThreadInMemHead[i].thd == thd)
+            return tblThreadInMemHead+i;
+    }
+    return NULL;
+}
+
+//clear all entries
+void clearThdInMemTbl(){
+    for(int i=0; i<TBLCAPACITY; i++)
+       tblThreadInMemHead[i].thd = NULL;
+}
+
+/* 
+ * Gives one empty entry for the thread (thd)  which is going to be put into memory
+ * This includes following actions:
+ * 1. Check tblThreadInMem for an empty entry
+ * 2. If none is found, evict one entry based on useFreq. 
+ * Note the evicted thread will not be taken out of memory until function takeThdOutofMem is called!!
+ */
+threadInMemEntry *giveEmptyThdInMemEntry(){
+
+    for(int i=0; i<TBLCAPACITY; i++){
+        if(tblThreadInMemHead[i].thd == NULL)
+            return tblThreadInMemHead+i;
+    }
+
+    //Here, we know there is no empty entry in the table   
+    return findLeastUsedThdInMemEntry();
+}
+
+/* Just find the least used entry */
+threadInMemEntry *findLeastUsedThdInMemEntry(){
+    threadInMemEntry *leastAccessedEntry=tblThreadInMemHead;
+    assert(leastAccessedEntry->thd);
+    int leastFreq = leastAccessedEntry->useFreq;
+    
+    for(int i=1; i<TBLCAPACITY; i++){
+        threadInMemEntry *p = tblThreadInMemHead + i;
+        assert(p->thd);        
+        if(p->useFreq < leastFreq){
+            leastAccessedEntry = p;
+            leastFreq = p->useFreq;
+        }
+    }
+    
+    return leastAccessedEntry;
+}
+
+/* Find and delete the least accessed entry */
+threadInMemEntry *detachLeastUsedThdInMemEntry(){
+    return NULL;
+}
+
+void bgOutOfCoreSchedule(threadInfo *curThd){
+    int outThdID=-1;    
+
+    if(!curThd->startOutOfCore){
+        DEBUGM(4, ("to execute not in ooc mode\n"));
+       clearThdInMemTbl();
+        return;
+    }
+
+    if(!checkThreadInCore(curThd)){   
+
+        DEBUGM(4, ("to execute in ooc mode\n"));
+
+        threadInMemEntry *thdEntry = giveEmptyThdInMemEntry();
+
+        threadInfo *toBeSwapped = thdEntry->thd;
+        if(toBeSwapped!=NULL){ //the returned entry is not empty thus needing eviction
+
+            if(toBeSwapped->startOOCChanged){
+                //indicate AMPI_Init is called and before it is finished, out-of-core should not 
+                //happen for this thread
+                //just to track the 0->1 change phase (which means MPI_Init is finished)
+                //the 1->0 phase is not tracked because "startOutOfCore" is unset so that
+                //the next processing of a msg will not go into this part of code
+                toBeSwapped->startOOCChanged=0;
+            }else{                                
+                assert(toBeSwapped->isCoreOnDisk==0);
+                outThdID=toBeSwapped->globalId;
+                CmiSwitchToPE(outThdID);
+                toBeSwapped->takenOutofMem();
+                CmiSwitchToPE(curThd->globalId);
+                
+                DEBUGM(4, ("Taking thread %d out, bring thread %d in\n", outThdID, curThd->globalId));                        
+            }
+        }
+        thdEntry->thd = curThd;
+
+        //if this thread's core has been dumped to disk, then we need to bring it back.
+        //otherwise, it is the first time for this thread to process a message, thus
+        //no need to resort to disk to find its core
+        if(curThd->isCoreOnDisk){                        
+            curThd->broughtIntoMem();            
+        }
+        updateThdInMemTable(curThd);
+
+        //DEBUGF(("BG > current NOT in core\n"));
+        //if(emptyEntry) printTblThdInMem();
+        //printTblThdInMem();
+    }else{
+        DEBUGM(4, ("to execute not in ooc mode\n"));
+    }
+
+    /*//Output Stats
+    printf("In thread %d\n", globalId);
+    if(outThdID!=-1) printf("Take thread %d out\n", outThdID);
+    printTblThdInMem();    
+    */
+}
+
+/* Set the thread indicated by threadID to the most recently accessed one */
+void updateThdInMemTable(/*int threadID*/threadInfo *thd){
+    threadInMemEntry *p = tblThreadInMemHead;
+    for(int i=0; i<TBLCAPACITY; i++, p++){
+        if(p->thd==thd)
+            p->useFreq = MOSTRECENTACCESSED;
+        else
+            (p->useFreq)--;        
+    } 
+}
+
+void printTblThdInMem(){
+    printf("====thread in memory table stats=======\n");
+    threadInMemEntry *p = tblThreadInMemHead;
+    for(int i=0; i<TBLCAPACITY; i++, p++){
+        CmiPrintf("entry %d: thread global id: %d, usefreq: %d\n", i+1, (p->thd)->globalId, p->useFreq);
+    }
+    CmiPrintf("\n");
+}
+
+#else //more complex version
+//This version decides the number of target processors images staying 
+//in the memory according to the current memory available.    
+
+void initTblThreadInMem(){ 
+  tblThreadInMemHead = NULL;
+}
+
+//clearing all entries is the same with
+//free the space for this table
+void deInitTblThreadInMem(){
+    threadInMemEntry *p = tblThreadInMemHead;
+    while(p){
+        threadInMemEntry *tmp = p;        
+        p = p->nextEntry;
+        delete tmp;
+    }
+    tblThreadInMemHead = NULL;    
+}
+
+//if found return the entry of this thread, otherwise return NULL
+threadInMemEntry *checkThreadInCore(/*int threadID*/threadInfo *thd){
+    threadInMemEntry *p = tblThreadInMemHead;
+    while(p){
+        if(p->thd == thd)
+            return p;
+        p = p->nextEntry;
+    }
+    return NULL;
+}
+
+/* 
+ * Gives one empty entry for the thread (thd)  which is going to be put into memory
+ * This includes following actions:
+ * 1. Check tblThreadInMem for an empty entry
+ * 2. If none is found, evict one entry based on useFreq. 
+ * Note the evicted thread will not be taken out of memory until function takeThdOutofMem is called!!
+ */
+threadInMemEntry *giveEmptyThdInMemEntry(){
+
+    if(tblThreadInMemHead==NULL){
+        tblThreadInMemHead = new threadInMemEntry();        
+        return tblThreadInMemHead;
+    }
+    
+    threadInMemEntry *returnEntry = detachLeastUsedThdInMemEntry();
+    /*    //add a new entry the table
+        returnEntry = new threadInMemEntry();
+        returnEntry->nextEntry = tblThreadInMemHead;
+        tblThreadInMemHead = returnEntry;
+   */
+
+    return returnEntry;
+}
+
+threadInMemEntry *addNewThdInMemEntry(threadInfo *curThd){
+    if(tblThreadInMemHead==NULL){
+        tblThreadInMemHead = new threadInMemEntry();        
+       tblThreadInMemHead->thd = curThd;
+        return tblThreadInMemHead;
+    }
+    
+    threadInMemEntry *returnEntry = new threadInMemEntry();
+    returnEntry->nextEntry = tblThreadInMemHead;
+    tblThreadInMemHead = returnEntry;
+    returnEntry->thd = curThd;
+    return returnEntry;
+
+}
+
+/* Just find the least used entry */
+threadInMemEntry *findLeastUsedThdInMemEntry(){
+    threadInMemEntry *leastAccessedEntry=tblThreadInMemHead;
+    int leastFreq = leastAccessedEntry->useFreq;
+    
+    threadInMemEntry *cur = leastAccessedEntry->nextEntry;
+    while(cur){        
+        if(cur->useFreq < leastFreq){
+            leastAccessedEntry = cur;
+            leastFreq = cur->useFreq;            
+        }        
+        cur = cur->nextEntry;
+    }    
+    assert(leastAccessedEntry->thd);
+
+    return leastAccessedEntry;
+}
+
+/* Find and delete the least accessed entry */
+//If the least accessed thread is the curThd, then we don't detach it from the queue
+threadInMemEntry *detachLeastUsedThdInMemEntry(){
+    threadInMemEntry *leastAccessedEntry=tblThreadInMemHead;
+    int leastFreq = leastAccessedEntry->useFreq;
+
+    threadInMemEntry *leastPrev = NULL;
+    threadInMemEntry *prev = leastAccessedEntry;
+    threadInMemEntry *cur = leastAccessedEntry->nextEntry;
+    while(cur){        
+        if(cur->useFreq < leastFreq){
+            leastAccessedEntry = cur;
+            leastFreq = cur->useFreq;
+            leastPrev = prev;
+        }
+        prev = cur;
+        cur = cur->nextEntry;
+    }    
+    assert(leastAccessedEntry->thd);
+
+    //detach the least accessed entry
+    if(leastAccessedEntry == tblThreadInMemHead){        
+        tblThreadInMemHead = tblThreadInMemHead->nextEntry;                
+    }else{
+        leastPrev->nextEntry = leastAccessedEntry->nextEntry;
+    }
+
+    return leastAccessedEntry;
+}
+
+void bgOutOfCoreSchedule(threadInfo *curThd){
+
+//the memory eviction is based on the memory availabe now and
+//the eviction uses LRU policy. The curThd may be the least accessed
+//thd. In this case, if the out-of-core happens, curThd will be evicted
+//out of the memory. To avoid this, we first update the access frequency of
+//all threads in memory so that curThd must not be the least accessed.
+
+    if(!curThd->startOutOfCore){
+       DEBUGM(4, ("to execute not in ooc mode\n"));
+       deInitTblThreadInMem();
+       return;
+    }    
+
+    updateThdInMemTable(curThd);
+
+    //double curMemUsage = CmiMemoryUsage()/1024.0/1024.0;
+    double curMemUsage = bgGetProcessMemUsage();
+    printf("Current physical memory used: %lf\n", curMemUsage);
+
+    //the "evictThdCase" shows the two different cases:
+    //0: the current thd is in core but finding the whole emulation
+    //is going to run out of memory (in terms of bgOOCMaxMemSize), so 
+    //another thd in core has to be evicted to free space
+    //1: the current thd is not in core and finding not enough memory
+    //to allow the current thd, so another thd in core has to be evicted..
+    int evictThdCase = 0;
+    if(checkThreadInCore(curThd)){
+       assert(curThd->isCoreOnDisk==0);
+       if(curMemUsage > bgOOCMaxMemSize){
+            DEBUGM(1, ("BG > existing memory usage (%.3f) exceeds the limit!\n", curMemUsage));
+       }
+       if(curMemUsage < (1-LEASTMEMRATE)*bgOOCMaxMemSize) return;
+       evictThdCase = 0;
+    }else{
+       //assert(curThd->isCoreOnDisk==1);
+       //curThd->isCoreOnDisk maybe 0 because this "curThd" is the first thread
+       //that will be recorded in the list of threads whose head is tblThreadInMemHead
+       if(curMemUsage + curThd->memUsed < (1-LEASTMEMRATE)*bgOOCMaxMemSize) {
+           //add curThd to the thd tbl and there's no need to evict other thds
+           //besides bringing this thd into core if its core is on disk
+           threadInMemEntry *newEntry = addNewThdInMemEntry(curThd);
+           newEntry->useFreq = MOSTRECENTACCESSED;
+           if(curThd->isCoreOnDisk){
+               curThd->broughtIntoMem();
+           }
+           return;
+       }
+       evictThdCase = 1;
+    }
+
+    int outThdID = -1;
+    threadInMemEntry *thdEntry = giveEmptyThdInMemEntry();
+    threadInfo *toBeSwapped = thdEntry->thd;
+    if(toBeSwapped==curThd){
+       //this means there's only one thread in core, we have to reinsert this entry
+       //into the list of thds in memory
+       thdEntry->thd = curThd;
+       thdEntry->useFreq = MOSTRECENTACCESSED;
+       thdEntry->nextEntry = tblThreadInMemHead;
+       tblThreadInMemHead = thdEntry;
+       return;
+    }else if(toBeSwapped!=NULL){
+       if(toBeSwapped->startOOCChanged){
+            //indicate AMPI_Init is called and before it is finished, out-of-core should not 
+            //happen for this thread
+            //just to track the 0->1 change phase (which means MPI_Init is finished)
+            //the 1->0 phase is not tracked because "startOutOfCore" is unset so that
+            //the next processing of a msg will not go into this part of code
+           toBeSwapped->startOOCChanged = 0;
+           printf("After finishing MPI_Init, the mem footprint is: %lf\n", curMemUsage);
+       }else{
+           assert(toBeSwapped->isCoreOnDisk==0);
+           outThdID = toBeSwapped->globalId;
+           CmiSwitchToPE(outThdID);
+           toBeSwapped->takenOutofMem();
+           CmiSwitchToPE(curThd->globalId);
+           DEBUGM(4, ("Taking thread %d out, bring thread %d in\n", outThdID, curThd->globalId));
+       }
+    }
+    thdEntry->thd = curThd;
+    thdEntry->useFreq = MOSTRECENTACCESSED;
+
+    //the isCoreOnDisk may be 0 if evictThdCase is 0
+    //or it's the first thread inserted into the thd table
+    //after finishing MPI_Init
+    if(curThd->isCoreOnDisk){
+       assert(evictThdCase);
+       curThd->broughtIntoMem();
+    } 
+
+    /*//Output Stats
+    printf("In thread %d\n", globalId);
+    if(outThdID!=-1) printf("Take thread %d out\n", outThdID);
+    printTblThdInMem();    
+    */
+}
+
+/* Set the thread indicated by threadID to the most recently accessed one */
+void updateThdInMemTable(/*int threadID*/threadInfo *thd){
+    threadInMemEntry *p = tblThreadInMemHead;
+    while(p){
+        if(p->thd==thd)
+            p->useFreq = MOSTRECENTACCESSED;
+        else
+            (p->useFreq)--;
+        p = p->nextEntry;
+    } 
+}
+
+//=============helping functions===============
+void printTblThdInMem(){
+    printf("====thread in memory table stats=======\n");
+    threadInMemEntry *p = tblThreadInMemHead;
+    int cnt=1;
+    while(p){
+        if(p->thd){
+            CmiPrintf("entry %d: thread global id: %d, usefreq: %d\n", cnt++, (p->thd)->globalId, p->useFreq);
+        }
+        p = p->nextEntry;
+    }
+    CmiPrintf("\n");
+}
+
+int getNumThdTblEntries(){
+    threadInMemEntry *p = tblThreadInMemHead;
+    int totalCnt=0;
+    while(p){
+       totalCnt++;
+       p = p->nextEntry;
+    }
+    return totalCnt;
+}
+
+//the argument should range from 1 to #table entries.
+threadInMemEntry *getNthThdEntry(int nth){
+    if(nth<1) return NULL;
+    threadInMemEntry *p = tblThreadInMemHead;
+    for(int i=1; i<nth && p; i++, p=p->nextEntry);
+    return p;
+}
+#endif
+
+
+//=====functions related with system memory information=====
+//the unit is MB
+double bgGetSysTotalMemSize(){
+    FILE *memf = fopen(MEMINFOFILE, "r");
+    int totalM = 0;
+    fscanf(memf, "MemTotal: %dkB\n", &totalM);
+    fclose(memf);
+    return totalM/1024.0;
+}
+
+double bgGetSysFreeMemSize(){
+    FILE *memf = fopen(MEMINFOFILE, "r");
+    int freeM = 0;
+    fscanf(memf, "MemTotal: %dkB\n", &freeM);
+    fscanf(memf, "MemFree: %dkB\n", &freeM);
+    fclose(memf);
+    return freeM/1024.0;
+}
+
+int bgMemPageSize;
+char bgMemStsFile[25];
+
+double bgGetProcessMemUsage(){
+    FILE *memf = fopen(bgMemStsFile, "r");
+    long progsize, memused;
+    double retval;
+
+    fscanf(memf, "%ld %ld", &progsize, &memused);
+    retval = (double)memused/1024.0*bgMemPageSize/1024.0;
+    
+    fclose(memf);
+    return retval;
+
+}
+
diff --git a/src/langs/bluegene/bigsim_ooc.h b/src/langs/bluegene/bigsim_ooc.h
new file mode 100644 (file)
index 0000000..06693e1
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef BIGSIM_OOO_H
+#define BIGSIM_OOO_H
+
+#include "blue_impl.h"
+
+extern int bgUseOutOfCore;
+
+/* This variable indicates the max memory all cores can occupy in a physical processor */
+extern double bgOOCMaxMemSize;
+/* System should always keep LEASTMEMRATE*bgOOCMaxMemSize memory for remaining simulations */
+#define LEASTMEMRATE 0.01
+
+/* Declarations related with out-of-core scheduling */
+#define MOSTRECENTACCESSED 1000
+
+struct threadInMemEntry
+{
+    threadInfo *thd;
+    //int threadID; //global thread ID; -1 means this entry is empty
+
+    /*
+     * parameter deciding which thread to be put to disk.
+     * Currently, this simulates LRU policy.
+     * When some thread (say A) is brought into memory, this parameter for A is set
+     * to MOSTRECENTACCESSED and other threads' will be decreased by 1   
+     */
+    int useFreq;
+    //may be used later
+    double thdSize;
+
+    threadInMemEntry *nextEntry;
+
+    threadInMemEntry(){
+        thd = NULL;
+        //useFreq = MOSTRECENTACCESSED; 
+        useFreq = -1;
+
+        thdSize = 0.0;
+        nextEntry = NULL;
+    }
+
+    void initSelf(){
+        thd = NULL;
+        //useFreq = MOSTRECENTACCESSED; 
+        useFreq = -1;
+
+        thdSize = 0.0;
+        nextEntry = NULL;
+    }
+    /*threadInMemEntry(){
+        thd = NULL;
+        useFreq = -1;
+    }*/
+};
+//threadInMemEntry;
+
+extern int TBLCAPACITY;
+
+extern threadInMemEntry *tblThreadInMemHead;
+//extern threadInMemEntry *tblThreadInMemTail;
+//extern int tblThreadInMemActualSize;
+
+//Initialize the table that keeps which threads are in the memory
+//The table size is initially allocated to the half size of TBLCAPACITY
+void initTblThreadInMem();
+
+void deInitTblThreadInMem();
+
+//if found return the entry of this thread, otherwise return NULL
+threadInMemEntry *checkThreadInCore(/*int threadID*/threadInfo *thd);
+
+/*
+ * Gives one empty entry for the thread which is going to be put into memory.
+ * This includes following actions:
+ * 1. Check tblThreadInMem for an empty entry
+ * 2. If none is found, evict one entry based on useFreq and then take that thread out of memory
+ */
+threadInMemEntry *giveEmptyThdInMemEntry();
+
+threadInMemEntry *findLeastUsedThdInMemEntry();
+threadInMemEntry *detachLeastUsedThdInMemEntry();
+
+/* Set the thread indicated by threadID to the most recently accessed one */
+void updateThdInMemTable(/*int threadID*/threadInfo *thd);
+
+/* printing tblThdInMem */
+void printTblThdInMem();
+
+
+void bgOutOfCoreSchedule(threadInfo *thd);
+//The following two functions are now embeded into the class workThreadInfo
+//void bringThdIntoMem(/*int threadID*/threadInfo *thd);
+//void takeThdOutofMem(/*int threadID*/threadInfo *thd);
+
+//functions related with getting memory usage information
+#define MEMINFOFILE "/proc/meminfo"
+//The /proc/meminfo file is in the following format:
+//MemTotal:  <size>kB
+//MemFree:   <size>kB
+
+//the unit is MB
+double bgGetSysTotalMemSize();
+
+double bgGetSysFreeMemSize();
+
+//Get the process memory usage information from the /proc/<PID>/statm file
+//The file is arranged in the format: <program size> <resident set size> ...
+//The second filed means how many physical pages this process occupies.
+//So to get the physical mmeory usage of this process, we also need to know
+//the memory page size which could be obtained from getpagesize() sys call.
+
+extern int bgMemPageSize;
+extern char bgMemStsFile[25];
+
+double bgGetProcessMemUsage();
+
+#endif
index 5bea160e729f7a2eb11a0ba5af356ae52f13b902..e40e1d6fda03831e3b4366c8fa0a961324dd6ba0 100644 (file)
@@ -1,9 +1,15 @@
-
+#include <assert.h>
 #include "blue.h"
 #include "blue_impl.h"         // implementation header file
 //#include "blue_timing.h"     // timing module
+#include "ckcheckpoint.h"
+
+#include "bigsim_ooc.h"
+
+#include "bigsim_debug.h"
 
-#define  DEBUGF(x)      //CmiPrintf x;
+#undef DEBUGLEVEL
+#define DEBUGLEVEL 10
 
 extern BgStartHandler  workStartFunc;
 extern "C" void CthResumeNormalThread(CthThreadToken* token);
@@ -30,6 +36,7 @@ void commThreadInfo::run()
 
   threadQueue *commQ = myNode->commThQ;
 
+  //int recvd=0; //for debugging only
   for (;;) {
     char *msg = getFullBuffer();
     if (!msg) { 
@@ -42,6 +49,8 @@ void commThreadInfo::run()
       continue;
     }
     DEBUGF(("[%d] comm thread has a msg.\n", BgMyNode()));
+       
+       //printf("on node %d, comm thread process a msg %p with type %d\n", BgMyNode(), msg, CmiBgMsgType(msg));
     /* schedule a worker thread, if small work do it itself */
     if (CmiBgMsgType(msg) == SMALL_WORK) {
       if (CmiBgMsgRecvTime(msg) > tCURRTIME)  tCURRTIME = CmiBgMsgRecvTime(msg);
@@ -53,14 +62,23 @@ void commThreadInfo::run()
 #if BLUEGENE_TIMING
       correctMsgTime(msg);
 #endif
-      if (CmiBgMsgThreadID(msg) == ANYTHREAD) {
+    
+    //recvd++;
+    //DEBUGM(4, ("[N%d] C[%d] will add a msg (handler=%d | cnt=%d", BgMyNode(), id, CmiBgMsgHandle(msg), recvd));
+    int msgLen = CmiBgMsgLength(msg);
+    DEBUGM(4, (" | len: %d | type: %d | node id: %d | src pe: %d\n" , msgLen, CmiBgMsgType(msg), CmiBgMsgNodeID(msg), CmiBgMsgSrcPe(msg)));
+      
+     if (CmiBgMsgThreadID(msg) == ANYTHREAD) {
         DEBUGF(("anythread, call addBgNodeMessage\n"));
         addBgNodeMessage(msg);                 /* non-affinity message */
+       DEBUGM(4, ("The message is added to node\n\n"));
       }
       else {
         DEBUGF(("[N%d] affinity msg, call addBgThreadMessage to tID:%d\n", 
                        BgMyNode(), CmiBgMsgThreadID(msg)));
+       
         addBgThreadMessage(msg, CmiBgMsgThreadID(msg));
+       DEBUGM(4, ("The message is added to thread(%d)\n\n", CmiBgMsgThreadID(msg)));
       }
     }
     /* let other communication thread do their jobs */
@@ -107,6 +125,16 @@ void BgDeliverMsgs(int nmsg)
   BgScheduler(nmsg);
 }
 
+//static int inCore();
+//static int outCore();
+
+//If AMPI_Init is called, then we begin to do out-of-core emulation
+//in the case of emulating AMPI programs. This is based on the assumption
+//that during initialization, the memory should be enough
+//Later this is not necessary if the out-of-core emulation is triggered
+//by the free memory available.
+
+//The original version of scheduler
 void workThreadInfo::scheduler(int count)
 {
   ckMsgQueue &q1 = myNode->nodeQ;
@@ -138,8 +166,9 @@ void workThreadInfo::scheduler(int count)
     /* if no msg is ready, go back to sleep */
     if ( msg == NULL ) {
 //      tCURRTIME += (CmiWallTimer()-tSTARTTIME);
+      DEBUGM(4,("N[%d] work thread %d has no msg and go to sleep!\n", BgMyNode(), id));
       CthSuspend();
-      DEBUGF(("[N-%d] work thread T-%d awakened.\n", BgMyNode(), id));
+      DEBUGM(4, ("N[%d] work thread %d awakened!\n", BgMyNode(), id));      
       continue;
     }
 #if BLUEGENE_TIMING
@@ -160,7 +189,7 @@ void workThreadInfo::scheduler(int count)
     }
 #endif
 #endif   /* TIMING */
-    DEBUGF(("[N%d] work thread T%d has a msg with recvT:%e msgId:%d.\n", BgMyNode(), id, CmiBgMsgRecvTime(msg), CmiBgMsgID(msg)));
+    DEBUGM(2, ("[N%d] work thread T%d has a msg with recvT:%e msgId:%d.\n", BgMyNode(), id, CmiBgMsgRecvTime(msg), CmiBgMsgID(msg)));
 
 //if (tMYNODEID==0)
 //CmiPrintf("[%d] recvT: %e\n", tMYNODEID, CmiBgMsgRecvTime(msg));
@@ -174,9 +203,59 @@ void workThreadInfo::scheduler(int count)
     else q1.deq();
 #endif
 
+
+    recvd ++;  
+    DEBUGM(4, ("[N%d] W[%d] will process a msg (handler=%d | cnt=%d", BgMyNode(), id, CmiBgMsgHandle(msg), recvd));
+    int msgLen = CmiBgMsgLength(msg);
+    DEBUGM(4, (" | len: %d | type: %d | node id: %d | src pe: %d\n" , msgLen, CmiBgMsgType(msg), CmiBgMsgNodeID(msg), CmiBgMsgSrcPe(msg)));
+    for(int msgIndex=CmiBlueGeneMsgHeaderSizeBytes-1; msgIndex<msgLen; msgIndex++)
+        DEBUGM(2, ("%d,", msg[msgIndex]));
+    DEBUGM(2,("\n"));
+
+    DEBUGM(4, ("[N%d] W[%d] now has %d msgs from own queue and %d from affinity before processing msg\n", BgMyNode(), id, q1.length(), q2.length()));
+
     BG_ENTRYSTART(msg);
+
+    //CmiMemoryCheck();
+
     // BgProcessMessage may trap into scheduler
-    BgProcessMessage(msg);
+    if(bgUseOutOfCore){
+#if 0 
+       if(startOutOfCore){
+           DEBUGM(4, ("to execute in ooc mode\n"));
+           if(isCoreOnDisk) this->broughtIntoMem();  
+           BgProcessMessage(msg); //startOutOfCore may be changed in processing this msg (AMPI_Init)    
+    
+           if(startOOCChanged){ 
+                //indicate AMPI_Init is called and before it is finished, out-of-core is not executed
+                //just to track the 0->1 change phase (which means MPI_Init is finished)
+                //the 1->0 phase is not tracked because "startOutOfCore" is unset so that
+                //the next processing of a msg will not go into this part of code
+                startOOCChanged=0;
+           }else{
+                //if(!isCoreOnDisk) { //the condition is added for virtual process
+                    this->takenOutofMem();
+                //}
+           }
+       }else{
+           DEBUGM(4, ("to execute not in ooc mode\n"));
+           if(isCoreOnDisk) {
+                CmiAbort("This should never be entered!\n");
+                this->broughtIntoMem();  
+           }
+           //put before processing msg since thread may be scheduled during processing the msg
+           BgProcessMessage(msg);
+       }
+#else
+        bgOutOfCoreSchedule(this);
+        BgProcessMessage(msg);
+#endif
+    }else{
+        DEBUGM(4, ("to execute not in ooc mode\n"));
+        BgProcessMessage(msg);
+    }
+    
+    DEBUGM(4, ("[N%d] W[%d] now has %d msgs from own queue and %d from affinity after processing msg\n\n", BgMyNode(), id, q1.length(), q2.length()));
     BG_ENTRYEND();
 
     // counter of processed real mesgs
@@ -188,9 +267,11 @@ void workThreadInfo::scheduler(int count)
     else q1.deq();
 #endif
 
-    DEBUGF(("[N%d] work thread T%d finish a msg.\n", BgMyNode(), id));
+    //recvd ++;
 
-    recvd ++;
+    //DEBUGF(("[N%d] work thread T%d finish a msg.\n", BgMyNode(), id));
+    //CmiPrintf("[N%d] work thread T%d finish a msg (msg=%s, cnt=%d).\n", BgMyNode(), id, msg, recvd);
+    
     if ( recvd == count) return;
 
     if (cycle != CsdStopFlag) break;
@@ -254,3 +335,127 @@ void workThreadInfo::addAffMessage(char *msgPtr)
   }
 }
 
+
+//=====Begin of stuff related with out-of-core scheduling======
+extern int BgOutOfCoreFlag;
+
+void threadInfo::broughtIntoMem(){
+    DEBUGM(5, ("=====[N%d] work thread T[%d] into mem=====.\n", BgMyNode(), id));
+    //CmiPrintStackTrace(0);    
+
+    assert(isCoreOnDisk==1);
+
+    char *dirname = "/tmp/CORE";
+    //every body make dir in case it is local directory
+    CmiMkdir(dirname);
+    char filename[128];
+    sprintf(filename, "%s/%d.dat", dirname, globalId);
+    FILE* fp = fopen(filename, "r");
+    if(fp==NULL){
+        printf("Error: %s cannot be opened when bringing thread %d to core\n", filename, globalId);
+        return;
+    }
+
+    BgOutOfCoreFlag=2;
+    PUP::fromDisk p(fp);
+    //out-of-core is not a real migration, so turn off the notifyListener option
+    CkPupArrayElementsData(p, 0);
+    fclose(fp);
+    BgOutOfCoreFlag=0;
+    
+    //printf("mem usage after thread %d in: %fMB\n",globalId, CmiMemoryUsage()/1024.0/1024.0);    
+    isCoreOnDisk = 0;
+}
+
+void threadInfo::takenOutofMem(){
+    DEBUGM(5, ("=====[N%d] work thread T[%d] outof mem=====.\n", BgMyNode(), id));
+    //CmiPrintStackTrace(0);    
+
+    assert(isCoreOnDisk==0);
+
+    char *dirname = "/tmp/CORE";
+    //every body make dir in case it is local directory
+    CmiMkdir(dirname);
+    char filename[128];
+    sprintf(filename, "%s/%d.dat", dirname, globalId);
+    FILE* fp = fopen(filename, "wb");
+    if(fp==NULL){
+        printf("Error: %s cannot be opened when bringing thread %d to core\n", filename, globalId);
+        return;
+    }
+
+    BgOutOfCoreFlag=1;
+    PUP::toDisk p(fp);
+    //out-of-core is not a real migration, so turn off the notifyListener option
+    p.becomeDeleting();
+    CkPupArrayElementsData(p, 0);
+
+    long fsize = 0;
+    fseek(fp, 0, SEEK_END);
+    fsize = ftell(fp);
+    //set this thread's memory usage
+    memUsed = fsize/1024.0/1024.0;
+
+    fflush(fp);
+
+    fclose(fp);
+
+    DEBUGM(6,("Before removing array elements on proc[%d]\n", globalId));   
+    CkRemoveArrayElements();
+    BgOutOfCoreFlag=0;
+    isCoreOnDisk=1;
+    //printf("mem usage after thread %d out: %fMB\n", globalId, CmiMemoryUsage()/1024.0/1024.0);  
+}
+
+/*
+static int outCore()
+{
+  BgOutOfCoreFlag = 1;
+  //printf("memory usage: out core before remove arrays %fMB\n", CmiMemoryUsage()/1024.0/1024.0);
+  int id = BgGetGlobalWorkerThreadID();
+  //printf("[%d] Out core\n", id);
+  char *dirname = "/tmp/COREORIG";
+  // every body make dir in case it is local directory
+  CmiMkdir(dirname);
+  char filename[128];
+  sprintf(filename,"%s/%d.dat",dirname,id);
+  FILE* fp = fopen(filename,"wb");
+  if (fp == 0) {
+    perror("file");
+    exit(1);
+  }
+  PUP::toDisk p(fp);
+  CkPupArrayElementsData(p, 0);
+  fdatasync(fileno(fp));
+  fclose(fp);
+
+  CkRemoveArrayElements();
+  //printf("memory usage: out core after remove arrays %fMB\n", CmiMemoryUsage()/1024.0/1024.0);
+  BgOutOfCoreFlag = 0;
+}
+
+static int inCore()
+{
+  BgOutOfCoreFlag = 2;
+//CmiPrintStackTrace(0);
+  //printf("memory usage: in core before load core %fMB\n", CmiMemoryUsage()/1024.0/1024.0);
+  int id = BgGetGlobalWorkerThreadID();
+  //printf("[%d] In core\n", id);
+  char *dirname = "/tmp/COREORIG";
+  // every body make dir in case it is local directory
+  CmiMkdir(dirname);
+  char filename[128];
+  sprintf(filename,"%s/%d.dat",dirname,id);
+  FILE* fp = fopen(filename,"r");
+  if (fp == NULL) return 0;
+  PUP::fromDisk p(fp);
+  CkPupArrayElementsData(p, 0);
+  fdatasync(fileno(fp));
+  fclose(fp);
+  //printf("memory usage: in core after load core %fMB\n", CmiMemoryUsage()/1024.0/1024.0);
+  BgOutOfCoreFlag = 0;
+}
+*/
+
+//=====End of stuff related with out-of-core scheduling=======
index 2caf022ab3c94b6d54333ec9f66ae58b64e4c9d6..3fa34ba234d6556bd0257913781fc875a6de3ffa 100644 (file)
@@ -13,6 +13,9 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <math.h>
+#include <strings.h>
+#include <unistd.h>
 
 #include "cklists.h"
 #include "queueing.h"
 #include "blue_impl.h"         // implementation header file
 //#include "blue_timing.h"     // timing module
 
-#define  DEBUGF(x)      //CmiPrintf x;
+#include "bigsim_ooc.h" //out-of-core module
+#include "bigsim_debug.h"
+
+//#define  DEBUGF(x)      //CmiPrintf x;
+
+#undef DEBUGLEVEL
+#define DEBUGLEVEL 10
 
 /* node level variables */
 CpvDeclare(nodeInfo*, nodeinfo);               /* represent a bluegene node */
@@ -180,7 +189,7 @@ inline BgHandlerInfo * HandlerTable::getHandle(int handler)
       CmiAbort("Invalid handler!");
     }
 #endif
-    if (handler >= handlerTableCount) return NULL;
+    if (handler >= handlerTableCount || handler<0) return NULL;
     return &handlerTable[handler];
 }
 
@@ -402,6 +411,9 @@ void addBgNodeInbuffer(char *msgPtr, int lnodeID)
   if (lnodeID >= cva(numNodes)) CmiAbort("NodeID is out of range!");
 #endif
   nodeInfo &nInfo = cva(nodeinfo)[lnodeID];
+
+  //printf("Adding a msg %p to local node %d and its thread %d\n", msgPtr, lnodeID, CmiBgMsgThreadID(msgPtr)); 
+       
   nInfo.addBgNodeInbuffer(msgPtr);
 }
 
@@ -659,6 +671,8 @@ void CmiSendPacket(int x, int y, int z, int msgSize,char *msg)
 /* user data is not free'd in this routine, user can reuse the data ! */
 void sendPacket_(nodeInfo *myNode, int x, int y, int z, int threadID, int handlerID, WorkType type, int numbytes, char* sendmsg, int local)
 {
+  //CmiPrintStackTrace(0);
+
   double latency;
   CmiSetHandler(sendmsg, cva(simState).msgHandler);
   CmiBgMsgNodeID(sendmsg) = nodeInfo::XYZ2Global(x,y,z);
@@ -683,8 +697,17 @@ void sendPacket_(nodeInfo *myNode, int x, int y, int z, int threadID, int handle
   // timing
   BG_ADDMSG(sendmsg, CmiBgMsgNodeID(sendmsg), threadID, sendT, local, 1);
 
-  if (local)
-    addBgNodeInbuffer(sendmsg, myNode->id);
+  //static int addCnt=1; //for debugging only
+  //DEBUGM(4, ("N[%d] add a msg (handler=%d | cnt=%d | len=%d | type=%d | node id:%d\n", BgMyNode(), handlerID, addCnt, numbytes, type, CmiBgMsgNodeID(sendmsg)));  
+  //addCnt++;
+
+  if (local){
+      /* Here local refers to the fact that msg is sent to the processor itself
+       * therefore, we just add this msg to the thread itself
+       */
+      //addBgThreadMessage(sendmsg,threadID);
+      addBgNodeInbuffer(sendmsg, myNode->id);
+  }    
   else
     CmiSendPacket(x, y, z, numbytes, sendmsg);
 
@@ -1019,17 +1042,22 @@ void BgSetWorkerThreadStart(BgStartHandler f)
   workStartFunc = f;
 }
 
+extern "C" void CthResumeNormalThread(CthThreadToken* token);
+
 // kernel function for processing a bluegene message
 void BgProcessMessage(char *msg)
 {
+  DEBUGM(5, ("=====Begin of BgProcessing a msg on node[%d]=====\n", BgMyNode()));
   int handler = CmiBgMsgHandle(msg);
   DEBUGF(("[%d] call handler %d\n", BgMyNode(), handler));
 
   BgHandlerInfo *handInfo;
 #if  CMK_BLUEGENE_NODE
-  handInfo = tMYNODE->handlerTable.getHandle(handler);
+  HandlerTable hdlTbl = tMYNODE->handlerTable;
+  handInfo = hdlTbl.getHandle(handler);
 #else
-  handInfo = tHANDLETAB.getHandle(handler);
+  HandlerTable hdlTbl = tHANDLETAB;
+  handInfo = hdlTbl.getHandle(handler);
   if (handInfo == NULL) handInfo = tMYNODE->handlerTable.getHandle(handler);
 #endif
 
@@ -1050,9 +1078,13 @@ void BgProcessMessage(char *msg)
   // don't count thread overhead and timing overhead
   startVTimer();
 
+  DEBUGM(5, ("Executing function %p\n", entryFunc));    
+
   entryFunc(msg, handInfo->userPtr);
 
   stopVTimer();
+
+  DEBUGM(5, ("=====End of BgProcessing a msg on node[%d]=====\n\n", BgMyNode()));
 }
 
 
@@ -1281,6 +1313,25 @@ CmiStartFn bgMain(int argc, char **argv)
     cva(bgMach).traceroot = root;
   }
 
+  /* parameters related with out-of-core execution */
+  if (CmiGetArgDoubleDesc(argv, "+bgooc", &bgOOCMaxMemSize, "Simulate with out-of-core support and the threshhold of memory size")){
+      bgUseOutOfCore = 1;
+      BgInOutOfCoreMode = 1; //the global (the whole converse layer) out-of-core flag
+
+      double curFreeMem = bgGetSysFreeMemSize();
+      if(fabs(bgOOCMaxMemSize - 0.0)<=1e-6){
+       //using the memory available of the system right now
+       //assuming no other programs will run after this program runs
+       bgOOCMaxMemSize = curFreeMem;
+       CmiPrintf("Using the system's current memory available: %.3fMB\n", bgOOCMaxMemSize);
+      }
+      if(bgOOCMaxMemSize > curFreeMem){
+       CmiPrintf("Warning: not enough memory for the specified memory size, now use the current available memory %3.fMB.\n", curFreeMem);
+       bgOOCMaxMemSize = curFreeMem;
+      }
+      DEBUGF(("out-of-core turned on!\n"));
+  }      
+
 #if BLUEGENE_DEBUG_LOG
   {
     char ln[200];
@@ -1376,6 +1427,15 @@ CmiStartFn bgMain(int argc, char **argv)
 
   cva(simState).simStartTime = CmiWallTimer();
 
+  if(bgUseOutOfCore)
+      initTblThreadInMem();
+
+  //initialize variables related to get precise
+  //physical memory usage info for a process
+  bgMemPageSize = getpagesize();
+  memset(bgMemStsFile, 0, 25); 
+  sprintf(bgMemStsFile, "/proc/%d/statm", getpid());
+    
   return 0;
 }
 
@@ -1756,6 +1816,9 @@ void CthEnqueueBigSimThread(CthThreadToken* token, int s,
   #error "ERROR HERE"
 #endif
     // local message into queue
+  DEBUGM(4, ("In EnqueueBigSimThread method!\n"));
+
+  DEBUGM(4, ("token [%p] is added to queue pointing to thread[%p]\n", token, token->thread));
   BgSendPacket(x,y,z, t, CpvAccess(CthResumeBigSimThreadIdx), LARGE_WORK, sizeof(CthThreadToken), (char *)token);
 } 
 
index 3ba3ff02c0edff07a9ef0b0830d66e9a81e377a7..7406e5c35ae3d3b9d52d41225a3b1924c7811670 100644 (file)
@@ -264,6 +264,8 @@ void BgDeliverMsgs(int);
 /************************ Supporting AMPI ************************/
 
 void BgAttach(CthThread t);
+void BgSetStartOutOfCore();
+void BgUnsetStartOutOfCore();
 
 #if defined(__cplusplus)
 }
index 302a18bdb01b2e2fa21cb6a0cc089d591fe19c46..d3904404d4f86200d713686730b8673fc52fbcf9 100644 (file)
@@ -222,8 +222,10 @@ public:
     Global2XYZ(Local2Global(num), x, y, z);
   }
 
+#define NOT_FAST_CODE 1
     /* map global serial node number to PE ++++ */
   inline static int Global2PE(int num) { 
+#if NOT_FAST_CODE
     int n = _bgSize/CmiNumPes();
     int bn = _bgSize%CmiNumPes();
     int start = 0; 
@@ -236,6 +238,38 @@ public:
     }
     CmiAbort("Global2PE: unknown pe!");
     return -1;
+#else
+   int avgNs = _bgSize/CmiNumPes();
+   int remains = _bgSize%CmiNumPes();
+   /*
+    * the bg nodes are mapped like the following:
+    * avgNs+1, avgNs+1, ..., avgNs+1 (of remains proccessors)
+    * avgNs, ..., avgNs (of CmiNumPes()-remains processors)
+    */
+
+   int middleCnt = (avgNs+1)*remains;
+   if(num < middleCnt){
+      //in the first part of emulating processors
+      int ret = num/(avgNs+1);
+   #if !CMK_OPTIMIZE
+      if(ret<0){
+          CmiAbort("Global2PE: unknown pe!");
+          return -1;
+      }
+   #endif
+      return ret;
+   }else{
+      //in the second part of emulating processors
+      int ret = (num-middleCnt)/avgNs+remains;
+   #if !CMK_OPTIMIZE
+      if(ret>=CmiNumPes()){
+          CmiAbort("Global2PE: unknown pe!");
+          return -1;
+      }
+   #endif
+      return ret;
+   }
+#endif
   }
 
     /* map global serial node ID to local node array index  ++++ */
@@ -385,16 +419,41 @@ public:
   nodeInfo *myNode;            /* the node belonged to */
   double  currTime;            /* thread timer */
 
+  /*
+   * It is needed for out-of-core scheduling
+   * If it is set to 0, then we know its core file is not on disk
+   * and it is first time for this thread to process a msg
+   * thus no need to bring it into memory.
+   * It is initialized to be 0;
+   * It is should be set to 1 when it is taken out of memory to disk
+   * and set to 0 when it is brought into memory
+   */
+    int isCoreOnDisk;
+    
+    double memUsed;            /* thread's memory footprint (unit is MB) */ 
+   
+    //Used for AMPI programs
+    int startOutOfCore;
+    int startOOCChanged;
+
 #if  CMK_BLUEGENE_THREAD
   HandlerTable   handlerTable;      /* thread level handler table */
 #endif
 
 public:
   threadInfo(int _id, ThreadType _type, nodeInfo *_node): 
-       id(_id), globalId(-1), type(_type), myNode(_node), currTime(0.0) {}
+       id(_id), globalId(-1), type(_type), myNode(_node), currTime(0.0), isCoreOnDisk(0), memUsed(0.0),
+       startOutOfCore(1), startOOCChanged(0){}
   inline void setThread(CthThread t) { me = t; }
   inline CthThread getThread() const { return me; }
   virtual void run() { CmiAbort("run not imlplemented"); }
+
+  //=====Begin of stuff related with out-of-core scheduling===========
+  void broughtIntoMem();
+  void takenOutofMem();
+  //=====End of stuff related with out-of-core scheduling=============
+
+
 }; 
 
 class workThreadInfo : public threadInfo {