Me@178: /* Me@178: * Copyright 2009 OpenSourceStewardshipFoundation.org Me@178: * Licensed under GNU General Public License version 2 Me@178: * Me@178: * Author: seanhalle@yahoo.com Me@178: * Me@178: */ Me@178: Me@178: #ifndef _VMS_H Me@178: #define _VMS_H Me@178: #define _GNU_SOURCE Me@178: Me@178: #include "VMS_primitive_data_types.h" Me@178: #include "Queue_impl/PrivateQueue.h" Me@178: #include "Histogram/Histogram.h" Me@178: #include "DynArray/DynArray.h" Me@178: #include "Hash_impl/PrivateHash.h" Me@178: #include "vmalloc.h" Me@178: Me@178: #include Me@178: #include Me@178: Me@178: Me@178: //=============================== Debug =================================== Me@178: // Me@178: //When SEQUENTIAL is defined, VMS does sequential exe in the main thread Me@178: // It still does co-routines and all the mechanisms are the same, it just Me@178: // has only a single thread and animates VPs one at a time Me@178: //#define SEQUENTIAL Me@178: Me@178: //#define USE_WORK_STEALING Me@178: Me@178: //turns on the probe-instrumentation in the application -- when not Me@178: // defined, the calls to the probe functions turn into comments Me@178: #define STATS__ENABLE_PROBES Me@178: //#define TURN_ON_DEBUG_PROBES Me@178: Me@178: //These defines turn types of bug messages on and off Me@178: // be sure debug messages are un-commented (next block of defines) Me@178: #define dbgAppFlow TRUE /* Top level flow of application code -- general*/ Me@178: #define dbgProbes FALSE /* for issues inside probes themselves*/ Me@178: #define dbgB2BMaster FALSE /* in coreloop, back to back master VPs*/ Me@178: #define dbgRqstHdlr FALSE /* in request handler code*/ Me@178: Me@178: //Comment or un- the substitute half to turn on/off types of debug message Me@178: #define DEBUG( bool, msg) \ Me@178: // if( bool){ printf(msg); fflush(stdin);} Me@178: #define DEBUG1( bool, msg, param) \ Me@178: // if(bool){printf(msg, param); fflush(stdin);} Me@178: #define DEBUG2( bool, msg, p1, p2) \ Me@178: // if(bool) {printf(msg, p1, p2); fflush(stdin);} Me@178: Me@178: #define ERROR(msg) printf(msg); Me@178: #define ERROR1(msg, param) printf(msg, param); Me@178: #define ERROR2(msg, p1, p2) printf(msg, p1, p2); Me@178: Me@178: //=========================== STATS ======================= Me@178: Me@178: //when MEAS__TIME_STAMP_SUSP is defined, causes code to be inserted and Me@178: // compiled-in that saves the low part of the time stamp count just before Me@178: // suspending a processor and just after resuming that processorsrc/VPThread_lib/VMS/VMS.h:322: warning: previous declaration of ‘VMS__create_procr’ was here. It is Me@178: // saved into a field added to VirtProcr. Have to sanity-check for Me@178: // rollover of low portion into high portion. Me@178: //#define MEAS__TIME_STAMP_SUSP Me@178: //#define MEAS__TIME_MASTER Me@178: #define MEAS__TIME_PLUGIN Me@178: #define MEAS__TIME_MALLOC Me@178: //#define MEAS__TIME_MASTER_LOCK Me@178: #define MEAS__NUM_TIMES_TO_RUN 100000 Me@178: Me@178: //For code that calculates normalization-offset between TSC counts of Me@178: // different cores. Me@178: #define NUM_TSC_ROUND_TRIPS 10 Me@178: Me@178: Me@178: //========================= Hardware related Constants ===================== Me@178: //This value is the number of hardware threads in the shared memory Me@178: // machine Me@178: //#define NUM_CORES 8 Me@178: Me@178: // tradeoff amortizing master fixed overhead vs imbalance potential Me@178: // when work-stealing, can make bigger, at risk of losing cache affinity Me@178: #define NUM_SCHED_SLOTS 5 Me@178: Me@178: #define MIN_WORK_UNIT_CYCLES 20000 Me@178: Me@178: #define MASTERLOCK_RETRIES 10000 Me@178: Me@178: // stack size in virtual processors created Me@178: #define VIRT_PROCR_STACK_SIZE 0x8000 /* 32K */ Me@178: Me@178: // memory for VMS__malloc Me@178: #define MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE 0x10000000 /* 256M */ Me@178: Me@178: #define CACHE_LINE 64 Me@178: #define PAGE_SIZE 4096 Me@178: Me@178: Me@178: //============================== Me@178: Me@178: #define SUCCESS 0 Me@178: Me@178: #define writeVMSQ writePrivQ Me@178: #define readVMSQ readPrivQ Me@178: #define makeVMSQ makeVMSPrivQ Me@178: #define numInVMSQ numInPrivQ Me@178: #define VMSQueueStruc PrivQueueStruc Me@178: Me@178: Me@178: Me@178: //=========================================================================== Me@178: typedef unsigned long long TSCount; Me@178: Me@178: typedef struct _SchedSlot SchedSlot; Me@178: typedef struct _VMSReqst VMSReqst; Me@178: typedef struct _VirtProcr VirtProcr; Me@178: typedef struct _IntervalProbe IntervalProbe; Me@178: typedef struct _GateStruc GateStruc; Me@178: Me@178: Me@178: typedef VirtProcr * (*SlaveScheduler) ( void *, int ); //semEnv, coreIdx Me@178: typedef void (*RequestHandler) ( VirtProcr *, void * ); //prWReqst, semEnv Me@178: typedef void (*VirtProcrFnPtr) ( void *, VirtProcr * ); //initData, animPr Me@178: typedef void VirtProcrFn ( void *, VirtProcr * ); //initData, animPr Me@178: typedef void (*ResumePrFnPtr) ( VirtProcr *, void * ); Me@178: Me@178: Me@178: //============= Requests =========== Me@178: // Me@178: Me@178: enum VMSReqstType //avoid starting enums at 0, for debug reasons Me@178: { Me@178: semantic = 1, Me@178: createReq, Me@178: dissipate, Me@178: VMSSemantic //goes with VMSSemReqst below Me@178: }; Me@178: Me@178: struct _VMSReqst Me@178: { Me@178: enum VMSReqstType reqType;//used for dissipate and in future for IO requests Me@178: void *semReqData; Me@178: Me@178: VMSReqst *nextReqst; Me@178: }; Me@178: //VMSReqst Me@178: Me@178: enum VMSSemReqstType //These are equivalent to semantic requests, but for Me@178: { // VMS's services available directly to app, like OS Me@178: createProbe = 1, // and probe services -- like a VMS-wide built-in lang Me@178: openFile, Me@178: otherIO Me@178: }; Me@178: Me@178: typedef struct Me@178: { enum VMSSemReqstType reqType; Me@178: VirtProcr *requestingPr; Me@178: char *nameStr; //for create probe Me@178: } Me@178: VMSSemReq; Me@178: Me@178: Me@178: //==================== Core data structures =================== Me@178: Me@178: struct _SchedSlot Me@178: { Me@178: int workIsDone; Me@178: int needsProcrAssigned; Me@178: VirtProcr *procrAssignedToSlot; Me@178: }; Me@178: //SchedSlot Me@178: Me@178: /*WARNING: re-arranging this data structure could cause VP switching Me@178: * assembly code to fail -- hard-codes offsets of fields Me@178: */ Me@178: struct _VirtProcr Me@178: { int procrID; //for debugging -- count up each time create Me@178: int coreAnimatedBy; Me@178: void *startOfStack; Me@178: void *stackPtr; Me@178: void *framePtr; Me@178: void *nextInstrPt; Me@178: Me@178: void *coreLoopStartPt; //allows proto-runtime to be linked later Me@178: void *coreLoopFramePtr; //restore before jmp back to core loop Me@178: void *coreLoopStackPtr; //restore before jmp back to core loop Me@178: Me@178: void *initialData; Me@178: Me@178: SchedSlot *schedSlot; Me@178: VMSReqst *requests; Me@178: Me@178: void *semanticData; //this livesUSE_GNU here for the life of VP Me@178: void *dataRetFromReq;//values returned from plugin to VP go here Me@178: Me@178: //=========== MEASUREMENT STUFF ========== Me@178: #ifdef MEAS__TIME_STAMP_SUSP Me@178: unsigned int preSuspTSCLow; Me@178: unsigned int postSuspTSCLow; Me@178: #endif Me@178: #ifdef MEAS__TIME_MASTER /* in VirtProcr because multiple masterVPs*/ Me@178: unsigned int startMasterTSCLow;USE_GNU Me@178: unsigned int endMasterTSCLow; Me@178: #endif Me@178: //======================================== Me@178: Me@178: float64 createPtInSecs; //have space but don't use on some configs Me@178: }; Me@178: //VirtProcr Me@178: Me@178: Me@178: /*WARNING: re-arranging this data structure could cause VP-switching Me@178: * assembly code to fail -- hard-codes offsets of fields Me@178: * (because -O3 messes with things otherwise) Me@178: */ Me@178: typedef struct Me@178: { Me@178: SlaveScheduler slaveScheduler; Me@178: RequestHandler requestHandler; Me@178: Me@178: SchedSlot ***allSchedSlots; Me@178: VMSQueueStruc **readyToAnimateQs; Me@178: VirtProcr **masterVPs; Me@178: Me@178: void *semanticEnv; Me@178: void *OSEventStruc; //for future, when add I/O to BLIS Me@178: MallocProlog *freeListHead; Me@178: int32 amtOfOutstandingMem; //total currently allocated Me@178: Me@178: void *coreLoopReturnPt;//addr to jump to to re-enter coreLoop Me@178: Me@178: int32 setupComplete; Me@178: volatile int32 masterLock; Me@178: Me@178: int32 numMasterInARow[NUM_CORES];//detect back-to-back masterVP Me@178: GateStruc *workStealingGates[ NUM_CORES ]; //concurrent work-steal Me@178: int32 workStealingLock; Me@178: Me@178: int32 numProcrsCreated; //gives ordering to processor creation Me@178: Me@178: //=========== MEASUREMENT STUFF ============= Me@178: IntervalProbe **intervalProbes; Me@178: PrivDynArrayInfo *dynIntervalProbesInfo; Me@178: HashTable *probeNameHashTbl; Me@178: int32 masterCreateProbeID; Me@178: float64 createPtInSecs; Me@178: Histogram **measHists; Me@178: PrivDynArrayInfo *measHistsInfo; Me@178: #ifdef MEAS__TIME_PLUGIN Me@178: Histogram *reqHdlrLowTimeHist; Me@178: Histogram *reqHdlrHighTimeHist; Me@178: #endif Me@178: #ifdef MEAS__TIME_MALLOC Me@178: Histogram *mallocTimeHist; Me@178: Histogram *freeTimeHist; Me@178: #endif Me@178: #ifdef MEAS__TIME_MASTER_LOCK Me@178: Histogram *masterLockLowTimeHist; Me@178: Histogram *masterLockHighTimeHist; Me@178: #endif Me@178: } Me@178: MasterEnv; Me@178: Me@178: //========================= Extra Stuff Data Strucs ======================= Me@178: typedef struct Me@178: { Me@178: Me@178: } Me@178: VMSExcp; Me@178: Me@178: struct _GateStruc Me@178: { Me@178: int32 gateClosed; Me@178: int32 preGateProgress; Me@178: int32 waitProgress; Me@178: int32 exitProgress; Me@178: }; Me@178: //GateStruc Me@178: Me@178: //======================= OS Thread related =============================== Me@178: Me@178: void * coreLoop( void *paramsIn ); //standard PThreads fn prototype Me@178: void * coreLoop_Seq( void *paramsIn ); //standard PThreads fn prototype Me@178: void masterLoop( void *initData, VirtProcr *masterPr ); Me@178: Me@178: Me@178: typedef struct Me@178: { Me@178: void *endThdPt; Me@178: unsigned int coreNum; Me@178: } Me@178: ThdParams; Me@178: Me@178: pthread_t coreLoopThdHandles[ NUM_CORES ]; //pthread's virt-procr state Me@178: ThdParams *coreLoopThdParams [ NUM_CORES ]; Me@178: pthread_mutex_t suspendLock; Me@178: pthread_cond_t suspend_cond; Me@178: Me@178: Me@178: Me@178: //===================== Global Vars =================== Me@178: Me@178: volatile MasterEnv *_VMSMasterEnv; Me@178: Me@178: Me@178: Me@178: Me@178: //=========================== Function Prototypes ========================= Me@178: Me@178: Me@178: //========== Setup and shutdown ========== Me@178: void Me@178: VMS__init(); Me@178: Me@178: void Me@178: VMS__init_Seq(); Me@178: Me@178: void Me@178: VMS__start_the_work_then_wait_until_done(); Me@178: Me@178: void Me@178: VMS__start_the_work_then_wait_until_done_Seq(); Me@178: Me@178: inline VirtProcr * Me@178: VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData ); Me@178: Me@178: void Me@178: VMS__dissipate_procr( VirtProcr *procrToDissipate ); Me@178: Me@178: //Use this to create processor inside entry point & other places outside Me@178: // the VMS system boundary (IE, not run in slave nor Master) Me@178: VirtProcr * Me@178: VMS_ext__create_procr( VirtProcrFnPtr fnPtr, void *initialData ); Me@178: Me@178: void Me@178: VMS_ext__dissipate_procr( VirtProcr *procrToDissipate ); Me@178: Me@178: void Me@178: VMS__throw_exception( char *msgStr, VirtProcr *reqstPr, VMSExcp *excpData ); Me@178: Me@178: void Me@178: VMS__shutdown(); Me@178: Me@178: void Me@178: VMS__cleanup_at_end_of_shutdown(); Me@178: Me@178: void * Me@178: VMS__give_sem_env_for( VirtProcr *animPr ); Me@178: Me@178: Me@178: //============== Request Related =============== Me@178: Me@178: void Me@178: VMS__suspend_procr( VirtProcr *callingPr ); Me@178: Me@178: inline void Me@178: VMS__add_sem_request_in_mallocd_VMSReqst( void *semReqData, VirtProcr *callingPr ); Me@178: Me@178: inline void Me@178: VMS__send_sem_request( void *semReqData, VirtProcr *callingPr ); Me@178: Me@178: void Me@178: VMS__send_create_procr_req( void *semReqData, VirtProcr *reqstingPr ); Me@178: Me@178: void inline Me@178: VMS__send_dissipate_req( VirtProcr *prToDissipate ); Me@178: Me@178: inline void Me@178: VMS__send_VMSSem_request( void *semReqData, VirtProcr *callingPr ); Me@178: Me@178: VMSReqst * Me@178: VMS__take_next_request_out_of( VirtProcr *procrWithReq ); Me@178: Me@178: inline void * Me@178: VMS__take_sem_reqst_from( VMSReqst *req ); Me@178: Me@178: void inline Me@178: VMS__handle_VMSSemReq( VMSReqst *req, VirtProcr *requestingPr, void *semEnv, Me@178: ResumePrFnPtr resumePrFnPtr ); Me@178: Me@178: //======================== STATS ====================== Me@178: Me@178: //===== RDTSC wrapper ===== //Also runs with x86_64 code Me@178: Me@178: #define saveTimeStampCountInto(low, high) \ Me@178: asm volatile("RDTSC; \ Me@178: movl %%eax, %0; \ Me@178: movl %%edx, %1;" \ Me@178: /* outputs */ : "=m" (low), "=m" (high)\ Me@178: /* inputs */ : \ Me@178: /* clobber */ : "%eax", "%edx" \ Me@178: ); Me@178: Me@178: #define saveLowTimeStampCountInto(low) \ Me@178: asm volatile("RDTSC; \ Me@178: movl %%eax, %0;" \ Me@178: /* outputs */ : "=m" (low) \ Me@178: /* inputs */ : \ Me@178: /* clobber */ : "%eax", "%edx" \ Me@178: ); Me@178: Me@178: //==================== Me@178: #define makeAMeasHist( idx, name, numBins, startVal, binWidth ) \ Me@178: makeHighestDynArrayIndexBeAtLeast( _VMSMasterEnv->measHistsInfo, idx ); \ Me@178: _VMSMasterEnv->measHists[idx] = \ Me@178: makeFixedBinHist( numBins, startVal, binWidth, name ); Me@178: Me@178: Me@178: #define MEAS__SUB_CREATE /*turn on/off subtraction of create from plugin*/ Me@178: Me@178: #ifdef VPTHREAD Me@178: Me@178: //VPThread Me@178: #define createHistIdx 0 Me@178: #define mutexLockHistIdx 1 Me@178: #define mutexUnlockHistIdx 2 Me@178: #define condWaitHistIdx 3 Me@178: #define condSignalHistIdx 4 Me@178: Me@178: #define MakeTheMeasHists() \ Me@178: _VMSMasterEnv->measHistsInfo = \ Me@178: makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \ Me@178: makeAMeasHist( createHistIdx, "create", 250, 0, 100 ) \ Me@178: makeAMeasHist( mutexLockHistIdx, "mutex_lock", 50, 0, 100 ) \ Me@178: makeAMeasHist( mutexUnlockHistIdx, "mutex_unlock", 50, 0, 100 ) \ Me@178: makeAMeasHist( condWaitHistIdx, "cond_wait", 50, 0, 100 ) \ Me@178: makeAMeasHist( condSignalHistIdx, "cond_signal", 50, 0, 100 ) Me@178: Me@178: #endif Me@178: Me@178: Me@178: #ifdef VCILK Me@178: Me@178: //VCilk Me@178: #define spawnHistIdx 0 Me@178: #define syncHistIdx 1 Me@178: Me@178: #define MakeTheMeasHists() \ Me@178: _VMSMasterEnv->measHistsInfo = \ Me@178: makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \ Me@178: makeAMeasHist( spawnHistIdx, "Spawn", 50, 0, 200 ) \ Me@178: makeAMeasHist( syncHistIdx, "Sync", 50, 0, 200 ) Me@178: Me@178: Me@178: #endif Me@178: Me@178: #ifdef SSR Me@178: Me@178: //SSR Me@178: #define SendFromToHistIdx 0 Me@178: #define SendOfTypeHistIdx 1 Me@178: #define ReceiveFromToHistIdx 2 Me@178: #define ReceiveOfTypeHistIdx 3 Me@178: Me@178: #define MakeTheMeasHists() \ Me@178: _VMSMasterEnv->measHistsInfo = \ Me@178: makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \ Me@178: makeAMeasHist( SendFromToHistIdx, "SendFromTo", 50, 0, 100 ) \ Me@178: makeAMeasHist( SendOfTypeHistIdx, "SendOfType", 50, 0, 100 ) \ Me@178: makeAMeasHist( ReceiveFromToHistIdx,"ReceiveFromTo", 50, 0, 100 ) \ Me@178: makeAMeasHist( ReceiveOfTypeHistIdx,"ReceiveOfType", 50, 0, 100 ) Me@178: Me@178: #endif Me@178: Me@178: //=========================================================================== Me@178: //VPThread Me@178: Me@178: Me@178: #define Meas_startCreate \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endCreate \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ createHistIdx ] ); Me@178: Me@178: #define Meas_startMutexLock \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endMutexLock \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ mutexLockHistIdx ] ); Me@178: Me@178: #define Meas_startMutexUnlock \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endMutexUnlock \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ mutexUnlockHistIdx ] ); Me@178: Me@178: #define Meas_startCondWait \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endCondWait \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ condWaitHistIdx ] ); Me@178: Me@178: #define Meas_startCondSignal \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endCondSignal \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ condSignalHistIdx ] ); Me@178: Me@178: //=========================================================================== Me@178: // VCilk Me@178: #define Meas_startSpawn \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endSpawn \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ spawnHistIdx ] ); Me@178: Me@178: #define Meas_startSync \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endSync \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ syncHistIdx ] ); Me@178: Me@178: //=========================================================================== Me@178: // SSR Me@178: #define Meas_startSendFromTo \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endSendFromTo \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ SendFromToHistIdx ] ); Me@178: Me@178: #define Meas_startSendOfType \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endSendOfType \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ SendOfTypeHistIdx ] ); Me@178: Me@178: #define Meas_startReceiveFromTo \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endReceiveFromTo \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ ReceiveFromToHistIdx ] ); Me@178: Me@178: #define Meas_startReceiveOfType \ Me@178: int32 startStamp, endStamp; \ Me@178: saveLowTimeStampCountInto( startStamp ); \ Me@178: Me@178: #define Meas_endReceiveOfType \ Me@178: saveLowTimeStampCountInto( endStamp ); \ Me@178: addIntervalToHist( startStamp, endStamp, \ Me@178: _VMSMasterEnv->measHists[ReceiveOfTypeHistIdx ] ); Me@178: Me@178: //===== Me@178: Me@178: #include "ProcrContext.h" Me@178: #include "probes.h" Me@178: #include "vutilities.h" Me@178: Me@178: #endif /* _VMS_H */ Me@178: