comparison AnimationMaster.c @ 268:e5bd470b562b

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