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