Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VSs_impls > VSs__MC_shared_impl
view VSs.c @ 29:dd1efbf29ff9
Moved counter recordings to PR services, about to delete trans & singleton
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Thu, 07 Feb 2013 16:30:16 -0800 |
| parents | 91caa8a9d591 |
| children | a40859b8dc33 |
line source
1 /*
2 * Copyright 2010 OpenSourceCodeStewardshipFoundation
3 *
4 * Licensed under BSD
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <malloc.h>
11 #include "Queue_impl/PrivateQueue.h"
12 #include "Hash_impl/PrivateHash.h"
14 #include "VSs.h"
15 #include "PR_impl/Services_Offered_by_PR/Measurement_and_Stats/PR_MEAS__Counter_Recording.h"
16 //==========================================================================
17 void
18 VSs__init_Helper();
20 SlaveVP *
21 VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData,
22 int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd );
24 //==========================================================================
28 //===========================================================================
31 /*These are the library functions *called in the application*
32 *
33 *There's a pattern for the outside sequential code to interact with the
34 * PR_HW code.
35 *The PR_HW system is inside a boundary.. every VSs system is in its
36 * own directory that contains the functions for each of the processor types.
37 * One of the processor types is the "seed" processor that starts the
38 * cascade of creating all the processors that do the work.
39 *So, in the directory is a file called "EntryPoint.c" that contains the
40 * function, named appropriately to the work performed, that the outside
41 * sequential code calls. This function follows a pattern:
42 *1) it calls VSs__init()
43 *2) it creates the initial data for the seed processor, which is passed
44 * in to the function
45 *3) it creates the seed VSs processor, with the data to start it with.
46 *4) it calls startVSsThenWaitUntilWorkDone
47 *5) it gets the returnValue from the transfer struc and returns that
48 * from the function
49 *
50 *For now, a new VSs system has to be created via VSs__init every
51 * time an entry point function is called -- later, might add letting the
52 * VSs system be created once, and let all the entry points just reuse
53 * it -- want to be as simple as possible now, and see by using what makes
54 * sense for later..
55 */
59 //===========================================================================
61 int32
62 VSs__giveMinWorkUnitCycles( float32 percentOverhead )
63 {
64 return MIN_WORK_UNIT_CYCLES;
65 }
67 int32
68 VSs__giveIdealNumWorkUnits()
69 {
70 return NUM_ANIM_SLOTS * NUM_CORES;
71 }
73 int32
74 VSs__give_number_of_cores_to_schedule_onto()
75 {
76 return NUM_CORES;
77 }
79 /*For now, use TSC -- later, make these two macros with assembly that first
80 * saves jump point, and second jumps back several times to get reliable time
81 */
82 void
83 VSs__begin_primitive( SlaveVP *animSlv )
84 { VSsLangData *langData;
86 langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER);
88 saveLowTimeStampCountInto( langData->primitiveStartTime );
89 }
91 /*Just quick and dirty for now -- make reliable later
92 * will want this to jump back several times -- to be sure cache is warm
93 * because don't want comm time included in calc-time measurement -- and
94 * also to throw out any "weird" values due to OS interrupt or TSC rollover
95 */
96 int32
97 VSs__end_primitive_and_give_cycles( SlaveVP *animSlv )
98 { int32 endTime, startTime;
99 VSsLangData *langData;
101 //TODO: fix by repeating time-measurement
102 saveLowTimeStampCountInto( endTime );
103 langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER);
104 startTime = langData->primitiveStartTime;
105 return (endTime - startTime);
106 }
110 //===========================================================================
112 SlaveVP *
113 VSs__create_thread( TopLevelFnPtr fnPtr, void *initData,
114 SlaveVP *creatingThd )
115 {
116 return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID,
117 ANY_CORE, creatingThd );
118 }
120 SlaveVP *
121 VSs__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID,
122 SlaveVP *creatingThd )
123 {
124 return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, thdID,
125 ANY_CORE, creatingThd );
126 }
128 /* old version -- looks safe to delete
129 SlaveVP *
130 VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData,
131 SlaveVP *creatingSlv, int32 coreToAssignOnto )
132 { VSsLangReq reqData;
134 //the lang request data is on the stack and disappears when this
135 // call returns -- it's guaranteed to remain in the VP's stack for as
136 // long as the VP is suspended.
137 reqData.reqType = create_slave_w_aff; //not used, May 2012
138 reqData.coreToAssignOnto = coreToAssignOnto;
139 reqData.fnPtr = fnPtr;
140 reqData.initData = initData;
141 reqData.callingSlv = creatingSlv;
143 PR_WL__send_create_slaveVP_req( &reqData, creatingSlv, VSs_MAGIC_NUMBER );
145 return creatingSlv->dataRetFromReq;
146 }
147 */
150 SlaveVP *
151 VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData,
152 int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd )
153 { VSsLangReq reqData;
155 //the lang request data is on the stack and disappears when this
156 // call returns -- it's guaranteed to remain in the VP's stack for as
157 // long as the VP is suspended.
158 reqData.reqType = create_slave; //know type because in a PR create req
159 reqData.coreToAssignOnto = coreToAssignOnto;
160 reqData.fnPtr = fnPtr;
161 reqData.initData = initData;
163 PR_WL__send_create_slaveVP_req( &reqData, thdID, (CreateHandler)&handleCreateThd,
164 creatingThd, VSs_MAGIC_NUMBER );
165 return (SlaveVP *)creatingThd->dataRetFromReq;
166 }
168 /*This is always the last thing done in the code animated by a thread VP.
169 * Normally, this would be the last line of the thread's top level function.
170 * But, if the thread exits from any point, it has to do so by calling
171 * this.
172 *
173 *It simply sends a dissipate request, which handles all the state cleanup.
174 */
175 void
176 VSs__end_thread( SlaveVP *thdToEnd )
177 {
178 //the lang request is null for VSs version of end slave
179 PR_WL__send_end_slave_req( NULL, (RequestHandler)&handleDissipate, thdToEnd,
180 VSs_MAGIC_NUMBER );
181 }
185 //===========================================================================
188 //======================= task submit and end ==============================
189 /*
190 */
191 void
192 VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv)
193 { VSsLangReq reqData;
195 reqData.reqType = submit_task;
197 reqData.taskType = taskType;
198 reqData.args = args;
199 reqData.callingSlv = animSlv;
201 //Create task is a special form, so have to pass as parameters, the
202 // top-level-fn of task and the data for that fn, plus lang's req,
203 // animating slave, and lang's magic number
204 PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID,
205 &handleSubmitTask, animSlv, VSs_MAGIC_NUMBER );
206 }
208 void
209 VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID,
210 SlaveVP *animSlv )
211 { VSsLangReq reqData;
213 reqData.reqType = submit_task;
215 reqData.taskType = taskType;
216 reqData.args = args;
217 reqData.callingSlv = animSlv;
219 PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID,
220 &handleSubmitTask, animSlv, VSs_MAGIC_NUMBER );
221 }
224 /*This call is the last to happen in every task. It causes the slave to
225 * suspend and get the next task out of the task-queue. Notice there is no
226 * assigner here.. only one slave, no slave ReadyQ, and so on..
227 *Can either make the assigner take the next task out of the taskQ, or can
228 * leave all as it is, and make task-end take the next task.
229 *Note: this fits the case in the new PR for no-context tasks, so will use
230 * the built-in taskQ of new PR, and should be local and much faster.
231 *
232 *The task-stub is saved in the animSlv, so the request handler will get it
233 * from there, along with the task-type which has arg types, and so on..
234 *
235 * NOTE: if want, don't need to send the animating SlaveVP around..
236 * instead, can make a single slave per core, and coreCtrlr looks up the
237 * slave from having the core number.
238 *
239 *But, to stay compatible with all the other PR languages, leave it in..
240 */
241 void
242 VSs__end_task( SlaveVP *animSlv )
243 { VSsLangReq reqData;
245 //VSs has nothing extra to communicate to end task handler, so lang req is NULL
246 PR_WL__send_end_task_request( NULL, &handleEndTask, animSlv, VSs_MAGIC_NUMBER );
247 }
250 /*Waits for all tasks that are direct children to end, then resumes calling
251 * task or thread
252 */
253 void
254 VSs__taskwait(SlaveVP *animSlv)
255 {
256 VSsLangReq reqData;
258 reqData.reqType = taskwait;
259 reqData.callingSlv = animSlv;
261 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleTaskwait, animSlv,
262 VSs_MAGIC_NUMBER );
263 }
267 //========================== send and receive ============================
268 //
270 inline
271 int32 *
272 VSs__give_self_taskID( SlaveVP *animSlv )
273 {
274 return PR__give_ID_from_slave( animSlv, VSs_MAGIC_NUMBER );
275 }
277 //================================ send ===================================
279 void
280 VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID,
281 SlaveVP *senderSlv )
282 { VSsLangReq reqData;
284 reqData.reqType = send_type_to;
286 reqData.msg = msg;
287 reqData.msgType = type;
288 reqData.receiverID = receiverID;
289 reqData.senderSlv = senderSlv;
291 reqData.nextReqInHashEntry = NULL;
293 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleSendTypeTo,
294 senderSlv, VSs_MAGIC_NUMBER );
296 //When come back from suspend, no longer own data reachable from msg
297 }
299 void
300 VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv )
301 { VSsLangReq reqData;
303 reqData.reqType = send_from_to;
305 reqData.msg = msg;
306 reqData.senderID = senderID;
307 reqData.receiverID = receiverID;
308 reqData.senderSlv = senderSlv;
310 reqData.nextReqInHashEntry = NULL;
312 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleSendFromTo,
313 senderSlv, VSs_MAGIC_NUMBER );
314 }
317 //================================ receive ================================
319 /*The "type" version of send and receive creates a many-to-one relationship.
320 * The sender is anonymous, and many sends can stack up, waiting to be
321 * received. The same receiver can also have send from-to's
322 * waiting for it, and those will be kept separate from the "type"
323 * messages.
324 */
325 void *
326 VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv )
327 { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] );
328 VSsLangReq reqData;
330 reqData.reqType = receive_type_to;
332 reqData.msgType = type;
333 reqData.receiverID = receiverID;
334 reqData.receiverSlv = receiverSlv;
336 reqData.nextReqInHashEntry = NULL;
338 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleReceiveTypeTo,
339 receiverSlv, VSs_MAGIC_NUMBER );
341 return receiverSlv->dataRetFromReq;
342 }
346 /*Call this at the point a receiving task wants in-coming data.
347 * Use this from-to form when know senderID -- it makes a direct channel
348 * between sender and receiver.
349 */
350 void *
351 VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv )
352 {
353 VSsLangReq reqData;
355 reqData.reqType = receive_from_to;
357 reqData.senderID = senderID;
358 reqData.receiverID = receiverID;
359 reqData.receiverSlv = receiverSlv;
361 reqData.nextReqInHashEntry = NULL;
362 DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]);
364 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleReceiveFromTo,
365 receiverSlv, VSs_MAGIC_NUMBER );
367 return receiverSlv->dataRetFromReq;
368 }
373 //==========================================================================
374 //
375 /*A function singleton is a function whose body executes exactly once, on a
376 * single core, no matter how many times the fuction is called and no
377 * matter how many cores or the timing of cores calling it.
378 *
379 *A data singleton is a ticket attached to data. That ticket can be used
380 * to get the data through the function exactly once, no matter how many
381 * times the data is given to the function, and no matter the timing of
382 * trying to get the data through from different cores.
383 */
385 /*asm function declarations*/
386 void asm_save_ret_to_singleton(VSsSingleton *singletonPtrAddr);
387 void asm_write_ret_from_singleton(VSsSingleton *singletonPtrAddr);
389 /*Fn singleton uses ID as index into array of singleton structs held in the
390 * language environment.
391 */
392 void
393 VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv )
394 {
395 VSsLangReq reqData;
397 //
398 reqData.reqType = singleton_fn_start;
399 reqData.singletonID = singletonID;
401 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleStartFnSingleton,
402 animSlv, VSs_MAGIC_NUMBER );
403 if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton
404 {
405 VSsLangEnv *langEnv =
406 PR_int__give_lang_env_for_slave( animSlv, VSs_MAGIC_NUMBER );
407 asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID]));
408 }
409 }
411 /*Data singleton hands addr of loc holding a pointer to a singleton struct.
412 * The start_data_singleton makes the structure and puts its addr into the
413 * location.
414 */
415 void
416 VSs__start_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv )
417 {
418 VSsLangReq reqData;
420 if( *singletonAddr && (*singletonAddr)->hasFinished )
421 goto JmpToEndSingleton;
423 reqData.reqType = singleton_data_start;
424 reqData.singletonPtrAddr = singletonAddr;
426 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleStartDataSingleton,
427 animSlv, VSs_MAGIC_NUMBER );
428 if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr
429 { //Assembly code changes the return addr on the stack to the one
430 // saved into the singleton by the end-singleton-fn
431 //The return addr is at 0x4(%%ebp)
432 JmpToEndSingleton:
433 asm_write_ret_from_singleton(*singletonAddr);
434 }
435 //now, simply return
436 //will exit either from the start singleton call or the end-singleton call
437 }
439 /*Uses ID as index into array of flags. If flag already set, resumes from
440 * end-label. Else, sets flag and resumes normally.
441 *
442 *Note, this call cannot be inlined because the instr addr at the label
443 * inside is shared by all invocations of a given singleton ID.
444 */
445 void
446 VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv )
447 {
448 VSsLangReq reqData;
450 //don't need this addr until after at least one singleton has reached
451 // this function
452 VSsLangEnv *
453 langEnv = PR_int__give_lang_env_for_slave( animSlv, VSs_MAGIC_NUMBER );
455 asm_write_ret_from_singleton(&(langEnv->fnSingletons[ singletonID]));
457 reqData.reqType = singleton_fn_end;
458 reqData.singletonID = singletonID;
460 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleEndFnSingleton,
461 animSlv, VSs_MAGIC_NUMBER );
463 EndSingletonInstrAddr:
464 return;
465 }
467 void
468 VSs__end_data_singleton( VSsSingleton **singletonPtrAddr, SlaveVP *animSlv )
469 {
470 VSsLangReq reqData;
472 //don't need this addr until after singleton struct has reached
473 // this function for first time
474 //do assembly that saves the return addr of this fn call into the
475 // data singleton -- that data-singleton can only be given to exactly
476 // one instance in the code of this function. However, can use this
477 // function in different places for different data-singletons.
478 asm_save_ret_to_singleton(*singletonPtrAddr);
480 reqData.reqType = singleton_data_end;
481 reqData.singletonPtrAddr = singletonPtrAddr;
483 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleEndDataSingleton,
484 animSlv, VSs_MAGIC_NUMBER );
485 }
487 /*This executes the function in the masterVP, so it executes in isolation
488 * from any other copies -- only one copy of the function can ever execute
489 * at a time.
490 *
491 *It suspends to the master, and the request handler takes the function
492 * pointer out of the request and calls it, then resumes the VP.
493 *Only very short functions should be called this way -- for longer-running
494 * isolation, use transaction-start and transaction-end, which run the code
495 * between as work-code.
496 */
497 void
498 VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
499 void *data, SlaveVP *animSlv )
500 {
501 VSsLangReq reqData;
503 //
504 reqData.reqType = atomic;
505 reqData.fnToExecInMaster = ptrToFnToExecInMaster;
506 reqData.dataForFn = data;
508 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleAtomic,
509 animSlv, VSs_MAGIC_NUMBER );
510 }
513 /*This suspends to the master.
514 *First, it looks at the VP's data, to see the highest transactionID that VP
515 * already has entered. If the current ID is not larger, it throws an
516 * exception stating a bug in the code. Otherwise it puts the current ID
517 * there, and adds the ID to a linked list of IDs entered -- the list is
518 * used to check that exits are properly ordered.
519 *Next it is uses transactionID as index into an array of transaction
520 * structures.
521 *If the "VP_currently_executing" field is non-null, then put requesting VP
522 * into queue in the struct. (At some point a holder will request
523 * end-transaction, which will take this VP from the queue and resume it.)
524 *If NULL, then write requesting into the field and resume.
525 */
526 void
527 VSs__start_transaction( int32 transactionID, SlaveVP *animSlv )
528 {
529 VSsLangReq reqData;
531 //
532 reqData.callingSlv = animSlv;
533 reqData.reqType = trans_start;
534 reqData.transID = transactionID;
536 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleTransStart,
537 animSlv, VSs_MAGIC_NUMBER );
538 }
540 /*This suspends to the master, then uses transactionID as index into an
541 * array of transaction structures.
542 *It looks at VP_currently_executing to be sure it's same as requesting VP.
543 * If different, throws an exception, stating there's a bug in the code.
544 *Next it looks at the queue in the structure.
545 *If it's empty, it sets VP_currently_executing field to NULL and resumes.
546 *If something in, gets it, sets VP_currently_executing to that VP, then
547 * resumes both.
548 */
549 void
550 VSs__end_transaction( int32 transactionID, SlaveVP *animSlv )
551 {
552 VSsLangReq reqData;
554 //
555 reqData.callingSlv = animSlv;
556 reqData.reqType = trans_end;
557 reqData.transID = transactionID;
559 PR_WL__send_lang_request( &reqData, (RequestHandler)&handleTransEnd,
560 animSlv, VSs_MAGIC_NUMBER );
561 }
563 //======================== Internal ==================================
