seanhalle@0: /* seanhalle@0: * Copyright 2010 OpenSourceCodeStewardshipFoundation seanhalle@0: * seanhalle@0: * Licensed under BSD seanhalle@0: */ seanhalle@0: seanhalle@0: #include seanhalle@0: #include seanhalle@0: #include seanhalle@0: seanhalle@0: #include "Queue_impl/PrivateQueue.h" seanhalle@0: #include "Hash_impl/PrivateHash.h" seanhalle@0: seanhalle@2: #include "VSs.h" seanhalle@29: #include "PR_impl/Services_Offered_by_PR/Measurement_and_Stats/PR_MEAS__Counter_Recording.h" seanhalle@0: //========================================================================== seanhalle@27: void seanhalle@27: VSs__init_Helper(); seanhalle@27: seanhalle@27: SlaveVP * seanhalle@27: VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, seanhalle@27: int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ); seanhalle@0: seanhalle@0: //========================================================================== seanhalle@0: seanhalle@0: seanhalle@0: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@0: seanhalle@0: /*These are the library functions *called in the application* seanhalle@0: * seanhalle@0: *There's a pattern for the outside sequential code to interact with the seanhalle@26: * PR_HW code. seanhalle@26: *The PR_HW system is inside a boundary.. every VSs system is in its seanhalle@0: * own directory that contains the functions for each of the processor types. seanhalle@0: * One of the processor types is the "seed" processor that starts the seanhalle@0: * cascade of creating all the processors that do the work. seanhalle@0: *So, in the directory is a file called "EntryPoint.c" that contains the seanhalle@0: * function, named appropriately to the work performed, that the outside seanhalle@0: * sequential code calls. This function follows a pattern: seanhalle@2: *1) it calls VSs__init() seanhalle@0: *2) it creates the initial data for the seed processor, which is passed seanhalle@0: * in to the function seanhalle@2: *3) it creates the seed VSs processor, with the data to start it with. seanhalle@2: *4) it calls startVSsThenWaitUntilWorkDone seanhalle@0: *5) it gets the returnValue from the transfer struc and returns that seanhalle@0: * from the function seanhalle@0: * seanhalle@2: *For now, a new VSs system has to be created via VSs__init every seanhalle@0: * time an entry point function is called -- later, might add letting the seanhalle@2: * VSs system be created once, and let all the entry points just reuse seanhalle@0: * it -- want to be as simple as possible now, and see by using what makes seanhalle@0: * sense for later.. seanhalle@0: */ seanhalle@0: seanhalle@0: seanhalle@0: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@0: int32 seanhalle@2: VSs__giveMinWorkUnitCycles( float32 percentOverhead ) seanhalle@0: { seanhalle@0: return MIN_WORK_UNIT_CYCLES; seanhalle@0: } seanhalle@0: seanhalle@0: int32 seanhalle@2: VSs__giveIdealNumWorkUnits() seanhalle@0: { seanhalle@0: return NUM_ANIM_SLOTS * NUM_CORES; seanhalle@0: } seanhalle@0: seanhalle@0: int32 seanhalle@2: VSs__give_number_of_cores_to_schedule_onto() seanhalle@0: { seanhalle@0: return NUM_CORES; seanhalle@0: } seanhalle@0: seanhalle@0: /*For now, use TSC -- later, make these two macros with assembly that first seanhalle@0: * saves jump point, and second jumps back several times to get reliable time seanhalle@0: */ seanhalle@0: void seanhalle@27: VSs__begin_primitive( SlaveVP *animSlv ) seanhalle@27: { VSsLangData *langData; seanhalle@26: seanhalle@27: langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER); seanhalle@26: seanhalle@27: saveLowTimeStampCountInto( langData->primitiveStartTime ); seanhalle@0: } seanhalle@0: seanhalle@0: /*Just quick and dirty for now -- make reliable later seanhalle@0: * will want this to jump back several times -- to be sure cache is warm seanhalle@0: * because don't want comm time included in calc-time measurement -- and seanhalle@0: * also to throw out any "weird" values due to OS interrupt or TSC rollover seanhalle@0: */ seanhalle@0: int32 seanhalle@27: VSs__end_primitive_and_give_cycles( SlaveVP *animSlv ) seanhalle@0: { int32 endTime, startTime; seanhalle@27: VSsLangData *langData; seanhalle@26: seanhalle@0: //TODO: fix by repeating time-measurement seanhalle@0: saveLowTimeStampCountInto( endTime ); seanhalle@27: langData = (VSsLangData *)PR_WL__give_lang_data( animSlv, VSs_MAGIC_NUMBER); seanhalle@27: startTime = langData->primitiveStartTime; seanhalle@0: return (endTime - startTime); seanhalle@0: } seanhalle@0: seanhalle@26: seanhalle@0: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@2: SlaveVP * seanhalle@7: VSs__create_thread( TopLevelFnPtr fnPtr, void *initData, seanhalle@7: SlaveVP *creatingThd ) seanhalle@26: { seanhalle@26: return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, NO_ID, seanhalle@26: ANY_CORE, creatingThd ); seanhalle@26: } seanhalle@26: seanhalle@26: SlaveVP * seanhalle@26: VSs__create_thread_w_ID( TopLevelFnPtr fnPtr, void *initData, int32 *thdID, seanhalle@26: SlaveVP *creatingThd ) seanhalle@26: { seanhalle@26: return VSs__create_thread_w_ID_and_affinity( fnPtr, initData, thdID, seanhalle@26: ANY_CORE, creatingThd ); seanhalle@26: } seanhalle@26: seanhalle@27: seanhalle@26: seanhalle@26: SlaveVP * seanhalle@26: VSs__create_thread_w_ID_and_affinity( TopLevelFnPtr fnPtr, void *initData, seanhalle@26: int32 *thdID, int32 coreToAssignOnto, SlaveVP *creatingThd ) seanhalle@27: { VSsLangReq reqData; seanhalle@0: seanhalle@27: //the lang request data is on the stack and disappears when this seanhalle@0: // call returns -- it's guaranteed to remain in the VP's stack for as seanhalle@0: // long as the VP is suspended. seanhalle@27: reqData.reqType = create_slave; //know type because in a PR create req seanhalle@27: reqData.coreToAssignOnto = coreToAssignOnto; seanhalle@27: reqData.fnPtr = fnPtr; seanhalle@27: reqData.initData = initData; seanhalle@26: seanhalle@30: PR_WL__send_create_slaveVP_req( &reqData, thdID, (CreateHandler)&VSs__handleCreateThd, seanhalle@26: creatingThd, VSs_MAGIC_NUMBER ); seanhalle@27: return (SlaveVP *)creatingThd->dataRetFromReq; seanhalle@0: } seanhalle@0: seanhalle@10: /*This is always the last thing done in the code animated by a thread VP. seanhalle@7: * Normally, this would be the last line of the thread's top level function. seanhalle@7: * But, if the thread exits from any point, it has to do so by calling seanhalle@7: * this. seanhalle@10: * seanhalle@10: *It simply sends a dissipate request, which handles all the state cleanup. seanhalle@7: */ seanhalle@2: void seanhalle@7: VSs__end_thread( SlaveVP *thdToEnd ) seanhalle@26: { seanhalle@27: //the lang request is null for VSs version of end slave seanhalle@30: PR_WL__send_end_slave_req( NULL, (RequestHandler)&VSs__handleDissipate, thdToEnd, seanhalle@28: VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@0: seanhalle@10: seanhalle@0: //=========================================================================== seanhalle@0: seanhalle@0: seanhalle@4: //======================= task submit and end ============================== seanhalle@4: /* seanhalle@2: */ seanhalle@4: void seanhalle@2: VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv) seanhalle@27: { VSsLangReq reqData; seanhalle@0: seanhalle@2: reqData.reqType = submit_task; seanhalle@4: seanhalle@2: reqData.taskType = taskType; seanhalle@2: reqData.args = args; seanhalle@4: reqData.callingSlv = animSlv; seanhalle@4: seanhalle@26: //Create task is a special form, so have to pass as parameters, the seanhalle@26: // top-level-fn of task and the data for that fn, plus lang's req, seanhalle@26: // animating slave, and lang's magic number seanhalle@27: PR_WL__send_create_task_req( taskType->fn, args, &reqData, NO_ID, seanhalle@30: &VSs__handleSubmitTask, animSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: void seanhalle@4: VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, seanhalle@27: SlaveVP *animSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@26: seanhalle@4: reqData.reqType = submit_task; seanhalle@4: seanhalle@30: reqData.taskType = taskType; //VSs info about args, dependencies, etc seanhalle@4: reqData.args = args; seanhalle@4: reqData.callingSlv = animSlv; seanhalle@4: seanhalle@27: PR_WL__send_create_task_req( taskType->fn, args, &reqData, taskID, seanhalle@30: &VSs__handleSubmitTask, animSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: /*This call is the last to happen in every task. It causes the slave to seanhalle@2: * suspend and get the next task out of the task-queue. Notice there is no seanhalle@2: * assigner here.. only one slave, no slave ReadyQ, and so on.. seanhalle@2: *Can either make the assigner take the next task out of the taskQ, or can seanhalle@2: * leave all as it is, and make task-end take the next task. seanhalle@26: *Note: this fits the case in the new PR for no-context tasks, so will use seanhalle@26: * the built-in taskQ of new PR, and should be local and much faster. seanhalle@2: * seanhalle@2: *The task-stub is saved in the animSlv, so the request handler will get it seanhalle@2: * from there, along with the task-type which has arg types, and so on.. seanhalle@4: * seanhalle@4: * NOTE: if want, don't need to send the animating SlaveVP around.. seanhalle@4: * instead, can make a single slave per core, and coreCtrlr looks up the seanhalle@4: * slave from having the core number. seanhalle@4: * seanhalle@26: *But, to stay compatible with all the other PR languages, leave it in.. seanhalle@0: */ seanhalle@0: void seanhalle@2: VSs__end_task( SlaveVP *animSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@2: seanhalle@27: //VSs has nothing extra to communicate to end task handler, so lang req is NULL seanhalle@30: PR_WL__send_end_task_request( NULL, &VSs__handleEndTask, animSlv, VSs_MAGIC_NUMBER ); seanhalle@0: } seanhalle@0: seanhalle@4: seanhalle@26: /*Waits for all tasks that are direct children to end, then resumes calling seanhalle@26: * task or thread seanhalle@26: */ nengel@5: void nengel@5: VSs__taskwait(SlaveVP *animSlv) seanhalle@26: { seanhalle@27: VSsLangReq reqData; nengel@5: nengel@5: reqData.reqType = taskwait; nengel@5: reqData.callingSlv = animSlv; nengel@5: seanhalle@30: PR_WL__send_lang_request( &reqData, (RequestHandler)&VSs__handleTaskwait, animSlv, seanhalle@28: VSs_MAGIC_NUMBER ); seanhalle@26: } nengel@5: seanhalle@30: void seanhalle@30: VSs__wait_for_all_VSs_created_work_to_end( SlaveVP *seedSlv ) seanhalle@30: { seanhalle@30: VSsLangReq reqData; nengel@5: seanhalle@30: reqData.reqType = activity_cease_wait; seanhalle@30: reqData.callingSlv = seedSlv; seanhalle@30: seanhalle@30: PR_WL__send_lang_request( &reqData, (RequestHandler)&VSs__handleWaitForVSsWorkToEnd, seedSlv, seanhalle@30: VSs_MAGIC_NUMBER ); seanhalle@30: } seanhalle@30: seanhalle@30: seanhalle@30: seanhalle@30: /*This is called by the application -- normally the seed slave. It causes a seanhalle@30: * request to be sent that frees the VSs lang env and all its contents. seanhalle@30: *The seed slave resumes from the built-in PRServ langlet's environment. It seanhalle@30: * will be PRServ that causes return from this call. seanhalle@30: */ seanhalle@30: void seanhalle@30: VSs__shutdown( SlaveVP *seedSlv ) seanhalle@30: { seanhalle@30: PR_WL__send_lang_shutdown_request( seedSlv, VSs_MAGIC_NUMBER ); seanhalle@30: } nengel@5: seanhalle@4: //========================== send and receive ============================ seanhalle@4: // seanhalle@4: seanhalle@28: inline seanhalle@28: int32 * seanhalle@4: VSs__give_self_taskID( SlaveVP *animSlv ) seanhalle@30: { void *metaTask; seanhalle@30: metaTask = PR_WL__give_lang_meta_task_from_slave( animSlv, VSs_MAGIC_NUMBER ); seanhalle@30: return PR__give_ID_from_lang_meta_task( metaTask ); seanhalle@4: } seanhalle@4: seanhalle@4: //================================ send =================================== seanhalle@4: seanhalle@4: void seanhalle@4: VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID, seanhalle@4: SlaveVP *senderSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = send_type_to; seanhalle@4: seanhalle@4: reqData.msg = msg; seanhalle@4: reqData.msgType = type; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.senderSlv = senderSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: seanhalle@30: PR_WL__send_lang_request( &reqData, (RequestHandler)&VSs__handleSendTypeTo, seanhalle@28: senderSlv, VSs_MAGIC_NUMBER ); seanhalle@4: seanhalle@4: //When come back from suspend, no longer own data reachable from msg seanhalle@4: } seanhalle@4: seanhalle@4: void seanhalle@4: VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ) seanhalle@27: { VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = send_from_to; seanhalle@4: seanhalle@4: reqData.msg = msg; seanhalle@4: reqData.senderID = senderID; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.senderSlv = senderSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: seanhalle@30: PR_WL__send_lang_request( &reqData, (RequestHandler)&VSs__handleSendFromTo, seanhalle@28: senderSlv, VSs_MAGIC_NUMBER ); seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: //================================ receive ================================ seanhalle@4: seanhalle@4: /*The "type" version of send and receive creates a many-to-one relationship. seanhalle@4: * The sender is anonymous, and many sends can stack up, waiting to be seanhalle@4: * received. The same receiver can also have send from-to's seanhalle@4: * waiting for it, and those will be kept separate from the "type" seanhalle@4: * messages. seanhalle@4: */ seanhalle@4: void * seanhalle@4: VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ) seanhalle@4: { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] ); seanhalle@27: VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = receive_type_to; seanhalle@4: seanhalle@4: reqData.msgType = type; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.receiverSlv = receiverSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: seanhalle@30: PR_WL__send_lang_request( &reqData, (RequestHandler)&VSs__handleReceiveTypeTo, seanhalle@28: receiverSlv, VSs_MAGIC_NUMBER ); seanhalle@4: seanhalle@4: return receiverSlv->dataRetFromReq; seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: seanhalle@4: /*Call this at the point a receiving task wants in-coming data. seanhalle@4: * Use this from-to form when know senderID -- it makes a direct channel seanhalle@4: * between sender and receiver. seanhalle@4: */ seanhalle@4: void * seanhalle@4: VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ) seanhalle@4: { seanhalle@27: VSsLangReq reqData; seanhalle@4: seanhalle@4: reqData.reqType = receive_from_to; seanhalle@4: seanhalle@4: reqData.senderID = senderID; seanhalle@4: reqData.receiverID = receiverID; seanhalle@4: reqData.receiverSlv = receiverSlv; seanhalle@4: seanhalle@4: reqData.nextReqInHashEntry = NULL; seanhalle@4: DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); seanhalle@4: seanhalle@30: PR_WL__send_lang_request( &reqData, (RequestHandler)&VSs__handleReceiveFromTo, seanhalle@28: receiverSlv, VSs_MAGIC_NUMBER ); seanhalle@4: seanhalle@4: return receiverSlv->dataRetFromReq; seanhalle@4: } seanhalle@4: seanhalle@4: seanhalle@4: seanhalle@4: seanhalle@0: