| rev |
line source |
|
seanhalle@230
|
1 /*
|
|
seanhalle@268
|
2 * Copyright 2010 OpenSourceResearchInstitute
|
|
seanhalle@230
|
3 *
|
|
seanhalle@230
|
4 * Licensed under BSD
|
|
seanhalle@230
|
5 */
|
|
seanhalle@230
|
6
|
|
seanhalle@230
|
7
|
|
seanhalle@230
|
8
|
|
seanhalle@230
|
9 #include <stdio.h>
|
|
seanhalle@230
|
10 #include <stddef.h>
|
|
seanhalle@230
|
11
|
|
seanhalle@260
|
12 #include "PR.h"
|
|
seanhalle@261
|
13 #include "VSs_impl/VSs.h"
|
|
seanhalle@230
|
14
|
|
seanhalle@268
|
15 /*
|
|
seanhalle@268
|
16 void PRHandle_CreateTask_SL(SlaveVP *slave);
|
|
seanhalle@230
|
17
|
|
seanhalle@268
|
18 void PRHandle_CreateSlave_SL(SlaveVP *slave);
|
|
seanhalle@268
|
19 void PRHandle_Dissipate_SL(SlaveVP *slave);
|
|
seanhalle@268
|
20 void PR_int__handle_PRServiceReq_SL(SlaveVP *slave);
|
|
seanhalle@268
|
21 */
|
|
seanhalle@268
|
22 inline void PRHandle_CreateTask( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
23 inline void PRHandle_EndTask( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
24 inline void PRHandle_CreateSlave(PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
25 void PRHandle_Dissipate( PRReqst *req, SlaveVP *slave );
|
|
seanhalle@268
|
26
|
|
seanhalle@268
|
27
|
|
seanhalle@268
|
28 //inline void masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot );
|
|
seanhalle@268
|
29 inline void masterFunction_MultiLang( AnimSlot *slot );
|
|
seanhalle@268
|
30 inline PRProcess * pickAProcess( AnimSlot *slot );
|
|
seanhalle@268
|
31 inline SlaveVP * assignWork( PRProcess *process, AnimSlot *slot );
|
|
seanhalle@230
|
32
|
|
seanhalle@230
|
33 /*The animationMaster embodies most of the animator of the language. The
|
|
seanhalle@230
|
34 * animator is what emodies the behavior of language constructs.
|
|
seanhalle@230
|
35 * As such, it is the animationMaster, in combination with the plugin
|
|
seanhalle@230
|
36 * functions, that make the language constructs do their behavior.
|
|
seanhalle@230
|
37 *
|
|
seanhalle@230
|
38 *Within the code, this is the top-level-function of the masterVPs, and
|
|
seanhalle@230
|
39 * runs when the coreController has no more slave VPs. It's job is to
|
|
seanhalle@260
|
40 * refill the animation slots with slaves that have work.
|
|
seanhalle@230
|
41 *
|
|
seanhalle@260
|
42 *There are multiple versions of the master, each tuned to a specific
|
|
seanhalle@260
|
43 * combination of modes. This keeps the master simple, with reduced overhead,
|
|
seanhalle@260
|
44 * when the application is not using the extra complexity.
|
|
seanhalle@260
|
45 *
|
|
seanhalle@260
|
46 *As of Sept 2012, the versions available will be:
|
|
seanhalle@260
|
47 * 1) Single langauge, which only exposes slaves (such as SSR or Vthread)
|
|
seanhalle@260
|
48 * 2) Single language, which only exposes tasks (such as pure dataflow)
|
|
seanhalle@260
|
49 * 3) Single language, which exposes both (like Cilk, StarSs, and OpenMP)
|
|
seanhalle@260
|
50 * 4) Multi-language, which always assumes both tasks and slaves
|
|
seanhalle@260
|
51 * 5) Multi-language and multi-process, which also assumes both tasks and slaves
|
|
seanhalle@260
|
52 *
|
|
seanhalle@260
|
53 *
|
|
seanhalle@260
|
54 *
|
|
seanhalle@260
|
55 */
|
|
seanhalle@260
|
56
|
|
seanhalle@268
|
57 //This version of the master selects one of three loops, depending upon
|
|
seanhalle@268
|
58 // whether stand-alone single language (just slaves), or standalone with
|
|
seanhalle@268
|
59 // tasks, or multi-lang (implies multi-process)
|
|
seanhalle@268
|
60 void animationMaster( void *_environment, SlaveVP *masterVP )
|
|
seanhalle@268
|
61 {
|
|
seanhalle@268
|
62 TopEnv *masterEnv = (TopEnv *)_environment;
|
|
seanhalle@268
|
63 int32 slotIdx;
|
|
seanhalle@268
|
64 AnimSlot *currSlot;
|
|
seanhalle@268
|
65 //Used while scanning and filling animation slots
|
|
seanhalle@268
|
66 AnimSlot **animSlots;
|
|
seanhalle@268
|
67
|
|
seanhalle@268
|
68 //Local copies, for performance
|
|
seanhalle@268
|
69 int32 thisCoresIdx;
|
|
seanhalle@268
|
70
|
|
seanhalle@268
|
71 //======================== Initializations ========================
|
|
seanhalle@268
|
72 thisCoresIdx = masterVP->coreAnimatedBy;
|
|
seanhalle@268
|
73 animSlots = masterEnv->allAnimSlots[thisCoresIdx];
|
|
seanhalle@268
|
74
|
|
seanhalle@268
|
75 HOLISTIC__Insert_Master_Global_Vars;
|
|
seanhalle@268
|
76
|
|
seanhalle@268
|
77 //======================== animationMaster ========================
|
|
seanhalle@268
|
78 //Have three different modes, and the master behavior is different for
|
|
seanhalle@268
|
79 // each, so jump to the loop that corresponds to the mode.
|
|
seanhalle@268
|
80 //
|
|
seanhalle@268
|
81 switch(masterEnv->mode)
|
|
seanhalle@268
|
82 {
|
|
seanhalle@268
|
83 /*
|
|
seanhalle@268
|
84 { case SingleLang:
|
|
seanhalle@268
|
85 while(1)
|
|
seanhalle@268
|
86 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@268
|
87 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@268
|
88 {
|
|
seanhalle@268
|
89 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@268
|
90
|
|
seanhalle@268
|
91 masterFunction_StandaloneSlavesOnly( masterEnv, currSlot );
|
|
seanhalle@268
|
92 }
|
|
seanhalle@268
|
93 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@268
|
94 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@268
|
95 flushRegisters();
|
|
seanhalle@268
|
96 }
|
|
seanhalle@268
|
97
|
|
seanhalle@268
|
98 case SingleLang:
|
|
seanhalle@268
|
99 { PRLangEnv *protoLangEnv = _PRTopEnv->protoLangEnv;
|
|
seanhalle@268
|
100 while(1)
|
|
seanhalle@268
|
101 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@268
|
102 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@268
|
103 {
|
|
seanhalle@268
|
104 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@268
|
105
|
|
seanhalle@268
|
106 masterFunction_SingleLang( protoLangEnv, currSlot );
|
|
seanhalle@268
|
107 }
|
|
seanhalle@268
|
108 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@268
|
109 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@268
|
110 flushRegisters();
|
|
seanhalle@268
|
111 }
|
|
seanhalle@268
|
112 }
|
|
seanhalle@268
|
113 */
|
|
seanhalle@268
|
114 case MultiLang:
|
|
seanhalle@268
|
115 { while(1)
|
|
seanhalle@268
|
116 { MEAS__Capture_Pre_Master_Point
|
|
seanhalle@268
|
117 for( slotIdx = 0; slotIdx < NUM_ANIM_SLOTS; slotIdx++)
|
|
seanhalle@268
|
118 {
|
|
seanhalle@268
|
119 currSlot = animSlots[ slotIdx ];
|
|
seanhalle@268
|
120
|
|
seanhalle@268
|
121 masterFunction_MultiLang( currSlot );
|
|
seanhalle@268
|
122 }
|
|
seanhalle@268
|
123 MEAS__Capture_Post_Master_Point;
|
|
seanhalle@268
|
124 masterSwitchToCoreCtlr( masterVP ); //returns when ctlr switches back to master
|
|
seanhalle@268
|
125 flushRegisters();
|
|
seanhalle@268
|
126 }
|
|
seanhalle@268
|
127 }
|
|
seanhalle@268
|
128 }
|
|
seanhalle@268
|
129 }
|
|
seanhalle@268
|
130
|
|
seanhalle@268
|
131
|
|
seanhalle@261
|
132
|
|
seanhalle@260
|
133 //===================== The versions of the Animation Master =================
|
|
seanhalle@260
|
134 //
|
|
seanhalle@260
|
135 //==============================================================================
|
|
seanhalle@260
|
136
|
|
seanhalle@260
|
137 /* 1) This version is for a single language, that has only slaves, no tasks,
|
|
seanhalle@260
|
138 * such as Vthread or SSR.
|
|
seanhalle@260
|
139 *This version is for when an application has only a single language, and
|
|
seanhalle@260
|
140 * that language exposes slaves explicitly (as opposed to a task based
|
|
seanhalle@260
|
141 * language like pure dataflow).
|
|
seanhalle@260
|
142 *
|
|
seanhalle@260
|
143 *
|
|
seanhalle@260
|
144 *It scans the animation slots for just-completed slaves.
|
|
seanhalle@260
|
145 * Each completed slave has a request in it. So, the master hands each to
|
|
seanhalle@260
|
146 * the plugin's request handler (there is only one plugin, because only one
|
|
seanhalle@260
|
147 * lang).
|
|
seanhalle@230
|
148 *Each request represents a language construct that has been encountered
|
|
seanhalle@230
|
149 * by the application code in the slave. Passing the request to the
|
|
seanhalle@230
|
150 * request handler is how that language construct's behavior gets invoked.
|
|
seanhalle@230
|
151 * The request handler then performs the actions of the construct's
|
|
seanhalle@230
|
152 * behavior. So, the request handler encodes the behavior of the
|
|
seanhalle@230
|
153 * language's parallelism constructs, and performs that when the master
|
|
seanhalle@230
|
154 * hands it a slave containing a request to perform that construct.
|
|
seanhalle@230
|
155 *
|
|
seanhalle@230
|
156 *On a shared-memory machine, the behavior of parallelism constructs
|
|
seanhalle@230
|
157 * equals control, over order of execution of code. Hence, the behavior
|
|
seanhalle@230
|
158 * of the language constructs performed by the request handler is to
|
|
seanhalle@230
|
159 * choose the order that slaves get animated, and thereby control the
|
|
seanhalle@230
|
160 * order that application code in the slaves executes.
|
|
seanhalle@230
|
161 *
|
|
seanhalle@230
|
162 *To control order of animation of slaves, the request handler has a
|
|
seanhalle@268
|
163 * language environment that holds data structures used to hold slaves
|
|
seanhalle@230
|
164 * and choose when they're ready to be animated.
|
|
seanhalle@230
|
165 *
|
|
seanhalle@230
|
166 *Once a slave is marked as ready to be animated by the request handler,
|
|
seanhalle@230
|
167 * it is the second plugin function, the Assigner, which chooses the core
|
|
seanhalle@230
|
168 * the slave gets assigned to for animation. Hence, the Assigner doesn't
|
|
seanhalle@230
|
169 * perform any of the semantic behavior of language constructs, rather
|
|
seanhalle@230
|
170 * it gives the language a chance to improve performance. The performance
|
|
seanhalle@230
|
171 * of application code is strongly related to communication between
|
|
seanhalle@230
|
172 * cores. On shared-memory machines, communication is caused during
|
|
seanhalle@230
|
173 * execution of code, by memory accesses, and how much depends on contents
|
|
seanhalle@230
|
174 * of caches connected to the core executing the code. So, the placement
|
|
seanhalle@230
|
175 * of slaves determines the communication caused during execution of the
|
|
seanhalle@230
|
176 * slave's code.
|
|
seanhalle@230
|
177 *The point of the Assigner, then, is to use application information during
|
|
seanhalle@230
|
178 * execution of the program, to make choices about slave placement onto
|
|
seanhalle@230
|
179 * cores, with the aim to put slaves close to caches containing the data
|
|
seanhalle@230
|
180 * used by the slave's code.
|
|
seanhalle@230
|
181 *
|
|
seanhalle@230
|
182 *==========================================================================
|
|
seanhalle@230
|
183 *In summary, the animationMaster scans the slots, finds slaves
|
|
seanhalle@230
|
184 * just-finished, which hold requests, pass those to the request handler,
|
|
seanhalle@268
|
185 * along with the language environment, and the request handler then manages
|
|
seanhalle@268
|
186 * the structures in the language env, which controls the order of
|
|
seanhalle@230
|
187 * animation of slaves, and so embodies the behavior of the language
|
|
seanhalle@230
|
188 * constructs.
|
|
seanhalle@230
|
189 *The animationMaster then rescans the slots, offering each empty one to
|
|
seanhalle@268
|
190 * the Assigner, along with the language environment. The Assigner chooses
|
|
seanhalle@268
|
191 * among the ready slaves in the language env, finding the one best suited
|
|
seanhalle@230
|
192 * to be animated by that slot's associated core.
|
|
seanhalle@230
|
193 *
|
|
seanhalle@230
|
194 *==========================================================================
|
|
seanhalle@230
|
195 *Implementation Details:
|
|
seanhalle@230
|
196 *
|
|
seanhalle@268
|
197 *There is a separate masterVP for each core, but a single language
|
|
seanhalle@230
|
198 * environment shared by all cores. Each core also has its own scheduling
|
|
seanhalle@230
|
199 * slots, which are used to communicate slaves between animationMaster and
|
|
seanhalle@261
|
200 * coreController. There is only one global variable, _PRTopEnv, which
|
|
seanhalle@268
|
201 * holds the language env and other things shared by the different
|
|
seanhalle@230
|
202 * masterVPs. The request handler and Assigner are registered with
|
|
seanhalle@230
|
203 * the animationMaster by the language's init function, and a pointer to
|
|
seanhalle@261
|
204 * each is in the _PRTopEnv. (There are also some pthread related global
|
|
seanhalle@260
|
205 * vars, but they're only used during init of PR).
|
|
seanhalle@260
|
206 *PR gains control over the cores by essentially "turning off" the OS's
|
|
seanhalle@230
|
207 * scheduler, using pthread pin-to-core commands.
|
|
seanhalle@230
|
208 *
|
|
seanhalle@230
|
209 *The masterVPs are created during init, with this animationMaster as their
|
|
seanhalle@230
|
210 * top level function. The masterVPs use the same SlaveVP data structure,
|
|
seanhalle@230
|
211 * even though they're not slave VPs.
|
|
seanhalle@230
|
212 *A "seed slave" is also created during init -- this is equivalent to the
|
|
seanhalle@260
|
213 * "main" function in C, and acts as the entry-point to the PR-language-
|
|
seanhalle@230
|
214 * based application.
|
|
seanhalle@260
|
215 *The masterVPs share a single system-wide master-lock, so only one
|
|
seanhalle@230
|
216 * masterVP may be animated at a time.
|
|
seanhalle@261
|
217 *The core controllers access _PRTopEnv to get the masterVP, and when
|
|
seanhalle@230
|
218 * they start, the slots are all empty, so they run their associated core's
|
|
seanhalle@230
|
219 * masterVP. The first of those to get the master lock sees the seed slave
|
|
seanhalle@268
|
220 * in the shared language environment, so when it runs the Assigner, that
|
|
seanhalle@230
|
221 * returns the seed slave, which the animationMaster puts into a scheduling
|
|
seanhalle@230
|
222 * slot then switches to the core controller. That then switches the core
|
|
seanhalle@230
|
223 * over to the seed slave, which then proceeds to execute language
|
|
seanhalle@230
|
224 * constructs to create more slaves, and so on. Each of those constructs
|
|
seanhalle@230
|
225 * causes the seed slave to suspend, switching over to the core controller,
|
|
seanhalle@230
|
226 * which eventually switches to the masterVP, which executes the
|
|
seanhalle@260
|
227 * request handler, which uses PR primitives to carry out the creation of
|
|
seanhalle@230
|
228 * new slave VPs, which are marked as ready for the Assigner, and so on..
|
|
seanhalle@230
|
229 *
|
|
seanhalle@230
|
230 *On animation slots, and system behavior:
|
|
seanhalle@260
|
231 * A request may linger in an animation slot for a long time while
|
|
seanhalle@230
|
232 * the slaves in the other slots are animated. This only becomes a problem
|
|
seanhalle@230
|
233 * when such a request is a choke-point in the constraints, and is needed
|
|
seanhalle@260
|
234 * to free work for *other* cores. To reduce this occurrence, the number
|
|
seanhalle@230
|
235 * of animation slots should be kept low. In balance, having multiple
|
|
seanhalle@230
|
236 * animation slots amortizes the overhead of switching to the masterVP and
|
|
seanhalle@230
|
237 * executing the animationMaster code, which drives for more than one. In
|
|
seanhalle@230
|
238 * practice, the best balance should be discovered by profiling.
|
|
seanhalle@230
|
239 */
|
|
seanhalle@268
|
240 /*
|
|
seanhalle@268
|
241 void masterFunction_StandaloneSlavesOnly( AnimSlot *slot )
|
|
seanhalle@230
|
242 {
|
|
seanhalle@268
|
243 SlaveVP *slave;
|
|
seanhalle@268
|
244 PRReqst *req;
|
|
seanhalle@268
|
245 PRLangEnv *langEnv = _PRTopEnv->langEnv;
|
|
seanhalle@268
|
246
|
|
seanhalle@230
|
247
|
|
seanhalle@230
|
248 //======================== animationMaster ========================
|
|
seanhalle@268
|
249
|
|
seanhalle@268
|
250 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@268
|
251 if( slot->workIsDone )
|
|
seanhalle@268
|
252 { slot->workIsDone = FALSE;
|
|
seanhalle@268
|
253 slot->needsWorkAssigned = TRUE;
|
|
seanhalle@230
|
254
|
|
seanhalle@230
|
255
|
|
seanhalle@268
|
256 HOLISTIC__Record_AppResponder_start;
|
|
seanhalle@268
|
257 MEAS__startReqHdlr;
|
|
seanhalle@268
|
258 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@268
|
259 slave = slot->slaveAssignedToSlot;
|
|
seanhalle@268
|
260 req = slave->request;
|
|
seanhalle@260
|
261
|
|
seanhalle@268
|
262 //Handle task create and end first -- they're special cases..
|
|
seanhalle@268
|
263 switch( req->reqType )
|
|
seanhalle@268
|
264 { case SlvCreate: PRHandle_CreateSlave( slave ); break;
|
|
seanhalle@268
|
265 case SlvDissipate: PRHandle_Dissipate( slave ); break;
|
|
seanhalle@268
|
266 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own language env
|
|
seanhalle@268
|
267 case Hardware: //for future expansion
|
|
seanhalle@268
|
268 case IO: //for future expansion
|
|
seanhalle@268
|
269 case OSCall: //for future expansion
|
|
seanhalle@268
|
270 PR_int__throw_exception("Not implemented"); break;
|
|
seanhalle@268
|
271 case Language: //normal lang request
|
|
seanhalle@268
|
272 {
|
|
seanhalle@268
|
273 (*langEnv->requestHdlr)( req->langReq, slave, langEnv );
|
|
seanhalle@230
|
274 }
|
|
seanhalle@230
|
275 }
|
|
seanhalle@268
|
276 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@268
|
277 MEAS__endReqHdlr;
|
|
seanhalle@230
|
278 }
|
|
seanhalle@268
|
279 //If slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@268
|
280 if( slot->needsWorkAssigned )
|
|
seanhalle@268
|
281 { //Call plugin's Assigner to give slot a new slave
|
|
seanhalle@268
|
282 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@230
|
283
|
|
seanhalle@268
|
284 if( langEnv->hasWork )
|
|
seanhalle@268
|
285 { (*langEnv->slaveAssigner)( langEnv, slot ); //calls PR fn that inserts work into slot
|
|
seanhalle@268
|
286 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@268
|
287 }
|
|
seanhalle@268
|
288 else
|
|
seanhalle@268
|
289 goto NoWork;
|
|
seanhalle@268
|
290 }
|
|
seanhalle@230
|
291
|
|
seanhalle@268
|
292 NoWork:
|
|
seanhalle@268
|
293 //No work, if reach here..
|
|
seanhalle@268
|
294 {
|
|
seanhalle@268
|
295 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@268
|
296 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@268
|
297 returnSlv = process->idleSlv[coreNum][slotNum];
|
|
seanhalle@268
|
298
|
|
seanhalle@268
|
299 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@268
|
300 // never go there
|
|
seanhalle@268
|
301 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@268
|
302 Unit newU;
|
|
seanhalle@268
|
303 newU.vp = returnSlv->slaveNum;
|
|
seanhalle@268
|
304 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@268
|
305 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@268
|
306
|
|
seanhalle@268
|
307 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@268
|
308 { Dependency newD; // to this one
|
|
seanhalle@268
|
309 newD.from_vp = returnSlv->slaveNum;
|
|
seanhalle@268
|
310 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@268
|
311 newD.to_vp = returnSlv->slaveNum;
|
|
seanhalle@268
|
312 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@268
|
313 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@268
|
314 }
|
|
seanhalle@268
|
315 #endif
|
|
seanhalle@268
|
316 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
317 return;
|
|
seanhalle@268
|
318 }
|
|
seanhalle@268
|
319
|
|
seanhalle@268
|
320 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@268
|
321 {
|
|
seanhalle@268
|
322 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
323 return;
|
|
seanhalle@268
|
324 }
|
|
seanhalle@230
|
325 }
|
|
seanhalle@268
|
326 */
|
|
seanhalle@260
|
327
|
|
seanhalle@260
|
328
|
|
seanhalle@260
|
329 /*This is the master when just multi-lang, but not multi-process mode is on.
|
|
seanhalle@260
|
330 * This version has to handle both tasks and slaves, and do extra work of
|
|
seanhalle@268
|
331 * looking up the language env and handlers to use, for each completed bit of
|
|
seanhalle@260
|
332 * work.
|
|
seanhalle@268
|
333 *It also has to search through the language envs to find one with work,
|
|
seanhalle@260
|
334 * then ask that env's assigner to return a unit of that work.
|
|
seanhalle@260
|
335 *
|
|
seanhalle@260
|
336 *The language is written to startup in the same way as if it were the only
|
|
seanhalle@260
|
337 * language in the app, and it operates in the same way,
|
|
seanhalle@260
|
338 * the only difference between single language and multi-lang is here, in the
|
|
seanhalle@260
|
339 * master.
|
|
seanhalle@260
|
340 *This invisibility to mode is why the language has to use registration calls
|
|
seanhalle@260
|
341 * for everything during startup -- those calls do different things depending
|
|
seanhalle@260
|
342 * on whether it's single-language or multi-language mode.
|
|
seanhalle@260
|
343 *
|
|
seanhalle@260
|
344 *In this version of the master, work can either be a task or a resumed slave
|
|
seanhalle@260
|
345 *Having two cases makes this logic complex.. can be finishing either, and
|
|
seanhalle@260
|
346 * then the next available work may be either.. so really have two distinct
|
|
seanhalle@260
|
347 * loops that are inter-twined..
|
|
seanhalle@260
|
348 *
|
|
seanhalle@260
|
349 *Some special cases:
|
|
seanhalle@260
|
350 * A task-end is a special case for a few reasons (below).
|
|
seanhalle@260
|
351 * A task-end can't block a slave (can't cause it to "logically suspend")
|
|
seanhalle@260
|
352 * A task available for work can only be assigned to a special slave, which
|
|
seanhalle@260
|
353 * has been set aside for doing tasks, one such task-slave is always
|
|
seanhalle@260
|
354 * assigned to each slot. So, when a task ends, a new task is assigned to
|
|
seanhalle@260
|
355 * that slot's task-slave right away.
|
|
seanhalle@260
|
356 * But if no tasks are available, then have to switch over to looking at
|
|
seanhalle@260
|
357 * slaves to find one ready to resume, to find work for the slot.
|
|
seanhalle@260
|
358 * If a task just suspends, not ends, then its task-slave is no longer
|
|
seanhalle@260
|
359 * available to take new tasks, so a new task-slave has to be assigned to
|
|
seanhalle@260
|
360 * that slot. Then the slave of the suspended task is turned into a free
|
|
seanhalle@260
|
361 * task-slave and request handling is done on it as if it were a slave
|
|
seanhalle@260
|
362 * that suspended.
|
|
seanhalle@260
|
363 * After request handling, do the same sequence of looking for a task to be
|
|
seanhalle@260
|
364 * work, and if none, look for a slave ready to resume, as work for the slot.
|
|
seanhalle@260
|
365 * If a slave suspends, handle its request, then look for work.. first for a
|
|
seanhalle@260
|
366 * task to assign, and if none, slaves ready to resume.
|
|
seanhalle@260
|
367 * Another special case is when task-end is done on a free task-slave.. in
|
|
seanhalle@260
|
368 * that case, the slave has no more work and no way to get more.. so place
|
|
seanhalle@260
|
369 * it into a recycle queue.
|
|
seanhalle@260
|
370 * If no work is found of either type, then do a special thing to prune down
|
|
seanhalle@260
|
371 * the extra slaves in the recycle queue, just so don't get too many..
|
|
seanhalle@260
|
372 *
|
|
seanhalle@260
|
373 *The multi-lang thing complicates matters..
|
|
seanhalle@260
|
374 *
|
|
seanhalle@268
|
375 *For request handling, it means have to first fetch the language environment
|
|
seanhalle@260
|
376 * of the language, and then do the request handler pointed to by that
|
|
seanhalle@268
|
377 * language env.
|
|
seanhalle@260
|
378 *For assigning, things get more complex because of competing goals.. One
|
|
seanhalle@260
|
379 * goal is for language specific stuff to be used during assignment, so
|
|
seanhalle@260
|
380 * assigner can make higher quality decisions.. but with multiple languages,
|
|
seanhalle@260
|
381 * which only get mixed in the application, the assigners can't be written
|
|
seanhalle@260
|
382 * with knowledge of each other. So, they can only make localized decisions,
|
|
seanhalle@260
|
383 * and so different language's assigners may interfere with each other..
|
|
seanhalle@260
|
384 *
|
|
seanhalle@260
|
385 *So, have some possibilities available:
|
|
seanhalle@260
|
386 *1) can have a fixed scheduler in the proto-runtime, that all the
|
|
seanhalle@260
|
387 * languages give their work to.. (but then lose language-specific info,
|
|
seanhalle@260
|
388 * there is a standard PR format for assignment info, and the langauge
|
|
seanhalle@260
|
389 * attaches this to the work-unit when it gives it to PR.. also have issue
|
|
seanhalle@260
|
390 * with HWSim, which uses a priority Q instead of FIFO, and requests can
|
|
seanhalle@260
|
391 * "undo" previous work put in, so request handlers need way to manipulate
|
|
seanhalle@260
|
392 * the work-holding Q..) (this might be fudgeable with
|
|
seanhalle@260
|
393 * HWSim, if the master did a lang-supplied callback each time it assigns a
|
|
seanhalle@260
|
394 * unit to a slot.. then HWSim can keep exactly one unit of work in PR's
|
|
seanhalle@260
|
395 * queue at a time.. but this is quite hack-like.. or perhaps HWSim supplies
|
|
seanhalle@260
|
396 * a task-end handler that kicks the next unit of work from HWSim internal
|
|
seanhalle@260
|
397 * priority queue, over to PR readyQ)
|
|
seanhalle@268
|
398 *2) can have each language have its own language env, that holds its own
|
|
seanhalle@260
|
399 * work, which is assigned by its own assigner.. then the master searches
|
|
seanhalle@268
|
400 * through all the language envs to find one with work and asks it give work..
|
|
seanhalle@260
|
401 * (this has downside of blinding assigners to each other.. but does work
|
|
seanhalle@260
|
402 * for HWSim case)
|
|
seanhalle@260
|
403 *3) could make PR have a different readyQ for each core, and ask the lang
|
|
seanhalle@260
|
404 * to put work to the core it prefers.. but the work may be moved by PR if
|
|
seanhalle@260
|
405 * needed, say if one core idles for too long. This is a hybrid approach,
|
|
seanhalle@260
|
406 * letting the language decide which core, but PR keeps the work and does it
|
|
seanhalle@260
|
407 * FIFO style.. (this might als be fudgeable with HWSim, in similar fashion,
|
|
seanhalle@260
|
408 * but it would be complicated by having to track cores separately)
|
|
seanhalle@260
|
409 *
|
|
seanhalle@260
|
410 *Choosing 2, to keep compatibility with single-lang mode.. it allows the same
|
|
seanhalle@260
|
411 * assigner to be used for single-lang as for multi-lang.. the overhead of
|
|
seanhalle@260
|
412 * the extra master search for work is part of the price of the flexibility,
|
|
seanhalle@260
|
413 * but should be fairly small.. takes the first env that has work available,
|
|
seanhalle@260
|
414 * and whatever it returns is assigned to the slot..
|
|
seanhalle@260
|
415 *
|
|
seanhalle@260
|
416 *As a hybrid, giving an option for a unified override assigner to be registered
|
|
seanhalle@260
|
417 * and used.. This allows something like a static analysis to detect
|
|
seanhalle@260
|
418 * which languages are grouped together, and then analyze the pattern of
|
|
seanhalle@260
|
419 * construct calls, and generate a custom assigner that uses info from all
|
|
seanhalle@260
|
420 * the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@260
|
421 * but making it possible.
|
|
seanhalle@260
|
422 */
|
|
seanhalle@268
|
423 /*
|
|
seanhalle@268
|
424 inline
|
|
seanhalle@268
|
425 void
|
|
seanhalle@268
|
426 masterFunction_SingleLang( PRLangEnv *protoLangEnv, AnimSlot *slot )
|
|
seanhalle@268
|
427 { //Scan the animation slots
|
|
seanhalle@268
|
428 SlaveVP *slave;
|
|
seanhalle@268
|
429 PRReqst *req;
|
|
seanhalle@268
|
430
|
|
seanhalle@268
|
431 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@268
|
432 if( slot->workIsDone )
|
|
seanhalle@268
|
433 { slot->workIsDone = FALSE;
|
|
seanhalle@268
|
434 slot->needsWorkAssigned = TRUE;
|
|
seanhalle@268
|
435
|
|
seanhalle@268
|
436 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@268
|
437 MEAS__startReqHdlr;
|
|
seanhalle@268
|
438
|
|
seanhalle@268
|
439
|
|
seanhalle@268
|
440 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@268
|
441 slave = slot->slaveAssignedToSlot;
|
|
seanhalle@268
|
442 req = slave->request;
|
|
seanhalle@268
|
443
|
|
seanhalle@268
|
444 //If the requesting slave is a slot slave, and request is not
|
|
seanhalle@268
|
445 // task-end, then turn it into a free task slave.
|
|
seanhalle@268
|
446 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
|
|
seanhalle@268
|
447 PR_int__replace_with_new_slot_slv( slave );
|
|
seanhalle@268
|
448
|
|
seanhalle@268
|
449 //Handle task create and end first -- they're special cases..
|
|
seanhalle@268
|
450 switch( req->reqType )
|
|
seanhalle@268
|
451 { case TaskEnd:
|
|
seanhalle@268
|
452 { //do PR handler, which calls lang's hdlr and does recycle of
|
|
seanhalle@268
|
453 // free task slave if needed -- PR handler checks for free task Slv
|
|
seanhalle@268
|
454 PRHandle_EndTask_SL( slave ); break;
|
|
seanhalle@268
|
455 }
|
|
seanhalle@268
|
456 case TaskCreate:
|
|
seanhalle@268
|
457 { //Do PR's create-task handler, which calls the lang's hdlr
|
|
seanhalle@268
|
458 // PR handler checks for free task Slv
|
|
seanhalle@268
|
459 PRHandle_CreateTask_SL( slave ); break;
|
|
seanhalle@268
|
460 }
|
|
seanhalle@268
|
461 case SlvCreate: PRHandle_CreateSlave_SL( slave ); break;
|
|
seanhalle@268
|
462 case SlvDissipate: PRHandle_Dissipate_SL( slave ); break;
|
|
seanhalle@268
|
463 case Service: PR_int__handle_PRServiceReq_SL( slave ); break; //resume into PR's own language env
|
|
seanhalle@268
|
464 case Hardware: //for future expansion
|
|
seanhalle@268
|
465 case IO: //for future expansion
|
|
seanhalle@268
|
466 case OSCall: //for future expansion
|
|
seanhalle@268
|
467 PR_int__throw_exception("Not implemented", slave, NULL); break;
|
|
seanhalle@268
|
468 case Language: //normal lang request
|
|
seanhalle@268
|
469 {
|
|
seanhalle@268
|
470 (*protoLangEnv->requestHdlr)( req->langReq, slave, (void*)PR_int__give_lang_env(protoLangEnv ));
|
|
seanhalle@268
|
471 }
|
|
seanhalle@268
|
472 }
|
|
seanhalle@268
|
473
|
|
seanhalle@268
|
474 MEAS__endReqHdlr;
|
|
seanhalle@268
|
475 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@268
|
476 } //if have request to be handled
|
|
seanhalle@268
|
477
|
|
seanhalle@268
|
478 //If slot empty, hand to Assigner to fill with a slave
|
|
seanhalle@268
|
479 if( slot->needsWorkAssigned )
|
|
seanhalle@268
|
480 { //Call plugin's Assigner to give slot a new slave
|
|
seanhalle@268
|
481 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@268
|
482
|
|
seanhalle@268
|
483 if( protoLangEnv->hasWork )
|
|
seanhalle@268
|
484 { (*protoLangEnv->slaveAssigner)( protoLangEnv, slot ); //calls PR fn that inserts work into slot
|
|
seanhalle@268
|
485 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@268
|
486 }
|
|
seanhalle@268
|
487 else
|
|
seanhalle@268
|
488 goto NoWork;
|
|
seanhalle@268
|
489 }
|
|
seanhalle@260
|
490
|
|
seanhalle@268
|
491 NoWork:
|
|
seanhalle@268
|
492 //No work, if reach here..
|
|
seanhalle@268
|
493 {
|
|
seanhalle@268
|
494 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@268
|
495 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@268
|
496 returnSlv = process->idleSlv[coreNum][slotNum];
|
|
seanhalle@268
|
497
|
|
seanhalle@268
|
498 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@268
|
499 // never go there
|
|
seanhalle@268
|
500 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@268
|
501 Unit newU;
|
|
seanhalle@268
|
502 newU.vp = returnSlv->slaveNum;
|
|
seanhalle@268
|
503 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@268
|
504 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@260
|
505
|
|
seanhalle@268
|
506 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@268
|
507 { Dependency newD; // to this one
|
|
seanhalle@268
|
508 newD.from_vp = returnSlv->slaveNum;
|
|
seanhalle@268
|
509 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@268
|
510 newD.to_vp = returnSlv->slaveNum;
|
|
seanhalle@268
|
511 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@268
|
512 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@268
|
513 }
|
|
seanhalle@268
|
514 #endif
|
|
seanhalle@268
|
515 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
516 return;
|
|
seanhalle@268
|
517 }
|
|
seanhalle@268
|
518
|
|
seanhalle@268
|
519 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@260
|
520 {
|
|
seanhalle@268
|
521 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
522 return;
|
|
seanhalle@267
|
523 }
|
|
seanhalle@267
|
524 }
|
|
seanhalle@268
|
525 */
|
|
seanhalle@267
|
526
|
|
seanhalle@261
|
527 inline
|
|
seanhalle@261
|
528 void
|
|
seanhalle@268
|
529 masterFunction_MultiLang( AnimSlot *slot )
|
|
seanhalle@261
|
530 { //Scan the animation slots
|
|
seanhalle@261
|
531 int32 magicNumber;
|
|
seanhalle@261
|
532 SlaveVP *slave;
|
|
seanhalle@268
|
533 PRLangEnv *langEnv;
|
|
seanhalle@261
|
534 PRReqst *req;
|
|
seanhalle@261
|
535 RequestHandler requestHandler;
|
|
seanhalle@268
|
536 PRProcess *process;
|
|
seanhalle@260
|
537
|
|
seanhalle@268
|
538 //Check if newly-done slave in slot, which will need request handled
|
|
seanhalle@268
|
539 if( slot->workIsDone )
|
|
seanhalle@268
|
540 { slot->workIsDone = FALSE;
|
|
seanhalle@268
|
541 slot->needsWorkAssigned = TRUE;
|
|
seanhalle@261
|
542
|
|
seanhalle@268
|
543 HOLISTIC__Record_AppResponder_start; //TODO: update to check which process for each slot
|
|
seanhalle@268
|
544 MEAS__startReqHdlr;
|
|
seanhalle@261
|
545
|
|
seanhalle@268
|
546
|
|
seanhalle@268
|
547 //process the request made by the slave (held inside slave struc)
|
|
seanhalle@268
|
548 slave = slot->slaveAssignedToSlot;
|
|
seanhalle@268
|
549 req = slave->request;
|
|
seanhalle@268
|
550
|
|
seanhalle@268
|
551 //If the requesting slave is a slot slave, and request is not
|
|
seanhalle@268
|
552 // task-end, then turn it into a free task slave.
|
|
seanhalle@268
|
553 if( slave->typeOfVP == SlotTaskSlv && req->reqType != TaskEnd )
|
|
seanhalle@268
|
554 PR_int__replace_with_new_slot_slv( slave );
|
|
seanhalle@268
|
555
|
|
seanhalle@268
|
556 //Handle task create and end first -- they're special cases..
|
|
seanhalle@268
|
557 switch( req->reqType )
|
|
seanhalle@268
|
558 { case TaskEnd:
|
|
seanhalle@268
|
559 { //do PR handler, which calls lang's hdlr and does recycle of
|
|
seanhalle@268
|
560 // free task slave if needed -- PR handler checks for free task Slv
|
|
seanhalle@268
|
561 PRHandle_EndTask( req, slave ); break;
|
|
seanhalle@267
|
562 }
|
|
seanhalle@268
|
563 case TaskCreate:
|
|
seanhalle@268
|
564 { //Do PR's create-task handler, which calls the lang's hdlr
|
|
seanhalle@268
|
565 // PR handler checks for free task Slv
|
|
seanhalle@268
|
566 PRHandle_CreateTask( req, slave ); break;
|
|
seanhalle@268
|
567 }
|
|
seanhalle@268
|
568 case SlvCreate: PRHandle_CreateSlave( req, slave ); break;
|
|
seanhalle@268
|
569 case SlvDissipate: PRHandle_Dissipate( req, slave ); break;
|
|
seanhalle@268
|
570 case Service: PR_int__handle_PRServiceReq( slave ); break; //resume into PR's own language env
|
|
seanhalle@268
|
571 case Hardware: //for future expansion
|
|
seanhalle@268
|
572 case IO: //for future expansion
|
|
seanhalle@268
|
573 case OSCall: //for future expansion
|
|
seanhalle@268
|
574 PR_int__throw_exception("Not implemented", slave, NULL); break;
|
|
seanhalle@268
|
575 case Language: //normal lang request
|
|
seanhalle@268
|
576 { magicNumber = req->langMagicNumber;
|
|
seanhalle@268
|
577 langEnv = PR_PI__give_lang_env_for( slave, magicNumber );
|
|
seanhalle@268
|
578 (*req->handler)( req->langReq, slave, langEnv );
|
|
seanhalle@268
|
579 }
|
|
seanhalle@268
|
580 }
|
|
seanhalle@261
|
581
|
|
seanhalle@268
|
582 MEAS__endReqHdlr;
|
|
seanhalle@267
|
583 HOLISTIC__Record_AppResponder_end;
|
|
seanhalle@268
|
584 } //if have request to be handled
|
|
seanhalle@268
|
585
|
|
seanhalle@268
|
586 if( slot->needsWorkAssigned )
|
|
seanhalle@268
|
587 {
|
|
seanhalle@268
|
588 HOLISTIC__Record_Assigner_start;
|
|
seanhalle@268
|
589
|
|
seanhalle@268
|
590 //Pick a process to get this slot
|
|
seanhalle@268
|
591 process = pickAProcess( slot );
|
|
seanhalle@268
|
592
|
|
seanhalle@268
|
593 //Scan lang environs, looking for langEnv with ready work.
|
|
seanhalle@268
|
594 // call the Assigner for that lang Env, to get a slave for the slot
|
|
seanhalle@268
|
595 assignWork( process, slot );
|
|
seanhalle@268
|
596
|
|
seanhalle@268
|
597 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
598 }//if slot needs slave assigned
|
|
seanhalle@261
|
599 }
|
|
seanhalle@260
|
600
|
|
seanhalle@268
|
601 /*When several processes exist, use some pattern for picking one to give
|
|
seanhalle@268
|
602 * the animation slot to.
|
|
seanhalle@268
|
603 *First, it has to be a process that has work available.
|
|
seanhalle@268
|
604 *For now, just do a round-robin
|
|
seanhalle@261
|
605 */
|
|
seanhalle@268
|
606 inline
|
|
seanhalle@268
|
607 PRProcess *
|
|
seanhalle@268
|
608 pickAProcess( AnimSlot *slot )
|
|
seanhalle@268
|
609 { int32 idx;
|
|
seanhalle@268
|
610 PRProcess *process;
|
|
seanhalle@268
|
611
|
|
seanhalle@268
|
612 for( idx = _PRTopEnv->currProcessIdx; idx < _PRTopEnv->numProcesses; idx++)
|
|
seanhalle@268
|
613 {
|
|
seanhalle@268
|
614 process = _PRTopEnv->processes[ idx ];
|
|
seanhalle@268
|
615 if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
616 { _PRTopEnv->currProcessIdx = idx;
|
|
seanhalle@268
|
617 return process;
|
|
seanhalle@268
|
618 }
|
|
seanhalle@261
|
619 }
|
|
seanhalle@268
|
620 for( idx = 0; idx < _PRTopEnv->currProcessIdx; idx++)
|
|
seanhalle@268
|
621 {
|
|
seanhalle@268
|
622 process = _PRTopEnv->processes[ idx ];
|
|
seanhalle@268
|
623 if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
624 { _PRTopEnv->currProcessIdx = idx;
|
|
seanhalle@268
|
625 return process;
|
|
seanhalle@268
|
626 }
|
|
seanhalle@268
|
627 }
|
|
seanhalle@268
|
628 //none found
|
|
seanhalle@268
|
629 return NULL;
|
|
seanhalle@260
|
630 }
|
|
seanhalle@260
|
631
|
|
seanhalle@261
|
632 /*This does:
|
|
seanhalle@268
|
633 * 1) searches the language environments for one with work ready
|
|
seanhalle@261
|
634 * if finds one, asks its assigner to return work
|
|
seanhalle@261
|
635 * 2) checks what kind of work: new task, resuming task, resuming slave
|
|
seanhalle@261
|
636 * if new task, gets the slot slave and assigns task to it and returns slave
|
|
seanhalle@261
|
637 * else, gets the slave attached to the metaTask and returns that.
|
|
seanhalle@261
|
638 * 3) if no work found, then prune former task slaves waiting to be recycled.
|
|
seanhalle@261
|
639 * If no work and no slaves to prune, check for shutdown conditions.
|
|
seanhalle@261
|
640 *
|
|
seanhalle@268
|
641 * language env keeps its own work in its own structures, and has its own
|
|
seanhalle@261
|
642 * assigner. It chooses
|
|
seanhalle@261
|
643 * However, include a switch that switches-in an override assigner, which
|
|
seanhalle@268
|
644 * sees all the work in all the language env's. This is most likely
|
|
seanhalle@261
|
645 * generated by static tools and included in the executable. That means it
|
|
seanhalle@261
|
646 * has to be called via a registered pointer from here. The idea is that
|
|
seanhalle@261
|
647 * the static tools know which languages are grouped together.. and the
|
|
seanhalle@261
|
648 * override enables them to generate a custom assigner that uses info from
|
|
seanhalle@261
|
649 * all the languages in a unified way.. Don't really expect this to happen,
|
|
seanhalle@261
|
650 * but am making it possible.
|
|
seanhalle@260
|
651 */
|
|
seanhalle@268
|
652 inline
|
|
seanhalle@268
|
653 SlaveVP *
|
|
seanhalle@261
|
654 assignWork( PRProcess *process, AnimSlot *slot )
|
|
seanhalle@261
|
655 { SlaveVP *returnSlv;
|
|
seanhalle@261
|
656 int32 coreNum, slotNum;
|
|
seanhalle@267
|
657 PRMetaTask *assignedMetaTask;
|
|
seanhalle@260
|
658
|
|
seanhalle@261
|
659 coreNum = slot->coreSlotIsOn;
|
|
seanhalle@260
|
660
|
|
seanhalle@267
|
661 if( process->overrideAssigner != NULL )
|
|
seanhalle@268
|
662 { if( process->numEnvsWithWork != 0 )
|
|
seanhalle@268
|
663 { (*process->overrideAssigner)( process, slot ); //calls PR fn that inserts work into slot
|
|
seanhalle@268
|
664 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@261
|
665 }
|
|
seanhalle@268
|
666 else
|
|
seanhalle@261
|
667 goto NoWork;
|
|
seanhalle@261
|
668 }
|
|
seanhalle@261
|
669
|
|
seanhalle@268
|
670 //If here, then no override assigner, so search language envs for work
|
|
seanhalle@268
|
671 int32 envIdx, numEnvs; PRLangEnv **langEnvsList, *langEnv;
|
|
seanhalle@268
|
672 langEnvsList = process->langEnvsList;
|
|
seanhalle@268
|
673 numEnvs = process->numLangEnvs;
|
|
seanhalle@268
|
674 for( envIdx = 0; envIdx < numEnvs; envIdx++ ) //keep langEnvs in hash & array
|
|
seanhalle@268
|
675 { langEnv = langEnvsList[envIdx];
|
|
seanhalle@268
|
676 if( langEnv->hasWork )
|
|
seanhalle@268
|
677 { (*langEnv->slaveAssigner)( langEnv, slot ); //assigner calls PR to put slave/task into slot
|
|
seanhalle@268
|
678 goto ReturnAfterAssigningWork; //quit for-loop, cause found work
|
|
seanhalle@268
|
679 //NOTE: bad search alg -- should start where left off, then wrap around
|
|
seanhalle@260
|
680 }
|
|
seanhalle@260
|
681 }
|
|
seanhalle@268
|
682 //If reach here, then have searched all langEnv's & none have work..
|
|
seanhalle@260
|
683
|
|
seanhalle@268
|
684 NoWork: //No work, if end up here..
|
|
seanhalle@260
|
685 {
|
|
seanhalle@260
|
686 #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
|
|
seanhalle@268
|
687 returnSlv = process->idleSlv[coreNum][slotNum];
|
|
seanhalle@260
|
688
|
|
seanhalle@260
|
689 //things that would normally happen in resume(), but idle VPs
|
|
seanhalle@260
|
690 // never go there
|
|
seanhalle@261
|
691 returnSlv->numTimesAssignedToASlot++; //gives each idle unit a unique ID
|
|
seanhalle@260
|
692 Unit newU;
|
|
seanhalle@268
|
693 newU.vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
694 newU.task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
695 addToListOfArrays(Unit,newU,process->unitList);
|
|
seanhalle@260
|
696
|
|
seanhalle@261
|
697 if (returnSlv->numTimesAssignedToASlot > 1) //make a dependency from prev idle unit
|
|
seanhalle@260
|
698 { Dependency newD; // to this one
|
|
seanhalle@268
|
699 newD.from_vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
700 newD.from_task = returnSlv->numTimesAssignedToASlot - 1;
|
|
seanhalle@268
|
701 newD.to_vp = returnSlv->slaveNum;
|
|
seanhalle@261
|
702 newD.to_task = returnSlv->numTimesAssignedToASlot;
|
|
seanhalle@261
|
703 addToListOfArrays(Dependency, newD ,process->ctlDependenciesList);
|
|
seanhalle@260
|
704 }
|
|
seanhalle@268
|
705 #endif
|
|
seanhalle@268
|
706 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
707 return;
|
|
seanhalle@260
|
708 }
|
|
seanhalle@268
|
709
|
|
seanhalle@268
|
710 ReturnAfterAssigningWork: //All paths goto here.. to provide single point for holistic..
|
|
seanhalle@268
|
711 {
|
|
seanhalle@268
|
712 HOLISTIC__Record_Assigner_end;
|
|
seanhalle@268
|
713 return;
|
|
seanhalle@260
|
714 }
|
|
seanhalle@260
|
715 }
|
|
seanhalle@260
|
716
|
|
seanhalle@260
|
717
|
|
seanhalle@268
|
718
|
|
seanhalle@268
|
719 /*This is first thing called when creating a slave.. it hands off to the
|
|
seanhalle@268
|
720 * langlet's creator, then adds updates of its own..
|
|
seanhalle@268
|
721 *
|
|
seanhalle@268
|
722 *There's a question of things like lang data, meta tasks, and such..
|
|
seanhalle@268
|
723 *In creator, only PR related things happen, and things for the langlet whose
|
|
seanhalle@261
|
724 * creator construct was used.
|
|
seanhalle@268
|
725 *
|
|
seanhalle@268
|
726 *Other langlets still get a chance to create langData -- but by registering a
|
|
seanhalle@268
|
727 * "createLangData" handler in the langEnv. When a construct of the langlet
|
|
seanhalle@268
|
728 * calls "PR__give_lang_data()", if there is no langData for that langlet,
|
|
seanhalle@268
|
729 * the PR will call the creator in the langlet's langEnv, place whatever it
|
|
seanhalle@268
|
730 * makes as the langData in that slave for that langlet, and return that langData
|
|
seanhalle@261
|
731 *
|
|
seanhalle@261
|
732 *So, as far as counting things, a langlet is only allowed to count creation
|
|
seanhalle@261
|
733 * of slaves it creates itself.. may have to change this later.. add a way for
|
|
seanhalle@261
|
734 * langlet to register a trigger Fn called each time a slave gets created..
|
|
seanhalle@261
|
735 * need more experience with what langlets will do at create time.. think Cilk
|
|
seanhalle@261
|
736 * has interesting create behavior.. not sure how that will differ in light
|
|
seanhalle@261
|
737 * of true tasks and langlet approach. Look at it after all done and start
|
|
seanhalle@261
|
738 * modifying the langs to be langlets..
|
|
seanhalle@261
|
739 *
|
|
seanhalle@261
|
740 *PR itself needs to create the slave, then update numLiveSlaves in process,
|
|
seanhalle@261
|
741 * copy processID from requestor to newly created
|
|
seanhalle@261
|
742 */
|
|
seanhalle@268
|
743 inline
|
|
seanhalle@268
|
744 void
|
|
seanhalle@268
|
745 PRHandle_CreateSlave( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@268
|
746 { SlaveVP *newSlv;
|
|
seanhalle@261
|
747 PRProcess *process;
|
|
seanhalle@268
|
748 PRLangEnv *protoLangEnv;
|
|
seanhalle@261
|
749
|
|
seanhalle@268
|
750 process = slave->processSlaveIsIn;
|
|
seanhalle@268
|
751 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, req->langMagicNumber );
|
|
seanhalle@268
|
752
|
|
seanhalle@268
|
753 // newSlv = PR_int__create_slave( req->topLevelFn, req->initData );
|
|
seanhalle@268
|
754
|
|
seanhalle@268
|
755 //create slv has diff prototype than standard reqst hdlr
|
|
seanhalle@268
|
756 newSlv =
|
|
seanhalle@268
|
757 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv));
|
|
seanhalle@268
|
758
|
|
seanhalle@261
|
759 newSlv->typeOfVP = GenericSlv;
|
|
seanhalle@261
|
760 newSlv->processSlaveIsIn = process;
|
|
seanhalle@268
|
761 newSlv->ID = req->ID;
|
|
seanhalle@266
|
762 process->numLiveGenericSlvs += 1;
|
|
seanhalle@260
|
763 }
|
|
seanhalle@260
|
764
|
|
seanhalle@268
|
765 /*The dissipate handler has to, update the number of slaves of the type, within
|
|
seanhalle@261
|
766 * the process, and call the langlet handler linked into the request,
|
|
seanhalle@261
|
767 * and after that returns, then call the PR function that frees the slave state
|
|
seanhalle@261
|
768 * (or recycles the slave).
|
|
seanhalle@261
|
769 *
|
|
seanhalle@261
|
770 *The PR function that frees the slave state has to also free all of the
|
|
seanhalle@268
|
771 * langData in the slave.. or else reset all of the langDatas.. by, say, marking
|
|
seanhalle@268
|
772 * them, then in PR__give_langData( magicNum ) call the langlet registered
|
|
seanhalle@268
|
773 * "resetLangData" Fn.
|
|
seanhalle@261
|
774 */
|
|
seanhalle@268
|
775 inline
|
|
seanhalle@268
|
776 void
|
|
seanhalle@268
|
777 PRHandle_Dissipate( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@261
|
778 { PRProcess *process;
|
|
seanhalle@268
|
779 PRLangEnv *protoLangEnv;
|
|
seanhalle@261
|
780
|
|
seanhalle@261
|
781 process = slave->processSlaveIsIn;
|
|
seanhalle@261
|
782
|
|
seanhalle@261
|
783 //do the language's dissipate handler
|
|
seanhalle@268
|
784 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave, slave->request->langMagicNumber );
|
|
seanhalle@268
|
785
|
|
seanhalle@268
|
786 if(req->handler != NULL)
|
|
seanhalle@268
|
787 (*req->handler)( req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@261
|
788
|
|
seanhalle@266
|
789 process->numLiveGenericSlvs -= 1;
|
|
seanhalle@268
|
790 PR_int__recycle_slave__ML( slave );
|
|
seanhalle@267
|
791
|
|
seanhalle@261
|
792 //check End Of Process Condition
|
|
seanhalle@261
|
793 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
794 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@268
|
795 PR_SS__shutdown_process__ML( process );
|
|
seanhalle@261
|
796 }
|
|
seanhalle@261
|
797
|
|
seanhalle@261
|
798 /*Create task is a special form, that has PR behavior in addition to plugin
|
|
seanhalle@268
|
799 * behavior. Master calls this first, and it then calls the plugin's
|
|
seanhalle@261
|
800 * create task handler.
|
|
seanhalle@267
|
801 *
|
|
seanhalle@267
|
802 *Note: the requesting slave must be either generic slave or free task slave
|
|
seanhalle@261
|
803 */
|
|
seanhalle@268
|
804 inline
|
|
seanhalle@268
|
805 void
|
|
seanhalle@268
|
806 PRHandle_CreateTask( PRReqst *req, SlaveVP *slave )
|
|
seanhalle@267
|
807 { PRMetaTask *metaTask;
|
|
seanhalle@267
|
808 PRProcess *process;
|
|
seanhalle@268
|
809 PRLangEnv *protoLangEnv;
|
|
seanhalle@268
|
810 void *task;
|
|
seanhalle@267
|
811
|
|
seanhalle@268
|
812 process = slave->processSlaveIsIn;
|
|
seanhalle@268
|
813
|
|
seanhalle@268
|
814 protoLangEnv = PR_int__give_proto_lang_env_for_slave__ML( slave,
|
|
seanhalle@268
|
815 req->langMagicNumber );
|
|
seanhalle@268
|
816
|
|
seanhalle@268
|
817 //Do the langlet's create-task handler, which keeps the task
|
|
seanhalle@268
|
818 // inside the langlet's lang env, but returns the langMetaTask
|
|
seanhalle@268
|
819 // so PR can put stuff into the prolog
|
|
seanhalle@268
|
820 task =
|
|
seanhalle@268
|
821 (*req->createHdlr)(req->langReq, slave, PR_int__give_lang_env(protoLangEnv) );
|
|
seanhalle@268
|
822 metaTask = PR_int__give_prolog_of_task( task );
|
|
seanhalle@268
|
823 metaTask->ID = req->ID; //may be NULL
|
|
seanhalle@267
|
824 metaTask->topLevelFn = req->topLevelFn;
|
|
seanhalle@267
|
825 metaTask->initData = req->initData;
|
|
seanhalle@261
|
826
|
|
seanhalle@261
|
827 process->numLiveTasks += 1;
|
|
seanhalle@267
|
828
|
|
seanhalle@261
|
829 return;
|
|
seanhalle@261
|
830 }
|
|
seanhalle@261
|
831
|
|
seanhalle@261
|
832 /*When a task ends, are two scenarios: 1) task ran to completion, or 2) task
|
|
seanhalle@261
|
833 * suspended at some point in its code.
|
|
seanhalle@261
|
834 *For 1, just decr count of live tasks (and check for end condition) -- the
|
|
seanhalle@261
|
835 * master loop will decide what goes into the slot freed up by this task end,
|
|
seanhalle@261
|
836 * so, here, don't worry about assigning a new task to the slot slave.
|
|
seanhalle@261
|
837 *For 2, the task's slot slave has been converted to a free task slave, which
|
|
seanhalle@261
|
838 * now has nothing more to do, so send it to the recycle Q (which includes
|
|
seanhalle@268
|
839 * freeing all the langData and meta task structs alloc'd for it). Then
|
|
seanhalle@261
|
840 * decrement the live task count and check end condition.
|
|
seanhalle@261
|
841 *
|
|
seanhalle@261
|
842 *PR has to update count of live tasks, and check end of process condition.
|
|
seanhalle@267
|
843 * The "main" can invoke constructs that wait for a process to end, so when
|
|
seanhalle@267
|
844 * end detected, have to resume what's waiting..
|
|
seanhalle@267
|
845 *Thing is, that wait involves the main OS thread. That means
|
|
seanhalle@261
|
846 * PR internals have to do OS thread signaling. Want to do that in the
|
|
seanhalle@267
|
847 * core controller, which has the original stack of an OS thread. So the
|
|
seanhalle@267
|
848 * end process handling happens in the core controller.
|
|
seanhalle@261
|
849 *
|
|
seanhalle@261
|
850 *So here, when detect process end, signal to the core controller, which will
|
|
seanhalle@267
|
851 * then do the condition variable notify to the OS thread that's waiting.
|
|
seanhalle@267
|
852 *
|
|
seanhalle@267
|
853 *Note: slave may be either a slot slave or a free task slave.
|
|
seanhalle@261
|
854 */
|
|
seanhalle@268
|
855 inline
|
|
seanhalle@268
|
856 void
|
|
seanhalle@268
|
857 PRHandle_EndTask( PRReqst *req, SlaveVP *requestingSlv )
|
|
seanhalle@268
|
858 { void *langEnv;
|
|
seanhalle@261
|
859 PRProcess *process;
|
|
seanhalle@268
|
860 void *langMetaTask;
|
|
seanhalle@267
|
861
|
|
seanhalle@268
|
862 langEnv = PR_int__give_lang_env_of_req__ML( req, requestingSlv ); //magic num in req
|
|
seanhalle@268
|
863 langMetaTask = PR_int__give_lang_meta_task_from_slave__ML( requestingSlv, req->langMagicNumber);
|
|
seanhalle@261
|
864
|
|
seanhalle@267
|
865 //Do the langlet's request handler
|
|
seanhalle@268
|
866 //Want to keep PR structs hidden from plugin, so extract langReq..
|
|
seanhalle@268
|
867 (*req->handler)( req->langReq, requestingSlv, langEnv );
|
|
seanhalle@267
|
868
|
|
seanhalle@267
|
869 //Now that the langlet's done with it, recycle the slave if it's a freeTaskSlv
|
|
seanhalle@267
|
870 if( requestingSlv->typeOfVP == FreeTaskSlv )
|
|
seanhalle@268
|
871 PR_int__recycle_slave__ML( requestingSlv );
|
|
seanhalle@261
|
872
|
|
seanhalle@261
|
873 process->numLiveTasks -= 1;
|
|
seanhalle@261
|
874
|
|
seanhalle@261
|
875 //check End Of Process Condition
|
|
seanhalle@261
|
876 if( process->numLiveTasks == 0 &&
|
|
seanhalle@266
|
877 process->numLiveGenericSlvs == 0 )
|
|
seanhalle@268
|
878 { //Tell the core controller to do wakeup of any waiting OS thread
|
|
seanhalle@268
|
879 PR_SS__shutdown_process__ML( process );
|
|
seanhalle@268
|
880 }
|
|
seanhalle@261
|
881 }
|
|
seanhalle@261
|
882
|