seanhalle@230: /* seanhalle@230: * Copyright 2010 OpenSourceStewardshipFoundation seanhalle@230: * seanhalle@230: * Licensed under BSD seanhalle@230: */ seanhalle@230: seanhalle@230: seanhalle@230: seanhalle@230: #include seanhalle@230: #include seanhalle@230: seanhalle@230: #include "VMS.h" seanhalle@230: seanhalle@230: seanhalle@230: //========================= Local Fn Prototypes ============================= seanhalle@230: void inline seanhalle@230: stealWorkInto( SchedSlot *currSlot, VMSQueueStruc *readyToAnimateQ, seanhalle@230: SlaveVP *masterVP ); seanhalle@230: seanhalle@230: //=========================================================================== seanhalle@230: seanhalle@230: seanhalle@230: seanhalle@230: /*The animationMaster embodies most of the animator of the language. The seanhalle@230: * animator is what emodies the behavior of language constructs. seanhalle@230: * As such, it is the animationMaster, in combination with the plugin seanhalle@230: * functions, that make the language constructs do their behavior. seanhalle@230: * seanhalle@230: *Within the code, this is the top-level-function of the masterVPs, and seanhalle@230: * runs when the coreController has no more slave VPs. It's job is to seanhalle@230: * refill the animation slots with slaves. seanhalle@230: * seanhalle@230: *To do this, it scans the animation slots for just-completed slaves. seanhalle@230: * Each of these has a request in it. So, the master hands each to the seanhalle@230: * plugin's request handler. seanhalle@230: *Each request represents a language construct that has been encountered seanhalle@230: * by the application code in the slave. Passing the request to the seanhalle@230: * request handler is how that language construct's behavior gets invoked. seanhalle@230: * The request handler then performs the actions of the construct's seanhalle@230: * behavior. So, the request handler encodes the behavior of the seanhalle@230: * language's parallelism constructs, and performs that when the master seanhalle@230: * hands it a slave containing a request to perform that construct. seanhalle@230: * seanhalle@230: *On a shared-memory machine, the behavior of parallelism constructs seanhalle@230: * equals control, over order of execution of code. Hence, the behavior seanhalle@230: * of the language constructs performed by the request handler is to seanhalle@230: * choose the order that slaves get animated, and thereby control the seanhalle@230: * order that application code in the slaves executes. seanhalle@230: * seanhalle@230: *To control order of animation of slaves, the request handler has a seanhalle@230: * semantic environment that holds data structures used to hold slaves seanhalle@230: * and choose when they're ready to be animated. seanhalle@230: * seanhalle@230: *Once a slave is marked as ready to be animated by the request handler, seanhalle@230: * it is the second plugin function, the Assigner, which chooses the core seanhalle@230: * the slave gets assigned to for animation. Hence, the Assigner doesn't seanhalle@230: * perform any of the semantic behavior of language constructs, rather seanhalle@230: * it gives the language a chance to improve performance. The performance seanhalle@230: * of application code is strongly related to communication between seanhalle@230: * cores. On shared-memory machines, communication is caused during seanhalle@230: * execution of code, by memory accesses, and how much depends on contents seanhalle@230: * of caches connected to the core executing the code. So, the placement seanhalle@230: * of slaves determines the communication caused during execution of the seanhalle@230: * slave's code. seanhalle@230: *The point of the Assigner, then, is to use application information during seanhalle@230: * execution of the program, to make choices about slave placement onto seanhalle@230: * cores, with the aim to put slaves close to caches containing the data seanhalle@230: * used by the slave's code. seanhalle@230: * seanhalle@230: *========================================================================== seanhalle@230: *In summary, the animationMaster scans the slots, finds slaves seanhalle@230: * just-finished, which hold requests, pass those to the request handler, seanhalle@230: * along with the semantic environment, and the request handler then manages seanhalle@230: * the structures in the semantic env, which controls the order of seanhalle@230: * animation of slaves, and so embodies the behavior of the language seanhalle@230: * constructs. seanhalle@230: *The animationMaster then rescans the slots, offering each empty one to seanhalle@230: * the Assigner, along with the semantic environment. The Assigner chooses seanhalle@230: * among the ready slaves in the semantic Env, finding the one best suited seanhalle@230: * to be animated by that slot's associated core. seanhalle@230: * seanhalle@230: *========================================================================== seanhalle@230: *Implementation Details: seanhalle@230: * seanhalle@230: *There is a separate masterVP for each core, but a single semantic seanhalle@230: * environment shared by all cores. Each core also has its own scheduling seanhalle@230: * slots, which are used to communicate slaves between animationMaster and seanhalle@230: * coreController. There is only one global variable, _VMSMasterEnv, which seanhalle@230: * holds the semantic env and other things shared by the different seanhalle@230: * masterVPs. The request handler and Assigner are registered with seanhalle@230: * the animationMaster by the language's init function, and a pointer to seanhalle@230: * each is in the _VMSMasterEnv. (There are also some pthread related global seanhalle@230: * vars, but they're only used during init of VMS). seanhalle@230: *VMS gains control over the cores by essentially "turning off" the OS's seanhalle@230: * scheduler, using pthread pin-to-core commands. seanhalle@230: * seanhalle@230: *The masterVPs are created during init, with this animationMaster as their seanhalle@230: * top level function. The masterVPs use the same SlaveVP data structure, seanhalle@230: * even though they're not slave VPs. seanhalle@230: *A "seed slave" is also created during init -- this is equivalent to the seanhalle@230: * "main" function in C, and acts as the entry-point to the VMS-language- seanhalle@230: * based application. seanhalle@230: *The masterVPs shared a single system-wide master-lock, so only one seanhalle@230: * masterVP may be animated at a time. seanhalle@230: *The core controllers access _VMSMasterEnv to get the masterVP, and when seanhalle@230: * they start, the slots are all empty, so they run their associated core's seanhalle@230: * masterVP. The first of those to get the master lock sees the seed slave seanhalle@230: * in the shared semantic environment, so when it runs the Assigner, that seanhalle@230: * returns the seed slave, which the animationMaster puts into a scheduling seanhalle@230: * slot then switches to the core controller. That then switches the core seanhalle@230: * over to the seed slave, which then proceeds to execute language seanhalle@230: * constructs to create more slaves, and so on. Each of those constructs seanhalle@230: * causes the seed slave to suspend, switching over to the core controller, seanhalle@230: * which eventually switches to the masterVP, which executes the seanhalle@230: * request handler, which uses VMS primitives to carry out the creation of seanhalle@230: * new slave VPs, which are marked as ready for the Assigner, and so on.. seanhalle@230: * seanhalle@230: *On animation slots, and system behavior: seanhalle@230: * A request may linger in a animation slot for a long time while seanhalle@230: * the slaves in the other slots are animated. This only becomes a problem seanhalle@230: * when such a request is a choke-point in the constraints, and is needed seanhalle@230: * to free work for *other* cores. To reduce this occurance, the number seanhalle@230: * of animation slots should be kept low. In balance, having multiple seanhalle@230: * animation slots amortizes the overhead of switching to the masterVP and seanhalle@230: * executing the animationMaster code, which drives for more than one. In seanhalle@230: * practice, the best balance should be discovered by profiling. seanhalle@230: */ seanhalle@230: void animationMaster( void *initData, SlaveVP *masterVP ) seanhalle@230: { seanhalle@230: //Used while scanning and filling animation slots seanhalle@230: int32 slotIdx, numSlotsFilled; seanhalle@230: SchedSlot *currSlot, **schedSlots; seanhalle@230: SlaveVP *assignedSlaveVP; //the slave chosen by the assigner seanhalle@230: seanhalle@230: //Local copies, for performance seanhalle@230: MasterEnv *masterEnv; seanhalle@230: SlaveAssigner slaveAssigner; seanhalle@230: RequestHandler requestHandler; seanhalle@230: void *semanticEnv; seanhalle@230: int32 thisCoresIdx; seanhalle@230: seanhalle@230: //======================== Initializations ======================== seanhalle@230: masterEnv = (MasterEnv*)_VMSMasterEnv; seanhalle@230: seanhalle@230: thisCoresIdx = masterVP->coreAnimatedBy; seanhalle@230: schedSlots = masterEnv->allSchedSlots[thisCoresIdx]; seanhalle@230: seanhalle@230: requestHandler = masterEnv->requestHandler; seanhalle@230: slaveAssigner = masterEnv->slaveAssigner; seanhalle@230: semanticEnv = masterEnv->semanticEnv; seanhalle@230: seanhalle@230: seanhalle@230: //======================== animationMaster ======================== seanhalle@230: while(1){ seanhalle@230: seanhalle@230: MEAS__Capture_Pre_Master_Point seanhalle@230: seanhalle@230: //Scan the animation slots seanhalle@230: numSlotsFilled = 0; seanhalle@230: for( slotIdx = 0; slotIdx < NUM_SCHED_SLOTS; slotIdx++) seanhalle@230: { seanhalle@230: currSlot = schedSlots[ slotIdx ]; seanhalle@230: seanhalle@230: //Check if newly-done slave in slot, which will need request handld seanhalle@230: if( currSlot->workIsDone ) seanhalle@230: { seanhalle@230: currSlot->workIsDone = FALSE; seanhalle@230: currSlot->needsSlaveAssigned = TRUE; seanhalle@230: seanhalle@230: MEAS__startReqHdlr; seanhalle@230: seanhalle@230: //process the requests made by the slave (held inside slave struc) seanhalle@230: (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv ); seanhalle@230: seanhalle@230: MEAS__endReqHdlr; seanhalle@230: } seanhalle@230: //If slot empty, hand to Assigner to fill with a slave seanhalle@230: if( currSlot->needsSlaveAssigned ) seanhalle@230: { //Call plugin's Assigner to give slot a new slave seanhalle@230: assignedSlaveVP = seanhalle@230: (*slaveAssigner)( semanticEnv, currSlot ); seanhalle@230: seanhalle@230: //put the chosen slave into slot, and adjust flags and state seanhalle@230: if( assignedSlaveVP != NULL ) seanhalle@230: { currSlot->slaveAssignedToSlot = assignedSlaveVP; seanhalle@233: assignedSlaveVP->schedSlotAssignedTo = currSlot; seanhalle@230: currSlot->needsSlaveAssigned = FALSE; seanhalle@230: numSlotsFilled += 1; seanhalle@230: } seanhalle@230: } seanhalle@230: } seanhalle@230: seanhalle@230: MEAS__Capture_Post_Master_Point; seanhalle@230: seanhalle@231: masterSwitchToCoreCtlr( masterVP ); seanhalle@230: flushRegisters(); seanhalle@232: }//while(1) seanhalle@230: } seanhalle@230: