annotate AnimationMaster.c @ 267:608833ae2c5d

Checkpoint -- about to clean up AnimationMaster, deleting a bunch of stuff
author Sean Halle <seanhalle@yahoo.com>
date Sun, 04 Nov 2012 18:39:28 -0800
parents a5fa1e087c7e
children e5bd470b562b
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@261 13 #include "VSs_impl/VSs.h"
seanhalle@230 14
seanhalle@261 15 inline void
seanhalle@267 16 replaceWithNewSlotSlv( SlaveVP *slave );
seanhalle@230 17
seanhalle@230 18
seanhalle@230 19 /*The animationMaster embodies most of the animator of the language. The
seanhalle@230 20 * animator is what emodies the behavior of language constructs.
seanhalle@230 21 * As such, it is the animationMaster, in combination with the plugin
seanhalle@230 22 * functions, that make the language constructs do their behavior.
seanhalle@230 23 *
seanhalle@230 24 *Within the code, this is the top-level-function of the masterVPs, and
seanhalle@230 25 * runs when the coreController has no more slave VPs. It's job is to
seanhalle@260 26 * refill the animation slots with slaves that have work.
seanhalle@230 27 *
seanhalle@260 28 *There are multiple versions of the master, each tuned to a specific
seanhalle@260 29 * combination of modes. This keeps the master simple, with reduced overhead,
seanhalle@260 30 * when the application is not using the extra complexity.
seanhalle@260 31 *
seanhalle@260 32 *As of Sept 2012, the versions available will be:
seanhalle@260 33 * 1) Single langauge, which only exposes slaves (such as SSR or Vthread)
seanhalle@260 34 * 2) Single language, which only exposes tasks (such as pure dataflow)
seanhalle@260 35 * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP)
seanhalle@260 36 * 4) Multi-language, which always assumes both tasks and slaves
seanhalle@260 37 * 5) Multi-language and multi-process, which also assumes both tasks and slaves
seanhalle@260 38 *
seanhalle@260 39 *
seanhalle@260 40 *
seanhalle@260 41 */
seanhalle@260 42
seanhalle@261 43
seanhalle@260 44 //===================== The versions of the Animation Master =================
seanhalle@260 45 //
seanhalle@260 46 //==============================================================================
seanhalle@260 47
seanhalle@260 48 /* 1) This version is for a single language, that has only slaves, no tasks,
seanhalle@260 49 * such as Vthread or SSR.
seanhalle@260 50 *This version is for when an application has only a single language, and
seanhalle@260 51 * that language exposes slaves explicitly (as opposed to a task based
seanhalle@260 52 * language like pure dataflow).
seanhalle@260 53 *
seanhalle@260 54 *
seanhalle@260 55 *It scans the animation slots for just-completed slaves.
seanhalle@260 56 * Each completed slave has a request in it. So, the master hands each to
seanhalle@260 57 * the plugin's request handler (there is only one plugin, because only one
seanhalle@260 58 * lang).
seanhalle@230 59 *Each request represents a language construct that has been encountered
seanhalle@230 60 * by the application code in the slave. Passing the request to the
seanhalle@230 61 * request handler is how that language construct's behavior gets invoked.
seanhalle@230 62 * The request handler then performs the actions of the construct's
seanhalle@230 63 * behavior. So, the request handler encodes the behavior of the
seanhalle@230 64 * language's parallelism constructs, and performs that when the master
seanhalle@230 65 * hands it a slave containing a request to perform that construct.
seanhalle@230 66 *
seanhalle@230 67 *On a shared-memory machine, the behavior of parallelism constructs
seanhalle@230 68 * equals control, over order of execution of code. Hence, the behavior
seanhalle@230 69 * of the language constructs performed by the request handler is to
seanhalle@230 70 * choose the order that slaves get animated, and thereby control the
seanhalle@230 71 * order that application code in the slaves executes.
seanhalle@230 72 *
seanhalle@230 73 *To control order of animation of slaves, the request handler has a
seanhalle@230 74 * semantic environment that holds data structures used to hold slaves
seanhalle@230 75 * and choose when they're ready to be animated.
seanhalle@230 76 *
seanhalle@230 77 *Once a slave is marked as ready to be animated by the request handler,
seanhalle@230 78 * it is the second plugin function, the Assigner, which chooses the core
seanhalle@230 79 * the slave gets assigned to for animation. Hence, the Assigner doesn't
seanhalle@230 80 * perform any of the semantic behavior of language constructs, rather
seanhalle@230 81 * it gives the language a chance to improve performance. The performance
seanhalle@230 82 * of application code is strongly related to communication between
seanhalle@230 83 * cores. On shared-memory machines, communication is caused during
seanhalle@230 84 * execution of code, by memory accesses, and how much depends on contents
seanhalle@230 85 * of caches connected to the core executing the code. So, the placement
seanhalle@230 86 * of slaves determines the communication caused during execution of the
seanhalle@230 87 * slave's code.
seanhalle@230 88 *The point of the Assigner, then, is to use application information during
seanhalle@230 89 * execution of the program, to make choices about slave placement onto
seanhalle@230 90 * cores, with the aim to put slaves close to caches containing the data
seanhalle@230 91 * used by the slave's code.
seanhalle@230 92 *
seanhalle@230 93 *==========================================================================
seanhalle@230 94 *In summary, the animationMaster scans the slots, finds slaves
seanhalle@230 95 * just-finished, which hold requests, pass those to the request handler,
seanhalle@230 96 * along with the semantic environment, and the request handler then manages
seanhalle@230 97 * the structures in the semantic env, which controls the order of
seanhalle@230 98 * animation of slaves, and so embodies the behavior of the language
seanhalle@230 99 * constructs.
seanhalle@230 100 *The animationMaster then rescans the slots, offering each empty one to
seanhalle@230 101 * the Assigner, along with the semantic environment. The Assigner chooses
seanhalle@230 102 * among the ready slaves in the semantic Env, finding the one best suited
seanhalle@230 103 * to be animated by that slot's associated core.
seanhalle@230 104 *
seanhalle@230 105 *==========================================================================
seanhalle@230 106 *Implementation Details:
seanhalle@230 107 *
seanhalle@230 108 *There is a separate masterVP for each core, but a single semantic
seanhalle@230 109 * environment shared by all cores. Each core also has its own scheduling
seanhalle@230 110 * slots, which are used to communicate slaves between animationMaster and
seanhalle@261 111 * coreController. There is only one global variable, _PRTopEnv, which
seanhalle@230 112 * holds the semantic env and other things shared by the different
seanhalle@230 113 * masterVPs. The request handler and Assigner are registered with
seanhalle@230 114 * the animationMaster by the language's init function, and a pointer to
seanhalle@261 115 * each is in the _PRTopEnv. (There are also some pthread related global
seanhalle@260 116 * vars, but they're only used during init of PR).
seanhalle@260 117 *PR gains control over the cores by essentially "turning off" the OS's
seanhalle@230 118 * scheduler, using pthread pin-to-core commands.
seanhalle@230 119 *
seanhalle@230 120 *The masterVPs are created during init, with this animationMaster as their
seanhalle@230 121 * top level function. The masterVPs use the same SlaveVP data structure,
seanhalle@230 122 * even though they're not slave VPs.
seanhalle@230 123 *A "seed slave" is also created during init -- this is equivalent to the
seanhalle@260 124 * "main" function in C, and acts as the entry-point to the PR-language-
seanhalle@230 125 * based application.
seanhalle@260 126 *The masterVPs share a single system-wide master-lock, so only one
seanhalle@230 127 * masterVP may be animated at a time.
seanhalle@261 128 *The core controllers access _PRTopEnv to get the masterVP, and when
seanhalle@230 129 * they start, the slots are all empty, so they run their associated core's
seanhalle@230 130 * masterVP. The first of those to get the master lock sees the seed slave
seanhalle@230 131 * in the shared semantic environment, so when it runs the Assigner, that
seanhalle@230 132 * returns the seed slave, which the animationMaster puts into a scheduling
seanhalle@230 133 * slot then switches to the core controller. That then switches the core
seanhalle@230 134 * over to the seed slave, which then proceeds to execute language
seanhalle@230 135 * constructs to create more slaves, and so on. Each of those constructs
seanhalle@230 136 * causes the seed slave to suspend, switching over to the core controller,
seanhalle@230 137 * which eventually switches to the masterVP, which executes the
seanhalle@260 138 * request handler, which uses PR primitives to carry out the creation of
seanhalle@230 139 * new slave VPs, which are marked as ready for the Assigner, and so on..
seanhalle@230 140 *
seanhalle@230 141 *On animation slots, and system behavior:
seanhalle@260 142 * A request may linger in an animation slot for a long time while
seanhalle@230 143 * the slaves in the other slots are animated. This only becomes a problem
seanhalle@230 144 * when such a request is a choke-point in the constraints, and is needed
seanhalle@260 145 * to free work for *other* cores. To reduce this occurrence, the number
seanhalle@230 146 * of animation slots should be kept low. In balance, having multiple
seanhalle@230 147 * animation slots amortizes the overhead of switching to the masterVP and
seanhalle@230 148 * executing the animationMaster code, which drives for more than one. In
seanhalle@230 149 * practice, the best balance should be discovered by profiling.
seanhalle@230 150 */
seanhalle@230 151 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@230 152 {
seanhalle@230 153 //Used while scanning and filling animation slots
seanhalle@230 154 int32 slotIdx, numSlotsFilled;
seanhalle@235 155 AnimSlot *currSlot, **animSlots;
seanhalle@230 156 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@230 157
seanhalle@230 158 //Local copies, for performance
seanhalle@230 159 MasterEnv *masterEnv;
seanhalle@230 160 SlaveAssigner slaveAssigner;
seanhalle@230 161 RequestHandler requestHandler;
seanhalle@230 162 void *semanticEnv;
seanhalle@230 163 int32 thisCoresIdx;
nengel@238 164
seanhalle@230 165 //======================== Initializations ========================
seanhalle@261 166 masterEnv = (MasterEnv*)_PRTopEnv;
seanhalle@230 167
seanhalle@230 168 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@235 169 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@230 170
seanhalle@230 171 requestHandler = masterEnv->requestHandler;
seanhalle@230 172 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@230 173 semanticEnv = masterEnv->semanticEnv;
nengel@238 174
nengel@238 175 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@230 176
seanhalle@230 177 //======================== animationMaster ========================
seanhalle@230 178 while(1){
seanhalle@230 179
seanhalle@230 180 MEAS__Capture_Pre_Master_Point
seanhalle@230 181
seanhalle@230 182 //Scan the animation slots
seanhalle@230 183 numSlotsFilled = 0;
seanhalle@236 184 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@230 185 {
seanhalle@235 186 currSlot = animSlots[ slotIdx ];
seanhalle@230 187
nengel@239 188 //Check if newly-done slave in slot, which will need request handled
seanhalle@230 189 if( currSlot->workIsDone )
seanhalle@230 190 {
seanhalle@230 191 currSlot->workIsDone = FALSE;
seanhalle@267 192 currSlot->needsWorkAssigned = TRUE;
nengel@238 193
nengel@238 194 HOLISTIC__Record_AppResponder_start;
seanhalle@230 195 MEAS__startReqHdlr;
seanhalle@230 196
seanhalle@260 197 currSlot->workIsDone = FALSE;
seanhalle@267 198 currSlot->needsWorkAssigned = TRUE;
seanhalle@260 199 SlaveVP *currSlave = currSlot->slaveAssignedToSlot;
seanhalle@260 200
seanhalle@260 201 justAddedReqHdlrChg();
seanhalle@261 202 //handle the request, either by PR or by the language
seanhalle@260 203 if( currSlave->requests->reqType != LangReq )
seanhalle@261 204 { //The request is a standard PR one, not one defined by the
seanhalle@261 205 // language, so PR handles it, then queues slave to be assigned
seanhalle@261 206 handleReqInPR( currSlave );
seanhalle@261 207 writePrivQ( currSlave, PRReadyQ ); //Q slave to be assigned below
seanhalle@260 208 }
seanhalle@260 209 else
seanhalle@260 210 { MEAS__startReqHdlr;
seanhalle@260 211
seanhalle@260 212 //Language handles request, which is held inside slave struc
seanhalle@260 213 (*requestHandler)( currSlave, semanticEnv );
seanhalle@260 214
seanhalle@260 215 MEAS__endReqHdlr;
seanhalle@260 216 }
seanhalle@260 217 }
seanhalle@260 218
seanhalle@260 219 //process the requests made by the slave (held inside slave struc)
seanhalle@230 220 (*requestHandler)( currSlot->slaveAssignedToSlot, semanticEnv );
seanhalle@230 221
nengel@238 222 HOLISTIC__Record_AppResponder_end;
seanhalle@230 223 MEAS__endReqHdlr;
seanhalle@230 224 }
seanhalle@230 225 //If slot empty, hand to Assigner to fill with a slave
seanhalle@267 226 if( currSlot->needsWorkAssigned )
seanhalle@230 227 { //Call plugin's Assigner to give slot a new slave
nengel@238 228 HOLISTIC__Record_Assigner_start;
seanhalle@230 229 assignedSlaveVP =
seanhalle@230 230 (*slaveAssigner)( semanticEnv, currSlot );
seanhalle@230 231
seanhalle@230 232 //put the chosen slave into slot, and adjust flags and state
seanhalle@230 233 if( assignedSlaveVP != NULL )
seanhalle@230 234 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@235 235 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@267 236 currSlot->needsWorkAssigned = FALSE;
seanhalle@230 237 numSlotsFilled += 1;
nengel@238 238
nengel@238 239 HOLISTIC__Record_Assigner_end;
seanhalle@230 240 }
seanhalle@230 241 }
seanhalle@230 242 }
seanhalle@230 243
seanhalle@230 244 MEAS__Capture_Post_Master_Point;
seanhalle@230 245
seanhalle@231 246 masterSwitchToCoreCtlr( masterVP );
seanhalle@230 247 flushRegisters();
seanhalle@235 248 DEBUG__printf(FALSE,"came back after switch to core -- so lock released!");
seanhalle@232 249 }//while(1)
seanhalle@230 250 }
seanhalle@230 251
seanhalle@260 252
seanhalle@260 253 /* 2) This version is for a single language that has only tasks, which
seanhalle@260 254 * cannot be suspended.
seanhalle@260 255 */
seanhalle@260 256 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@260 257 {
seanhalle@260 258 //Used while scanning and filling animation slots
seanhalle@260 259 int32 slotIdx, numSlotsFilled;
seanhalle@260 260 AnimSlot *currSlot, **animSlots;
seanhalle@260 261 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@260 262
seanhalle@260 263 //Local copies, for performance
seanhalle@260 264 MasterEnv *masterEnv;
seanhalle@260 265 SlaveAssigner slaveAssigner;
seanhalle@260 266 RequestHandler requestHandler;
seanhalle@260 267 PRSemEnv *semanticEnv;
seanhalle@260 268 int32 thisCoresIdx;
seanhalle@260 269
seanhalle@260 270 //#ifdef MODE__MULTI_LANG
seanhalle@260 271 SlaveVP *slave;
seanhalle@260 272 PRProcess *process;
seanhalle@260 273 int32 langMagicNumber;
seanhalle@260 274 //#endif
seanhalle@260 275
seanhalle@260 276 //======================== Initializations ========================
seanhalle@261 277 masterEnv = (MasterEnv*)_PRTopEnv;
seanhalle@260 278
seanhalle@260 279 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@260 280 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@260 281
seanhalle@260 282 requestHandler = masterEnv->requestHandler;
seanhalle@260 283 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@260 284 semanticEnv = masterEnv->semanticEnv;
seanhalle@260 285
seanhalle@260 286 //initialize, for non-multi-lang, non multi-proc case
seanhalle@260 287 // default handler gets put into master env by a registration call by lang
seanhalle@260 288 endTaskHandler = masterEnv->defaultTaskHandler;
seanhalle@260 289
seanhalle@260 290 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@260 291
seanhalle@260 292 //======================== animationMaster ========================
seanhalle@260 293 //Do loop gets requests handled and work assigned to slots..
seanhalle@260 294 // work can either be a task or a resumed slave
seanhalle@260 295 //Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 296 // then the next available work may be either.. so really have two distinct
seanhalle@260 297 // loops that are inter-twined..
seanhalle@260 298 while(1){
seanhalle@260 299
seanhalle@260 300 MEAS__Capture_Pre_Master_Point
seanhalle@260 301
seanhalle@260 302 //Scan the animation slots
seanhalle@260 303 numSlotsFilled = 0;
seanhalle@260 304 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@260 305 {
seanhalle@260 306 currSlot = animSlots[ slotIdx ];
seanhalle@260 307
seanhalle@260 308 //Check if newly-done slave in slot, which will need request handled
seanhalle@260 309 if( currSlot->workIsDone )
seanhalle@260 310 { currSlot->workIsDone = FALSE;
seanhalle@260 311
seanhalle@260 312 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@260 313 MEAS__startReqHdlr;
seanhalle@260 314
seanhalle@260 315
seanhalle@260 316 //process the request made by the slave (held inside slave struc)
seanhalle@260 317 slave = currSlot->slaveAssignedToSlot;
seanhalle@260 318
seanhalle@260 319 //check if the completed work was a task..
seanhalle@267 320 if( slave->metaTask->isATask )
seanhalle@260 321 {
seanhalle@267 322 if( slave->request->type == TaskEnd )
seanhalle@260 323 { //do task end handler, which is registered separately
seanhalle@260 324 //note, end hdlr may use semantic data from reqst..
seanhalle@260 325 //#ifdef MODE__MULTI_LANG
seanhalle@260 326 //get end-task handler
seanhalle@260 327 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
seanhalle@267 328 taskEndHandler = slave->metaTask->endTaskHandler;
seanhalle@260 329 //#endif
seanhalle@260 330 (*taskEndHandler)( slave, semanticEnv );
seanhalle@260 331
seanhalle@260 332 goto AssignWork;
seanhalle@260 333 }
seanhalle@260 334 else //is a task, and just suspended
seanhalle@260 335 { //turn slot slave into free task slave & make replacement
seanhalle@266 336 if( slave->typeOfVP == SlotTaskSlv ) changeSlvType();
seanhalle@260 337
seanhalle@260 338 //goto normal slave request handling
seanhalle@260 339 goto SlaveReqHandling;
seanhalle@260 340 }
seanhalle@260 341 }
seanhalle@260 342 else //is a slave that suspended
seanhalle@260 343 {
seanhalle@260 344 SlaveReqHandling:
seanhalle@260 345 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
seanhalle@260 346
seanhalle@260 347 HOLISTIC__Record_AppResponder_end;
seanhalle@260 348 MEAS__endReqHdlr;
seanhalle@260 349
seanhalle@260 350 goto AssignWork;
seanhalle@260 351 }
seanhalle@260 352 } //if has suspended slave that needs handling
seanhalle@260 353
seanhalle@260 354 //if slot empty, hand to Assigner to fill with a slave
seanhalle@267 355 if( currSlot->needsWorkAssigned )
seanhalle@260 356 { //Call plugin's Assigner to give slot a new slave
seanhalle@260 357 HOLISTIC__Record_Assigner_start;
seanhalle@260 358
seanhalle@260 359 AssignWork:
seanhalle@260 360
seanhalle@260 361 assignedSlaveVP = assignWork( semanticEnv, currSlot );
seanhalle@260 362
seanhalle@260 363 //put the chosen slave into slot, and adjust flags and state
seanhalle@260 364 if( assignedSlaveVP != NULL )
seanhalle@260 365 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 366 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@267 367 currSlot->needsWorkAssigned = FALSE;
seanhalle@260 368 numSlotsFilled += 1;
seanhalle@260 369 }
seanhalle@260 370 else
seanhalle@260 371 {
seanhalle@267 372 currSlot->needsWorkAssigned = TRUE; //local write
seanhalle@260 373 }
seanhalle@260 374 HOLISTIC__Record_Assigner_end;
seanhalle@260 375 }//if slot needs slave assigned
seanhalle@260 376 }//for( slotIdx..
seanhalle@260 377
seanhalle@260 378 MEAS__Capture_Post_Master_Point;
seanhalle@260 379
seanhalle@260 380 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@260 381 flushRegisters();
seanhalle@260 382 }//while(1)
seanhalle@260 383 }
seanhalle@260 384
seanhalle@260 385
seanhalle@260 386 /*This is the master when just multi-lang, but not multi-process mode is on.
seanhalle@260 387 * This version has to handle both tasks and slaves, and do extra work of
seanhalle@260 388 * looking up the semantic env and handlers to use, for each completed bit of
seanhalle@260 389 * work.
seanhalle@260 390 *It also has to search through the semantic envs to find one with work,
seanhalle@260 391 * then ask that env's assigner to return a unit of that work.
seanhalle@260 392 *
seanhalle@260 393 *The language is written to startup in the same way as if it were the only
seanhalle@260 394 * language in the app, and it operates in the same way,
seanhalle@260 395 * the only difference between single language and multi-lang is here, in the
seanhalle@260 396 * master.
seanhalle@260 397 *This invisibility to mode is why the language has to use registration calls
seanhalle@260 398 * for everything during startup -- those calls do different things depending
seanhalle@260 399 * on whether it's single-language or multi-language mode.
seanhalle@260 400 *
seanhalle@260 401 *In this version of the master, work can either be a task or a resumed slave
seanhalle@260 402 *Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 403 * then the next available work may be either.. so really have two distinct
seanhalle@260 404 * loops that are inter-twined..
seanhalle@260 405 *
seanhalle@260 406 *Some special cases:
seanhalle@260 407 * A task-end is a special case for a few reasons (below).
seanhalle@260 408 * A task-end can't block a slave (can't cause it to "logically suspend")
seanhalle@260 409 * A task available for work can only be assigned to a special slave, which
seanhalle@260 410 * has been set aside for doing tasks, one such task-slave is always
seanhalle@260 411 * assigned to each slot. So, when a task ends, a new task is assigned to
seanhalle@260 412 * that slot's task-slave right away.
seanhalle@260 413 * But if no tasks are available, then have to switch over to looking at
seanhalle@260 414 * slaves to find one ready to resume, to find work for the slot.
seanhalle@260 415 * If a task just suspends, not ends, then its task-slave is no longer
seanhalle@260 416 * available to take new tasks, so a new task-slave has to be assigned to
seanhalle@260 417 * that slot. Then the slave of the suspended task is turned into a free
seanhalle@260 418 * task-slave and request handling is done on it as if it were a slave
seanhalle@260 419 * that suspended.
seanhalle@260 420 * After request handling, do the same sequence of looking for a task to be
seanhalle@260 421 * work, and if none, look for a slave ready to resume, as work for the slot.
seanhalle@260 422 * If a slave suspends, handle its request, then look for work.. first for a
seanhalle@260 423 * task to assign, and if none, slaves ready to resume.
seanhalle@260 424 * Another special case is when task-end is done on a free task-slave.. in
seanhalle@260 425 * that case, the slave has no more work and no way to get more.. so place
seanhalle@260 426 * it into a recycle queue.
seanhalle@260 427 * If no work is found of either type, then do a special thing to prune down
seanhalle@260 428 * the extra slaves in the recycle queue, just so don't get too many..
seanhalle@260 429 *
seanhalle@260 430 *The multi-lang thing complicates matters..
seanhalle@260 431 *
seanhalle@260 432 *For request handling, it means have to first fetch the semantic environment
seanhalle@260 433 * of the language, and then do the request handler pointed to by that
seanhalle@260 434 * semantic env.
seanhalle@260 435 *For assigning, things get more complex because of competing goals.. One
seanhalle@260 436 * goal is for language specific stuff to be used during assignment, so
seanhalle@260 437 * assigner can make higher quality decisions.. but with multiple languages,
seanhalle@260 438 * which only get mixed in the application, the assigners can't be written
seanhalle@260 439 * with knowledge of each other. So, they can only make localized decisions,
seanhalle@260 440 * and so different language's assigners may interfere with each other..
seanhalle@260 441 *
seanhalle@260 442 *So, have some possibilities available:
seanhalle@260 443 *1) can have a fixed scheduler in the proto-runtime, that all the
seanhalle@260 444 * languages give their work to.. (but then lose language-specific info,
seanhalle@260 445 * there is a standard PR format for assignment info, and the langauge
seanhalle@260 446 * attaches this to the work-unit when it gives it to PR.. also have issue
seanhalle@260 447 * with HWSim, which uses a priority Q instead of FIFO, and requests can
seanhalle@260 448 * "undo" previous work put in, so request handlers need way to manipulate
seanhalle@260 449 * the work-holding Q..) (this might be fudgeable with
seanhalle@260 450 * HWSim, if the master did a lang-supplied callback each time it assigns a
seanhalle@260 451 * unit to a slot.. then HWSim can keep exactly one unit of work in PR's
seanhalle@260 452 * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies
seanhalle@260 453 * a task-end handler that kicks the next unit of work from HWSim internal
seanhalle@260 454 * priority queue, over to PR readyQ)
seanhalle@260 455 *2) can have each language have its own semantic env, that holds its own
seanhalle@260 456 * work, which is assigned by its own assigner.. then the master searches
seanhalle@260 457 * through all the semantic envs to find one with work and asks it give work..
seanhalle@260 458 * (this has downside of blinding assigners to each other.. but does work
seanhalle@260 459 * for HWSim case)
seanhalle@260 460 *3) could make PR have a different readyQ for each core, and ask the lang
seanhalle@260 461 * to put work to the core it prefers.. but the work may be moved by PR if
seanhalle@260 462 * needed, say if one core idles for too long. This is a hybrid approach,
seanhalle@260 463 * letting the language decide which core, but PR keeps the work and does it
seanhalle@260 464 * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion,
seanhalle@260 465 * but it would be complicated by having to track cores separately)
seanhalle@260 466 *
seanhalle@260 467 *Choosing 2, to keep compatibility with single-lang mode.. it allows the same
seanhalle@260 468 * assigner to be used for single-lang as for multi-lang.. the overhead of
seanhalle@260 469 * the extra master search for work is part of the price of the flexibility,
seanhalle@260 470 * but should be fairly small.. takes the first env that has work available,
seanhalle@260 471 * and whatever it returns is assigned to the slot..
seanhalle@260 472 *
seanhalle@260 473 *As a hybrid, giving an option for a unified override assigner to be registered
seanhalle@260 474 * and used.. This allows something like a static analysis to detect
seanhalle@260 475 * which languages are grouped together, and then analyze the pattern of
seanhalle@260 476 * construct calls, and generate a custom assigner that uses info from all
seanhalle@260 477 * the languages in a unified way.. Don't really expect this to happen,
seanhalle@260 478 * but making it possible.
seanhalle@260 479 */
seanhalle@260 480 #ifdef MODE__MULTI_LANG
seanhalle@260 481 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@260 482 {
seanhalle@260 483 //Used while scanning and filling animation slots
seanhalle@260 484 int32 slotIdx, numSlotsFilled;
seanhalle@260 485 AnimSlot *currSlot, **animSlots;
seanhalle@260 486 SlaveVP *assignedSlaveVP; //the slave chosen by the assigner
seanhalle@260 487
seanhalle@260 488 //Local copies, for performance
seanhalle@260 489 MasterEnv *masterEnv;
seanhalle@260 490 SlaveAssigner slaveAssigner;
seanhalle@260 491 RequestHandler requestHandler;
seanhalle@260 492 PRSemEnv *semanticEnv;
seanhalle@260 493 int32 thisCoresIdx;
seanhalle@260 494
seanhalle@260 495 //#ifdef MODE__MULTI_LANG
seanhalle@260 496 SlaveVP *slave;
seanhalle@260 497 PRProcess *process;
seanhalle@260 498 int32 langMagicNumber;
seanhalle@260 499 //#endif
seanhalle@260 500
seanhalle@260 501 //======================== Initializations ========================
seanhalle@261 502 masterEnv = (MasterEnv*)_PRTopEnv;
seanhalle@260 503
seanhalle@260 504 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@260 505 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@260 506
seanhalle@260 507 requestHandler = masterEnv->requestHandler;
seanhalle@260 508 slaveAssigner = masterEnv->slaveAssigner;
seanhalle@260 509 semanticEnv = masterEnv->semanticEnv;
seanhalle@260 510
seanhalle@260 511 //initialize, for non-multi-lang, non multi-proc case
seanhalle@260 512 // default handler gets put into master env by a registration call by lang
seanhalle@260 513 endTaskHandler = masterEnv->defaultTaskHandler;
seanhalle@260 514
seanhalle@260 515 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@260 516
seanhalle@260 517 //======================== animationMaster ========================
seanhalle@260 518 //Do loop gets requests handled and work assigned to slots..
seanhalle@260 519 // work can either be a task or a resumed slave
seanhalle@260 520 //Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 521 // then the next available work may be either.. so really have two distinct
seanhalle@260 522 // loops that are inter-twined..
seanhalle@260 523 while(1){
seanhalle@260 524
seanhalle@260 525 MEAS__Capture_Pre_Master_Point
seanhalle@260 526
seanhalle@260 527 //Scan the animation slots
seanhalle@260 528 numSlotsFilled = 0;
seanhalle@260 529 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@260 530 {
seanhalle@260 531 currSlot = animSlots[ slotIdx ];
seanhalle@260 532
seanhalle@260 533 //Check if newly-done slave in slot, which will need request handled
seanhalle@260 534 if( currSlot->workIsDone )
seanhalle@260 535 { currSlot->workIsDone = FALSE;
seanhalle@260 536
seanhalle@260 537 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@260 538 MEAS__startReqHdlr;
seanhalle@260 539
seanhalle@260 540
seanhalle@260 541 //process the request made by the slave (held inside slave struc)
seanhalle@260 542 slave = currSlot->slaveAssignedToSlot;
seanhalle@260 543
seanhalle@260 544 //check if the completed work was a task..
seanhalle@260 545 if( slave->taskMetaInfo->isATask )
seanhalle@260 546 {
seanhalle@260 547 if( slave->reqst->type == TaskEnd )
seanhalle@260 548 { //do task end handler, which is registered separately
seanhalle@260 549 //note, end hdlr may use semantic data from reqst..
seanhalle@260 550 //#ifdef MODE__MULTI_LANG
seanhalle@260 551 //get end-task handler
seanhalle@260 552 //taskEndHandler = lookup( slave->reqst->langMagicNumber, processEnv );
seanhalle@260 553 taskEndHandler = slave->taskMetaInfo->endTaskHandler;
seanhalle@260 554 //#endif
seanhalle@260 555 (*taskEndHandler)( slave, semanticEnv );
seanhalle@260 556
seanhalle@260 557 goto AssignWork;
seanhalle@260 558 }
seanhalle@260 559 else //is a task, and just suspended
seanhalle@260 560 { //turn slot slave into free task slave & make replacement
seanhalle@266 561 if( slave->typeOfVP == SlotTaskSlv ) changeSlvType();
seanhalle@260 562
seanhalle@260 563 //goto normal slave request handling
seanhalle@260 564 goto SlaveReqHandling;
seanhalle@260 565 }
seanhalle@260 566 }
seanhalle@260 567 else //is a slave that suspended
seanhalle@260 568 {
seanhalle@260 569 SlaveReqHandling:
seanhalle@260 570 (*requestHandler)( slave, semanticEnv ); //(note: indirect Fn call more efficient when use fewer params, instead re-fetch from slave)
seanhalle@260 571
seanhalle@260 572 HOLISTIC__Record_AppResponder_end;
seanhalle@260 573 MEAS__endReqHdlr;
seanhalle@260 574
seanhalle@260 575 goto AssignWork;
seanhalle@260 576 }
seanhalle@260 577 } //if has suspended slave that needs handling
seanhalle@260 578
seanhalle@260 579 //if slot empty, hand to Assigner to fill with a slave
seanhalle@267 580 if( currSlot->needsWorkAssigned )
seanhalle@260 581 { //Call plugin's Assigner to give slot a new slave
seanhalle@260 582 HOLISTIC__Record_Assigner_start;
seanhalle@260 583
seanhalle@260 584 AssignWork:
seanhalle@260 585
seanhalle@260 586 assignedSlaveVP = assignWork( semanticEnv, currSlot );
seanhalle@260 587
seanhalle@260 588 //put the chosen slave into slot, and adjust flags and state
seanhalle@260 589 if( assignedSlaveVP != NULL )
seanhalle@260 590 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 591 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@267 592 currSlot->needsWorkAssigned = FALSE;
seanhalle@260 593 numSlotsFilled += 1;
seanhalle@260 594 }
seanhalle@260 595 else
seanhalle@260 596 {
seanhalle@267 597 currSlot->needsWorkAssigned = TRUE; //local write
seanhalle@260 598 }
seanhalle@260 599 HOLISTIC__Record_Assigner_end;
seanhalle@260 600 }//if slot needs slave assigned
seanhalle@260 601 }//for( slotIdx..
seanhalle@260 602
seanhalle@260 603 MEAS__Capture_Post_Master_Point;
seanhalle@260 604
seanhalle@260 605 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@260 606 flushRegisters();
seanhalle@260 607 }//while(1)
seanhalle@260 608 }
seanhalle@260 609 #endif //MODE__MULTI_LANG
seanhalle@260 610
seanhalle@260 611
seanhalle@260 612
seanhalle@260 613 //This is the master when both multi-lang and multi-process modes are turned on
seanhalle@260 614 //#ifdef MODE__MULTI_LANG
seanhalle@260 615 //#ifdef MODE__MULTI_PROCESS
seanhalle@260 616 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@260 617 {
seanhalle@261 618 int32 slotIdx;
seanhalle@261 619 AnimSlot *currSlot;
seanhalle@260 620 //Used while scanning and filling animation slots
seanhalle@261 621 AnimSlot **animSlots;
seanhalle@260 622
seanhalle@260 623 //Local copies, for performance
seanhalle@260 624 MasterEnv *masterEnv;
seanhalle@260 625 int32 thisCoresIdx;
seanhalle@260 626
seanhalle@260 627 //======================== Initializations ========================
seanhalle@261 628 masterEnv = (MasterEnv*)_PRTopEnv;
seanhalle@260 629
seanhalle@260 630 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@260 631 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@261 632
seanhalle@260 633 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@260 634
seanhalle@260 635 //======================== animationMaster ========================
seanhalle@260 636 //Do loop gets requests handled and work assigned to slots..
seanhalle@260 637 // work can either be a task or a resumed slave
seanhalle@260 638 //Having two cases makes this logic complex.. can be finishing either, and
seanhalle@260 639 // then the next available work may be either.. so really have two distinct
seanhalle@260 640 // loops that are inter-twined..
seanhalle@261 641 while(1)
seanhalle@261 642 {
seanhalle@261 643 MEAS__Capture_Pre_Master_Point
seanhalle@261 644
seanhalle@261 645 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@261 646 {
seanhalle@261 647 currSlot = animSlots[ slotIdx ];
seanhalle@260 648
seanhalle@261 649 masterFunction_multiLang( currSlot );
seanhalle@261 650 }
seanhalle@261 651
seanhalle@261 652 MEAS__Capture_Post_Master_Point;
seanhalle@261 653
seanhalle@261 654 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@261 655 flushRegisters();
seanhalle@261 656 }
seanhalle@261 657 }
seanhalle@261 658 #endif //MODE__MULTI_LANG
seanhalle@261 659 #endif //MODE__MULTI_PROCESS
seanhalle@261 660
seanhalle@267 661
seanhalle@267 662 //This version of the master selects one of three loops, depending upon
seanhalle@267 663 // whether stand-alone single language (just slaves), or standalone with
seanhalle@267 664 // tasks, or multi-lang (implies multi-process)
seanhalle@267 665 void animationMaster( void *initData, SlaveVP *masterVP )
seanhalle@267 666 {
seanhalle@267 667 int32 slotIdx;
seanhalle@267 668 AnimSlot *currSlot;
seanhalle@267 669 //Used while scanning and filling animation slots
seanhalle@267 670 AnimSlot **animSlots;
seanhalle@267 671
seanhalle@267 672 //Local copies, for performance
seanhalle@267 673 MasterEnv *masterEnv;
seanhalle@267 674 int32 thisCoresIdx;
seanhalle@267 675
seanhalle@267 676 //======================== Initializations ========================
seanhalle@267 677 masterEnv = (MasterEnv*)_PRTopEnv;
seanhalle@267 678
seanhalle@267 679 thisCoresIdx = masterVP->coreAnimatedBy;
seanhalle@267 680 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
seanhalle@267 681
seanhalle@267 682 HOLISTIC__Insert_Master_Global_Vars;
seanhalle@267 683
seanhalle@267 684 //======================== animationMaster ========================
seanhalle@267 685 //Have three different modes, and the master behavior is different for
seanhalle@267 686 // each, so jump to the loop that corresponds to the mode.
seanhalle@267 687 //
seanhalle@267 688 switch(mode)
seanhalle@267 689 { case StandaloneSlavesOnly:
seanhalle@267 690 while(1)
seanhalle@267 691 { MEAS__Capture_Pre_Master_Point
seanhalle@267 692 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@267 693 {
seanhalle@267 694 currSlot = animSlots[ slotIdx ];
seanhalle@267 695
seanhalle@267 696 masterFunction_StandaloneSlavesOnly( currSlot );
seanhalle@267 697 }
seanhalle@267 698 MEAS__Capture_Post_Master_Point;
seanhalle@267 699 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@267 700 flushRegisters();
seanhalle@267 701 }
seanhalle@267 702 case StandaloneWTasks:
seanhalle@267 703 while(1)
seanhalle@267 704 { MEAS__Capture_Pre_Master_Point
seanhalle@267 705 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@267 706 {
seanhalle@267 707 currSlot = animSlots[ slotIdx ];
seanhalle@267 708
seanhalle@267 709 masterFunction_StandaloneWTasks( currSlot );
seanhalle@267 710 }
seanhalle@267 711 MEAS__Capture_Post_Master_Point;
seanhalle@267 712 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@267 713 flushRegisters();
seanhalle@267 714 }
seanhalle@267 715 case MultiLang:
seanhalle@267 716 while(1)
seanhalle@267 717 { MEAS__Capture_Pre_Master_Point
seanhalle@267 718 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
seanhalle@267 719 {
seanhalle@267 720 currSlot = animSlots[ slotIdx ];
seanhalle@267 721
seanhalle@267 722 masterFunction_multiLang( currSlot );
seanhalle@267 723 }
seanhalle@267 724 MEAS__Capture_Post_Master_Point;
seanhalle@267 725 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
seanhalle@267 726 flushRegisters();
seanhalle@267 727 }
seanhalle@267 728 }
seanhalle@267 729 }
seanhalle@267 730
seanhalle@267 731
seanhalle@261 732 inline
seanhalle@261 733 void
seanhalle@261 734 masterFunction_multiLang( AnimSlot *currSlot )
seanhalle@261 735 { //Scan the animation slots
seanhalle@261 736 int32 magicNumber;
seanhalle@261 737 SlaveVP *slave;
seanhalle@261 738 SlaveVP *assignedSlaveVP;
seanhalle@261 739 PRSemEnv *semanticEnv;
seanhalle@261 740 PRReqst *req;
seanhalle@261 741 RequestHandler requestHandler;
seanhalle@260 742
seanhalle@260 743 //Check if newly-done slave in slot, which will need request handled
seanhalle@260 744 if( currSlot->workIsDone )
seanhalle@260 745 { currSlot->workIsDone = FALSE;
seanhalle@267 746 currSlot->needsWorkAssigned = TRUE;
seanhalle@260 747
seanhalle@260 748 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
seanhalle@260 749 MEAS__startReqHdlr;
seanhalle@260 750
seanhalle@260 751
seanhalle@260 752 //process the request made by the slave (held inside slave struc)
seanhalle@260 753 slave = currSlot->slaveAssignedToSlot;
seanhalle@267 754 req = slave->request;
seanhalle@261 755
seanhalle@267 756 //If the requesting slave is a slot slave, and request is not
seanhalle@267 757 // task-end, then turn it into a free task slave.
seanhalle@267 758 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
seanhalle@267 759 replaceWithNewSlotSlv( slave );
seanhalle@261 760
seanhalle@267 761 //Handle task create and end first -- they're special cases..
seanhalle@267 762 switch( req->reqType )
seanhalle@267 763 { case TaskEnd:
seanhalle@267 764 { //do PR handler, which calls lang's hdlr and does recycle of
seanhalle@267 765 // free task slave if needed -- PR handler checks for free task Slv
seanhalle@267 766 PRHandle_EndTask( slave ); break;
seanhalle@267 767 }
seanhalle@267 768 case TaskCreate:
seanhalle@267 769 { //Do PR's create-task handler, which calls the lang's hdlr
seanhalle@267 770 // PR handler checks for free task Slv
seanhalle@267 771 PRHandle_CreateTask( slave ); break;
seanhalle@267 772 }
seanhalle@267 773 case SlvCreate: PRHandle_CreateSlave( slave ); break;
seanhalle@267 774 case SlvDissipate: PRHandle_Dissipate( slave ); break;
seanhalle@267 775 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own semantic env
seanhalle@267 776 case Hardware: //for future expansion
seanhalle@267 777 case IO: //for future expansion
seanhalle@267 778 case OSCall: //for future expansion
seanhalle@267 779 PR_int__throw_exception("Not implemented"); break;
seanhalle@267 780 case Language: //normal sem request
seanhalle@267 781 magicNumber = req->langMagicNumber;
seanhalle@267 782 semanticEnv = PR_PI__give_sem_env_for( slave, magicNumber );
seanhalle@267 783 requestHandler = semanticEnv->requestHdlr;
seanhalle@267 784 (*requestHandler)( req->semReq, slave, semanticEnv );
seanhalle@267 785 }
seanhalle@261 786
seanhalle@267 787 HOLISTIC__Record_AppResponder_end;
seanhalle@267 788 MEAS__endReqHdlr;
seanhalle@267 789 } //if have request to be handled
seanhalle@260 790
seanhalle@267 791 if( currSlot->needsWorkAssigned )
seanhalle@267 792 {
seanhalle@267 793 HOLISTIC__Record_Assigner_start;
seanhalle@267 794
seanhalle@261 795 //Scan sem environs, looking for semEnv with ready work.
seanhalle@261 796 // call the Assigner for that sem Env, to get a slave for the slot
seanhalle@260 797 assignedSlaveVP = assignWork( semanticEnv, currSlot );
seanhalle@260 798
seanhalle@267 799 //if work found, put into slot, and adjust flags and state
seanhalle@260 800 if( assignedSlaveVP != NULL )
seanhalle@260 801 { currSlot->slaveAssignedToSlot = assignedSlaveVP;
seanhalle@260 802 assignedSlaveVP->animSlotAssignedTo = currSlot;
seanhalle@267 803 currSlot->needsWorkAssigned = FALSE;
seanhalle@260 804 }
seanhalle@260 805 HOLISTIC__Record_Assigner_end;
seanhalle@260 806 }//if slot needs slave assigned
seanhalle@261 807 }
seanhalle@260 808
seanhalle@261 809 //==========================================================================
seanhalle@261 810 /*When a task in a slot slave suspends, the slot slave has to be changed to
seanhalle@261 811 * a free task slave, then the slot slave replaced. The replacement can be
seanhalle@261 812 * either a recycled free task slave that finished it's task and has been
seanhalle@261 813 * idle in the recycle queue, or else create a new slave to be the slot slave.
seanhalle@261 814 *The master only calls this with a slot slave that needs to be replaced.
seanhalle@261 815 */
seanhalle@261 816 inline void
seanhalle@266 817 replaceWithNewSlotSlv( SlaveVP *requestingSlv, PRProcess *process )
seanhalle@261 818 { SlaveVP *newSlotSlv;
seanhalle@261 819
seanhalle@267 820 When slot slave converted to a free task slave, insert the process pointer -- slot slaves are not assigned to any process;
seanhalle@267 821 when convert from slot slave to free task slave, check what should do about num (live slaves + live tasks) inside VSs's task stub, and properly update process's count of liveFreeTaskSlaves
seanhalle@267 822
seanhalle@261 823 //get a new slave to be the slot slave
seanhalle@266 824 newSlotSlv = readPrivQ( process->freeTaskSlvRecycleQ );
seanhalle@261 825 if( newSlotSlv == NULL )
seanhalle@266 826 { newSlotSlv = PR_int__create_slaveVP( &idle_fn, NULL, process, 0);
seanhalle@261 827 //just made a new free task slave, so count it
seanhalle@266 828 process->numLiveFreeTaskSlvs += 1;
seanhalle@261 829 }
seanhalle@260 830
seanhalle@261 831 //set slave values to make it the slot slave
seanhalle@261 832 newSlotSlv->metaTask = NULL;
seanhalle@266 833 newSlotSlv->typeOfVP = SlotTaskSlv;
seanhalle@267 834 // newSlotSlv->needsTaskAssigned = TRUE;
seanhalle@261 835
seanhalle@261 836 //a slot slave is pinned to a particular slot on a particular core
seanhalle@261 837 //Note, this happens before the request is seen by handler, so nothing
seanhalle@261 838 // has had a chance to change the coreAnimatedBy or anything else..
seanhalle@261 839 newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo;
seanhalle@261 840 newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy;
seanhalle@261 841
seanhalle@261 842 //put it into the slot slave matrix
seanhalle@261 843 int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx;
seanhalle@261 844 int32 coreNum = requestingSlv->coreAnimatedBy;
seanhalle@266 845 process->slotTaskSlvs[coreNum][slotNum] = newSlotSlv;
seanhalle@261 846
seanhalle@261 847 //Fix up requester, to be an extra slave now (but not an ended one)
seanhalle@261 848 // because it's active, doesn't go into freeTaskSlvRecycleQ
seanhalle@261 849 requestingSlv->typeOfVP = FreeTaskSlv;
seanhalle@267 850 requestingSlv->metaTask->taskType = FreeTask;
seanhalle@260 851 }
seanhalle@260 852
seanhalle@260 853
seanhalle@261 854
seanhalle@261 855 /*This does:
seanhalle@261 856 * 1) searches the semantic environments for one with work ready
seanhalle@261 857 * if finds one, asks its assigner to return work
seanhalle@261 858 * 2) checks what kind of work: new task, resuming task, resuming slave
seanhalle@261 859 * if new task, gets the slot slave and assigns task to it and returns slave
seanhalle@261 860 * else, gets the slave attached to the metaTask and returns that.
seanhalle@261 861 * 3) if no work found, then prune former task slaves waiting to be recycled.
seanhalle@261 862 * If no work and no slaves to prune, check for shutdown conditions.
seanhalle@261 863 *
seanhalle@261 864 * Semantic env keeps its own work in its own structures, and has its own
seanhalle@261 865 * assigner. It chooses
seanhalle@261 866 * However, include a switch that switches-in an override assigner, which
seanhalle@261 867 * sees all the work in all the semantic env's. This is most likely
seanhalle@261 868 * generated by static tools and included in the executable. That means it
seanhalle@261 869 * has to be called via a registered pointer from here. The idea is that
seanhalle@261 870 * the static tools know which languages are grouped together.. and the
seanhalle@261 871 * override enables them to generate a custom assigner that uses info from
seanhalle@261 872 * all the languages in a unified way.. Don't really expect this to happen,
seanhalle@261 873 * but am making it possible.
seanhalle@260 874 */
seanhalle@260 875 inline SlaveVP *
seanhalle@261 876 assignWork( PRProcess *process, AnimSlot *slot )
seanhalle@261 877 { SlaveVP *returnSlv;
seanhalle@261 878 int32 coreNum, slotNum;
seanhalle@267 879 PRMetaTask *assignedMetaTask;
seanhalle@260 880
seanhalle@261 881 coreNum = slot->coreSlotIsOn;
seanhalle@260 882
seanhalle@267 883 if( process->overrideAssigner != NULL )
seanhalle@267 884 { assignedMetaTask = (*process->overrideAssigner)( process, slot );
seanhalle@261 885 if( assignedMetaTask != NULL )
seanhalle@261 886 {
seanhalle@261 887 //have work, so reset Done flag (caused by work generated on other core)
seanhalle@267 888 // if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
seanhalle@267 889 // process->coreIsDone[coreNum] = FALSE; //don't just write always
seanhalle@261 890
seanhalle@267 891 // switch( assignedMetaTask->taskType )
seanhalle@267 892 // { case GenericSlave: goto AssignSlave;
seanhalle@267 893 // case FreeTask: goto AssignSlave;
seanhalle@267 894 // case SlotTask: goto AssignNewTask;
seanhalle@267 895 // default: PR_int__throw_exception( "unknown task type ret by assigner" );
seanhalle@267 896 // }
seanhalle@267 897 //If meta task has a slave attached, then goto assign slave,
seanhalle@267 898 // else it's a new task, so goto where assign it to a slot slave
seanhalle@267 899 if( assignedMetaTask->slaveAssignedTo != NULL )
seanhalle@267 900 goto AssignSlave;
seanhalle@267 901 else
seanhalle@267 902 goto AssignNewTask;
seanhalle@261 903 }
seanhalle@267 904 else //metaTask is NULL, so no work..
seanhalle@261 905 goto NoWork;
seanhalle@261 906 }
seanhalle@261 907
seanhalle@261 908 //If here, then no override assigner, so search semantic envs for work
seanhalle@261 909 int32 envIdx, numEnvs; PRSemEnv **semEnvs, *semEnv; SlaveAssigner assigner;
seanhalle@261 910 semEnvs = process->semEnvs;
seanhalle@261 911 numEnvs = process->numSemEnvs;
seanhalle@267 912 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep semEnvs in hash & array
seanhalle@260 913 { semEnv = semEnvs[envIdx];
seanhalle@260 914 if( semEnv->hasWork )
seanhalle@266 915 { assigner = semEnv->slaveAssigner;
seanhalle@261 916 assignedMetaTask = (*assigner)( semEnv, slot );
seanhalle@260 917
seanhalle@261 918 //have work, so reset Done flag (caused by work generated on other core)
seanhalle@267 919 // if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
seanhalle@267 920 // process->coreIsDone[coreNum] = FALSE; //don't just write always
seanhalle@261 921
seanhalle@267 922 // switch( assignedMetaTask->taskType )
seanhalle@267 923 // { case GenericSlave: goto AssignSlave;
seanhalle@267 924 // case FreeTask: goto AssignSlave;
seanhalle@267 925 // case SlotTask: goto AssignNewTask;
seanhalle@267 926 // default: PR_int__throw_exception( "unknown task type ret by assigner" );
seanhalle@267 927 // }
seanhalle@267 928 //If meta task has a slave attached, then goto assign slave,
seanhalle@267 929 // else it's a new task, so goto where assign it to a slot slave
seanhalle@267 930 if( assignedMetaTask->slaveAssignedTo != NULL )
seanhalle@267 931 goto AssignSlave;
seanhalle@267 932 else
seanhalle@267 933 goto AssignNewTask;
seanhalle@260 934 }
seanhalle@260 935 }
seanhalle@267 936 //If reach here, then have searched all semEnv's & none have work..
seanhalle@260 937
seanhalle@261 938 NoWork:
seanhalle@261 939 //No work, if reach here..
seanhalle@266 940 { goto ReturnTheSlv;
seanhalle@261 941 }
seanhalle@266 942
seanhalle@267 943 AssignSlave: //Have a metaTask attached to a slave, so get the slave & ret it
seanhalle@267 944 { returnSlv = assignedMetaTask->slaveAssignedTo;
seanhalle@261 945 returnSlv->coreAnimatedBy = coreNum;
seanhalle@260 946
seanhalle@260 947 goto ReturnTheSlv;
seanhalle@260 948 }
seanhalle@261 949
seanhalle@267 950 AssignNewTask: //Have a new metaTask that has no slave yet.. assign to slot slv
seanhalle@260 951 {
seanhalle@260 952 //get the slot slave to assign the task to..
seanhalle@261 953 slotNum = slot->slotIdx;
seanhalle@261 954 returnSlv = process->slotTaskSlvs[coreNum][slotNum];
seanhalle@260 955
seanhalle@267 956 //point slave to task's function
seanhalle@260 957 PR_int__reset_slaveVP_to_TopLvlFn( returnSlv,
seanhalle@261 958 assignedMetaTask->topLevelFn, assignedMetaTask->initData );
seanhalle@267 959 returnSlv->metaTask = assignedMetaTask;
seanhalle@261 960 assignedMetaTask->slaveAssignedTo = returnSlv;
seanhalle@267 961 // returnSlv->needsTaskAssigned = FALSE; //slot slave is a "Task" slave type
seanhalle@260 962
seanhalle@260 963 //have work, so reset Done flag, if was set
seanhalle@267 964 // if( process->coreIsDone[coreNum] == TRUE ) //reads are higher perf
seanhalle@267 965 // process->coreIsDone[coreNum] = FALSE; //don't just write always
seanhalle@260 966
seanhalle@260 967 goto ReturnTheSlv;
seanhalle@260 968 }
seanhalle@260 969
seanhalle@260 970
seanhalle@260 971 ReturnTheSlv: //All paths goto here.. to provide single point for holistic..
seanhalle@260 972
seanhalle@260 973 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
seanhalle@260 974 if( returnSlv == NULL )
seanhalle@261 975 { returnSlv = process->idleSlv[coreNum][slotNum];
seanhalle@260 976
seanhalle@260 977 //things that would normally happen in resume(), but idle VPs
seanhalle@260 978 // never go there
seanhalle@261 979 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
seanhalle@260 980 Unit newU;
seanhalle@260 981 newU.vp = returnSlv->slaveID;
seanhalle@261 982 newU.task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 983 addToListOfArrays(Unit,newU,process->unitList);
seanhalle@260 984
seanhalle@261 985 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
seanhalle@260 986 { Dependency newD; // to this one
seanhalle@260 987 newD.from_vp = returnSlv->slaveID;
seanhalle@261 988 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
seanhalle@260 989 newD.to_vp = returnSlv->slaveID;
seanhalle@261 990 newD.to_task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 991 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
seanhalle@260 992 }
seanhalle@260 993 }
seanhalle@260 994 else //have a slave will be assigned to the slot
seanhalle@260 995 { //assignSlv->numTimesAssigned++;
seanhalle@260 996 //get previous occupant of the slot
seanhalle@260 997 Unit prev_in_slot =
seanhalle@261 998 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum];
seanhalle@260 999 if(prev_in_slot.vp != 0) //if not first slave in slot, make dependency
seanhalle@260 1000 { Dependency newD; // is a hardware dependency
seanhalle@260 1001 newD.from_vp = prev_in_slot.vp;
seanhalle@260 1002 newD.from_task = prev_in_slot.task;
seanhalle@260 1003 newD.to_vp = returnSlv->slaveID;
seanhalle@261 1004 newD.to_task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 1005 addToListOfArrays(Dependency,newD,process->hwArcs);
seanhalle@260 1006 }
seanhalle@260 1007 prev_in_slot.vp = returnSlv->slaveID; //make new slave the new previous
seanhalle@261 1008 prev_in_slot.task = returnSlv->numTimesAssignedToASlot;
seanhalle@261 1009 process->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] =
seanhalle@260 1010 prev_in_slot;
seanhalle@260 1011 }
seanhalle@260 1012 #endif
seanhalle@260 1013
seanhalle@260 1014 return( returnSlv );
seanhalle@260 1015 }
seanhalle@260 1016
seanhalle@260 1017
seanhalle@261 1018 /*In creator, only PR related things happen, and things in the langlet whose
seanhalle@261 1019 * creator construct was used.
seanhalle@261 1020 *Other langlet still gets a chance to create semData -- but by registering a
seanhalle@261 1021 * "createSemData" handler in the semEnv. When a construct of the langlet
seanhalle@261 1022 * calls "PR__give_sem_data()", if there is no semData for that langlet,
seanhalle@261 1023 * the PR will call the creator in the langlet's semEnv, place whatever it
seanhalle@261 1024 * makes as the semData in that slave for that langlet, and return that semData
seanhalle@261 1025 *
seanhalle@261 1026 *So, as far as counting things, a langlet is only allowed to count creation
seanhalle@261 1027 * of slaves it creates itself.. may have to change this later.. add a way for
seanhalle@261 1028 * langlet to register a trigger Fn called each time a slave gets created..
seanhalle@261 1029 * need more experience with what langlets will do at create time.. think Cilk
seanhalle@261 1030 * has interesting create behavior.. not sure how that will differ in light
seanhalle@261 1031 * of true tasks and langlet approach. Look at it after all done and start
seanhalle@261 1032 * modifying the langs to be langlets..
seanhalle@261 1033 *
seanhalle@261 1034 *PR itself needs to create the slave, then update numLiveSlaves in process,
seanhalle@261 1035 * copy processID from requestor to newly created
seanhalle@261 1036 */
seanhalle@261 1037 PRHandle_CreateSlave( PRReqst *req, SlaveVP *requestingSlv )
seanhalle@261 1038 { SlaveVP *newSlv;
seanhalle@261 1039 PRMetaTask metaTask;
seanhalle@261 1040 PRProcess *process;
seanhalle@261 1041
seanhalle@261 1042 process = requestingSlv->processSlaveIsIn;
seanhalle@261 1043 newSlv = PR_int__create_slaveVP();
seanhalle@261 1044 newSlv->typeOfVP = GenericSlv;
seanhalle@261 1045 newSlv->processSlaveIsIn = process;
seanhalle@266 1046 process->numLiveGenericSlvs += 1;
seanhalle@261 1047 metaTask = PR_int__create_slave_meta_task();
seanhalle@261 1048 metaTask->taskID = req->ID;
seanhalle@267 1049 // metaTask->taskType = GenericSlave;
seanhalle@260 1050
seanhalle@267 1051 (*req->handler)( req->semReq, newSlv, requestingSlv, semEnv );
seanhalle@260 1052 }
seanhalle@260 1053
seanhalle@267 1054 /*The dissipate handler has to, sdate the number of slaves of the type, within
seanhalle@261 1055 * the process, and call the langlet handler linked into the request,
seanhalle@261 1056 * and after that returns, then call the PR function that frees the slave state
seanhalle@261 1057 * (or recycles the slave).
seanhalle@261 1058 *
seanhalle@261 1059 *The PR function that frees the slave state has to also free all of the
seanhalle@261 1060 * semData in the slave.. or else reset all of the semDatas.. by, say, marking
seanhalle@261 1061 * them, then in PR__give_semData( magicNum ) call the langlet registered
seanhalle@261 1062 * "resetSemData" Fn.
seanhalle@261 1063 */
seanhalle@261 1064 PRHandle_Dissipate( SlaveVP *slave )
seanhalle@261 1065 { PRProcess *process;
seanhalle@261 1066 void *semEnv;
seanhalle@261 1067
seanhalle@261 1068 process = slave->processSlaveIsIn;
seanhalle@261 1069
seanhalle@261 1070 //do the language's dissipate handler
seanhalle@267 1071 semEnv = PR_int__give_sem_env_for_slave( slave, slave->request->langMagicNumber );
seanhalle@267 1072 (*slave->request->handler)( slave->request->semReq, slave, semEnv );
seanhalle@261 1073
seanhalle@266 1074 process->numLiveGenericSlvs -= 1;
seanhalle@267 1075 PR_int__recycle_slave_multilang( requestingSlv );
seanhalle@267 1076
seanhalle@261 1077 //check End Of Process Condition
seanhalle@261 1078 if( process->numLiveTasks == 0 &&
seanhalle@266 1079 process->numLiveGenericSlvs == 0 )
seanhalle@267 1080 PR_SS__shutdown_process( process );
seanhalle@261 1081 }
seanhalle@261 1082
seanhalle@261 1083 /*Create task is a special form, that has PR behavior in addition to plugin
seanhalle@267 1084 * behavior. Master calls this first, and then calls the plugin's
seanhalle@261 1085 * create task handler.
seanhalle@267 1086 *
seanhalle@267 1087 *Note: the requesting slave must be either generic slave or free task slave
seanhalle@261 1088 */
seanhalle@267 1089 inline PRMetaTask *
seanhalle@267 1090 PRHandle_CreateTask( PRReqst *req, SlaveVP *requestingSlv )
seanhalle@267 1091 { PRMetaTask *metaTask;
seanhalle@267 1092 PRProcess *process;
seanhalle@261 1093 PRLangMetaTask *langMetaTask;
seanhalle@267 1094 PRSemEnv *semanticEnv;
seanhalle@267 1095
seanhalle@261 1096 process = requestingSlv->processSlaveIsIn;
seanhalle@261 1097
seanhalle@267 1098 metaTask = PR_int__create_meta_task( req );
seanhalle@267 1099 metaTask->taskID = req->ID; //may be NULL
seanhalle@267 1100 metaTask->topLevelFn = req->topLevelFn;
seanhalle@267 1101 metaTask->initData = req->initData;
seanhalle@261 1102
seanhalle@261 1103 process->numLiveTasks += 1;
seanhalle@267 1104
seanhalle@267 1105 semanticEnv = PR_int__give_sem_env_for_slave( slave,
seanhalle@267 1106 req->langMagicNumber );
seanhalle@267 1107
seanhalle@267 1108 //Do the langlet's create-task handler, which keeps the task
seanhalle@267 1109 // inside the langlet's sem env, but returns the langMetaTask
seanhalle@267 1110 // so PR can hook it to the PRMetaTask.
seanhalle@267 1111 //(Could also do PRMetaTask as a prolog -- make a Fn that takes the size
seanhalle@267 1112 // of the lang's metaTask, and alloc's that plus the prolog and returns
seanhalle@267 1113 // ptr to position just above the prolog)
seanhalle@267 1114 langMetaTask = (*req->handler)(req->semReq, slave, semanticEnv);
seanhalle@261 1115 metaTask->langMetaTask = langMetaTask;
seanhalle@261 1116 langMetaTask->protoMetaTask = metaTask;
seanhalle@267 1117
seanhalle@261 1118 return;
seanhalle@261 1119 }
seanhalle@261 1120
seanhalle@261 1121 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
seanhalle@261 1122 * suspended at some point in its code.
seanhalle@261 1123 *For 1, just decr count of live tasks (and check for end condition) -- the
seanhalle@261 1124 * master loop will decide what goes into the slot freed up by this task end,
seanhalle@261 1125 * so, here, don't worry about assigning a new task to the slot slave.
seanhalle@261 1126 *For 2, the task's slot slave has been converted to a free task slave, which
seanhalle@261 1127 * now has nothing more to do, so send it to the recycle Q (which includes
seanhalle@261 1128 * freeing all the semData and meta task structs alloc'd for it). Then
seanhalle@261 1129 * decrement the live task count and check end condition.
seanhalle@261 1130 *
seanhalle@261 1131 *PR has to update count of live tasks, and check end of process condition.
seanhalle@267 1132 * The "main" can invoke constructs that wait for a process to end, so when
seanhalle@267 1133 * end detected, have to resume what's waiting..
seanhalle@267 1134 *Thing is, that wait involves the main OS thread. That means
seanhalle@261 1135 * PR internals have to do OS thread signaling. Want to do that in the
seanhalle@267 1136 * core controller, which has the original stack of an OS thread. So the
seanhalle@267 1137 * end process handling happens in the core controller.
seanhalle@261 1138 *
seanhalle@261 1139 *So here, when detect process end, signal to the core controller, which will
seanhalle@267 1140 * then do the condition variable notify to the OS thread that's waiting.
seanhalle@267 1141 *
seanhalle@267 1142 *Note: slave may be either a slot slave or a free task slave.
seanhalle@261 1143 */
seanhalle@261 1144 inline void
seanhalle@261 1145 PRHandle_EndTask( SlaveVP *requestingSlv )
seanhalle@267 1146 { void *semEnv;
seanhalle@267 1147 PRReqst *req;
seanhalle@267 1148 PRLangMetaTask *langMetaTask;
seanhalle@261 1149 PRProcess *process;
seanhalle@267 1150
seanhalle@261 1151 req = requestingSlv->request;
seanhalle@267 1152 semEnv = PR_int__give_sem_env_of_req( req, requestingSlv ); //magic num in req
seanhalle@267 1153 langMetaTask = requestingSlv->metaTask->langMetaTask;
seanhalle@261 1154
seanhalle@267 1155 //Do the langlet's request handler
seanhalle@267 1156 //Want to keep PR structs hidden from plugin, so extract semReq..
seanhalle@267 1157 (*req->handler)( langMetaTask, req->semReq, semEnv );
seanhalle@267 1158
seanhalle@267 1159 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
seanhalle@267 1160 if( requestingSlv->typeOfVP == FreeTaskSlv )
seanhalle@267 1161 PR_int__recycle_slave_multilang( requestingSlv );
seanhalle@261 1162
seanhalle@261 1163 process->numLiveTasks -= 1;
seanhalle@261 1164
seanhalle@261 1165 //check End Of Process Condition
seanhalle@261 1166 if( process->numLiveTasks == 0 &&
seanhalle@266 1167 process->numLiveGenericSlvs == 0 )
seanhalle@267 1168 //Tell the core controller to do wakeup of any waiting OS thread
seanhalle@267 1169 PR_SS__shutdown_process( process );
seanhalle@261 1170 }
seanhalle@261 1171