annotate SchedulingMaster.c @ 228:125f0f90a0d3

integrating holistic model in common ancestor - not finished yet
author Nina Engelhardt <nengel@mailbox.tu-berlin.de>
date Thu, 15 Mar 2012 18:28:29 +0100
parents b0b93147adfb
children
rev   line source
seanhalle@222 1 /*
seanhalle@222 2 * Copyright 2010 OpenSourceStewardshipFoundation
seanhalle@222 3 *
seanhalle@222 4 * Licensed under BSD
seanhalle@222 5 */
seanhalle@222 6
seanhalle@222 7
seanhalle@222 8
seanhalle@222 9 #include <stdio.h>
seanhalle@222 10 #include <stddef.h>
seanhalle@222 11
seanhalle@222 12 #include "VMS.h"
seanhalle@222 13
seanhalle@222 14
seanhalle@222 15 //===========================================================================
seanhalle@222 16 void inline
seanhalle@222 17 stealWorkInto( SchedSlot *currSlot, VMSQueueStruc *readyToAnimateQ,
seanhalle@222 18 SlaveVP *masterVP );
seanhalle@222 19
seanhalle@222 20 //===========================================================================
seanhalle@222 21
seanhalle@222 22
seanhalle@222 23
seanhalle@222 24 /*This code is animated by the virtual Master processor.
seanhalle@222 25 *
seanhalle@222 26 *Polls each sched slot exactly once, hands any requests made by a newly
seanhalle@222 27 * done slave to the "request handler" plug-in function
seanhalle@222 28 *
seanhalle@223 29 *Any slots that need a Slv assigned are given to the "assign"
seanhalle@222 30 * plug-in function, which tries to assign a Slv (slave) to it.
seanhalle@222 31 *
seanhalle@223 32 *When all slots needing a processor have been given to the assign plug-in,
seanhalle@223 33 * a fraction of the slaves successfully assigned are put into the
seanhalle@222 34 * work queue, then a continuation of this function is put in, then the rest
seanhalle@223 35 * of the Slvs that were successfully assigned.
seanhalle@222 36 *
seanhalle@222 37 *The first thing the continuation does is busy-wait until the previous
seanhalle@222 38 * animation completes. This is because an (unlikely) continuation may
seanhalle@222 39 * sneak through queue before previous continuation is done putting second
seanhalle@223 40 * part of assigned slaves in, which is the only race condition.
seanhalle@222 41 *
seanhalle@222 42 */
seanhalle@222 43
seanhalle@222 44 /*May 29, 2010 -- birth a Master during init so that first core controller to
seanhalle@222 45 * start running gets it and does all the stuff for a newly born --
seanhalle@222 46 * from then on, will be doing continuation, but do suspension self
seanhalle@222 47 * directly at end of master loop
seanhalle@222 48 *So VMS_WL__init just births the master virtual processor same way it births
seanhalle@222 49 * all the others -- then does any extra setup needed and puts it into the
seanhalle@222 50 * work queue.
seanhalle@222 51 *However means have to make masterEnv a global static volatile the same way
seanhalle@222 52 * did with readyToAnimateQ in core controller. -- for performance, put the
seanhalle@222 53 * jump to the core controller directly in here, and have it directly jump back.
seanhalle@222 54 *
seanhalle@222 55 *
seanhalle@222 56 *Aug 18, 2010 -- Going to a separate MasterVP for each core, to see if this
seanhalle@222 57 * avoids the suspected bug in the system stack that causes bizarre faults
seanhalle@222 58 * at random places in the system code.
seanhalle@222 59 *
seanhalle@222 60 *So, this function is coupled to each of the MasterVPs, -- meaning this
seanhalle@222 61 * function can't rely on a particular stack and frame -- each MasterVP that
seanhalle@222 62 * animates this function has a different one.
seanhalle@222 63 *
seanhalle@222 64 *At this point, the schedulingMaster does not write itself into the queue anymore,
seanhalle@222 65 * instead, the coreCtlr acquires the masterLock when it has nothing to
seanhalle@222 66 * animate, and then animates its own schedulingMaster. However, still try to put
seanhalle@222 67 * several AppSlvs into the queue to amortize the startup cost of switching
seanhalle@222 68 * to the MasterVP. Note, don't have to worry about latency of requests much
seanhalle@222 69 * because most requests generate work for same core -- only latency issue
seanhalle@222 70 * is case when other cores starved and one core's requests generate work
seanhalle@222 71 * for them -- so keep max in queue to 3 or 4..
seanhalle@222 72 */
seanhalle@222 73 void schedulingMaster( void *initData, SlaveVP *animatingSlv )
seanhalle@222 74 {
seanhalle@222 75 int32 slotIdx, numSlotsFilled;
seanhalle@222 76 SlaveVP *schedSlaveVP;
seanhalle@222 77 SchedSlot *currSlot, **schedSlots;
seanhalle@222 78 MasterEnv *masterEnv;
seanhalle@222 79 VMSQueueStruc *readyToAnimateQ;
seanhalle@222 80
seanhalle@223 81 SlaveAssigner slaveAssigner;
seanhalle@222 82 RequestHandler requestHandler;
seanhalle@222 83 void *semanticEnv;
seanhalle@222 84
seanhalle@222 85 int32 thisCoresIdx;
seanhalle@222 86 SlaveVP *masterVP;
seanhalle@222 87 volatile SlaveVP *volatileMasterVP;
seanhalle@222 88
seanhalle@222 89 volatileMasterVP = animatingSlv;
seanhalle@222 90 masterVP = (SlaveVP*)volatileMasterVP; //used to force re-define after jmp
seanhalle@222 91
seanhalle@222 92 //First animation of each MasterVP will in turn animate this part
seanhalle@222 93 // of setup code.. (Slv creator sets up the stack as if this function
seanhalle@222 94 // was called normally, but actually get here by jmp)
seanhalle@222 95 //So, setup values about stack ptr, jmp pt and all that
seanhalle@222 96 //masterVP->resumeInstrPtr = &&schedulingMasterStartPt;
seanhalle@222 97
seanhalle@222 98
seanhalle@222 99 //Note, got rid of writing the stack and frame ptr up here, because
seanhalle@222 100 // only one
seanhalle@222 101 // core can ever animate a given MasterVP, so don't need to communicate
seanhalle@222 102 // new frame and stack ptr to the MasterVP storage before a second
seanhalle@222 103 // version of that MasterVP can get animated on a different core.
seanhalle@222 104 //Also got rid of the busy-wait.
seanhalle@222 105
seanhalle@222 106
seanhalle@222 107 //schedulingMasterStartPt:
seanhalle@222 108 while(1){
seanhalle@222 109
seanhalle@222 110 MEAS__Capture_Pre_Master_Point
seanhalle@222 111
seanhalle@222 112 masterEnv = (MasterEnv*)_VMSMasterEnv;
seanhalle@222 113
seanhalle@222 114 //GCC may optimize so doesn't always re-define from frame-storage
seanhalle@222 115 masterVP = (SlaveVP*)volatileMasterVP; //just to make sure after jmp
seanhalle@222 116 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@222 117 schedSlots = masterEnv->allSchedSlots[thisCoresIdx];
seanhalle@222 118
seanhalle@222 119 requestHandler = masterEnv->requestHandler;
seanhalle@222 120 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@222 121 semanticEnv = masterEnv->semanticEnv;
seanhalle@222 122
seanhalle@222 123
seanhalle@222 124 //Poll each slot's Done flag
seanhalle@222 125 numSlotsFilled = 0;
seanhalle@222 126 for( slotIdx = 0; slotIdx < NUM_SCHED_SLOTS; slotIdx++)
seanhalle@222 127 {
seanhalle@222 128 currSlot = schedSlots[ slotIdx ];
seanhalle@222 129
seanhalle@222 130 if( currSlot->workIsDone )
seanhalle@222 131 {
seanhalle@222 132 currSlot->workIsDone = FALSE;
seanhalle@222 133 currSlot->needsSlaveAssigned = TRUE;
seanhalle@222 134
seanhalle@222 135 MEAS__startReqHdlr;
seanhalle@222 136
seanhalle@222 137 //process the requests made by the slave (held inside slave struc)
seanhalle@222 138 (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv );
seanhalle@222 139
seanhalle@222 140 MEAS__endReqHdlr;
seanhalle@222 141 }
seanhalle@222 142 if( currSlot->needsSlaveAssigned )
seanhalle@222 143 { //give slot a new Slv
seanhalle@222 144 schedSlaveVP =
seanhalle@223 145 (*slaveAssigner)( semanticEnv, thisCoresIdx, currSlot );
seanhalle@222 146
seanhalle@222 147 if( schedSlaveVP != NULL )
seanhalle@222 148 { currSlot->slaveAssignedToSlot = schedSlaveVP;
seanhalle@222 149 schedSlaveVP->schedSlot = currSlot;
seanhalle@222 150 currSlot->needsSlaveAssigned = FALSE;
seanhalle@222 151 numSlotsFilled += 1;
seanhalle@222 152 }
seanhalle@222 153 }
seanhalle@222 154 }
seanhalle@222 155
seanhalle@222 156
seanhalle@222 157 #ifdef SYS__TURN_ON_WORK_STEALING
seanhalle@222 158 //If no slots filled, means no more work, look for work to steal.
seanhalle@222 159 if( numSlotsFilled == 0 )
seanhalle@222 160 { gateProtected_stealWorkInto( currSlot, readyToAnimateQ, masterVP );
seanhalle@222 161 }
seanhalle@222 162 #endif
seanhalle@222 163
seanhalle@222 164 MEAS__Capture_Post_Master_Point;
seanhalle@222 165
seanhalle@222 166 masterSwitchToCoreCtlr(animatingSlv);
seanhalle@222 167 flushRegisters();
seanhalle@222 168 }//MasterLoop
seanhalle@222 169
seanhalle@222 170
seanhalle@222 171 }
seanhalle@222 172
seanhalle@222 173
seanhalle@222 174
seanhalle@222 175 /*This has a race condition -- the coreloops are accessing their own queues
seanhalle@222 176 * at the same time that this work-stealer on a different core is trying to
seanhalle@222 177 */
seanhalle@222 178 void inline
seanhalle@222 179 stealWorkInto( SchedSlot *currSlot, VMSQueueStruc *readyToAnimateQ,
seanhalle@222 180 SlaveVP *masterVP )
seanhalle@222 181 {
seanhalle@222 182 SlaveVP *stolenSlv;
seanhalle@222 183 int32 coreIdx, i;
seanhalle@222 184 VMSQueueStruc *currQ;
seanhalle@222 185
seanhalle@222 186 stolenSlv = NULL;
seanhalle@222 187 coreIdx = masterVP->coreAnimatedBy;
seanhalle@222 188 for( i = 0; i < NUM_CORES -1; i++ )
seanhalle@222 189 {
seanhalle@222 190 if( coreIdx >= NUM_CORES -1 )
seanhalle@222 191 { coreIdx = 0;
seanhalle@222 192 }
seanhalle@222 193 else
seanhalle@222 194 { coreIdx++;
seanhalle@222 195 }
seanhalle@225 196 //TODO: fix this for coreCtlr scans slots
seanhalle@225 197 // currQ = _VMSMasterEnv->readyToAnimateQs[coreIdx];
seanhalle@222 198 if( numInVMSQ( currQ ) > 0 )
seanhalle@222 199 { stolenSlv = readVMSQ (currQ );
seanhalle@222 200 break;
seanhalle@222 201 }
seanhalle@222 202 }
seanhalle@222 203
seanhalle@222 204 if( stolenSlv != NULL )
seanhalle@222 205 { currSlot->slaveAssignedToSlot = stolenSlv;
seanhalle@222 206 stolenSlv->schedSlot = currSlot;
seanhalle@222 207 currSlot->needsSlaveAssigned = FALSE;
seanhalle@222 208
seanhalle@222 209 writeVMSQ( stolenSlv, readyToAnimateQ );
seanhalle@222 210 }
seanhalle@222 211 }
seanhalle@222 212
seanhalle@222 213 /*This algorithm makes the common case fast. Make the coreloop passive,
seanhalle@222 214 * and show its progress. Make the stealer control a gate that coreloop
seanhalle@222 215 * has to pass.
seanhalle@222 216 *To avoid interference, only one stealer at a time. Use a global
seanhalle@222 217 * stealer-lock.
seanhalle@222 218 *
seanhalle@222 219 *The pattern is based on a gate -- stealer shuts the gate, then monitors
seanhalle@222 220 * to be sure any already past make it all the way out, before starting.
seanhalle@222 221 *So, have a "progress" measure just before the gate, then have two after it,
seanhalle@222 222 * one is in a "waiting room" outside the gate, the other is at the exit.
seanhalle@222 223 *Then, the stealer first shuts the gate, then checks the progress measure
seanhalle@222 224 * outside it, then looks to see if the progress measure at the exit is the
seanhalle@222 225 * same. If yes, it knows the protected area is empty 'cause no other way
seanhalle@222 226 * to get in and the last to get in also exited.
seanhalle@222 227 *If the progress measure at the exit is not the same, then the stealer goes
seanhalle@222 228 * into a loop checking both the waiting-area and the exit progress-measures
seanhalle@222 229 * until one of them shows the same as the measure outside the gate. Might
seanhalle@222 230 * as well re-read the measure outside the gate each go around, just to be
seanhalle@222 231 * sure. It is guaranteed that one of the two will eventually match the one
seanhalle@222 232 * outside the gate.
seanhalle@222 233 *
seanhalle@222 234 *Here's an informal proof of correctness:
seanhalle@222 235 *The gate can be closed at any point, and have only four cases:
seanhalle@222 236 * 1) coreloop made it past the gate-closing but not yet past the exit
seanhalle@222 237 * 2) coreloop made it past the pre-gate progress update but not yet past
seanhalle@222 238 * the gate,
seanhalle@222 239 * 3) coreloop is right before the pre-gate update
seanhalle@222 240 * 4) coreloop is past the exit and far from the pre-gate update.
seanhalle@222 241 *
seanhalle@222 242 * Covering the cases in reverse order,
seanhalle@222 243 * 4) is not a problem -- stealer will read pre-gate progress, see that it
seanhalle@222 244 * matches exit progress, and the gate is closed, so stealer can proceed.
seanhalle@222 245 * 3) stealer will read pre-gate progress just after coreloop updates it..
seanhalle@222 246 * so stealer goes into a loop until the coreloop causes wait-progress
seanhalle@222 247 * to match pre-gate progress, so then stealer can proceed
seanhalle@222 248 * 2) same as 3..
seanhalle@222 249 * 1) stealer reads pre-gate progress, sees that it's different than exit,
seanhalle@222 250 * so goes into loop until exit matches pre-gate, now it knows coreloop
seanhalle@222 251 * is not in protected and cannot get back in, so can proceed.
seanhalle@222 252 *
seanhalle@222 253 *Implementation for the stealer:
seanhalle@222 254 *
seanhalle@222 255 *First, acquire the stealer lock -- only cores with no work to do will
seanhalle@222 256 * compete to steal, so not a big performance penalty having only one --
seanhalle@222 257 * will rarely have multiple stealers in a system with plenty of work -- and
seanhalle@222 258 * in a system with little work, it doesn't matter.
seanhalle@222 259 *
seanhalle@222 260 *Note, have single-reader, single-writer pattern for all variables used to
seanhalle@222 261 * communicate between stealer and victims
seanhalle@222 262 *
seanhalle@222 263 *So, scan the queues of the core controllers, until find non-empty. Each core
seanhalle@222 264 * has its own list that it scans. The list goes in order from closest to
seanhalle@222 265 * furthest core, so it steals first from close cores. Later can add
seanhalle@222 266 * taking info from the app about overlapping footprints, and scan all the
seanhalle@222 267 * others then choose work with the most footprint overlap with the contents
seanhalle@222 268 * of this core's cache.
seanhalle@222 269 *
seanhalle@222 270 *Now, have a victim want to take work from. So, shut the gate in that
seanhalle@222 271 * coreloop, by setting the "gate closed" var on its stack to TRUE.
seanhalle@222 272 *Then, read the core's pre-gate progress and compare to the core's exit
seanhalle@222 273 * progress.
seanhalle@222 274 *If same, can proceed to take work from the coreloop's queue. When done,
seanhalle@222 275 * write FALSE to gate closed var.
seanhalle@222 276 *If different, then enter a loop that reads the pre-gate progress, then
seanhalle@222 277 * compares to exit progress then to wait progress. When one of two
seanhalle@222 278 * matches, proceed. Take work from the coreloop's queue. When done,
seanhalle@222 279 * write FALSE to the gate closed var.
seanhalle@222 280 *
seanhalle@222 281 */
seanhalle@222 282 void inline
seanhalle@222 283 gateProtected_stealWorkInto( SchedSlot *currSlot,
seanhalle@222 284 VMSQueueStruc *myReadyToAnimateQ,
seanhalle@222 285 SlaveVP *masterVP )
seanhalle@222 286 {
seanhalle@222 287 SlaveVP *stolenSlv;
seanhalle@222 288 int32 coreIdx, i, haveAVictim, gotLock;
seanhalle@222 289 VMSQueueStruc *victimsQ;
seanhalle@222 290
seanhalle@222 291 volatile GateStruc *vicGate;
seanhalle@222 292 int32 coreMightBeInProtected;
seanhalle@222 293
seanhalle@222 294
seanhalle@222 295
seanhalle@222 296 //see if any other cores have work available to steal
seanhalle@222 297 haveAVictim = FALSE;
seanhalle@222 298 coreIdx = masterVP->coreAnimatedBy;
seanhalle@222 299 for( i = 0; i < NUM_CORES -1; i++ )
seanhalle@222 300 {
seanhalle@222 301 if( coreIdx >= NUM_CORES -1 )
seanhalle@222 302 { coreIdx = 0;
seanhalle@222 303 }
seanhalle@222 304 else
seanhalle@222 305 { coreIdx++;
seanhalle@222 306 }
seanhalle@225 307 //TODO: fix this for coreCtlr scans slots
seanhalle@225 308 // victimsQ = _VMSMasterEnv->readyToAnimateQs[coreIdx];
seanhalle@222 309 if( numInVMSQ( victimsQ ) > 0 )
seanhalle@222 310 { haveAVictim = TRUE;
seanhalle@222 311 vicGate = _VMSMasterEnv->workStealingGates[ coreIdx ];
seanhalle@222 312 break;
seanhalle@222 313 }
seanhalle@222 314 }
seanhalle@222 315 if( !haveAVictim ) return; //no work to steal, exit
seanhalle@222 316
seanhalle@222 317 //have a victim core, now get the stealer-lock
seanhalle@222 318 gotLock =__sync_bool_compare_and_swap( &(_VMSMasterEnv->workStealingLock),
seanhalle@222 319 UNLOCKED, LOCKED );
seanhalle@222 320 if( !gotLock ) return; //go back to core controller, which will re-start master
seanhalle@222 321
seanhalle@222 322
seanhalle@222 323 //====== Start Gate-protection =======
seanhalle@222 324 vicGate->gateClosed = TRUE;
seanhalle@222 325 coreMightBeInProtected= vicGate->preGateProgress != vicGate->exitProgress;
seanhalle@222 326 while( coreMightBeInProtected )
seanhalle@222 327 { //wait until sure
seanhalle@222 328 if( vicGate->preGateProgress == vicGate->waitProgress )
seanhalle@222 329 coreMightBeInProtected = FALSE;
seanhalle@222 330 if( vicGate->preGateProgress == vicGate->exitProgress )
seanhalle@222 331 coreMightBeInProtected = FALSE;
seanhalle@222 332 }
seanhalle@222 333
seanhalle@222 334 stolenSlv = readVMSQ ( victimsQ );
seanhalle@222 335
seanhalle@222 336 vicGate->gateClosed = FALSE;
seanhalle@222 337 //======= End Gate-protection =======
seanhalle@222 338
seanhalle@222 339
seanhalle@222 340 if( stolenSlv != NULL ) //victim could have been in protected and taken
seanhalle@222 341 { currSlot->slaveAssignedToSlot = stolenSlv;
seanhalle@222 342 stolenSlv->schedSlot = currSlot;
seanhalle@222 343 currSlot->needsSlaveAssigned = FALSE;
seanhalle@222 344
seanhalle@222 345 writeVMSQ( stolenSlv, myReadyToAnimateQ );
seanhalle@222 346 }
seanhalle@222 347
seanhalle@222 348 //unlock the work stealing lock
seanhalle@222 349 _VMSMasterEnv->workStealingLock = UNLOCKED;
seanhalle@222 350 }