# HG changeset patch # User Some Random Person # Date 1337804227 25200 # Node ID 67a3a05a39c01e7d4f68f77013c33393377f3a45 Initial add -- copied code, just junk still diff -r 000000000000 -r 67a3a05a39c0 .hgeol --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgeol Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,12 @@ + +[patterns] +**.py = native +**.txt = native +**.c = native +**.h = native +**.cpp = native +**.java = native +**.sh = native +**.pl = native +**.jpg = bin +**.gif = bin diff -r 000000000000 -r 67a3a05a39c0 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,3 @@ +syntax: glob + +*.o diff -r 000000000000 -r 67a3a05a39c0 Measurement/VSs_Counter_Recording.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Measurement/VSs_Counter_Recording.c Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,121 @@ +/* + * + * author: Nina Engelhardt + */ + +#include "VOMP_Counter_Recording.h" +#include "VMS_impl/VMS.h" +#include "VOMP.h" + +#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS + +void VOMP__init_counter_data_structs(){ + VOMPSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv; + int i; + for(i=0;icounterList[i] = makeListOfArrays(sizeof(CounterEvent), 128); + } +} + +void addToListOfArraysCounterEvent(CounterEvent value, ListOfArrays* list){ + int offset_in_fragment = list->next_free_index % list->num_entries_per_fragment; + if(offset_in_fragment == 0){ + void* newBlock = malloc(list->entry_size * list->num_entries_per_fragment); + addToDynArray(newBlock,list->dim1info); + } + CounterEvent* typedFragment = (CounterEvent*) ((list->dim1)[list->dim1info->numInArray -1]); + typedFragment[offset_in_fragment] = value; + list->next_free_index++; +} + +void VOMP__counter_handler(int evt_type, int vpid, int task, SlaveVP* pr, uint64 cycles, uint64 instrs) +{ + + if (pr->typeOfVP == Master || pr->typeOfVP == Shutdown) + { //Only save values for application work, done in a SlaveVP + return; + } + + VOMPSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv; + + CounterEvent e; + e.event_type = evt_type; + e.vp = vpid; + e.task = task; + + e.cycles = cycles; + e.instrs = instrs; + + if(pr){ + e.coreID = pr->coreAnimatedBy; + e.slot = pr->animSlotAssignedTo; + } else { + e.coreID = -1; + e.slot = NULL; + } + + int corenum; + + if(pr) corenum = pr->coreAnimatedBy; else return; + + if(evt_type==Work_start || evt_type==Work_end || evt_type==AppResponderInvocation_start){ + addToListOfArrays_ext(CounterEvent,e,semanticEnv->counterList[corenum]); + } else { + addToListOfArraysCounterEvent(e,semanticEnv->counterList[corenum]); + } +} + +void set_counter_file(FILE* f){ + counterfile = f; +} + +void print_counter_events_to_file(void* _e){ + CounterEvent* e = (CounterEvent*) _e; + fprintf(counterfile, "event, "); + switch(e->event_type){ + case AppResponderInvocation_start: + fprintf(counterfile, "AppResponderInvocation_start"); + break; + case AppResponder_start: + fprintf(counterfile, "AppResponder_start"); + break; + case AppResponder_end: + fprintf(counterfile, "AppResponder_end"); + break; + case AssignerInvocation_start: + fprintf(counterfile, "AssignerInvocation_start"); + break; + case NextAssigner_start: + fprintf(counterfile, "NextAssigner_start"); + break; + case Assigner_start: + fprintf(counterfile, "Assigner_start"); + break; + case Assigner_end: + fprintf(counterfile, "Assigner_end"); + break; + case Work_end: + fprintf(counterfile, "Work_end"); + break; + case Work_start: + fprintf(counterfile, "Work_start"); + break; + case HwResponderInvocation_start: + fprintf(counterfile, "HwResponderInvocation_start"); + break; + case Timestamp_start: + fprintf(counterfile, "Timestamp_start"); + break; + case Timestamp_end: + fprintf(counterfile, "Timestamp_end"); + break; + default: + fprintf(counterfile, "unknown event"); + } + fprintf(counterfile,", %d, %d, %llu, %llu",e->vp,e->task,e->cycles,e->instrs); + if(e->coreID >=0) + fprintf(counterfile,", %d",e->coreID); + fprintf(counterfile,"\n"); + fflush(counterfile); +} +#endif diff -r 000000000000 -r 67a3a05a39c0 Measurement/VSs_Counter_Recording.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Measurement/VSs_Counter_Recording.h Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,33 @@ +/* + * File: VOMP_Counter_Recording.h + * Author: nengel + * + * Created on January 11, 2012, 3:03 PM + */ + +#ifndef VOMP_COUNTER_RECORDING_H +#define VOMP_COUNTER_RECORDING_H + +#include "VMS_impl/VMS.h" + +typedef struct { + int event_type; + int coreID; + AnimSlot* slot; + int vp; + int task; + uint64 cycles; + uint64 instrs; +} CounterEvent; + +FILE* counterfile; + +void VOMP__init_counter_data_structs(); + +void VOMP__counter_handler(int evt_type, int vpid, int task, SlaveVP* pr, uint64 cycles, uint64 instrs); + +void set_counter_file(FILE* f); + +void print_counter_events_to_file(void* _e); +#endif /* VOMP_COUNTER_RECORDING_H */ + diff -r 000000000000 -r 67a3a05a39c0 Measurement/VSs_Measurement.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Measurement/VSs_Measurement.h Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright 2009 OpenSourceStewardshipFoundation.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _VOMP_MEAS_H +#define _VOMP_MEAS_H + + +#ifdef MEAS__TURN_ON_LANG_MEAS + + #ifdef MEAS__Make_Meas_Hists_for_Language + #undef MEAS__Make_Meas_Hists_for_Language + #endif + + +//=================== Language-specific Measurement Stuff =================== +// +// + #define SendFromToHistIdx 1 //note: starts at 1 + #define SendOfTypeHistIdx 2 + #define ReceiveFromToHistIdx 3 + #define ReceiveOfTypeHistIdx 4 + + #define MEAS__Make_Meas_Hists_for_Language \ + _VMSMasterEnv->measHistsInfo = \ + makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \ + makeAMeasHist( SendFromToHistIdx, "SendFromTo", 50, 0, 100 ) \ + makeAMeasHist( SendOfTypeHistIdx, "SendOfType", 50, 0, 100 ) \ + makeAMeasHist( ReceiveFromToHistIdx,"ReceiveFromTo", 50, 0, 100 ) \ + makeAMeasHist( ReceiveOfTypeHistIdx,"ReceiveOfType", 50, 0, 100 ) + + #define Meas_startSendFromTo \ + int32 startStamp, endStamp; \ + saveLowTimeStampCountInto( startStamp ); \ + + #define Meas_endSendFromTo \ + saveLowTimeStampCountInto( endStamp ); \ + addIntervalToHist( startStamp, endStamp, \ + _VMSMasterEnv->measHists[ SendFromToHistIdx ] ); + + #define Meas_startSendOfType \ + int32 startStamp, endStamp; \ + saveLowTimeStampCountInto( startStamp ); \ + + #define Meas_endSendOfType \ + saveLowTimeStampCountInto( endStamp ); \ + addIntervalToHist( startStamp, endStamp, \ + _VMSMasterEnv->measHists[ SendOfTypeHistIdx ] ); + + #define Meas_startReceiveFromTo \ + int32 startStamp, endStamp; \ + saveLowTimeStampCountInto( startStamp ); \ + + #define Meas_endReceiveFromTo \ + saveLowTimeStampCountInto( endStamp ); \ + addIntervalToHist( startStamp, endStamp, \ + _VMSMasterEnv->measHists[ ReceiveFromToHistIdx ] ); + + #define Meas_startReceiveOfType \ + int32 startStamp, endStamp; \ + saveLowTimeStampCountInto( startStamp ); \ + + #define Meas_endReceiveOfType \ + saveLowTimeStampCountInto( endStamp ); \ + addIntervalToHist( startStamp, endStamp, \ + _VMSMasterEnv->measHists[ReceiveOfTypeHistIdx ] ); + +#else //===================== turned off ========================== + + #define MEAS__Make_Meas_Hists_for_Language + #define Meas_startSendFromTo + #define Meas_endSendFromTo + #define Meas_startSendOfType + #define Meas_endSendOfType + #define Meas_startReceiveFromTo + #define Meas_endReceiveFromTo + #define Meas_startReceiveOfType + #define Meas_endReceiveOfType + +#endif /* MEAS__TURN_ON_LANG_MEAS */ + +#endif /* */ + diff -r 000000000000 -r 67a3a05a39c0 Measurement/dependency.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Measurement/dependency.c Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,78 @@ +#include "dependency.h" +#include "VMS_impl/VMS.h" + +Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task){ + Dependency* newDep = (Dependency*) VMS_int__malloc(sizeof(Dependency)); + if (newDep!=NULL){ + newDep->from_vp = from_vp; + newDep->from_task = from_task; + newDep->to_vp = to_vp; + newDep->to_task = to_task; + } + return newDep; +} + +NtoN* new_NtoN(int id){ + NtoN* newn = (NtoN*) VMS_int__malloc(sizeof(NtoN)); + newn->id = id; + newn->senders = makeListOfArrays(sizeof(Unit), 64); + newn->receivers = makeListOfArrays(sizeof(Unit), 64); + return newn; +} + +int set_dependency_file(FILE* file){ + dependency_file = file; +} + +void print_ctl_dependency_to_file(void* _dep){ + Dependency* dep = (Dependency*) _dep; + if(!dep) return; + fprintf(dependency_file,"ctlDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); +} + +void print_comm_dependency_to_file(void* _dep){ + Dependency* dep = (Dependency*) _dep; + if(!dep) return; + fprintf(dependency_file,"commDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); +} + +void print_dyn_dependency_to_file(void* _dep){ + Dependency* dep = (Dependency*) _dep; + if(!dep) return; + fprintf(dependency_file,"dynDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); +} + +void print_hw_dependency_to_file(void* _dep){ + Dependency* dep = (Dependency*) _dep; + if(!dep) return; + fprintf(dependency_file,"hwDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); +} + +void print_dependency_to_file(void* _dep){ + Dependency* dep = (Dependency*) _dep; + if(!dep) return; + fprintf(dependency_file,"VP_%d_%d -> VP_%d_%d;\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); +} + +void print_unit_to_file(void* _unit){ + Unit* unit = (Unit*) _unit; + if(!unit) return; + fprintf(dependency_file,"unit,%d,%d\n",unit->vp,unit->task); +} + +void print_nton_set_helper(void* _u){ + Unit* u = (Unit*) _u; + if(!u) return; + fprintf(dependency_file,",%d,%d",u->vp,u->task); +} + +void print_nton_to_file(void* _nton){ + NtoN* nton = (NtoN*) _nton; + if(!nton) return; + //assert(nton->senders->next_free_index==nton->receivers->next_free_index); + int numInSet = nton->senders->next_free_index; + fprintf(dependency_file,"NtoN,%d",numInSet); + forAllInListOfArraysDo(nton->senders,&print_nton_set_helper); + forAllInListOfArraysDo(nton->receivers,&print_nton_set_helper); + fprintf(dependency_file,"\n"); +} \ No newline at end of file diff -r 000000000000 -r 67a3a05a39c0 Measurement/dependency.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Measurement/dependency.h Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,56 @@ +/* + * File: dependency.h + * Author: Nina Engelhardt + * + * Created on 29. August 2011, 17:41 + */ + +#ifndef _DEPENDENCY_H +#define _DEPENDENCY_H + + +#include +#include "ListOfArrays/ListOfArrays.h" + +typedef struct { + int vp; + int task; +} Unit; + +typedef struct { + int from_vp; + int from_task; + int to_vp; + int to_task; +} Dependency; + +typedef struct { + int32 id; + ListOfArrays* senders; + ListOfArrays* receivers; +} NtoN; + +FILE* dependency_file; + +Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task); + +NtoN* new_NtoN(int id); + +int set_dependency_file(FILE* file); + +void print_ctl_dependency_to_file(void* _dep); + +void print_comm_dependency_to_file(void* _dep); + +void print_dyn_dependency_to_file(void* _dep); + +void print_hw_dependency_to_file(void* _dep); + +void print_dependency_to_file(void* dep); + +void print_unit_to_file(void* unit); + +void print_nton_to_file(void* _nton); + +#endif /* DEPENDENCY_H */ + diff -r 000000000000 -r 67a3a05a39c0 VSs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VSs.c Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,772 @@ +/* + * Copyright 2010 OpenSourceCodeStewardshipFoundation + * + * Licensed under BSD + */ + +#include +#include +#include + +#include "Queue_impl/PrivateQueue.h" +#include "Hash_impl/PrivateHash.h" + +#include "VOMP.h" +#include "VOMP_Counter_Recording.h" + +//========================================================================== + +void +VOMP__init(); + +void +VOMP__init_Helper(); +//========================================================================== + + + +//=========================================================================== + + +/*These are the library functions *called in the application* + * + *There's a pattern for the outside sequential code to interact with the + * VMS_HW code. + *The VMS_HW system is inside a boundary.. every VOMP system is in its + * own directory that contains the functions for each of the processor types. + * One of the processor types is the "seed" processor that starts the + * cascade of creating all the processors that do the work. + *So, in the directory is a file called "EntryPoint.c" that contains the + * function, named appropriately to the work performed, that the outside + * sequential code calls. This function follows a pattern: + *1) it calls VOMP__init() + *2) it creates the initial data for the seed processor, which is passed + * in to the function + *3) it creates the seed VOMP processor, with the data to start it with. + *4) it calls startVOMPThenWaitUntilWorkDone + *5) it gets the returnValue from the transfer struc and returns that + * from the function + * + *For now, a new VOMP system has to be created via VOMP__init every + * time an entry point function is called -- later, might add letting the + * VOMP system be created once, and let all the entry points just reuse + * it -- want to be as simple as possible now, and see by using what makes + * sense for later.. + */ + + + +//=========================================================================== + +/*This is the "border crossing" function -- the thing that crosses from the + * outside world, into the VMS_HW world. It initializes and starts up the + * VMS system, then creates one processor from the specified function and + * puts it into the readyQ. From that point, that one function is resp. + * for creating all the other processors, that then create others, and so + * forth. + *When all the processors, including the seed, have dissipated, then this + * function returns. The results will have been written by side-effect via + * pointers read from, or written into initData. + * + *NOTE: no Threads should exist in the outside program that might touch + * any of the data reachable from initData passed in to here + */ +void +VOMP__create_seed_procr_and_do_work( TopLevelFnPtr fnPtr, void *initData ) + { VOMPSemEnv *semEnv; + SlaveVP *seedPr; + + VOMP__init(); //normal multi-thd + + semEnv = _VMSMasterEnv->semanticEnv; + + //VOMP starts with one processor, which is put into initial environ, + // and which then calls create() to create more, thereby expanding work + seedPr = VOMP__create_procr_helper( fnPtr, initData, + semEnv, semEnv->nextCoreToGetNewPr++ ); + + resume_slaveVP( seedPr, semEnv ); + + VMS_SS__start_the_work_then_wait_until_done(); //normal multi-thd + + VOMP__cleanup_after_shutdown(); + } + + +int32 +VOMP__giveMinWorkUnitCycles( float32 percentOverhead ) + { + return MIN_WORK_UNIT_CYCLES; + } + +int32 +VOMP__giveIdealNumWorkUnits() + { + return NUM_ANIM_SLOTS * NUM_CORES; + } + +int32 +VOMP__give_number_of_cores_to_schedule_onto() + { + return NUM_CORES; + } + +/*For now, use TSC -- later, make these two macros with assembly that first + * saves jump point, and second jumps back several times to get reliable time + */ +void +VOMP__start_primitive() + { saveLowTimeStampCountInto( ((VOMPSemEnv *)(_VMSMasterEnv->semanticEnv))-> + primitiveStartTime ); + } + +/*Just quick and dirty for now -- make reliable later + * will want this to jump back several times -- to be sure cache is warm + * because don't want comm time included in calc-time measurement -- and + * also to throw out any "weird" values due to OS interrupt or TSC rollover + */ +int32 +VOMP__end_primitive_and_give_cycles() + { int32 endTime, startTime; + //TODO: fix by repeating time-measurement + saveLowTimeStampCountInto( endTime ); + startTime =((VOMPSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime; + return (endTime - startTime); + } + +//=========================================================================== + +/*Initializes all the data-structures for a VOMP system -- but doesn't + * start it running yet! + * + *This runs in the main thread -- before VMS starts up + * + *This sets up the semantic layer over the VMS system + * + *First, calls VMS_Setup, then creates own environment, making it ready + * for creating the seed processor and then starting the work. + */ +void +VOMP__init() + { + VMS_SS__init(); + //masterEnv, a global var, now is partially set up by init_VMS + // after this, have VMS_int__malloc and VMS_int__free available + + VOMP__init_Helper(); + } + + +void idle_fn(void* data, SlaveVP *animatingSlv){ + while(1){ + VMS_int__suspend_slaveVP_and_send_req(animatingSlv); + } +} + +void +VOMP__init_Helper() + { VOMPSemEnv *semanticEnv; + PrivQueueStruc **readyVPQs; + int coreIdx, i, j; + + //Hook up the semantic layer's plug-ins to the Master virt procr + _VMSMasterEnv->requestHandler = &VOMP__Request_Handler; + _VMSMasterEnv->slaveAssigner = &VOMP__assign_slaveVP_to_slot; + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS + _VMSMasterEnv->counterHandler = &VOMP__counter_handler; + #endif + + //create the semantic layer's environment (all its data) and add to + // the master environment + semanticEnv = VMS_int__malloc( sizeof( VOMPSemEnv ) ); + _VMSMasterEnv->semanticEnv = semanticEnv; + + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS + VOMP__init_counter_data_structs(); + #endif + semanticEnv->shutdownInitiated = FALSE; + for(i=0;iidlePr[i][j] = VMS_int__create_slaveVP(&idle_fn,NULL); + semanticEnv->idlePr[i][j]->coreAnimatedBy = i; + } + } + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + semanticEnv->unitList = makeListOfArrays(sizeof(Unit),128); + semanticEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); + semanticEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); + semanticEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); + semanticEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semanticEnv->ntonGroups),8); + + semanticEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); + memset(semanticEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); + #endif + + //create the ready queue, hash tables used for pairing send to receive + // and so forth + //TODO: add hash tables for pairing sends with receives, and + // initialize the data ownership system + readyVPQs = VMS_int__malloc( NUM_CORES * sizeof(PrivQueueStruc *) ); + + for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) + { + readyVPQs[ coreIdx ] = makeVMSQ(); + } + + semanticEnv->readyVPQs = readyVPQs; + + semanticEnv->nextCoreToGetNewPr = 0; + semanticEnv->numSlaveVP = 0; + + semanticEnv->commHashTbl = makeHashTable( 1<<16, &VMS_int__free );//start big + + //TODO: bug -- turn these arrays into dyn arrays to eliminate limit + //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); + //semanticEnv->transactionStrucs = makeDynArrayInfo( ); + for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) + { + semanticEnv->fnSingletons[i].endInstrAddr = NULL; + semanticEnv->fnSingletons[i].hasBeenStarted = FALSE; + semanticEnv->fnSingletons[i].hasFinished = FALSE; + semanticEnv->fnSingletons[i].waitQ = makeVMSQ(); + semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSQ(); + } + } + + +/*Frees any memory allocated by VOMP__init() then calls VMS_int__shutdown + */ +void +VOMP__cleanup_after_shutdown() + { VOMPSemEnv *semanticEnv; + + semanticEnv = _VMSMasterEnv->semanticEnv; + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + //UCC + FILE* output; + int n; + char filename[255]; + for(n=0;n<255;n++) + { + sprintf(filename, "./counters/UCC.%d",n); + output = fopen(filename,"r"); + if(output) + { + fclose(output); + }else{ + break; + } + } + if(n<255){ + printf("Saving UCC to File: %s ...\n", filename); + output = fopen(filename,"w+"); + if(output!=NULL){ + set_dependency_file(output); + //fprintf(output,"digraph Dependencies {\n"); + //set_dot_file(output); + //FIXME: first line still depends on counters being enabled, replace w/ unit struct! + //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); + forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file); + forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); + forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); + forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file); + //fprintf(output,"}\n"); + fflush(output); + + } else + printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); + } else { + printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); + } + //Loop Graph + for(n=0;n<255;n++) + { + sprintf(filename, "./counters/LoopGraph.%d",n); + output = fopen(filename,"r"); + if(output) + { + fclose(output); + }else{ + break; + } + } + if(n<255){ + printf("Saving LoopGraph to File: %s ...\n", filename); + output = fopen(filename,"w+"); + if(output!=NULL){ + set_dependency_file(output); + //fprintf(output,"digraph Dependencies {\n"); + //set_dot_file(output); + //FIXME: first line still depends on counters being enabled, replace w/ unit struct! + //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); + forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file ); + forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); + forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); + forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file ); + forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file ); + //fprintf(output,"}\n"); + fflush(output); + + } else + printf("Opening LoopGraph file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); + } else { + printf("Could not open LoopGraph file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); + } + + + freeListOfArrays(semanticEnv->unitList); + freeListOfArrays(semanticEnv->commDependenciesList); + freeListOfArrays(semanticEnv->ctlDependenciesList); + freeListOfArrays(semanticEnv->dynDependenciesList); + + #endif +#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS + for(n=0;n<255;n++) + { + sprintf(filename, "./counters/Counters.%d.csv",n); + output = fopen(filename,"r"); + if(output) + { + fclose(output); + }else{ + break; + } + } + if(n<255){ + printf("Saving Counter measurements to File: %s ...\n", filename); + output = fopen(filename,"w+"); + if(output!=NULL){ + set_counter_file(output); + int i; + for(i=0;icounterList[i], &print_counter_events_to_file ); + fflush(output); + } + + } else + printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); + } else { + printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); + } + +#endif +/* It's all allocated inside VMS's big chunk -- that's about to be freed, so + * nothing to do here + + + for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) + { + VMS_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); + VMS_int__free( semanticEnv->readyVPQs[coreIdx] ); + } + VMS_int__free( semanticEnv->readyVPQs ); + + freeHashTable( semanticEnv->commHashTbl ); + VMS_int__free( _VMSMasterEnv->semanticEnv ); + */ + VMS_SS__cleanup_at_end_of_shutdown(); + } + + +//=========================================================================== + +/* + */ + SlaveVP * +VOMP__create_procr_with( TopLevelFnPtr fnPtr, void *initData, + SlaveVP *creatingPr ) + { VOMPSemReq reqData; + + //the semantic request data is on the stack and disappears when this + // call returns -- it's guaranteed to remain in the VP's stack for as + // long as the VP is suspended. + reqData.reqType = 0; //know type because in a VMS create req + reqData.coreToAssignOnto = -1; //means round-robin assign + reqData.fnPtr = fnPtr; + reqData.initData = initData; + reqData.sendPr = creatingPr; + + VMS_WL__send_create_slaveVP_req( &reqData, creatingPr ); + + return creatingPr->dataRetFromReq; + } + + SlaveVP * +VOMP__create_procr_with_affinity( TopLevelFnPtr fnPtr, void *initData, + SlaveVP *creatingPr, int32 coreToAssignOnto ) + { VOMPSemReq reqData; + + //the semantic request data is on the stack and disappears when this + // call returns -- it's guaranteed to remain in the VP's stack for as + // long as the VP is suspended. + reqData.reqType = 0; //know type because in a VMS create req + reqData.coreToAssignOnto = coreToAssignOnto; + reqData.fnPtr = fnPtr; + reqData.initData = initData; + reqData.sendPr = creatingPr; + + VMS_WL__send_create_slaveVP_req( &reqData, creatingPr ); + + return creatingPr->dataRetFromReq; + } + + + void +VOMP__dissipate_procr( SlaveVP *procrToDissipate ) + { + VMS_WL__send_dissipate_req( procrToDissipate ); + } + + +//=========================================================================== + +void * +VOMP__malloc_to( int32 sizeToMalloc, SlaveVP *owningPr ) + { VOMPSemReq reqData; + + reqData.reqType = malloc_req; + reqData.sendPr = owningPr; + reqData.sizeToMalloc = sizeToMalloc; + + VMS_WL__send_sem_request( &reqData, owningPr ); + + return owningPr->dataRetFromReq; + } + + +/*Sends request to Master, which does the work of freeing + */ +void +VOMP__free( void *ptrToFree, SlaveVP *owningPr ) + { VOMPSemReq reqData; + + reqData.reqType = free_req; + reqData.sendPr = owningPr; + reqData.ptrToFree = ptrToFree; + + VMS_WL__send_sem_request( &reqData, owningPr ); + } + + +void +VOMP__transfer_ownership_of_from_to( void *data, SlaveVP *oldOwnerSlv, + SlaveVP *newOwnerPr ) + { + //TODO: put in the ownership system that automatically frees when no + // owners of data left -- will need keeper for keeping data around when + // future created processors might need it but don't exist yet + } + + +void +VOMP__add_ownership_by_to( SlaveVP *newOwnerSlv, void *data ) + { + + } + + +void +VOMP__remove_ownership_by_from( SlaveVP *loserSlv, void *dataLosing ) + { + + } + + +/*Causes the VOMP system to remove internal ownership, so data won't be + * freed when VOMP shuts down, and will persist in the external program. + * + *Must be called from the processor that currently owns the data. + * + *IMPL: Transferring ownership touches two different virtual processor's + * state -- which means it has to be done carefully -- the VMS rules for + * semantic layers say that a work-unit is only allowed to touch the + * virtual processor it is part of, and that only a single work-unit per + * virtual processor be assigned to a slave at a time. So, this has to + * modify the virtual processor that owns the work-unit that called this + * function, then create a request to have the other processor modified. + *However, in this case, the TO processor is the outside, and transfers + * are only allowed to be called by the giver-upper, so can mark caller of + * this function as no longer owner, and return -- done. + */ +void +VOMP__transfer_ownership_to_outside( void *data ) + { + //TODO: removeAllOwnersFrom( data ); + } + + +//=========================================================================== + +void +VOMP__send_of_type_to( SlaveVP *sendPr, void *msg, const int type, + SlaveVP *receivePr) + { VOMPSemReq reqData; + + reqData.receivePr = receivePr; + reqData.sendPr = sendPr; + reqData.reqType = send_type; + reqData.msgType = type; + reqData.msg = msg; + reqData.nextReqInHashEntry = NULL; + + //On ownership -- remove inside the send and let ownership sit in limbo + // as a potential in an entry in the hash table, when this receive msg + // gets paired to a send, the ownership gets added to the receivePr -- + // the next work-unit in the receivePr's trace will have ownership. + VMS_WL__send_sem_request( &reqData, sendPr ); + + //When come back from suspend, no longer own data reachable from msg + //TODO: release ownership here + } + +void +VOMP__send_from_to( void *msg, SlaveVP *sendPr, SlaveVP *receivePr ) + { VOMPSemReq reqData; + + //hash on the receiver, 'cause always know it, but sometimes want to + // receive from anonymous sender + + reqData.receivePr = receivePr; + reqData.sendPr = sendPr; + reqData.reqType = send_from_to; + reqData.msg = msg; + reqData.nextReqInHashEntry = NULL; + + VMS_WL__send_sem_request( &reqData, sendPr ); + } + + +//=========================================================================== + +void * +VOMP__receive_any_to( SlaveVP *receivePr ) + { + + } + +void * +VOMP__receive_type_to( const int type, SlaveVP *receivePr ) + { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to: %d", receivePr->slaveID); + VOMPSemReq reqData; + + reqData.receivePr = receivePr; + reqData.reqType = receive_type; + reqData.msgType = type; + reqData.nextReqInHashEntry = NULL; + + VMS_WL__send_sem_request( &reqData, receivePr ); + + return receivePr->dataRetFromReq; + } + + + +/*Call this at point receiving virt pr wants in-coming data. + * + *The reason receivePr must call this is that it modifies the receivPr + * loc structure directly -- and the VMS rules state a virtual processor + * loc structure can only be modified by itself. + */ +void * +VOMP__receive_from_to( SlaveVP *sendPr, SlaveVP *receivePr ) + { DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", sendPr->slaveID, receivePr->slaveID); + VOMPSemReq reqData; + + //hash on the receiver, 'cause always know it, but sometimes want to + // receive from anonymous sender + + reqData.receivePr = receivePr; + reqData.sendPr = sendPr; + reqData.reqType = receive_from_to; + reqData.nextReqInHashEntry = NULL; + + VMS_WL__send_sem_request( &reqData, receivePr ); + + return receivePr->dataRetFromReq; + } + + +//=========================================================================== +// +/*A function singleton is a function whose body executes exactly once, on a + * single core, no matter how many times the fuction is called and no + * matter how many cores or the timing of cores calling it. + * + *A data singleton is a ticket attached to data. That ticket can be used + * to get the data through the function exactly once, no matter how many + * times the data is given to the function, and no matter the timing of + * trying to get the data through from different cores. + */ + +/*asm function declarations*/ +void asm_save_ret_to_singleton(VOMPSingleton *singletonPtrAddr); +void asm_write_ret_from_singleton(VOMPSingleton *singletonPtrAddr); + +/*Fn singleton uses ID as index into array of singleton structs held in the + * semantic environment. + */ +void +VOMP__start_fn_singleton( int32 singletonID, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + // + reqData.reqType = singleton_fn_start; + reqData.singletonID = singletonID; + + VMS_WL__send_sem_request( &reqData, animPr ); + if( animPr->dataRetFromReq ) //will be 0 or addr of label in end singleton + { + VOMPSemEnv *semEnv = VMS_int__give_sem_env_for( animPr ); + asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); + } + } + +/*Data singleton hands addr of loc holding a pointer to a singleton struct. + * The start_data_singleton makes the structure and puts its addr into the + * location. + */ +void +VOMP__start_data_singleton( VOMPSingleton **singletonAddr, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + if( *singletonAddr && (*singletonAddr)->hasFinished ) + goto JmpToEndSingleton; + + reqData.reqType = singleton_data_start; + reqData.singletonPtrAddr = singletonAddr; + + VMS_WL__send_sem_request( &reqData, animPr ); + if( animPr->dataRetFromReq ) //either 0 or end singleton's return addr + { //Assembly code changes the return addr on the stack to the one + // saved into the singleton by the end-singleton-fn + //The return addr is at 0x4(%%ebp) + JmpToEndSingleton: + asm_write_ret_from_singleton(*singletonAddr); + } + //now, simply return + //will exit either from the start singleton call or the end-singleton call + } + +/*Uses ID as index into array of flags. If flag already set, resumes from + * end-label. Else, sets flag and resumes normally. + * + *Note, this call cannot be inlined because the instr addr at the label + * inside is shared by all invocations of a given singleton ID. + */ +void +VOMP__end_fn_singleton( int32 singletonID, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + //don't need this addr until after at least one singleton has reached + // this function + VOMPSemEnv *semEnv = VMS_int__give_sem_env_for( animPr ); + asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); + + reqData.reqType = singleton_fn_end; + reqData.singletonID = singletonID; + + VMS_WL__send_sem_request( &reqData, animPr ); + +EndSingletonInstrAddr: + return; + } + +void +VOMP__end_data_singleton( VOMPSingleton **singletonPtrAddr, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + //don't need this addr until after singleton struct has reached + // this function for first time + //do assembly that saves the return addr of this fn call into the + // data singleton -- that data-singleton can only be given to exactly + // one instance in the code of this function. However, can use this + // function in different places for different data-singletons. +// (*(singletonAddr))->endInstrAddr = &&EndDataSingletonInstrAddr; + + + asm_save_ret_to_singleton(*singletonPtrAddr); + + reqData.reqType = singleton_data_end; + reqData.singletonPtrAddr = singletonPtrAddr; + + VMS_WL__send_sem_request( &reqData, animPr ); + } + +/*This executes the function in the masterVP, so it executes in isolation + * from any other copies -- only one copy of the function can ever execute + * at a time. + * + *It suspends to the master, and the request handler takes the function + * pointer out of the request and calls it, then resumes the VP. + *Only very short functions should be called this way -- for longer-running + * isolation, use transaction-start and transaction-end, which run the code + * between as work-code. + */ +void +VOMP__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, + void *data, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + // + reqData.reqType = atomic; + reqData.fnToExecInMaster = ptrToFnToExecInMaster; + reqData.dataForFn = data; + + VMS_WL__send_sem_request( &reqData, animPr ); + } + + +/*This suspends to the master. + *First, it looks at the VP's data, to see the highest transactionID that VP + * already has entered. If the current ID is not larger, it throws an + * exception stating a bug in the code. Otherwise it puts the current ID + * there, and adds the ID to a linked list of IDs entered -- the list is + * used to check that exits are properly ordered. + *Next it is uses transactionID as index into an array of transaction + * structures. + *If the "VP_currently_executing" field is non-null, then put requesting VP + * into queue in the struct. (At some point a holder will request + * end-transaction, which will take this VP from the queue and resume it.) + *If NULL, then write requesting into the field and resume. + */ +void +VOMP__start_transaction( int32 transactionID, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + // + reqData.sendPr = animPr; + reqData.reqType = trans_start; + reqData.transID = transactionID; + + VMS_WL__send_sem_request( &reqData, animPr ); + } + +/*This suspends to the master, then uses transactionID as index into an + * array of transaction structures. + *It looks at VP_currently_executing to be sure it's same as requesting VP. + * If different, throws an exception, stating there's a bug in the code. + *Next it looks at the queue in the structure. + *If it's empty, it sets VP_currently_executing field to NULL and resumes. + *If something in, gets it, sets VP_currently_executing to that VP, then + * resumes both. + */ +void +VOMP__end_transaction( int32 transactionID, SlaveVP *animPr ) + { + VOMPSemReq reqData; + + // + reqData.sendPr = animPr; + reqData.reqType = trans_end; + reqData.transID = transactionID; + + VMS_WL__send_sem_request( &reqData, animPr ); + } diff -r 000000000000 -r 67a3a05a39c0 VSs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VSs.h Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,268 @@ +/* + * Copyright 2009 OpenSourceStewardshipFoundation.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _VOMP_H +#define _VOMP_H + +#include "Queue_impl/PrivateQueue.h" +#include "Hash_impl/PrivateHash.h" +#include "VMS_impl/VMS.h" +#include "dependency.h" + + +//=========================================================================== +#define NUM_STRUCS_IN_SEM_ENV 1000 + + //This is hardware dependent -- it's the number of cycles of scheduling + // overhead -- if a work unit is fewer than this, it is better being + // combined sequentially with other work + //This value depends on both VMS overhead and VOMP's plugin. At some point + // it will be derived by perf-counter measurements during init of VOMP +#define MIN_WORK_UNIT_CYCLES 20000 + +//=========================================================================== +/*This header defines everything specific to the VOMP semantic plug-in + */ +typedef struct _VOMPSemReq VOMPSemReq; +typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master +//=========================================================================== + +/*Semantic layer-specific data sent inside a request from lib called in app + * to request handler called in AnimationMaster + */ + +typedef struct + { + SlaveVP *VPCurrentlyExecuting; + PrivQueueStruc *waitingVPQ; + } +VOMPTrans; + +/*WARNING: assembly hard-codes position of endInstrAddr as first field + */ +typedef struct + { + void *endInstrAddr; + int32 hasBeenStarted; + int32 hasFinished; + PrivQueueStruc *waitQ; + } +VOMPSingleton; + +enum VOMPReqType + { + send_type = 1, + send_from_to, + receive_any, //order and grouping matter -- send before receive + receive_type, // and receive_any first of the receives -- Handlers + receive_from_to,// rely upon this ordering of enum + transfer_to, + transfer_out, + malloc_req, + free_req, + singleton_fn_start, + singleton_fn_end, + singleton_data_start, + singleton_data_end, + atomic, + trans_start, + trans_end + }; + +struct _VOMPSemReq + { enum VOMPReqType reqType; + SlaveVP *sendPr; + SlaveVP *receivePr; + int32 msgType; + void *msg; + VOMPSemReq *nextReqInHashEntry; + + void *initData; + TopLevelFnPtr fnPtr; + int32 coreToAssignOnto; + + int32 sizeToMalloc; + void *ptrToFree; + + int32 singletonID; + VOMPSingleton **singletonPtrAddr; + + PtrToAtomicFn fnToExecInMaster; + void *dataForFn; + + int32 transID; + } +/* VOMPSemReq */; + + +typedef struct + { + PrivQueueStruc **readyVPQs; + HashTable *commHashTbl; + int32 numSlaveVP; + int32 nextCoreToGetNewPr; + int32 primitiveStartTime; + + //fix limit on num with dynArray + VOMPSingleton fnSingletons[NUM_STRUCS_IN_SEM_ENV]; + VOMPTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + ListOfArrays* unitList; + ListOfArrays* ctlDependenciesList; + ListOfArrays* commDependenciesList; + NtoN** ntonGroups; + PrivDynArrayInfo* ntonGroupsInfo; + ListOfArrays* dynDependenciesList; + Unit last_in_slot[NUM_CORES * NUM_ANIM_SLOTS]; + ListOfArrays* hwArcs; + #endif + + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS + ListOfArrays* counterList[NUM_CORES]; + #endif + SlaveVP* idlePr[NUM_CORES][NUM_ANIM_SLOTS]; + int shutdownInitiated; + } +VOMPSemEnv; + + +typedef struct _TransListElem TransListElem; +struct _TransListElem + { + int32 transID; + TransListElem *nextTrans; + }; +//TransListElem + +typedef struct + { + int32 highestTransEntered; + TransListElem *lastTransEntered; + } +VOMPSemData; + +//=========================================================================== + +void +VOMP__create_seed_procr_and_do_work( TopLevelFnPtr fn, void *initData ); + +int32 +VOMP__giveMinWorkUnitCycles( float32 percentOverhead ); + +void +VOMP__start_primitive(); + +int32 +VOMP__end_primitive_and_give_cycles(); + +int32 +VOMP__giveIdealNumWorkUnits(); + +int32 +VOMP__give_number_of_cores_to_schedule_onto(); + +//======================= + +void +VOMP__init(); + +void +VOMP__cleanup_after_shutdown(); + +//======================= + + SlaveVP * +VOMP__create_procr_with( TopLevelFnPtr fnPtr, void *initData, + SlaveVP *creatingSlv ); + + SlaveVP * +VOMP__create_procr_with_affinity( TopLevelFnPtr fnPtr, void *initData, + SlaveVP *creatingPr, int32 coreToAssignOnto); + +void +VOMP__dissipate_procr( SlaveVP *procrToDissipate ); + +//======================= +void * +VOMP__malloc_to( int numBytes, SlaveVP *ownerSlv ); + +void +VOMP__free( void *ptrToFree, SlaveVP *owningSlv ); + +void +VOMP__transfer_ownership_of_from_to( void *data, SlaveVP *oldOwnerPr, + SlaveVP *newOwnerSlv ); + +void +VOMP__add_ownership_by_to( SlaveVP *newOwnerPr, void *data ); + +void +VOMP__remove_ownership_by_from( SlaveVP *loserPr, void *dataLosing ); + +void +VOMP__transfer_ownership_to_outside( void *dataToTransferOwnershipOf ); + + + +//======================= +void +VOMP__send_of_type_to( SlaveVP *sendPr, void *msg, const int type, + SlaveVP *receivePr); + +void +VOMP__send_from_to( void *msg, SlaveVP *sendPr, SlaveVP *receivePr); + +void * +VOMP__receive_type_to( const int type, SlaveVP *receiveSlv ); + +void * +VOMP__receive_from_to( SlaveVP *sendPr, SlaveVP *receiveSlv ); + + +//======================= Concurrency Stuff ====================== +void +VOMP__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ); + +void +VOMP__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ); + +void +VOMP__start_data_singleton( VOMPSingleton **singeltonAddr, SlaveVP *animSlv ); + +void +VOMP__end_data_singleton( VOMPSingleton **singletonAddr, SlaveVP *animSlv ); + +void +VOMP__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, + void *data, SlaveVP *animSlv ); + +void +VOMP__start_transaction( int32 transactionID, SlaveVP *animSlv ); + +void +VOMP__end_transaction( int32 transactionID, SlaveVP *animSlv ); + + +//========================= Internal use only ============================= +void +VOMP__Request_Handler( SlaveVP *requestingPr, void *_semEnv ); + +SlaveVP * +VOMP__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot ); + +SlaveVP* +VOMP__create_procr_helper( TopLevelFnPtr fnPtr, void *initData, + VOMPSemEnv *semEnv, int32 coreToAssignOnto ); + +//===================== Measurement of Lang Overheads ===================== +#include "VOMP_Measurement.h" + +//=========================================================================== +#endif /* _VOMP_H */ + diff -r 000000000000 -r 67a3a05a39c0 VSs_PluginFns.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VSs_PluginFns.c Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,302 @@ +/* + * Copyright 2010 OpenSourceCodeStewardshipFoundation + * + * Licensed under BSD + */ + +#include +#include + +#include "Queue_impl/PrivateQueue.h" +#include "VOMP.h" +#include "VOMP_Request_Handlers.h" + +//=========================== Local Fn Prototypes =========================== +void +resume_slaveVP( SlaveVP *procr, VOMPSemEnv *semEnv ); + +void +handleSemReq( VMSReqst *req, SlaveVP *requestingPr, VOMPSemEnv *semEnv ); + +void +handleDissipate( SlaveVP *requestingPr, VOMPSemEnv *semEnv ); + +void +handleCreate( VMSReqst *req, SlaveVP *requestingPr, VOMPSemEnv *semEnv ); + + +//============================== Assigner ================================== +// +/*For VOMP, assigning a slave simply takes the next work-unit off the + * ready-to-go work-unit queue and assigns it to the offered slot. + *If the ready-to-go work-unit queue is empty, then nothing to assign + * to the animation slot -- return FALSE to let Master loop know assigning + * that slot failed. + */ +SlaveVP * +VOMP__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot ) + { SlaveVP *assignPr; + VOMPSemEnv *semEnv; + int32 coreNum, slotNum; + + coreNum = slot->coreSlotIsOn; + slotNum = slot->slotIdx; + + semEnv = (VOMPSemEnv *)_semEnv; + + assignPr = readPrivQ( semEnv->readyVPQs[coreNum] ); + //Note, using a non-blocking queue -- it returns NULL if queue empty + if(!assignPr){ + assignPr = semEnv->idlePr[coreNum][slotNum]; + + if(semEnv->shutdownInitiated) { + assignPr = VMS_SS__create_shutdown_slave(); + } + //things that would normally happen in resume(), but these VPs never go there + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + assignPr->assignCount++; //Somewhere here! + Unit newu; + newu.vp = assignPr->slaveID; + newu.task = assignPr->assignCount; + addToListOfArrays(Unit,newu,semEnv->unitList); + + if (assignPr->assignCount > 1){ + Dependency newd; + newd.from_vp = assignPr->slaveID; + newd.from_task = assignPr->assignCount - 1; + newd.to_vp = assignPr->slaveID; + newd.to_task = assignPr->assignCount; + addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList); + } + #endif + } + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + if (assignPr) { + //assignPr->numTimesAssigned++; + Unit prev_in_slot = semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; + if(prev_in_slot.vp != 0){ + Dependency newd; + newd.from_vp = prev_in_slot.vp; + newd.from_task = prev_in_slot.task; + newd.to_vp = assignPr->slaveID; + newd.to_task = assignPr->assignCount; + addToListOfArrays(Dependency,newd,semEnv->hwArcs); + } + prev_in_slot.vp = assignPr->slaveID; + prev_in_slot.task = assignPr->assignCount; + semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = prev_in_slot; + } + #endif + return( assignPr ); + } + + +//=========================== Request Handler ============================= +// +/*Will get requests to send, to receive, and to create new processors. + * Upon send, check the hash to see if a receive is waiting. + * Upon receive, check hash to see if a send has already happened. + * When other is not there, put in. When other is there, the comm. + * completes, which means the receiver P gets assigned and + * picks up right after the receive request. So make the work-unit + * and put it into the queue of work-units ready to go. + * Other request is create a new Processor, with the function to run in the + * Processor, and initial data. + */ +void +VOMP__Request_Handler( SlaveVP *requestingPr, void *_semEnv ) + { VOMPSemEnv *semEnv; + VMSReqst *req; + + semEnv = (VOMPSemEnv *)_semEnv; + + req = VMS_PI__take_next_request_out_of( requestingPr ); + + while( req != NULL ) + { + switch( req->reqType ) + { case semantic: handleSemReq( req, requestingPr, semEnv); + break; + case createReq: handleCreate( req, requestingPr, semEnv); + break; + case dissipate: handleDissipate( requestingPr, semEnv); + break; + case VMSSemantic: VMS_PI__handle_VMSSemReq(req, requestingPr, semEnv, + (ResumeSlvFnPtr) &resume_slaveVP); + break; + default: + break; + } + + req = VMS_PI__take_next_request_out_of( requestingPr ); + } //while( req != NULL ) + + } + + +void +handleSemReq( VMSReqst *req, SlaveVP *reqPr, VOMPSemEnv *semEnv ) + { VOMPSemReq *semReq; + + semReq = VMS_PI__take_sem_reqst_from(req); + if( semReq == NULL ) return; + switch( semReq->reqType ) //sem handlers are all in other file + { + case send_type: handleSendType( semReq, semEnv); + break; + case send_from_to: handleSendFromTo( semReq, semEnv); + break; + case receive_type: handleReceiveType( semReq, semEnv); + break; + case receive_from_to: handleReceiveFromTo(semReq, semEnv); + break; + case transfer_to: handleTransferTo( semReq, semEnv); + break; + case transfer_out: handleTransferOut( semReq, semEnv); + break; + case malloc_req: handleMalloc( semReq, reqPr, semEnv); + break; + case free_req: handleFree( semReq, reqPr, semEnv); + break; + case singleton_fn_start: handleStartFnSingleton(semReq, reqPr, semEnv); + break; + case singleton_fn_end: handleEndFnSingleton( semReq, reqPr, semEnv); + break; + case singleton_data_start:handleStartDataSingleton(semReq,reqPr,semEnv); + break; + case singleton_data_end: handleEndDataSingleton(semReq, reqPr, semEnv); + break; + case atomic: handleAtomic( semReq, reqPr, semEnv); + break; + case trans_start: handleTransStart( semReq, reqPr, semEnv); + break; + case trans_end: handleTransEnd( semReq, reqPr, semEnv); + break; + } + } + + + +//=========================== VMS Request Handlers ============================== +// +void +handleDissipate( SlaveVP *requestingPr, VOMPSemEnv *semEnv ) + { + DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d",requestingPr->slaveID) + //free any semantic data allocated to the virt procr + VMS_PI__free( requestingPr->semanticData ); + + //Now, call VMS to free_all AppVP state -- stack and so on + VMS_PI__dissipate_slaveVP( requestingPr ); + + semEnv->numSlaveVP -= 1; + if( semEnv->numSlaveVP == 0 ) + { //no more work, so shutdown + semEnv->shutdownInitiated = TRUE; + //VMS_SS__shutdown(); + } + } + +/*Re-use this in the entry-point fn + */ + SlaveVP * +VOMP__create_procr_helper( TopLevelFnPtr fnPtr, void *initData, + VOMPSemEnv *semEnv, int32 coreToAssignOnto ) + { SlaveVP *newPr; + VOMPSemData *semData; + + //This is running in master, so use internal version + newPr = VMS_PI__create_slaveVP( fnPtr, initData ); + + semEnv->numSlaveVP += 1; + + semData = VMS_PI__malloc( sizeof(VOMPSemData) ); + semData->highestTransEntered = -1; + semData->lastTransEntered = NULL; + + newPr->semanticData = semData; + + //=================== Assign new processor to a core ===================== + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE + newPr->coreAnimatedBy = 0; + + #else + + if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES ) + { //out-of-range, so round-robin assignment + newPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr; + + if( semEnv->nextCoreToGetNewPr >= NUM_CORES - 1 ) + semEnv->nextCoreToGetNewPr = 0; + else + semEnv->nextCoreToGetNewPr += 1; + } + else //core num in-range, so use it + { newPr->coreAnimatedBy = coreToAssignOnto; + } + #endif + //======================================================================== + + return newPr; + } + +void +handleCreate( VMSReqst *req, SlaveVP *requestingPr, VOMPSemEnv *semEnv ) + { VOMPSemReq *semReq; + SlaveVP *newPr; + + + semReq = VMS_PI__take_sem_reqst_from( req ); + + newPr = VOMP__create_procr_helper( semReq->fnPtr, semReq->initData, semEnv, + semReq->coreToAssignOnto ); + + DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", requestingPr->slaveID, newPr->slaveID) + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = requestingPr->slaveID; + newd.from_task = requestingPr->assignCount; + newd.to_vp = newPr->slaveID; + newd.to_task = 1; + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); + #endif + + //For VOMP, caller needs ptr to created processor returned to it + requestingPr->dataRetFromReq = newPr; + + resume_slaveVP( newPr, semEnv ); + resume_slaveVP( requestingPr, semEnv ); + } + + +//=========================== Helper ============================== +void +resume_slaveVP( SlaveVP *procr, VOMPSemEnv *semEnv ) + { + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS +/* + int lastRecordIdx = procr->counter_history_array_info->numInArray -1; + CounterRecord* lastRecord = procr->counter_history[lastRecordIdx]; + saveLowTimeStampCountInto(lastRecord->unblocked_timestamp); +*/ + #endif + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + procr->assignCount++; //Somewhere here! + Unit newu; + newu.vp = procr->slaveID; + newu.task = procr->assignCount; + addToListOfArrays(Unit,newu,semEnv->unitList); + + if (procr->assignCount > 1){ + Dependency newd; + newd.from_vp = procr->slaveID; + newd.from_task = procr->assignCount - 1; + newd.to_vp = procr->slaveID; + newd.to_task = procr->assignCount; + addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList); + } + #endif + writePrivQ( procr, semEnv->readyVPQs[ procr->coreAnimatedBy] ); + } diff -r 000000000000 -r 67a3a05a39c0 VSs_Request_Handlers.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VSs_Request_Handlers.c Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,668 @@ +/* + * Copyright 2010 OpenSourceCodeStewardshipFoundation + * + * Licensed under BSD + */ + +#include +#include + +#include "VMS_impl/VMS.h" +#include "Queue_impl/PrivateQueue.h" +#include "Hash_impl/PrivateHash.h" +#include "VOMP.h" + + + +//=========================== Local Fn Prototypes =========================== +void +resume_slaveVP( SlaveVP *procr, VOMPSemEnv *semEnv ); + + + +//=========================================================================== +// Helpers + +/*Only clone the elements of req used in these reqst handlers + */ + VOMPSemReq * +cloneReq( VOMPSemReq *semReq ) + { VOMPSemReq *clonedReq; + + clonedReq = VMS_PI__malloc( sizeof(VOMPSemReq) ); + clonedReq->reqType = semReq->reqType; + clonedReq->sendPr = semReq->sendPr; + clonedReq->msg = semReq->msg; + clonedReq->nextReqInHashEntry = NULL; + + return clonedReq; + } + +HashEntry * +giveEntryElseInsertReqst( char *key, VOMPSemReq *semReq, + HashTable *commHashTbl ) + { HashEntry *entry; + VOMPSemReq *waitingReq; + + entry = getEntryFromTable( (char *)key, commHashTbl ); + if( entry == NULL ) + { //no waiting sends or receives, so add this request and exit + // note: have to clone the request because it's on stack of sender + addValueIntoTable( key, cloneReq( semReq ), commHashTbl ); + return NULL; + } + waitingReq = (VOMPSemReq *)entry->content; + if( waitingReq == NULL ) //might happen when last waiting gets paired + { //no waiting sends or receives, so add this request and exit + entry->content = semReq; + return NULL; + } + return entry; + } + + + + +//=========================================================================== +/*The semantic request has the receiving processor and the message type + * + *Note one value in this approach: without the extra VMS layer, + * the send and receive would happen in real time instead of virtual time, + * which would waste real time while one of them waited for other + * + *When successfully pair-up, transfer ownership of the sent data + * to the receiving processor + * + *Messages of a given Type have to be kept separate.. so need a separate + * entry in the hash table for each pair: receivePr, msgType + * + *Also, if same sender sends multiple before any get received, then need to + * stack the sends up -- even if a send waits until it's paired, several + * separate processors can send to the same receiver, and hashing on the + * receive processor, so they will stack up. + */ +void +handleSendType( VOMPSemReq *semReq, VOMPSemEnv *semEnv ) + { SlaveVP *sendPr, *receivePr; + int key[] = {0,0,0}; + VOMPSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf1(dbgRqstHdlr,"SendType request from processor %d",semReq->sendPr->slaveID) + + receivePr = semReq->receivePr; //For "send", know both send & recv procrs + sendPr = semReq->sendPr; + + //TODO: handle transfer of msg-locs ownership + //TODO: hash table implemented such that using "addEntry" or + // "addValue" to table causes the *value* in old entry to be + // *freed* -- this is bad. Want to stack up values in a linked + // list when multiple have the same key. + + //TODO: use a faster hash function -- see notes in intelligence gather + key[0] = (int)receivePr->slaveID; + key[1] = (int)(semReq->msgType); + //key[2] acts as the 0 that terminates the string + + entry = giveEntryElseInsertReqst( (char *)key, semReq, commHashTbl); + if( entry == NULL ) return; //was just inserted + + waitingReq = (VOMPSemReq *)entry->content; + + //At this point, know have waiting request(s) -- either sends or recv + //Note, can only have max of one receive waiting, and cannot have both + // sends and receives waiting (they would have paired off) + // but can have multiple sends from diff sending VPs, all same msg-type + if( waitingReq->reqType == send_type ) + { //waiting request is another send, so stack this up on list + // but first clone the sending request so it persists. + VOMPSemReq *clonedReq = cloneReq( semReq ); + clonedReq-> nextReqInHashEntry = waitingReq->nextReqInHashEntry; + waitingReq->nextReqInHashEntry = clonedReq; + DEBUG__printf2( dbgRqstHdlr, "linked requests: %p, %p ", clonedReq,\ + waitingReq ) + return; + } + else + { + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = sendPr->slaveID; + newd.from_task = sendPr->assignCount; + newd.to_vp = receivePr->slaveID; + newd.to_task = receivePr->assignCount +1; + //(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); + int32 groupId = semReq->msgType; + if(semEnv->ntonGroupsInfo->numInArray <= groupId){ + makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); + } + if(semEnv->ntonGroups[groupId] == NULL){ + semEnv->ntonGroups[groupId] = new_NtoN(groupId); + } + Unit u; + u.vp = sendPr->slaveID; + u.task = sendPr->assignCount; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); + u.vp = receivePr->slaveID; + u.task = receivePr->assignCount +1; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); + #endif + + //waiting request is a receive, so it pairs to this send + //First, remove the waiting receive request from the entry + entry->content = waitingReq->nextReqInHashEntry; + VMS_PI__free( waitingReq ); //Don't use contents -- so free it + + if( entry->content == NULL ) + { //TODO: mod hash table to double-link, so can delete entry from + // table without hashing the key and looking it up again + deleteEntryFromTable( entry->key, commHashTbl ); //frees hashEntry + } + + //attach msg that's in this send request to receiving procr + // when comes back from suspend will have msg in dataRetFromReq + receivePr->dataRetFromReq = semReq->msg; + + //bring both processors back from suspend + resume_slaveVP( sendPr, semEnv ); + resume_slaveVP( receivePr, semEnv ); + + return; + } + } + + +/*Looks like can make single handler for both sends.. + */ +//TODO: combine both send handlers into single handler +void +handleSendFromTo( VOMPSemReq *semReq, VOMPSemEnv *semEnv) + { SlaveVP *sendPr, *receivePr; + int key[] = {0,0,0}; + VOMPSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf2(dbgRqstHdlr,"SendFromTo request from processor %d to %d",semReq->sendPr->slaveID,semReq->receivePr->slaveID) + + receivePr = semReq->receivePr; //For "send", know both send & recv procrs + sendPr = semReq->sendPr; + + + key[0] = (int)receivePr->slaveID; + key[1] = (int)sendPr->slaveID; + //key[2] acts at the 0 that terminates the string + + entry = giveEntryElseInsertReqst( (char *)key, semReq, commHashTbl); + if( entry == NULL ) return; //was just inserted + + waitingReq = (VOMPSemReq *)entry->content; + + //At this point, know have waiting request(s) -- either sends or recv + if( waitingReq->reqType == send_from_to ) + { printf("\n ERROR: shouldn't be two send-from-tos waiting \n"); + } + else + { //waiting request is a receive, so it completes pair with this send + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = sendPr->slaveID; + newd.from_task = sendPr->assignCount; + newd.to_vp = receivePr->slaveID; + newd.to_task = receivePr->assignCount +1; + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); + #endif + //First, remove the waiting receive request from the entry + entry->content = waitingReq->nextReqInHashEntry; + VMS_PI__free( waitingReq ); //Don't use contents -- so free it + + //can only be one waiting req for "from-to" semantics + if( entry->content != NULL ) + { + printf("\nERROR in handleSendFromTo\n"); + } + deleteEntryFromTable( entry->key, commHashTbl ); //frees HashEntry + + //attach msg that's in this send request to receiving procr + // when comes back from suspend, will have msg in dataRetFromReq + receivePr->dataRetFromReq = semReq->msg; + + //bring both processors back from suspend + resume_slaveVP( sendPr, semEnv ); + resume_slaveVP( receivePr, semEnv ); + + return; + } + } + + + +//============================== Receives =========================== +// +/*Removed this one for now, because forces either a search or going to a + * two-level hash table, where one level the key is the receivePr, in the + * other level, the key is the type. + *So, each dest procr that either does a receive_type or that a send_type + * targets it, would have a hash table created just for it and placed + * into the first-level hash table entry for that receive procr. + *Then, doing a receive_type first looks up entry for receive procr in first + * table, gets the type-table out of that entry, and does a second lookup + * in the type-table. + *Doing a receive from-to looks up in the first table, gets the second table + * hashed on "from" procr. + *Doing a receive_any looks up in the first table, then looks to see if + * either of the hash tables have any entries -- would then have to do a + * linear search through the hash-table's array for the first non-empty + * spot + *Yuck. + * + *Alternatively, could keep two hash tables updated all the time -- one that + * does the receive_type and receive_from_to and a second that does + * receive_any -- would only hash the second table by the receive procr. + * When remove from one table, keep back-links to both tables, so can also + * quickly remove from other table. + *Cost is doing two hash-table lookups for every insert. + * If ever add receive_any, looking like this second option easier and even + * less costly. + */ +void +handleReceiveAny( VOMPSemReq *semReq, VOMPSemEnv *semEnv) + { + + } + + +void +handleReceiveType( VOMPSemReq *semReq, VOMPSemEnv *semEnv) + { SlaveVP *sendPr, *receivePr; + int key[] = {0,0,0}; + VOMPSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + receivePr = semReq->receivePr; + + DEBUG__printf1(dbgRqstHdlr,"ReceiveType request from processor %d",receivePr->slaveID) + + key[0] = (int)receivePr->slaveID; + key[1] = (int)(semReq->msgType); + //key[2] acts as the 0 that terminates the string + + + entry = giveEntryElseInsertReqst((char*)key, semReq, commHashTbl);//clones + if( entry == NULL ) return; //was just inserted + + waitingReq = (VOMPSemReq *)entry->content; //previously cloned by insert + + //At this point, know have waiting request(s) -- should be send(s) + if( waitingReq->reqType == send_type ) + { //waiting request is a send, so pair it with this receive + //first, remove the waiting send request from the list in entry + + entry->content = waitingReq->nextReqInHashEntry; + if( entry->content == NULL ) + { deleteEntryFromTable( entry->key, commHashTbl ); //frees HashEntry + } + + //attach msg that's in the send request to receiving procr + // when comes back from suspend, will have msg in dataRetFromReq + receivePr->dataRetFromReq = waitingReq->msg; + + //bring both processors back from suspend + sendPr = waitingReq->sendPr; + VMS_PI__free( waitingReq ); + + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = sendPr->slaveID; + newd.from_task = sendPr->assignCount; + newd.to_vp = receivePr->slaveID; + newd.to_task = receivePr->assignCount +1; + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); + int32 groupId = semReq->msgType; + if(semEnv->ntonGroupsInfo->numInArray <= groupId){ + makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); + } + if(semEnv->ntonGroups[groupId] == NULL){ + semEnv->ntonGroups[groupId] = new_NtoN(groupId); + } + Unit u; + u.vp = sendPr->slaveID; + u.task = sendPr->assignCount; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); + u.vp = receivePr->slaveID; + u.task = receivePr->assignCount +1; + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); + #endif + + resume_slaveVP( sendPr, semEnv ); + resume_slaveVP( receivePr, semEnv ); + + return; + } + printf("\nLang Impl Error: Should never be two waiting receives!\n"); + } + + +/* + */ +void +handleReceiveFromTo( VOMPSemReq *semReq, VOMPSemEnv *semEnv) + { SlaveVP *sendPr, *receivePr; + int key[] = {0,0,0}; + VOMPSemReq *waitingReq; + HashEntry *entry; + HashTable *commHashTbl = semEnv->commHashTbl; + + DEBUG__printf2(dbgRqstHdlr,"ReceiveFromTo %d : %d",semReq->sendPr->slaveID,semReq->receivePr->slaveID) + + receivePr = semReq->receivePr; + sendPr = semReq->sendPr; //for receive from-to, know send procr + + key[0] = (int)receivePr->slaveID; + key[1] = (int)sendPr->slaveID; + //key[2] acts at the 0 that terminates the string + + entry = giveEntryElseInsertReqst( (char *)key, semReq, commHashTbl); + if( entry == NULL ) return; //was just inserted + + waitingReq = (VOMPSemReq *)entry->content; + + //At this point, know have waiting request(s) -- should be send(s) + if( waitingReq->reqType == send_from_to ) + { //waiting request is a send, so pair it with this receive + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC + Dependency newd; + newd.from_vp = sendPr->slaveID; + newd.from_task = sendPr->assignCount; + newd.to_vp = receivePr->slaveID; + newd.to_task = receivePr->assignCount +1; + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); + #endif + //For from-to, should only ever be a single reqst waiting tobe paird + entry->content = waitingReq->nextReqInHashEntry; + if( entry->content != NULL ) printf("\nERROR in handleRecvFromTo\n"); + deleteEntryFromTable( entry->key, commHashTbl ); //frees entry too + + //attach msg that's in the send request to receiving procr + // when comes back from suspend, will have msg in dataRetFromReq + receivePr->dataRetFromReq = waitingReq->msg; + + //bring both processors back from suspend + sendPr = waitingReq->sendPr; + VMS_PI__free( waitingReq ); + + resume_slaveVP( sendPr, semEnv ); + resume_slaveVP( receivePr, semEnv ); + + return; + } + printf("\nLang Impl Error: Should never be two waiting receives!\n"); + } + + + +//=============================================== +void +handleTransferTo( VOMPSemReq *semReq, VOMPSemEnv *semEnv) + { + + } + +void +handleTransferOut( VOMPSemReq *semReq, VOMPSemEnv *semEnv) + { + + } + + +/* + */ +void +handleMalloc( VOMPSemReq *semReq, SlaveVP *requestingPr, VOMPSemEnv *semEnv ) + { void *ptr; + + DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingPr->slaveID) + + ptr = VMS_PI__malloc( semReq->sizeToMalloc ); + requestingPr->dataRetFromReq = ptr; + resume_slaveVP( requestingPr, semEnv ); + } + +/* + */ +void +handleFree( VOMPSemReq *semReq, SlaveVP *requestingPr, VOMPSemEnv *semEnv ) + { + DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingPr->slaveID) + VMS_PI__free( semReq->ptrToFree ); + resume_slaveVP( requestingPr, semEnv ); + } + + +//=========================================================================== +// +/*Uses ID as index into array of flags. If flag already set, resumes from + * end-label. Else, sets flag and resumes normally. + */ +void inline +handleStartSingleton_helper( VOMPSingleton *singleton, SlaveVP *reqstingPr, + VOMPSemEnv *semEnv ) + { + if( singleton->hasFinished ) + { //the code that sets the flag to true first sets the end instr addr + reqstingPr->dataRetFromReq = singleton->endInstrAddr; + resume_slaveVP( reqstingPr, semEnv ); + return; + } + else if( singleton->hasBeenStarted ) + { //singleton is in-progress in a diff slave, so wait for it to finish + writePrivQ(reqstingPr, singleton->waitQ ); + return; + } + else + { //hasn't been started, so this is the first attempt at the singleton + singleton->hasBeenStarted = TRUE; + reqstingPr->dataRetFromReq = 0x0; + resume_slaveVP( reqstingPr, semEnv ); + return; + } + } +void inline +handleStartFnSingleton( VOMPSemReq *semReq, SlaveVP *requestingPr, + VOMPSemEnv *semEnv ) + { VOMPSingleton *singleton; + DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingPr->slaveID) + + singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); + handleStartSingleton_helper( singleton, requestingPr, semEnv ); + } +void inline +handleStartDataSingleton( VOMPSemReq *semReq, SlaveVP *requestingPr, + VOMPSemEnv *semEnv ) + { VOMPSingleton *singleton; + + DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingPr->slaveID) + if( *(semReq->singletonPtrAddr) == NULL ) + { singleton = VMS_PI__malloc( sizeof(VOMPSingleton) ); + singleton->waitQ = makeVMSQ(); + singleton->endInstrAddr = 0x0; + singleton->hasBeenStarted = FALSE; + singleton->hasFinished = FALSE; + *(semReq->singletonPtrAddr) = singleton; + } + else + singleton = *(semReq->singletonPtrAddr); + handleStartSingleton_helper( singleton, requestingPr, semEnv ); + } + + +void inline +handleEndSingleton_helper( VOMPSingleton *singleton, SlaveVP *requestingPr, + VOMPSemEnv *semEnv ) + { PrivQueueStruc *waitQ; + int32 numWaiting, i; + SlaveVP *resumingPr; + + if( singleton->hasFinished ) + { //by definition, only one slave should ever be able to run end singleton + // so if this is true, is an error + ERROR1( "singleton code ran twice", requestingPr ); + } + + singleton->hasFinished = TRUE; + waitQ = singleton->waitQ; + numWaiting = numInPrivQ( waitQ ); + for( i = 0; i < numWaiting; i++ ) + { //they will resume inside start singleton, then jmp to end singleton + resumingPr = readPrivQ( waitQ ); + resumingPr->dataRetFromReq = singleton->endInstrAddr; + resume_slaveVP( resumingPr, semEnv ); + } + + resume_slaveVP( requestingPr, semEnv ); + +} +void inline +handleEndFnSingleton( VOMPSemReq *semReq, SlaveVP *requestingPr, + VOMPSemEnv *semEnv ) + { + VOMPSingleton *singleton; + + DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingPr->slaveID) + + singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); + handleEndSingleton_helper( singleton, requestingPr, semEnv ); + } +void inline +handleEndDataSingleton( VOMPSemReq *semReq, SlaveVP *requestingPr, + VOMPSemEnv *semEnv ) + { + VOMPSingleton *singleton; + + DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingPr->slaveID) + + singleton = *(semReq->singletonPtrAddr); + handleEndSingleton_helper( singleton, requestingPr, semEnv ); + } + + +/*This executes the function in the masterVP, take the function + * pointer out of the request and call it, then resume the VP. + */ +void +handleAtomic( VOMPSemReq *semReq, SlaveVP *requestingPr, VOMPSemEnv *semEnv ) + { + DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingPr->slaveID) + semReq->fnToExecInMaster( semReq->dataForFn ); + resume_slaveVP( requestingPr, semEnv ); + } + +/*First, it looks at the VP's semantic data, to see the highest transactionID + * that VP + * already has entered. If the current ID is not larger, it throws an + * exception stating a bug in the code. + *Otherwise it puts the current ID + * there, and adds the ID to a linked list of IDs entered -- the list is + * used to check that exits are properly ordered. + *Next it is uses transactionID as index into an array of transaction + * structures. + *If the "VP_currently_executing" field is non-null, then put requesting VP + * into queue in the struct. (At some point a holder will request + * end-transaction, which will take this VP from the queue and resume it.) + *If NULL, then write requesting into the field and resume. + */ +void +handleTransStart( VOMPSemReq *semReq, SlaveVP *requestingPr, + VOMPSemEnv *semEnv ) + { VOMPSemData *semData; + TransListElem *nextTransElem; + + DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingPr->slaveID) + + //check ordering of entering transactions is correct + semData = requestingPr->semanticData; + if( semData->highestTransEntered > semReq->transID ) + { //throw VMS exception, which shuts down VMS. + VMS_PI__throw_exception( "transID smaller than prev", requestingPr, NULL); + } + //add this trans ID to the list of transactions entered -- check when + // end a transaction + semData->highestTransEntered = semReq->transID; + nextTransElem = VMS_PI__malloc( sizeof(TransListElem) ); + nextTransElem->transID = semReq->transID; + nextTransElem->nextTrans = semData->lastTransEntered; + semData->lastTransEntered = nextTransElem; + + //get the structure for this transaction ID + VOMPTrans * + transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); + + if( transStruc->VPCurrentlyExecuting == NULL ) + { + transStruc->VPCurrentlyExecuting = requestingPr; + resume_slaveVP( requestingPr, semEnv ); + } + else + { //note, might make future things cleaner if save request with VP and + // add this trans ID to the linked list when gets out of queue. + // but don't need for now, and lazy.. + writePrivQ( requestingPr, transStruc->waitingVPQ ); + } + } + + +/*Use the trans ID to get the transaction structure from the array. + *Look at VP_currently_executing to be sure it's same as requesting VP. + * If different, throw an exception, stating there's a bug in the code. + *Next, take the first element off the list of entered transactions. + * Check to be sure the ending transaction is the same ID as the next on + * the list. If not, incorrectly nested so throw an exception. + * + *Next, get from the queue in the structure. + *If it's empty, set VP_currently_executing field to NULL and resume + * requesting VP. + *If get somethine, set VP_currently_executing to the VP from the queue, then + * resume both. + */ +void +handleTransEnd(VOMPSemReq *semReq, SlaveVP *requestingPr, VOMPSemEnv *semEnv) + { VOMPSemData *semData; + SlaveVP *waitingPr; + VOMPTrans *transStruc; + TransListElem *lastTrans; + + DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingPr->slaveID) + + transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); + + //make sure transaction ended in same VP as started it. + if( transStruc->VPCurrentlyExecuting != requestingPr ) + { + VMS_PI__throw_exception( "trans ended in diff VP", requestingPr, NULL ); + } + + //make sure nesting is correct -- last ID entered should == this ID + semData = requestingPr->semanticData; + lastTrans = semData->lastTransEntered; + if( lastTrans->transID != semReq->transID ) + { + VMS_PI__throw_exception( "trans incorrectly nested", requestingPr, NULL ); + } + + semData->lastTransEntered = semData->lastTransEntered->nextTrans; + + + waitingPr = readPrivQ( transStruc->waitingVPQ ); + transStruc->VPCurrentlyExecuting = waitingPr; + + if( waitingPr != NULL ) + resume_slaveVP( waitingPr, semEnv ); + + resume_slaveVP( requestingPr, semEnv ); + } diff -r 000000000000 -r 67a3a05a39c0 VSs_Request_Handlers.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VSs_Request_Handlers.h Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright 2009 OpenSourceStewardshipFoundation.org + * Licensed under GNU General Public License version 2 + * + * Author: seanhalle@yahoo.com + * + */ + +#ifndef _VOMP_REQ_H +#define _VOMP_REQ_H + +#include "VOMP.h" + +/*This header defines everything specific to the VOMP semantic plug-in + */ + +inline void +handleSendType( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleSendFromTo( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleReceiveAny( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleReceiveType( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleReceiveFromTo( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleTransferTo( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleTransferOut( VOMPSemReq *semReq, VOMPSemEnv *semEnv); +inline void +handleMalloc( VOMPSemReq *semReq, SlaveVP *requestingSlv, VOMPSemEnv *semEnv); +inline void +handleFree( VOMPSemReq *semReq, SlaveVP *requestingSlv, VOMPSemEnv *semEnv ); +inline void +handleTransEnd(VOMPSemReq *semReq, SlaveVP *requestingSlv, VOMPSemEnv*semEnv); +inline void +handleTransStart( VOMPSemReq *semReq, SlaveVP *requestingSlv, + VOMPSemEnv *semEnv ); +inline void +handleAtomic( VOMPSemReq *semReq, SlaveVP *requestingSlv, VOMPSemEnv *semEnv); +inline void +handleStartFnSingleton( VOMPSemReq *semReq, SlaveVP *reqstingSlv, + VOMPSemEnv *semEnv ); +inline void +handleEndFnSingleton( VOMPSemReq *semReq, SlaveVP *requestingSlv, + VOMPSemEnv *semEnv ); +inline void +handleStartDataSingleton( VOMPSemReq *semReq, SlaveVP *reqstingSlv, + VOMPSemEnv *semEnv ); +inline void +handleEndDataSingleton( VOMPSemReq *semReq, SlaveVP *requestingSlv, + VOMPSemEnv *semEnv ); + +#endif /* _VOMP_REQ_H */ + diff -r 000000000000 -r 67a3a05a39c0 VSs_singleton_asm.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VSs_singleton_asm.s Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,21 @@ + +//Assembly code takes the return addr off the stack and saves +// into the singleton. The first field in the singleton is the +// "endInstrAddr" field, and the return addr is at 0x4(%ebp) +.globl asm_save_ret_to_singleton +asm_save_ret_to_singleton: + movq 0x8(%rbp), %rax #get ret address, ebp is the same as in the calling function + movq %rax, (%rdi) #write ret addr to endInstrAddr field + ret + + +//Assembly code changes the return addr on the stack to the one +// saved into the singleton by the end-singleton-fn +//The stack's return addr is at 0x4(%%ebp) +.globl asm_write_ret_from_singleton +asm_write_ret_from_singleton: + movq (%rdi), %rax #get endInstrAddr field + movq %rax, 0x8(%rbp) #write return addr to the stack of the caller + ret + + diff -r 000000000000 -r 67a3a05a39c0 __brch__default --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/__brch__default Wed May 23 13:17:07 2012 -0700 @@ -0,0 +1,4 @@ +This branch is for the project structure defined Jan 2012.. the #includes reflect this directory structure. + +More importantly, the MC_shared version of VMS requires a separat malloc implemeted by VMS code.. so this branch has modified the library to use the VMS-specific malloc. +