annotate AnimationMaster.c @ 260:999f2966a3e5

new branch -- Dev_ML -- for making VMS take langlets whose constructs can be mixed
author Sean Halle <seanhalle@yahoo.com>
date Wed, 19 Sep 2012 23:12:44 -0700
parents 7ed97c961901
children dafae55597ce
rev   line source
seanhalle@230 1 /*
seanhalle@230 2 * Copyright 2010 OpenSourceStewardshipFoundation
seanhalle@230 3 *
seanhalle@230 4 * Licensed under BSD
seanhalle@230 5 */
seanhalle@230 6
seanhalle@230 7
seanhalle@230 8
seanhalle@230 9 #include <stdio.h>
seanhalle@230 10 #include <stddef.h>
seanhalle@230 11
seanhalle@260 12 #include "PR.h"
seanhalle@230 13
seanhalle@230 14
seanhalle@230 15
seanhalle@230 16 /*The animationMaster embodies most of the animator of the language. The
seanhalle@230 17 * animator is what emodies the behavior of language constructs.
seanhalle@230 18 * As such, it is the animationMaster, in combination with the plugin
seanhalle@230 19 * functions, that make the language constructs do their behavior.
seanhalle@230 20 *
seanhalle@230 21 *Within the code, this is the top-level-function of the masterVPs, and
seanhalle@230 22 * runs when the coreController has no more slave VPs. It's job is to
seanhalle@260 23 * refill the animation slots with slaves that have work.
seanhalle@230 24 *
seanhalle@260 25 *There are multiple versions of the master, each tuned to a specific
seanhalle@260 26 * combination of modes. This keeps the master simple, with reduced overhead,
seanhalle@260 27 * when the application is not using the extra complexity.
seanhalle@260 28 *
seanhalle@260 29 *As of Sept 2012, the versions available will be:
seanhalle@260 30 * 1) Single langauge, which only exposes slaves (such as SSR or Vthread)
seanhalle@260 31 * 2) Single language, which only exposes tasks (such as pure dataflow)
seanhalle@260 32 * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP)
seanhalle@260 33 * 4) Multi-language, which always assumes both tasks and slaves
seanhalle@260 34 * 5) Multi-language and multi-process, which also assumes both tasks and slaves
seanhalle@260 35 *
seanhalle@260 36 *
seanhalle@260 37 *
seanhalle@260 38 */
seanhalle@260 39
seanhalle@260 40
seanhalle@260 41 //===================== The versions of the Animation Master =================
seanhalle@260 42 //
seanhalle@260 43 //==============================================================================
seanhalle@260 44
seanhalle@260 45 /* 1) This version is for a single language, that has only slaves, no tasks,
seanhalle@260 46 * such as Vthread or SSR.
seanhalle@260 47 *This version is for when an application has only a single language, and
seanhalle@260 48 * that language exposes slaves explicitly (as opposed to a task based
seanhalle@260 49 * language like pure dataflow).
seanhalle@260 50 *
seanhalle@260 51 *
seanhalle@260 52 *It scans the animation slots for just-completed slaves.
seanhalle@260 53 * Each completed slave has a request in it. So, the master hands each to
seanhalle@260 54 * the plugin's request handler (there is only one plugin, because only one
seanhalle@260 55 * lang).
seanhalle@230 56 *Each request represents a language construct that has been encountered
seanhalle@230 57 * by the application code in the slave. Passing the request to the
seanhalle@230 58 * request handler is how that language construct's behavior gets invoked.
seanhalle@230 59 * The request handler then performs the actions of the construct's
seanhalle@230 60 * behavior. So, the request handler encodes the behavior of the
seanhalle@230 61 * language's parallelism constructs, and performs that when the master
seanhalle@230 62 * hands it a slave containing a request to perform that construct.
seanhalle@230 63 *
seanhalle@230 64 *On a shared-memory machine, the behavior of parallelism constructs
seanhalle@230 65 * equals control, over order of execution of code. Hence, the behavior
seanhalle@230 66 * of the language constructs performed by the request handler is to
seanhalle@230 67 * choose the order that slaves get animated, and thereby control the
seanhalle@230 68 * order that application code in the slaves executes.
seanhalle@230 69 *
seanhalle@230 70 *To control order of animation of slaves, the request handler has a
seanhalle@230 71 * semantic environment that holds data structures used to hold slaves
seanhalle@230 72 * and choose when they're ready to be animated.
seanhalle@230 73 *
seanhalle@230 74 *Once a slave is marked as ready to be animated by the request handler,
seanhalle@230 75 * it is the second plugin function, the Assigner, which chooses the core
seanhalle@230 76 * the slave gets assigned to for animation. Hence, the Assigner doesn't
seanhalle@230 77 * perform any of the semantic behavior of language constructs, rather
seanhalle@230 78 * it gives the language a chance to improve performance. The performance
seanhalle@230 79 * of application code is strongly related to communication between
seanhalle@230 80 * cores. On shared-memory machines, communication is caused during
seanhalle@230 81 * execution of code, by memory accesses, and how much depends on contents
seanhalle@230 82 * of caches connected to the core executing the code. So, the placement
seanhalle@230 83 * of slaves determines the communication caused during execution of the
seanhalle@230 84 * slave's code.
seanhalle@230 85 *The point of the Assigner, then, is to use application information during
seanhalle@230 86 * execution of the program, to make choices about slave placement onto
seanhalle@230 87 * cores, with the aim to put slaves close to caches containing the data
seanhalle@230 88 * used by the slave's code.
seanhalle@230 89 *
seanhalle@230 90 *==========================================================================
seanhalle@230 91 *In summary, the animationMaster scans the slots, finds slaves
seanhalle@230 92 * just-finished, which hold requests, pass those to the request handler,
seanhalle@230 93 * along with the semantic environment, and the request handler then manages
seanhalle@230 94 * the structures in the semantic env, which controls the order of
seanhalle@230 95 * animation of slaves, and so embodies the behavior of the language
seanhalle@230 96 * constructs.
seanhalle@230 97 *The animationMaster then rescans the slots, offering each empty one to
seanhalle@230 98 * the Assigner, along with the semantic environment. The Assigner chooses
seanhalle@230 99 * among the ready slaves in the semantic Env, finding the one best suited
seanhalle@230 100 * to be animated by that slot's associated core.
seanhalle@230 101 *
seanhalle@230 102 *==========================================================================
seanhalle@230 103 *Implementation Details:
seanhalle@230 104 *
seanhalle@230 105 *There is a separate masterVP for each core, but a single semantic
seanhalle@230 106 * environment shared by all cores. Each core also has its own scheduling
seanhalle@230 107 * slots, which are used to communicate slaves between animationMaster and
seanhalle@260 108 * coreController. There is only one global variable, _PRMasterEnv, which
seanhalle@230 109 * holds the semantic env and other things shared by the different
seanhalle@230 110 * masterVPs. The request handler and Assigner are registered with
seanhalle@230 111 * the animationMaster by the language's init function, and a pointer to
seanhalle@260 112 * each is in the _PRMasterEnv. (There are also some pthread related global
seanhalle@260 113 * vars, but they're only used during init of PR).
seanhalle@260 114 *PR gains control over the cores by essentially "turning off" the OS's
seanhalle@230 115 * scheduler, using pthread pin-to-core commands.
seanhalle@230 116 *
seanhalle@230 117 *The masterVPs are created during init, with this animationMaster as their
seanhalle@230 118 * top level function. The masterVPs use the same SlaveVP data structure,
seanhalle@230 119 * even though they're not slave VPs.
seanhalle@230 120 *A "seed slave" is also created during init -- this is equivalent to the
seanhalle@260 121 * "main" function in C, and acts as the entry-point to the PR-language-
seanhalle@230 122 * based application.
seanhalle@260 123 *The masterVPs share a single system-wide master-lock, so only one
seanhalle@230 124 * masterVP may be animated at a time.
seanhalle@260 125 *The core controllers access _PRMasterEnv to get the masterVP, and when
seanhalle@230 126 * they start, the slots are all empty, so they run their associated core's
seanhalle@230 127 * masterVP. The first of those to get the master lock sees the seed slave
seanhalle@230 128 * in the shared semantic environment, so when it runs the Assigner, that
seanhalle@230 129 * returns the seed slave, which the animationMaster puts into a scheduling
seanhalle@230 130 * slot then switches to the core controller. That then switches the core
seanhalle@230 131 * over to the seed slave, which then proceeds to execute language
seanhalle@230 132 * constructs to create more slaves, and so on. Each of those constructs
seanhalle@230 133 * causes the seed slave to suspend, switching over to the core controller,
seanhalle@230 134 * which eventually switches to the masterVP, which executes the
seanhalle@260 135 * request handler, which uses PR primitives to carry out the creation of
seanhalle@230 136 * new slave VPs, which are marked as ready for the Assigner, and so on..
seanhalle@230 137 *
seanhalle@230 138 *On animation slots, and system behavior:
seanhalle@260 139 * A request may linger in an animation slot for a long time while
seanhalle@230 140 * the slaves in the other slots are animated. This only becomes a problem
seanhalle@230 141 * when such a request is a choke-point in the constraints, and is needed
seanhalle@260 142 * to free work for *other* cores. To reduce this occurrence, the number
seanhalle@230 143 * of animation slots should be kept low. In balance, having multiple
seanhalle@230 144 * animation slots amortizes the overhead of switching to the masterVP and
seanhalle@230 145 * executing the animationMaster code, which drives for more than one. In
seanhalle@230 146 * practice, the best balance should be discovered by profiling.
seanhalle@230 147 */
seanhalle@230 148 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@230 149 {
seanhalle@230 150 //Used while scanning and filling animation slots
seanhalle@230 151 int32 slotIdx, numSlotsFilled;
seanhalle@235 152 AnimSlot *currSlot, **animSlots;
seanhalle@230 153 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@230 154
seanhalle@230 155 //Local copies, for performance
seanhalle@230 156 MasterEnv *masterEnv;
seanhalle@230 157 SlaveAssigner slaveAssigner;
seanhalle@230 158 RequestHandler requestHandler;
seanhalle@230 159 void *semanticEnv;
seanhalle@230 160 int32 thisCoresIdx;
nengel@238 161
seanhalle@230 162 //======================== Initializations ========================
seanhalle@230 163 masterEnv = (MasterEnv*)_VMSMasterEnv;
seanhalle@230 164
seanhalle@230 165 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@235 166 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@230 167
seanhalle@230 168 requestHandler = masterEnv->requestHandler;
seanhalle@230 169 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@230 170 semanticEnv = masterEnv->semanticEnv;
nengel@238 171
nengel@238 172 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@230 173
seanhalle@230 174 //======================== animationMaster ========================
seanhalle@230 175 while(1){
seanhalle@230 176
seanhalle@230 177 MEAS__Capture_Pre_Master_Point
seanhalle@230 178
seanhalle@230 179 //Scan the animation slots
seanhalle@230 180 numSlotsFilled = 0;
seanhalle@236 181 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@230 182 {
seanhalle@235 183 currSlot = animSlots[ slotIdx ];
seanhalle@230 184
nengel@239 185 //Check if newly-done slave in slot, which will need request handled
seanhalle@230 186 if( currSlot->workIsDone )
seanhalle@230 187 {
seanhalle@230 188 currSlot->workIsDone = FALSE;
seanhalle@230 189 currSlot->needsSlaveAssigned = TRUE;
nengel@238 190
nengel@238 191 HOLISTIC__Record_AppResponder_start;
seanhalle@230 192 MEAS__startReqHdlr;
seanhalle@230 193
seanhalle@260 194 currSlot->workIsDone = FALSE;
seanhalle@260 195 currSlot->needsSlaveAssigned = TRUE;
seanhalle@260 196 SlaveVP *currSlave = currSlot->slaveAssignedToSlot;
seanhalle@260 197
seanhalle@260 198 justAddedReqHdlrChg();
seanhalle@260 199 //handle the request, either by VMS or by the language
seanhalle@260 200 if( currSlave->requests->reqType != LangReq )
seanhalle@260 201 { //The request is a standard VMS one, not one defined by the
seanhalle@260 202 // language, so VMS handles it, then queues slave to be assigned
seanhalle@260 203 handleReqInVMS( currSlave );
seanhalle@260 204 writePrivQ( currSlave, VMSReadyQ ); //Q slave to be assigned below
seanhalle@260 205 }
seanhalle@260 206 else
seanhalle@260 207 { MEAS__startReqHdlr;
seanhalle@260 208
seanhalle@260 209 //Language handles request, which is held inside slave struc
seanhalle@260 210 (*requestHandler)( currSlave, semanticEnv );
seanhalle@260 211
seanhalle@260 212 MEAS__endReqHdlr;
seanhalle@260 213 }
seanhalle@260 214 }
seanhalle@260 215
seanhalle@260 216 //process the requests made by the slave (held inside slave struc)
seanhalle@230 217 (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv );
seanhalle@230 218
nengel@238 219 HOLISTIC__Record_AppResponder_end;
seanhalle@230 220 MEAS__endReqHdlr;
seanhalle@230 221 }
seanhalle@230 222 //If slot empty, hand to Assigner to fill with a slave
seanhalle@230 223 if( currSlot->needsSlaveAssigned )
seanhalle@230 224 { //Call plugin's Assigner to give slot a new slave
nengel@238 225 HOLISTIC__Record_Assigner_start;
seanhalle@230 226 assignedSlaveVP =
seanhalle@230 227 (*slaveAssigner)( semanticEnv, currSlot );
seanhalle@230 228
seanhalle@230 229 //put the chosen slave into slot, and adjust flags and state
seanhalle@230 230 if( assignedSlaveVP != NULL )
seanhalle@230 231 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@235 232 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@230 233 currSlot->needsSlaveAssigned = FALSE;
seanhalle@230 234 numSlotsFilled += 1;
nengel@238 235
nengel@238 236 HOLISTIC__Record_Assigner_end;
seanhalle@230 237 }
seanhalle@230 238 }
seanhalle@230 239 }
seanhalle@230 240
seanhalle@230 241 MEAS__Capture_Post_Master_Point;
seanhalle@230 242
seanhalle@231 243 masterSwitchToCoreCtlr( masterVP );
seanhalle@230 244 flushRegisters();
seanhalle@235 245 DEBUG__printf(FALSE,"came back after switch to core -- so lock released!");
seanhalle@232 246 }//while(1)
seanhalle@230 247 }
seanhalle@230 248
seanhalle@260 249
seanhalle@260 250 /* 2) This version is for a single language that has only tasks, which
seanhalle@260 251 * cannot be suspended.
seanhalle@260 252 */
seanhalle@260 253 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@260 254 {
seanhalle@260 255 //Used while scanning and filling animation slots
seanhalle@260 256 int32 slotIdx, numSlotsFilled;
seanhalle@260 257 AnimSlot *currSlot, **animSlots;
seanhalle@260 258 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@260 259
seanhalle@260 260 //Local copies, for performance
seanhalle@260 261 MasterEnv *masterEnv;
seanhalle@260 262 SlaveAssigner slaveAssigner;
seanhalle@260 263 RequestHandler requestHandler;
seanhalle@260 264 PRSemEnv *semanticEnv;
seanhalle@260 265 int32 thisCoresIdx;
seanhalle@260 266
seanhalle@260 267 //#ifdef MODE__MULTI_LANG
seanhalle@260 268 SlaveVP *slave;
seanhalle@260 269 PRProcess *process;
seanhalle@260 270 PRConstrEnvHolder *constrEnvHolder;
seanhalle@260 271 int32 langMagicNumber;
seanhalle@260 272 //#endif
seanhalle@260 273
seanhalle@260 274 //======================== Initializations ========================
seanhalle@260 275 masterEnv = (MasterEnv*)_PRMasterEnv;
seanhalle@260 276
seanhalle@260 277 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@260 278 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@260 279
seanhalle@260 280 requestHandler = masterEnv->requestHandler;
seanhalle@260 281 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@260 282 semanticEnv = masterEnv->semanticEnv;
seanhalle@260 283
seanhalle@260 284 //initialize, for non-multi-lang, non multi-proc case
seanhalle@260 285 // default handler gets put into master env by a registration call by lang
seanhalle@260 286 endTaskHandler = masterEnv->defaultTaskHandler;
seanhalle@260 287
seanhalle@260 288 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@260 289
seanhalle@260 290 //======================== animationMaster ========================
seanhalle@260 291 //Do loop gets requests handled and work assigned to slots..
seanhalle@260 292 // work can either be a task or a resumed slave
seanhalle@260 293 //Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 294 // then the next available work may be either.. so really have two distinct
seanhalle@260 295 // loops that are inter-twined..
seanhalle@260 296 while(1){
seanhalle@260 297
seanhalle@260 298 MEAS__Capture_Pre_Master_Point
seanhalle@260 299
seanhalle@260 300 //Scan the animation slots
seanhalle@260 301 numSlotsFilled = 0;
seanhalle@260 302 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@260 303 {
seanhalle@260 304 currSlot = animSlots[ slotIdx ];
seanhalle@260 305
seanhalle@260 306 //Check if newly-done slave in slot, which will need request handled
seanhalle@260 307 if( currSlot->workIsDone )
seanhalle@260 308 { currSlot->workIsDone = FALSE;
seanhalle@260 309
seanhalle@260 310 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@260 311 MEAS__startReqHdlr;
seanhalle@260 312
seanhalle@260 313
seanhalle@260 314 //process the request made by the slave (held inside slave struc)
seanhalle@260 315 slave = currSlot->slaveAssignedToSlot;
seanhalle@260 316
seanhalle@260 317 //check if the completed work was a task..
seanhalle@260 318 if( slave->taskMetaInfo->isATask )
seanhalle@260 319 {
seanhalle@260 320 if( slave->reqst->type == TaskEnd )
seanhalle@260 321 { //do task end handler, which is registered separately
seanhalle@260 322 //note, end hdlr may use semantic data from reqst..
seanhalle@260 323 //#ifdef MODE__MULTI_LANG
seanhalle@260 324 //get end-task handler
seanhalle@260 325 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
seanhalle@260 326 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
seanhalle@260 327 //#endif
seanhalle@260 328 (*taskEndHandler)( slave, semanticEnv );
seanhalle@260 329
seanhalle@260 330 goto AssignWork;
seanhalle@260 331 }
seanhalle@260 332 else //is a task, and just suspended
seanhalle@260 333 { //turn slot slave into free task slave & make replacement
seanhalle@260 334 if( slave->typeOfVP == TaskSlotSlv ) changeSlvType();
seanhalle@260 335
seanhalle@260 336 //goto normal slave request handling
seanhalle@260 337 goto SlaveReqHandling;
seanhalle@260 338 }
seanhalle@260 339 }
seanhalle@260 340 else //is a slave that suspended
seanhalle@260 341 {
seanhalle@260 342 SlaveReqHandling:
seanhalle@260 343 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
seanhalle@260 344
seanhalle@260 345 HOLISTIC__Record_AppResponder_end;
seanhalle@260 346 MEAS__endReqHdlr;
seanhalle@260 347
seanhalle@260 348 goto AssignWork;
seanhalle@260 349 }
seanhalle@260 350 } //if has suspended slave that needs handling
seanhalle@260 351
seanhalle@260 352 //if slot empty, hand to Assigner to fill with a slave
seanhalle@260 353 if( currSlot->needsSlaveAssigned )
seanhalle@260 354 { //Call plugin's Assigner to give slot a new slave
seanhalle@260 355 HOLISTIC__Record_Assigner_start;
seanhalle@260 356
seanhalle@260 357 AssignWork:
seanhalle@260 358
seanhalle@260 359 assignedSlaveVP = assignWork( semanticEnv, currSlot );
seanhalle@260 360
seanhalle@260 361 //put the chosen slave into slot, and adjust flags and state
seanhalle@260 362 if( assignedSlaveVP != NULL )
seanhalle@260 363 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 364 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@260 365 currSlot->needsSlaveAssigned = FALSE;
seanhalle@260 366 numSlotsFilled += 1;
seanhalle@260 367 }
seanhalle@260 368 else
seanhalle@260 369 {
seanhalle@260 370 currSlot->needsSlaveAssigned = TRUE; //local write
seanhalle@260 371 }
seanhalle@260 372 HOLISTIC__Record_Assigner_end;
seanhalle@260 373 }//if slot needs slave assigned
seanhalle@260 374 }//for( slotIdx..
seanhalle@260 375
seanhalle@260 376 MEAS__Capture_Post_Master_Point;
seanhalle@260 377
seanhalle@260 378 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@260 379 flushRegisters();
seanhalle@260 380 }//while(1)
seanhalle@260 381 }
seanhalle@260 382
seanhalle@260 383
seanhalle@260 384 /*This is the master when just multi-lang, but not multi-process mode is on.
seanhalle@260 385 * This version has to handle both tasks and slaves, and do extra work of
seanhalle@260 386 * looking up the semantic env and handlers to use, for each completed bit of
seanhalle@260 387 * work.
seanhalle@260 388 *It also has to search through the semantic envs to find one with work,
seanhalle@260 389 * then ask that env's assigner to return a unit of that work.
seanhalle@260 390 *
seanhalle@260 391 *The language is written to startup in the same way as if it were the only
seanhalle@260 392 * language in the app, and it operates in the same way,
seanhalle@260 393 * the only difference between single language and multi-lang is here, in the
seanhalle@260 394 * master.
seanhalle@260 395 *This invisibility to mode is why the language has to use registration calls
seanhalle@260 396 * for everything during startup -- those calls do different things depending
seanhalle@260 397 * on whether it's single-language or multi-language mode.
seanhalle@260 398 *
seanhalle@260 399 *In this version of the master, work can either be a task or a resumed slave
seanhalle@260 400 *Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 401 * then the next available work may be either.. so really have two distinct
seanhalle@260 402 * loops that are inter-twined..
seanhalle@260 403 *
seanhalle@260 404 *Some special cases:
seanhalle@260 405 * A task-end is a special case for a few reasons (below).
seanhalle@260 406 * A task-end can't block a slave (can't cause it to "logically suspend")
seanhalle@260 407 * A task available for work can only be assigned to a special slave, which
seanhalle@260 408 * has been set aside for doing tasks, one such task-slave is always
seanhalle@260 409 * assigned to each slot. So, when a task ends, a new task is assigned to
seanhalle@260 410 * that slot's task-slave right away.
seanhalle@260 411 * But if no tasks are available, then have to switch over to looking at
seanhalle@260 412 * slaves to find one ready to resume, to find work for the slot.
seanhalle@260 413 * If a task just suspends, not ends, then its task-slave is no longer
seanhalle@260 414 * available to take new tasks, so a new task-slave has to be assigned to
seanhalle@260 415 * that slot. Then the slave of the suspended task is turned into a free
seanhalle@260 416 * task-slave and request handling is done on it as if it were a slave
seanhalle@260 417 * that suspended.
seanhalle@260 418 * After request handling, do the same sequence of looking for a task to be
seanhalle@260 419 * work, and if none, look for a slave ready to resume, as work for the slot.
seanhalle@260 420 * If a slave suspends, handle its request, then look for work.. first for a
seanhalle@260 421 * task to assign, and if none, slaves ready to resume.
seanhalle@260 422 * Another special case is when task-end is done on a free task-slave.. in
seanhalle@260 423 * that case, the slave has no more work and no way to get more.. so place
seanhalle@260 424 * it into a recycle queue.
seanhalle@260 425 * If no work is found of either type, then do a special thing to prune down
seanhalle@260 426 * the extra slaves in the recycle queue, just so don't get too many..
seanhalle@260 427 *
seanhalle@260 428 *The multi-lang thing complicates matters..
seanhalle@260 429 *
seanhalle@260 430 *For request handling, it means have to first fetch the semantic environment
seanhalle@260 431 * of the language, and then do the request handler pointed to by that
seanhalle@260 432 * semantic env.
seanhalle@260 433 *For assigning, things get more complex because of competing goals.. One
seanhalle@260 434 * goal is for language specific stuff to be used during assignment, so
seanhalle@260 435 * assigner can make higher quality decisions.. but with multiple languages,
seanhalle@260 436 * which only get mixed in the application, the assigners can't be written
seanhalle@260 437 * with knowledge of each other. So, they can only make localized decisions,
seanhalle@260 438 * and so different language's assigners may interfere with each other..
seanhalle@260 439 *
seanhalle@260 440 *So, have some possibilities available:
seanhalle@260 441 *1) can have a fixed scheduler in the proto-runtime, that all the
seanhalle@260 442 * languages give their work to.. (but then lose language-specific info,
seanhalle@260 443 * there is a standard PR format for assignment info, and the langauge
seanhalle@260 444 * attaches this to the work-unit when it gives it to PR.. also have issue
seanhalle@260 445 * with HWSim, which uses a priority Q instead of FIFO, and requests can
seanhalle@260 446 * "undo" previous work put in, so request handlers need way to manipulate
seanhalle@260 447 * the work-holding Q..) (this might be fudgeable with
seanhalle@260 448 * HWSim, if the master did a lang-supplied callback each time it assigns a
seanhalle@260 449 * unit to a slot.. then HWSim can keep exactly one unit of work in PR's
seanhalle@260 450 * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies
seanhalle@260 451 * a task-end handler that kicks the next unit of work from HWSim internal
seanhalle@260 452 * priority queue, over to PR readyQ)
seanhalle@260 453 *2) can have each language have its own semantic env, that holds its own
seanhalle@260 454 * work, which is assigned by its own assigner.. then the master searches
seanhalle@260 455 * through all the semantic envs to find one with work and asks it give work..
seanhalle@260 456 * (this has downside of blinding assigners to each other.. but does work
seanhalle@260 457 * for HWSim case)
seanhalle@260 458 *3) could make PR have a different readyQ for each core, and ask the lang
seanhalle@260 459 * to put work to the core it prefers.. but the work may be moved by PR if
seanhalle@260 460 * needed, say if one core idles for too long. This is a hybrid approach,
seanhalle@260 461 * letting the language decide which core, but PR keeps the work and does it
seanhalle@260 462 * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion,
seanhalle@260 463 * but it would be complicated by having to track cores separately)
seanhalle@260 464 *
seanhalle@260 465 *Choosing 2, to keep compatibility with single-lang mode.. it allows the same
seanhalle@260 466 * assigner to be used for single-lang as for multi-lang.. the overhead of
seanhalle@260 467 * the extra master search for work is part of the price of the flexibility,
seanhalle@260 468 * but should be fairly small.. takes the first env that has work available,
seanhalle@260 469 * and whatever it returns is assigned to the slot..
seanhalle@260 470 *
seanhalle@260 471 *As a hybrid, giving an option for a unified override assigner to be registered
seanhalle@260 472 * and used.. This allows something like a static analysis to detect
seanhalle@260 473 * which languages are grouped together, and then analyze the pattern of
seanhalle@260 474 * construct calls, and generate a custom assigner that uses info from all
seanhalle@260 475 * the languages in a unified way.. Don't really expect this to happen,
seanhalle@260 476 * but making it possible.
seanhalle@260 477 */
seanhalle@260 478 #ifdef MODE__MULTI_LANG
seanhalle@260 479 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@260 480 {
seanhalle@260 481 //Used while scanning and filling animation slots
seanhalle@260 482 int32 slotIdx, numSlotsFilled;
seanhalle@260 483 AnimSlot *currSlot, **animSlots;
seanhalle@260 484 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@260 485
seanhalle@260 486 //Local copies, for performance
seanhalle@260 487 MasterEnv *masterEnv;
seanhalle@260 488 SlaveAssigner slaveAssigner;
seanhalle@260 489 RequestHandler requestHandler;
seanhalle@260 490 PRSemEnv *semanticEnv;
seanhalle@260 491 int32 thisCoresIdx;
seanhalle@260 492
seanhalle@260 493 //#ifdef MODE__MULTI_LANG
seanhalle@260 494 SlaveVP *slave;
seanhalle@260 495 PRProcess *process;
seanhalle@260 496 PRConstrEnvHolder *constrEnvHolder;
seanhalle@260 497 int32 langMagicNumber;
seanhalle@260 498 //#endif
seanhalle@260 499
seanhalle@260 500 //======================== Initializations ========================
seanhalle@260 501 masterEnv = (MasterEnv*)_PRMasterEnv;
seanhalle@260 502
seanhalle@260 503 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@260 504 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@260 505
seanhalle@260 506 requestHandler = masterEnv->requestHandler;
seanhalle@260 507 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@260 508 semanticEnv = masterEnv->semanticEnv;
seanhalle@260 509
seanhalle@260 510 //initialize, for non-multi-lang, non multi-proc case
seanhalle@260 511 // default handler gets put into master env by a registration call by lang
seanhalle@260 512 endTaskHandler = masterEnv->defaultTaskHandler;
seanhalle@260 513
seanhalle@260 514 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@260 515
seanhalle@260 516 //======================== animationMaster ========================
seanhalle@260 517 //Do loop gets requests handled and work assigned to slots..
seanhalle@260 518 // work can either be a task or a resumed slave
seanhalle@260 519 //Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 520 // then the next available work may be either.. so really have two distinct
seanhalle@260 521 // loops that are inter-twined..
seanhalle@260 522 while(1){
seanhalle@260 523
seanhalle@260 524 MEAS__Capture_Pre_Master_Point
seanhalle@260 525
seanhalle@260 526 //Scan the animation slots
seanhalle@260 527 numSlotsFilled = 0;
seanhalle@260 528 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@260 529 {
seanhalle@260 530 currSlot = animSlots[ slotIdx ];
seanhalle@260 531
seanhalle@260 532 //Check if newly-done slave in slot, which will need request handled
seanhalle@260 533 if( currSlot->workIsDone )
seanhalle@260 534 { currSlot->workIsDone = FALSE;
seanhalle@260 535
seanhalle@260 536 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@260 537 MEAS__startReqHdlr;
seanhalle@260 538
seanhalle@260 539
seanhalle@260 540 //process the request made by the slave (held inside slave struc)
seanhalle@260 541 slave = currSlot->slaveAssignedToSlot;
seanhalle@260 542
seanhalle@260 543 //check if the completed work was a task..
seanhalle@260 544 if( slave->taskMetaInfo->isATask )
seanhalle@260 545 {
seanhalle@260 546 if( slave->reqst->type == TaskEnd )
seanhalle@260 547 { //do task end handler, which is registered separately
seanhalle@260 548 //note, end hdlr may use semantic data from reqst..
seanhalle@260 549 //#ifdef MODE__MULTI_LANG
seanhalle@260 550 //get end-task handler
seanhalle@260 551 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
seanhalle@260 552 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
seanhalle@260 553 //#endif
seanhalle@260 554 (*taskEndHandler)( slave, semanticEnv );
seanhalle@260 555
seanhalle@260 556 goto AssignWork;
seanhalle@260 557 }
seanhalle@260 558 else //is a task, and just suspended
seanhalle@260 559 { //turn slot slave into free task slave & make replacement
seanhalle@260 560 if( slave->typeOfVP == TaskSlotSlv ) changeSlvType();
seanhalle@260 561
seanhalle@260 562 //goto normal slave request handling
seanhalle@260 563 goto SlaveReqHandling;
seanhalle@260 564 }
seanhalle@260 565 }
seanhalle@260 566 else //is a slave that suspended
seanhalle@260 567 {
seanhalle@260 568 SlaveReqHandling:
seanhalle@260 569 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
seanhalle@260 570
seanhalle@260 571 HOLISTIC__Record_AppResponder_end;
seanhalle@260 572 MEAS__endReqHdlr;
seanhalle@260 573
seanhalle@260 574 goto AssignWork;
seanhalle@260 575 }
seanhalle@260 576 } //if has suspended slave that needs handling
seanhalle@260 577
seanhalle@260 578 //if slot empty, hand to Assigner to fill with a slave
seanhalle@260 579 if( currSlot->needsSlaveAssigned )
seanhalle@260 580 { //Call plugin's Assigner to give slot a new slave
seanhalle@260 581 HOLISTIC__Record_Assigner_start;
seanhalle@260 582
seanhalle@260 583 AssignWork:
seanhalle@260 584
seanhalle@260 585 assignedSlaveVP = assignWork( semanticEnv, currSlot );
seanhalle@260 586
seanhalle@260 587 //put the chosen slave into slot, and adjust flags and state
seanhalle@260 588 if( assignedSlaveVP != NULL )
seanhalle@260 589 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 590 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@260 591 currSlot->needsSlaveAssigned = FALSE;
seanhalle@260 592 numSlotsFilled += 1;
seanhalle@260 593 }
seanhalle@260 594 else
seanhalle@260 595 {
seanhalle@260 596 currSlot->needsSlaveAssigned = TRUE; //local write
seanhalle@260 597 }
seanhalle@260 598 HOLISTIC__Record_Assigner_end;
seanhalle@260 599 }//if slot needs slave assigned
seanhalle@260 600 }//for( slotIdx..
seanhalle@260 601
seanhalle@260 602 MEAS__Capture_Post_Master_Point;
seanhalle@260 603
seanhalle@260 604 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@260 605 flushRegisters();
seanhalle@260 606 }//while(1)
seanhalle@260 607 }
seanhalle@260 608 #endif //MODE__MULTI_LANG
seanhalle@260 609
seanhalle@260 610
seanhalle@260 611
seanhalle@260 612 //This is the master when both multi-lang and multi-process modes are turned on
seanhalle@260 613 //#ifdef MODE__MULTI_LANG
seanhalle@260 614 //#ifdef MODE__MULTI_PROCESS
seanhalle@260 615 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@260 616 {
seanhalle@260 617 //Used while scanning and filling animation slots
seanhalle@260 618 int32 slotIdx, numSlotsFilled;
seanhalle@260 619 AnimSlot *currSlot, **animSlots;
seanhalle@260 620 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@260 621
seanhalle@260 622 //Local copies, for performance
seanhalle@260 623 MasterEnv *masterEnv;
seanhalle@260 624 SlaveAssigner slaveAssigner;
seanhalle@260 625 RequestHandler requestHandler;
seanhalle@260 626 PRSemEnv *semanticEnv;
seanhalle@260 627 int32 thisCoresIdx;
seanhalle@260 628
seanhalle@260 629 SlaveVP *slave;
seanhalle@260 630 PRProcess *process;
seanhalle@260 631 PRConstrEnvHolder *constrEnvHolder;
seanhalle@260 632 int32 langMagicNumber;
seanhalle@260 633
seanhalle@260 634 //======================== Initializations ========================
seanhalle@260 635 masterEnv = (MasterEnv*)_PRMasterEnv;
seanhalle@260 636
seanhalle@260 637 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@260 638 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@260 639
seanhalle@260 640 requestHandler = masterEnv->requestHandler;
seanhalle@260 641 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@260 642 semanticEnv = masterEnv->semanticEnv;
seanhalle@260 643
seanhalle@260 644 //initialize, for non-multi-lang, non multi-proc case
seanhalle@260 645 // default handler gets put into master env by a registration call by lang
seanhalle@260 646 endTaskHandler = masterEnv->defaultTaskHandler;
seanhalle@260 647
seanhalle@260 648 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@260 649
seanhalle@260 650 //======================== animationMaster ========================
seanhalle@260 651 //Do loop gets requests handled and work assigned to slots..
seanhalle@260 652 // work can either be a task or a resumed slave
seanhalle@260 653 //Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 654 // then the next available work may be either.. so really have two distinct
seanhalle@260 655 // loops that are inter-twined..
seanhalle@260 656 while(1){
seanhalle@260 657
seanhalle@260 658 MEAS__Capture_Pre_Master_Point
seanhalle@260 659
seanhalle@260 660 //Scan the animation slots
seanhalle@260 661 numSlotsFilled = 0;
seanhalle@260 662 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@260 663 {
seanhalle@260 664 currSlot = animSlots[ slotIdx ];
seanhalle@260 665
seanhalle@260 666 //Check if newly-done slave in slot, which will need request handled
seanhalle@260 667 if( currSlot->workIsDone )
seanhalle@260 668 { currSlot->workIsDone = FALSE;
seanhalle@260 669
seanhalle@260 670 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@260 671 MEAS__startReqHdlr;
seanhalle@260 672
seanhalle@260 673
seanhalle@260 674 //process the request made by the slave (held inside slave struc)
seanhalle@260 675 slave = currSlot->slaveAssignedToSlot;
seanhalle@260 676
seanhalle@260 677 //check if the completed work was a task..
seanhalle@260 678 if( slave->taskMetaInfo->isATask )
seanhalle@260 679 {
seanhalle@260 680 if( slave->reqst->type == TaskEnd )
seanhalle@260 681 { //do task end handler, which is registered separately
seanhalle@260 682 //note, end hdlr may use semantic data from reqst..
seanhalle@260 683 //get end-task handler
seanhalle@260 684 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
seanhalle@260 685 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
seanhalle@260 686
seanhalle@260 687 (*taskEndHandler)( slave, semanticEnv );
seanhalle@260 688
seanhalle@260 689 goto AssignWork;
seanhalle@260 690 }
seanhalle@260 691 else //is a task, and just suspended
seanhalle@260 692 { //turn slot slave into free task slave & make replacement
seanhalle@260 693 if( slave->typeOfVP == TaskSlotSlv ) changeSlvType();
seanhalle@260 694
seanhalle@260 695 //goto normal slave request handling
seanhalle@260 696 goto SlaveReqHandling;
seanhalle@260 697 }
seanhalle@260 698 }
seanhalle@260 699 else //is a slave that suspended
seanhalle@260 700 {
seanhalle@260 701
seanhalle@260 702 SlaveReqHandling:
seanhalle@260 703 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
seanhalle@260 704
seanhalle@260 705 HOLISTIC__Record_AppResponder_end;
seanhalle@260 706 MEAS__endReqHdlr;
seanhalle@260 707
seanhalle@260 708 goto AssignWork;
seanhalle@260 709 }
seanhalle@260 710 } //if has suspended slave that needs handling
seanhalle@260 711
seanhalle@260 712 //if slot empty, hand to Assigner to fill with a slave
seanhalle@260 713 if( currSlot->needsSlaveAssigned )
seanhalle@260 714 { //Scan sem environs, looking for one with ready work.
seanhalle@260 715 // call the Assigner for that sem Env, to give slot a new slave
seanhalle@260 716 HOLISTIC__Record_Assigner_start;
seanhalle@260 717
seanhalle@260 718 AssignWork:
seanhalle@260 719
seanhalle@260 720 assignedSlaveVP = assignWork( semanticEnv, currSlot );
seanhalle@260 721
seanhalle@260 722 //put the chosen slave into slot, and adjust flags and state
seanhalle@260 723 if( assignedSlaveVP != NULL )
seanhalle@260 724 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 725 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@260 726 currSlot->needsSlaveAssigned = FALSE;
seanhalle@260 727 numSlotsFilled += 1;
seanhalle@260 728 }
seanhalle@260 729 else
seanhalle@260 730 {
seanhalle@260 731 currSlot->needsSlaveAssigned = TRUE; //local write
seanhalle@260 732 }
seanhalle@260 733 HOLISTIC__Record_Assigner_end;
seanhalle@260 734 }//if slot needs slave assigned
seanhalle@260 735 }//for( slotIdx..
seanhalle@260 736
seanhalle@260 737 MEAS__Capture_Post_Master_Point;
seanhalle@260 738
seanhalle@260 739 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@260 740 flushRegisters();
seanhalle@260 741 }//while(1)
seanhalle@260 742 }
seanhalle@260 743 #endif //MODE__MULTI_LANG
seanhalle@260 744 #endif //MODE__MULTI_PROCESS
seanhalle@260 745
seanhalle@260 746
seanhalle@260 747 /*This does three things:
seanhalle@260 748 * 1) ask for a slave ready to resume
seanhalle@260 749 * 2) if none, then ask for a task, and assign to the slot slave
seanhalle@260 750 * 3) if none, then prune former task slaves waiting to be recycled.
seanhalle@260 751 *
seanhalle@260 752 //Have two separate assigners in each semantic env,
seanhalle@260 753 // which keeps its own work in its own structures.. the master, here,
seanhalle@260 754 // searches through the semantic environs, takes the first that has work
seanhalle@260 755 // available, and whatever it returns is assigned to the slot..
seanhalle@260 756 //However, also have an override assigner.. because static analysis tools know
seanhalle@260 757 // which languages are grouped together.. and the override enables them to
seanhalle@260 758 // generate a custom assigner that uses info from all the languages in a
seanhalle@260 759 // unified way.. Don't really expect this to happen, but making it possible.
seanhalle@260 760 */
seanhalle@260 761 inline SlaveVP *
seanhalle@260 762 assignWork( PRProcessEnv *processEnv, AnimSlot *slot )
seanhalle@260 763 { SlaveVP *returnSlv;
seanhalle@260 764 //VSsSemEnv *semEnv;
seanhalle@260 765 //VSsSemData *semData;
seanhalle@260 766 int32 coreNum, slotNum;
seanhalle@260 767 PRTaskMetaInfo *newTaskStub;
seanhalle@260 768 SlaveVP *freeTaskSlv;
seanhalle@260 769
seanhalle@260 770
seanhalle@260 771 //master has to handle slot slaves.. so either assigner returns
seanhalle@260 772 // taskMetaInfo or else two assigners, one for slaves, other for tasks..
seanhalle@260 773 semEnvs = processEnv->semEnvs;
seanhalle@260 774 numEnvs = processEnv->numSemEnvs;
seanhalle@260 775 for( envIdx = 0; envIdx < numEnvs; envIdx++ )
seanhalle@260 776 { semEnv = semEnvs[envIdx];
seanhalle@260 777 if( semEnv->hasWork )
seanhalle@260 778 { assigner = semEnv->assigner;
seanhalle@260 779 retTaskMetaInfo = (*assigner)( semEnv, slot );
seanhalle@260 780
seanhalle@260 781 return retTaskMetaInfo; //quit, have work
seanhalle@260 782 }
seanhalle@260 783 }
seanhalle@260 784
seanhalle@260 785 coreNum = slot->coreSlotIsOn;
seanhalle@260 786 slotNum = slot->slotIdx;
seanhalle@260 787
seanhalle@260 788 //first try to get a ready slave
seanhalle@260 789 returnSlv = getReadySlave();
seanhalle@260 790
seanhalle@260 791 if( returnSlv != NULL )
seanhalle@260 792 { returnSlv->coreAnimatedBy = coreNum;
seanhalle@260 793
seanhalle@260 794 //have work, so reset Done flag (when work generated on other core)
seanhalle@260 795 if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf
seanhalle@260 796 processEnv->coreIsDone[coreNum] = FALSE; //don't just write always
seanhalle@260 797
seanhalle@260 798 goto ReturnTheSlv;
seanhalle@260 799 }
seanhalle@260 800
seanhalle@260 801 //were no slaves, so try to get a ready task..
seanhalle@260 802 newTaskStub = getTaskStub();
seanhalle@260 803
seanhalle@260 804 if( newTaskStub != NULL )
seanhalle@260 805 {
seanhalle@260 806 //get the slot slave to assign the task to..
seanhalle@260 807 returnSlv = processEnv->slotTaskSlvs[coreNum][slotNum];
seanhalle@260 808
seanhalle@260 809 //point slave to task's function, and mark slave as having task
seanhalle@260 810 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv,
seanhalle@260 811 newTaskStub->taskType->fn, newTaskStub->args );
seanhalle@260 812 returnSlv->taskStub = newTaskStub;
seanhalle@260 813 newTaskStub->slaveAssignedTo = returnSlv;
seanhalle@260 814 returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type
seanhalle@260 815
seanhalle@260 816 //have work, so reset Done flag, if was set
seanhalle@260 817 if( processEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf
seanhalle@260 818 processEnv->coreIsDone[coreNum] = FALSE; //don't just write always
seanhalle@260 819
seanhalle@260 820 goto ReturnTheSlv;
seanhalle@260 821 }
seanhalle@260 822 else
seanhalle@260 823 { //no task, so prune the recycle pool of free task slaves
seanhalle@260 824 freeTaskSlv = readPrivQ( processEnv->freeTaskSlvRecycleQ );
seanhalle@260 825 if( freeTaskSlv != NULL )
seanhalle@260 826 { //delete to bound the num extras, and deliver shutdown cond
seanhalle@260 827 handleDissipate( freeTaskSlv, processEnv );
seanhalle@260 828 //then return NULL
seanhalle@260 829 returnSlv = NULL;
seanhalle@260 830
seanhalle@260 831 goto ReturnTheSlv;
seanhalle@260 832 }
seanhalle@260 833 else
seanhalle@260 834 { //candidate for shutdown.. if all extras dissipated, and no tasks
seanhalle@260 835 // and no ready to resume slaves, then no way to generate
seanhalle@260 836 // more tasks (on this core -- other core might have task still)
seanhalle@260 837 if( processEnv->numLiveExtraTaskSlvs == 0 &&
seanhalle@260 838 processEnv->numLiveThreadSlvs == 0 )
seanhalle@260 839 { //This core sees no way to generate more tasks, so say it
seanhalle@260 840 if( processEnv->coreIsDone[coreNum] == FALSE )
seanhalle@260 841 { processEnv->numCoresDone += 1;
seanhalle@260 842 processEnv->coreIsDone[coreNum] = TRUE;
seanhalle@260 843 #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE
seanhalle@260 844 processEnv->shutdownInitiated = TRUE;
seanhalle@260 845
seanhalle@260 846 #else
seanhalle@260 847 if( processEnv->numCoresDone == NUM_CORES )
seanhalle@260 848 { //means no cores have work, and none can generate more
seanhalle@260 849 processEnv->shutdownInitiated = TRUE;
seanhalle@260 850 }
seanhalle@260 851 #endif
seanhalle@260 852 }
seanhalle@260 853 }
seanhalle@260 854 //check if shutdown has been initiated by this or other core
seanhalle@260 855 if(processEnv->shutdownInitiated)
seanhalle@260 856 { returnSlv = PR_SS__create_shutdown_slave();
seanhalle@260 857 }
seanhalle@260 858 else
seanhalle@260 859 returnSlv = NULL;
seanhalle@260 860
seanhalle@260 861 goto ReturnTheSlv; //don't need, but completes pattern
seanhalle@260 862 } //if( freeTaskSlv != NULL )
seanhalle@260 863 } //if( newTaskStub == NULL )
seanhalle@260 864 //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL
seanhalle@260 865
seanhalle@260 866
seanhalle@260 867 ReturnTheSlv: //All paths goto here.. to provide single point for holistic..
seanhalle@260 868
seanhalle@260 869 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
seanhalle@260 870 if( returnSlv == NULL )
seanhalle@260 871 { returnSlv = processEnv->idleSlv[coreNum][slotNum];
seanhalle@260 872
seanhalle@260 873 //things that would normally happen in resume(), but idle VPs
seanhalle@260 874 // never go there
seanhalle@260 875 returnSlv->assignCount++; //gives each idle unit a unique ID
seanhalle@260 876 Unit newU;
seanhalle@260 877 newU.vp = returnSlv->slaveID;
seanhalle@260 878 newU.task = returnSlv->assignCount;
seanhalle@260 879 addToListOfArrays(Unit,newU,processEnv->unitList);
seanhalle@260 880
seanhalle@260 881 if (returnSlv->assignCount > 1) //make a dependency from prev idle unit
seanhalle@260 882 { Dependency newD; // to this one
seanhalle@260 883 newD.from_vp = returnSlv->slaveID;
seanhalle@260 884 newD.from_task = returnSlv->assignCount - 1;
seanhalle@260 885 newD.to_vp = returnSlv->slaveID;
seanhalle@260 886 newD.to_task = returnSlv->assignCount;
seanhalle@260 887 addToListOfArrays(Dependency, newD ,processEnv->ctlDependenciesList);
seanhalle@260 888 }
seanhalle@260 889 }
seanhalle@260 890 else //have a slave will be assigned to the slot
seanhalle@260 891 { //assignSlv->numTimesAssigned++;
seanhalle@260 892 //get previous occupant of the slot
seanhalle@260 893 Unit prev_in_slot =
seanhalle@260 894 processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
seanhalle@260 895 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency
seanhalle@260 896 { Dependency newD; // is a hardware dependency
seanhalle@260 897 newD.from_vp = prev_in_slot.vp;
seanhalle@260 898 newD.from_task = prev_in_slot.task;
seanhalle@260 899 newD.to_vp = returnSlv->slaveID;
seanhalle@260 900 newD.to_task = returnSlv->assignCount;
seanhalle@260 901 addToListOfArrays(Dependency,newD,processEnv->hwArcs);
seanhalle@260 902 }
seanhalle@260 903 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous
seanhalle@260 904 prev_in_slot.task = returnSlv->assignCount;
seanhalle@260 905 processEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
seanhalle@260 906 prev_in_slot;
seanhalle@260 907 }
seanhalle@260 908 #endif
seanhalle@260 909
seanhalle@260 910 return( returnSlv );
seanhalle@260 911 }
seanhalle@260 912
seanhalle@260 913
seanhalle@260 914 //=================================================================
seanhalle@260 915 //#else //is MODE__MULTI_LANG
seanhalle@260 916 //For multi-lang mode, first, get the constraint-env holder out of
seanhalle@260 917 // the process, which is in the slave.
seanhalle@260 918 //Second, get the magic number out of the request, use it to look up
seanhalle@260 919 // the constraint Env within the constraint-env holder.
seanhalle@260 920 //Then get the request handler out of the constr env
seanhalle@260 921 constrEnvHolder = slave->process->constrEnvHolder;
seanhalle@260 922 reqst = slave->request;
seanhalle@260 923 langMagicNumber = reqst->langMagicNumber;
seanhalle@260 924 semanticEnv = lookup( langMagicNumber, constrEnvHolder ); //a macro
seanhalle@260 925 if( slave->reqst->type == taskEnd ) //end-task is special
seanhalle@260 926 { //need to know what lang's task ended
seanhalle@260 927 taskEndHandler = semanticEnv->taskEndHandler;
seanhalle@260 928 (*taskEndHandler)( slave, reqst, semanticEnv ); //can put semantic data into task end reqst, for continuation, etc
seanhalle@260 929 //this is a slot slave, get a new task for it
seanhalle@260 930 if( !existsOverrideAssigner )//if exists, is set above, before loop
seanhalle@260 931 { //search for task assigner that has work
seanhalle@260 932 for( a = 0; a < num_assigners; a++ )
seanhalle@260 933 { if( taskAssigners[a]->hasWork )
seanhalle@260 934 { newTaskAssigner = taskAssigners[a];
seanhalle@260 935 (*newTaskAssigner)( slave, semanticEnv );
seanhalle@260 936 goto GotTask;
seanhalle@260 937 }
seanhalle@260 938 }
seanhalle@260 939 goto NoTasks;
seanhalle@260 940 }
seanhalle@260 941
seanhalle@260 942 GotTask:
seanhalle@260 943 continue; //have work, so do next iter of loop, don't call slave assigner
seanhalle@260 944 }
seanhalle@260 945 if( slave->typeOfVP == taskSlotSlv ) changeSlvType();//is suspended task
seanhalle@260 946 //now do normal suspended slave request handler
seanhalle@260 947 requestHandler = semanticEnv->requestHandler;
seanhalle@260 948 //#endif
seanhalle@260 949
seanhalle@260 950
seanhalle@260 951 }
seanhalle@260 952 //If make it here, then was no task for this slot
seanhalle@260 953 //slot empty, hand to Assigner to fill with a slave
seanhalle@260 954 if( currSlot->needsSlaveAssigned )
seanhalle@260 955 { //Call plugin's Assigner to give slot a new slave
seanhalle@260 956 HOLISTIC__Record_Assigner_start;
seanhalle@260 957
seanhalle@260 958 //#ifdef MODE__MULTI_LANG
seanhalle@260 959 NoTasks:
seanhalle@260 960 //First, choose an Assigner..
seanhalle@260 961 //There are several Assigners, one for each langlet.. they all
seanhalle@260 962 // indicate whether they have work available.. just pick the first
seanhalle@260 963 // one that has work.. Or, if there's a Unified Assigner, call
seanhalle@260 964 // that one.. So, go down array, checking..
seanhalle@260 965 if( !existsOverrideAssigner )
seanhalle@260 966 { for( a = 0; a < num_assigners; a++ )
seanhalle@260 967 { if( assigners[a]->hasWork )
seanhalle@260 968 { slaveAssigner = assigners[a];
seanhalle@260 969 goto GotAssigner;
seanhalle@260 970 }
seanhalle@260 971 }
seanhalle@260 972 //no work, so just continue to next iter of scan loop
seanhalle@260 973 continue;
seanhalle@260 974 }
seanhalle@260 975 //when exists override, the assigner is set, once, above, so do nothing
seanhalle@260 976 GotAssigner:
seanhalle@260 977 //#endif
seanhalle@260 978
seanhalle@260 979 assignedSlaveVP =
seanhalle@260 980 (*slaveAssigner)( semanticEnv, currSlot );
seanhalle@260 981
seanhalle@260 982 //put the chosen slave into slot, and adjust flags and state
seanhalle@260 983 if( assignedSlaveVP != NULL )
seanhalle@260 984 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 985 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@260 986 currSlot->needsSlaveAssigned = FALSE;
seanhalle@260 987 numSlotsFilled += 1;
seanhalle@260 988
seanhalle@260 989 HOLISTIC__Record_Assigner_end;
seanhalle@260 990 }
seanhalle@260 991 }//if slot needs slave assigned
seanhalle@260 992 }//for( slotIdx..
seanhalle@260 993
seanhalle@260 994 MEAS__Capture_Post_Master_Point;
seanhalle@260 995
seanhalle@260 996 masterSwitchToCoreCtlr( masterVP );
seanhalle@260 997 flushRegisters();
seanhalle@260 998 DEBUG__printf(FALSE,"came back after switch to core -- so lock released!");
seanhalle@260 999 }//while(1)
seanhalle@260 1000 }
seanhalle@260 1001