Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > DKU_impls > DKU__MC_shared_impl
changeset 0:9f2a7bd26dd9 tip
Initial add -- code is straight copy of VSs implementation.. to be modified
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Mon, 27 Aug 2012 02:14:35 -0700 |
| parents | |
| children | |
| files | .hgeol .hgignore DKU.c DKU.h DKU_PluginFns.c DKU_Request_Handlers.c DKU_Request_Handlers.h DKU_singleton_asm.s Measurement/DKU_Counter_Recording.c Measurement/DKU_Counter_Recording.h Measurement/DKU_Measurement.h Measurement/dependency.c Measurement/dependency.h __brch__default |
| diffstat | 14 files changed, 3419 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgeol Mon Aug 27 02:14:35 2012 -0700 1.3 @@ -0,0 +1,12 @@ 1.4 + 1.5 +[patterns] 1.6 +**.py = native 1.7 +**.txt = native 1.8 +**.c = native 1.9 +**.h = native 1.10 +**.cpp = native 1.11 +**.java = native 1.12 +**.sh = native 1.13 +**.pl = native 1.14 +**.jpg = bin 1.15 +**.gif = bin
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/.hgignore Mon Aug 27 02:14:35 2012 -0700 2.3 @@ -0,0 +1,3 @@ 2.4 +syntax: glob 2.5 + 2.6 +*.o
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/DKU.c Mon Aug 27 02:14:35 2012 -0700 3.3 @@ -0,0 +1,853 @@ 3.4 +/* 3.5 + * Copyright 2010 OpenSourceCodeStewardshipFoundation 3.6 + * 3.7 + * Licensed under BSD 3.8 + */ 3.9 + 3.10 +#include <stdio.h> 3.11 +#include <stdlib.h> 3.12 +#include <malloc.h> 3.13 + 3.14 +#include "Queue_impl/PrivateQueue.h" 3.15 +#include "Hash_impl/PrivateHash.h" 3.16 + 3.17 +#include "VSs.h" 3.18 +#include "Measurement/VSs_Counter_Recording.h" 3.19 + 3.20 +//========================================================================== 3.21 + 3.22 +void 3.23 +VSs__init(); 3.24 + 3.25 +void 3.26 +VSs__init_Helper(); 3.27 +//========================================================================== 3.28 + 3.29 + 3.30 + 3.31 +//=========================================================================== 3.32 + 3.33 + 3.34 +/*These are the library functions *called in the application* 3.35 + * 3.36 + *There's a pattern for the outside sequential code to interact with the 3.37 + * VMS_HW code. 3.38 + *The VMS_HW system is inside a boundary.. every VSs system is in its 3.39 + * own directory that contains the functions for each of the processor types. 3.40 + * One of the processor types is the "seed" processor that starts the 3.41 + * cascade of creating all the processors that do the work. 3.42 + *So, in the directory is a file called "EntryPoint.c" that contains the 3.43 + * function, named appropriately to the work performed, that the outside 3.44 + * sequential code calls. This function follows a pattern: 3.45 + *1) it calls VSs__init() 3.46 + *2) it creates the initial data for the seed processor, which is passed 3.47 + * in to the function 3.48 + *3) it creates the seed VSs processor, with the data to start it with. 3.49 + *4) it calls startVSsThenWaitUntilWorkDone 3.50 + *5) it gets the returnValue from the transfer struc and returns that 3.51 + * from the function 3.52 + * 3.53 + *For now, a new VSs system has to be created via VSs__init every 3.54 + * time an entry point function is called -- later, might add letting the 3.55 + * VSs system be created once, and let all the entry points just reuse 3.56 + * it -- want to be as simple as possible now, and see by using what makes 3.57 + * sense for later.. 3.58 + */ 3.59 + 3.60 + 3.61 + 3.62 +//=========================================================================== 3.63 + 3.64 +/*This is the "border crossing" function -- the thing that crosses from the 3.65 + * outside world, into the VMS_HW world. It initializes and starts up the 3.66 + * VMS system, then creates one processor from the specified function and 3.67 + * puts it into the readyQ. From that point, that one function is resp. 3.68 + * for creating all the other processors, that then create others, and so 3.69 + * forth. 3.70 + *When all the processors, including the seed, have dissipated, then this 3.71 + * function returns. The results will have been written by side-effect via 3.72 + * pointers read from, or written into initData. 3.73 + * 3.74 + *NOTE: no Threads should exist in the outside program that might touch 3.75 + * any of the data reachable from initData passed in to here 3.76 + */ 3.77 +void 3.78 +VSs__create_seed_slave_and_do_work( TopLevelFnPtr fnPtr, void *initData ) 3.79 + { VSsSemEnv *semEnv; 3.80 + SlaveVP *seedSlv; 3.81 + VSsSemData *semData; 3.82 + VSsTaskStub *threadTaskStub, *parentTaskStub; 3.83 + 3.84 + VSs__init(); //normal multi-thd 3.85 + 3.86 + semEnv = _VMSMasterEnv->semanticEnv; 3.87 + 3.88 + //VSs starts with one processor, which is put into initial environ, 3.89 + // and which then calls create() to create more, thereby expanding work 3.90 + seedSlv = VSs__create_slave_helper( fnPtr, initData, 3.91 + semEnv, semEnv->nextCoreToGetNewSlv++ ); 3.92 + 3.93 + //seed slave is a thread slave, so make a thread's task stub for it 3.94 + // and then make another to stand for the seed's parent task. Make 3.95 + // the parent be already ended, and have one child (the seed). This 3.96 + // will make the dissipate handler do the right thing when the seed 3.97 + // is dissipated. 3.98 + threadTaskStub = create_thread_task_stub( initData ); 3.99 + parentTaskStub = create_thread_task_stub( NULL ); 3.100 + parentTaskStub->isEnded = TRUE; 3.101 + parentTaskStub->numLiveChildThreads = 1; //so dissipate works for seed 3.102 + threadTaskStub->parentTaskStub = parentTaskStub; 3.103 + 3.104 + semData = (VSsSemData *)seedSlv->semanticData; 3.105 + //seedVP is a thread, so has a permanent task 3.106 + semData->needsTaskAssigned = FALSE; 3.107 + semData->taskStub = threadTaskStub; 3.108 + semData->slaveType = ThreadSlv; 3.109 + 3.110 + resume_slaveVP( seedSlv, semEnv ); //returns right away, just queues Slv 3.111 + 3.112 + VMS_SS__start_the_work_then_wait_until_done(); //normal multi-thd 3.113 + 3.114 + VSs__cleanup_after_shutdown(); 3.115 + } 3.116 + 3.117 + 3.118 +int32 3.119 +VSs__giveMinWorkUnitCycles( float32 percentOverhead ) 3.120 + { 3.121 + return MIN_WORK_UNIT_CYCLES; 3.122 + } 3.123 + 3.124 +int32 3.125 +VSs__giveIdealNumWorkUnits() 3.126 + { 3.127 + return NUM_ANIM_SLOTS * NUM_CORES; 3.128 + } 3.129 + 3.130 +int32 3.131 +VSs__give_number_of_cores_to_schedule_onto() 3.132 + { 3.133 + return NUM_CORES; 3.134 + } 3.135 + 3.136 +/*For now, use TSC -- later, make these two macros with assembly that first 3.137 + * saves jump point, and second jumps back several times to get reliable time 3.138 + */ 3.139 +void 3.140 +VSs__start_primitive() 3.141 + { saveLowTimeStampCountInto( ((VSsSemEnv *)(_VMSMasterEnv->semanticEnv))-> 3.142 + primitiveStartTime ); 3.143 + } 3.144 + 3.145 +/*Just quick and dirty for now -- make reliable later 3.146 + * will want this to jump back several times -- to be sure cache is warm 3.147 + * because don't want comm time included in calc-time measurement -- and 3.148 + * also to throw out any "weird" values due to OS interrupt or TSC rollover 3.149 + */ 3.150 +int32 3.151 +VSs__end_primitive_and_give_cycles() 3.152 + { int32 endTime, startTime; 3.153 + //TODO: fix by repeating time-measurement 3.154 + saveLowTimeStampCountInto( endTime ); 3.155 + startTime =((VSsSemEnv*)(_VMSMasterEnv->semanticEnv))->primitiveStartTime; 3.156 + return (endTime - startTime); 3.157 + } 3.158 + 3.159 +//=========================================================================== 3.160 + 3.161 +/*Initializes all the data-structures for a VSs system -- but doesn't 3.162 + * start it running yet! 3.163 + * 3.164 + *This runs in the main thread -- before VMS starts up 3.165 + * 3.166 + *This sets up the semantic layer over the VMS system 3.167 + * 3.168 + *First, calls VMS_Setup, then creates own environment, making it ready 3.169 + * for creating the seed processor and then starting the work. 3.170 + */ 3.171 +void 3.172 +VSs__init() 3.173 + { 3.174 + VMS_SS__init(); 3.175 + //masterEnv, a global var, now is partially set up by init_VMS 3.176 + // after this, have VMS_int__malloc and VMS_int__free available 3.177 + 3.178 + VSs__init_Helper(); 3.179 + } 3.180 + 3.181 + 3.182 +void idle_fn(void* data, SlaveVP *animatingSlv){ 3.183 + while(1){ 3.184 + VMS_int__suspend_slaveVP_and_send_req(animatingSlv); 3.185 + } 3.186 +} 3.187 + 3.188 +void 3.189 +VSs__init_Helper() 3.190 + { VSsSemEnv *semanticEnv; 3.191 + int32 i, coreNum, slotNum; 3.192 + VSsSemData *semData; 3.193 + 3.194 + //Hook up the semantic layer's plug-ins to the Master virt procr 3.195 + _VMSMasterEnv->requestHandler = &VSs__Request_Handler; 3.196 + _VMSMasterEnv->slaveAssigner = &VSs__assign_slaveVP_to_slot; 3.197 + 3.198 + //create the semantic layer's environment (all its data) and add to 3.199 + // the master environment 3.200 + semanticEnv = VMS_int__malloc( sizeof( VSsSemEnv ) ); 3.201 + _VMSMasterEnv->semanticEnv = semanticEnv; 3.202 + 3.203 + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 3.204 + _VMSMasterEnv->counterHandler = &VSs__counter_handler; 3.205 + VSs__init_counter_data_structs(); 3.206 + #endif 3.207 + 3.208 + semanticEnv->shutdownInitiated = FALSE; 3.209 + semanticEnv->coreIsDone = VMS_int__malloc( NUM_CORES * sizeof( bool32 ) ); 3.210 + //For each animation slot, there is an idle slave, and an initial 3.211 + // slave assigned as the current-task-slave. Create them here. 3.212 + SlaveVP *idleSlv, *slotTaskSlv; 3.213 + for( coreNum = 0; coreNum < NUM_CORES; coreNum++ ) 3.214 + { semanticEnv->coreIsDone[coreNum] = FALSE; //use during shutdown 3.215 + 3.216 + for( slotNum = 0; slotNum < NUM_ANIM_SLOTS; ++slotNum ) 3.217 + { idleSlv = VSs__create_slave_helper( &idle_fn, NULL, semanticEnv, 0); 3.218 + idleSlv->coreAnimatedBy = coreNum; 3.219 + idleSlv->animSlotAssignedTo = 3.220 + _VMSMasterEnv->allAnimSlots[coreNum][slotNum]; 3.221 + semanticEnv->idleSlv[coreNum][slotNum] = idleSlv; 3.222 + 3.223 + slotTaskSlv = VSs__create_slave_helper( &idle_fn, NULL, semanticEnv, 0); 3.224 + slotTaskSlv->coreAnimatedBy = coreNum; 3.225 + slotTaskSlv->animSlotAssignedTo = 3.226 + _VMSMasterEnv->allAnimSlots[coreNum][slotNum]; 3.227 + 3.228 + semData = slotTaskSlv->semanticData; 3.229 + semData->needsTaskAssigned = TRUE; 3.230 + semData->slaveType = SlotTaskSlv; 3.231 + semanticEnv->slotTaskSlvs[coreNum][slotNum] = slotTaskSlv; 3.232 + } 3.233 + } 3.234 + 3.235 + //create the ready queues, hash tables used for matching and so forth 3.236 + semanticEnv->slavesReadyToResumeQ = makeVMSQ(); 3.237 + semanticEnv->freeExtraTaskSlvQ = makeVMSQ(); 3.238 + semanticEnv->taskReadyQ = makeVMSQ(); 3.239 + 3.240 + semanticEnv->argPtrHashTbl = makeHashTable32( 16, &VMS_int__free ); 3.241 + semanticEnv->commHashTbl = makeHashTable32( 16, &VMS_int__free ); 3.242 + 3.243 + semanticEnv->nextCoreToGetNewSlv = 0; 3.244 + 3.245 + 3.246 + //TODO: bug -- turn these arrays into dyn arrays to eliminate limit 3.247 + //semanticEnv->singletonHasBeenExecutedFlags = makeDynArrayInfo( ); 3.248 + //semanticEnv->transactionStrucs = makeDynArrayInfo( ); 3.249 + for( i = 0; i < NUM_STRUCS_IN_SEM_ENV; i++ ) 3.250 + { 3.251 + semanticEnv->fnSingletons[i].endInstrAddr = NULL; 3.252 + semanticEnv->fnSingletons[i].hasBeenStarted = FALSE; 3.253 + semanticEnv->fnSingletons[i].hasFinished = FALSE; 3.254 + semanticEnv->fnSingletons[i].waitQ = makeVMSQ(); 3.255 + semanticEnv->transactionStrucs[i].waitingVPQ = makeVMSQ(); 3.256 + } 3.257 + 3.258 + semanticEnv->numLiveExtraTaskSlvs = 0; //must be last 3.259 + semanticEnv->numLiveThreadSlvs = 1; //must be last, counts the seed 3.260 + 3.261 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 3.262 + semanticEnv->unitList = makeListOfArrays(sizeof(Unit),128); 3.263 + semanticEnv->ctlDependenciesList = makeListOfArrays(sizeof(Dependency),128); 3.264 + semanticEnv->commDependenciesList = makeListOfArrays(sizeof(Dependency),128); 3.265 + semanticEnv->dynDependenciesList = makeListOfArrays(sizeof(Dependency),128); 3.266 + semanticEnv->ntonGroupsInfo = makePrivDynArrayOfSize((void***)&(semanticEnv->ntonGroups),8); 3.267 + 3.268 + semanticEnv->hwArcs = makeListOfArrays(sizeof(Dependency),128); 3.269 + memset(semanticEnv->last_in_slot,0,sizeof(NUM_CORES * NUM_ANIM_SLOTS * sizeof(Unit))); 3.270 + #endif 3.271 + } 3.272 + 3.273 + 3.274 +/*Frees any memory allocated by VSs__init() then calls VMS_int__shutdown 3.275 + */ 3.276 +void 3.277 +VSs__cleanup_after_shutdown() 3.278 + { VSsSemEnv *semanticEnv; 3.279 + 3.280 + semanticEnv = _VMSMasterEnv->semanticEnv; 3.281 + 3.282 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 3.283 + //UCC 3.284 + FILE* output; 3.285 + int n; 3.286 + char filename[255]; 3.287 + for(n=0;n<255;n++) 3.288 + { 3.289 + sprintf(filename, "./counters/UCC.%d",n); 3.290 + output = fopen(filename,"r"); 3.291 + if(output) 3.292 + { 3.293 + fclose(output); 3.294 + }else{ 3.295 + break; 3.296 + } 3.297 + } 3.298 + if(n<255){ 3.299 + printf("Saving UCC to File: %s ...\n", filename); 3.300 + output = fopen(filename,"w+"); 3.301 + if(output!=NULL){ 3.302 + set_dependency_file(output); 3.303 + //fprintf(output,"digraph Dependencies {\n"); 3.304 + //set_dot_file(output); 3.305 + //FIXME: first line still depends on counters being enabled, replace w/ unit struct! 3.306 + //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); 3.307 + forAllInListOfArraysDo(semanticEnv->unitList, &print_unit_to_file); 3.308 + forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); 3.309 + forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); 3.310 + forAllInDynArrayDo(semanticEnv->ntonGroupsInfo,&print_nton_to_file); 3.311 + //fprintf(output,"}\n"); 3.312 + fflush(output); 3.313 + 3.314 + } else 3.315 + printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); 3.316 + } else { 3.317 + printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); 3.318 + } 3.319 + //Loop Graph 3.320 + for(n=0;n<255;n++) 3.321 + { 3.322 + sprintf(filename, "./counters/LoopGraph.%d",n); 3.323 + output = fopen(filename,"r"); 3.324 + if(output) 3.325 + { 3.326 + fclose(output); 3.327 + }else{ 3.328 + break; 3.329 + } 3.330 + } 3.331 + if(n<255){ 3.332 + printf("Saving LoopGraph to File: %s ...\n", filename); 3.333 + output = fopen(filename,"w+"); 3.334 + if(output!=NULL){ 3.335 + set_dependency_file(output); 3.336 + //fprintf(output,"digraph Dependencies {\n"); 3.337 + //set_dot_file(output); 3.338 + //FIXME: first line still depends on counters being enabled, replace w/ unit struct! 3.339 + //forAllInDynArrayDo(_VMSMasterEnv->counter_history_array_info, &print_dot_node_info ); 3.340 + forAllInListOfArraysDo( semanticEnv->unitList, &print_unit_to_file ); 3.341 + forAllInListOfArraysDo( semanticEnv->commDependenciesList, &print_comm_dependency_to_file ); 3.342 + forAllInListOfArraysDo( semanticEnv->ctlDependenciesList, &print_ctl_dependency_to_file ); 3.343 + forAllInListOfArraysDo( semanticEnv->dynDependenciesList, &print_dyn_dependency_to_file ); 3.344 + forAllInListOfArraysDo( semanticEnv->hwArcs, &print_hw_dependency_to_file ); 3.345 + //fprintf(output,"}\n"); 3.346 + fflush(output); 3.347 + 3.348 + } else 3.349 + printf("Opening LoopGraph file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); 3.350 + } else { 3.351 + printf("Could not open LoopGraph file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); 3.352 + } 3.353 + 3.354 + 3.355 + freeListOfArrays(semanticEnv->unitList); 3.356 + freeListOfArrays(semanticEnv->commDependenciesList); 3.357 + freeListOfArrays(semanticEnv->ctlDependenciesList); 3.358 + freeListOfArrays(semanticEnv->dynDependenciesList); 3.359 + 3.360 + #endif 3.361 +#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 3.362 + for(n=0;n<255;n++) 3.363 + { 3.364 + sprintf(filename, "./counters/Counters.%d.csv",n); 3.365 + output = fopen(filename,"r"); 3.366 + if(output) 3.367 + { 3.368 + fclose(output); 3.369 + }else{ 3.370 + break; 3.371 + } 3.372 + } 3.373 + if(n<255){ 3.374 + printf("Saving Counter measurements to File: %s ...\n", filename); 3.375 + output = fopen(filename,"w+"); 3.376 + if(output!=NULL){ 3.377 + set_counter_file(output); 3.378 + int i; 3.379 + for(i=0;i<NUM_CORES;i++){ 3.380 + forAllInListOfArraysDo( semanticEnv->counterList[i], &print_counter_events_to_file ); 3.381 + fflush(output); 3.382 + } 3.383 + 3.384 + } else 3.385 + printf("Opening UCC file failed. Please check that folder \"counters\" exists in run directory and has write permission.\n"); 3.386 + } else { 3.387 + printf("Could not open UCC file, please clean \"counters\" folder. (Must contain less than 255 files.)\n"); 3.388 + } 3.389 + 3.390 +#endif 3.391 +/* It's all allocated inside VMS's big chunk -- that's about to be freed, so 3.392 + * nothing to do here 3.393 + 3.394 + 3.395 + for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ ) 3.396 + { 3.397 + VMS_int__free( semanticEnv->readyVPQs[coreIdx]->startOfData ); 3.398 + VMS_int__free( semanticEnv->readyVPQs[coreIdx] ); 3.399 + } 3.400 + VMS_int__free( semanticEnv->readyVPQs ); 3.401 + 3.402 + freeHashTable( semanticEnv->commHashTbl ); 3.403 + VMS_int__free( _VMSMasterEnv->semanticEnv ); 3.404 + */ 3.405 + VMS_SS__cleanup_at_end_of_shutdown(); 3.406 + } 3.407 + 3.408 + 3.409 +//=========================================================================== 3.410 + 3.411 +SlaveVP * 3.412 +VSs__create_thread( TopLevelFnPtr fnPtr, void *initData, 3.413 + SlaveVP *creatingThd ) 3.414 + { VSsSemReq reqData; 3.415 + 3.416 + //the semantic request data is on the stack and disappears when this 3.417 + // call returns -- it's guaranteed to remain in the VP's stack for as 3.418 + // long as the VP is suspended. 3.419 + reqData.reqType = 0; //know type because in a VMS create req 3.420 + reqData.fnPtr = fnPtr; 3.421 + reqData.initData = initData; 3.422 + reqData.callingSlv = creatingThd; 3.423 + 3.424 + VMS_WL__send_create_slaveVP_req( &reqData, creatingThd ); 3.425 + 3.426 + return creatingThd->dataRetFromReq; 3.427 + } 3.428 + 3.429 +/*This is always the last thing done in the code animated by a thread VP. 3.430 + * Normally, this would be the last line of the thread's top level function. 3.431 + * But, if the thread exits from any point, it has to do so by calling 3.432 + * this. 3.433 + * 3.434 + *It simply sends a dissipate request, which handles all the state cleanup. 3.435 + */ 3.436 +void 3.437 +VSs__end_thread( SlaveVP *thdToEnd ) 3.438 + { VSsSemData *semData; 3.439 + 3.440 + VMS_WL__send_dissipate_req( thdToEnd ); 3.441 + } 3.442 + 3.443 + 3.444 + 3.445 +//=========================================================================== 3.446 + 3.447 + 3.448 +//======================= task submit and end ============================== 3.449 +/* 3.450 + */ 3.451 +void 3.452 +VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv) 3.453 + { VSsSemReq reqData; 3.454 + 3.455 + reqData.reqType = submit_task; 3.456 + 3.457 + reqData.taskType = taskType; 3.458 + reqData.args = args; 3.459 + reqData.callingSlv = animSlv; 3.460 + 3.461 + reqData.taskID = NULL; 3.462 + 3.463 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.464 + } 3.465 + 3.466 +inline int32 * 3.467 +VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv ) 3.468 + { int32 *taskID; 3.469 + 3.470 + taskID = VMS_WL__malloc( sizeof(int32) + numInts * sizeof(int32) ); 3.471 + taskID[0] = numInts; 3.472 + return taskID; 3.473 + } 3.474 + 3.475 +void 3.476 +VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, 3.477 + SlaveVP *animSlv) 3.478 + { VSsSemReq reqData; 3.479 + 3.480 + reqData.reqType = submit_task; 3.481 + 3.482 + reqData.taskType = taskType; 3.483 + reqData.args = args; 3.484 + reqData.taskID = taskID; 3.485 + reqData.callingSlv = animSlv; 3.486 + 3.487 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.488 + } 3.489 + 3.490 + 3.491 +/*This call is the last to happen in every task. It causes the slave to 3.492 + * suspend and get the next task out of the task-queue. Notice there is no 3.493 + * assigner here.. only one slave, no slave ReadyQ, and so on.. 3.494 + *Can either make the assigner take the next task out of the taskQ, or can 3.495 + * leave all as it is, and make task-end take the next task. 3.496 + *Note: this fits the case in the new VMS for no-context tasks, so will use 3.497 + * the built-in taskQ of new VMS, and should be local and much faster. 3.498 + * 3.499 + *The task-stub is saved in the animSlv, so the request handler will get it 3.500 + * from there, along with the task-type which has arg types, and so on.. 3.501 + * 3.502 + * NOTE: if want, don't need to send the animating SlaveVP around.. 3.503 + * instead, can make a single slave per core, and coreCtrlr looks up the 3.504 + * slave from having the core number. 3.505 + * 3.506 + *But, to stay compatible with all the other VMS languages, leave it in.. 3.507 + */ 3.508 +void 3.509 +VSs__end_task( SlaveVP *animSlv ) 3.510 + { VSsSemReq reqData; 3.511 + 3.512 + reqData.reqType = end_task; 3.513 + reqData.callingSlv = animSlv; 3.514 + 3.515 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.516 + } 3.517 + 3.518 + 3.519 +void 3.520 +VSs__taskwait(SlaveVP *animSlv) 3.521 +{ 3.522 + VSsSemReq reqData; 3.523 + 3.524 + reqData.reqType = taskwait; 3.525 + reqData.callingSlv = animSlv; 3.526 + 3.527 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.528 +} 3.529 + 3.530 + 3.531 + 3.532 +//========================== send and receive ============================ 3.533 +// 3.534 + 3.535 +inline int32 * 3.536 +VSs__give_self_taskID( SlaveVP *animSlv ) 3.537 + { 3.538 + return ((VSsSemData*)animSlv->semanticData)->taskStub->taskID; 3.539 + } 3.540 + 3.541 +//================================ send =================================== 3.542 + 3.543 +void 3.544 +VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID, 3.545 + SlaveVP *senderSlv ) 3.546 + { VSsSemReq reqData; 3.547 + 3.548 + reqData.reqType = send_type_to; 3.549 + 3.550 + reqData.msg = msg; 3.551 + reqData.msgType = type; 3.552 + reqData.receiverID = receiverID; 3.553 + reqData.senderSlv = senderSlv; 3.554 + 3.555 + reqData.nextReqInHashEntry = NULL; 3.556 + 3.557 + VMS_WL__send_sem_request( &reqData, senderSlv ); 3.558 + 3.559 + //When come back from suspend, no longer own data reachable from msg 3.560 + } 3.561 + 3.562 +void 3.563 +VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ) 3.564 + { VSsSemReq reqData; 3.565 + 3.566 + reqData.reqType = send_from_to; 3.567 + 3.568 + reqData.msg = msg; 3.569 + reqData.senderID = senderID; 3.570 + reqData.receiverID = receiverID; 3.571 + reqData.senderSlv = senderSlv; 3.572 + 3.573 + reqData.nextReqInHashEntry = NULL; 3.574 + 3.575 + VMS_WL__send_sem_request( &reqData, senderSlv ); 3.576 + } 3.577 + 3.578 + 3.579 +//================================ receive ================================ 3.580 + 3.581 +/*The "type" version of send and receive creates a many-to-one relationship. 3.582 + * The sender is anonymous, and many sends can stack up, waiting to be 3.583 + * received. The same receiver can also have send from-to's 3.584 + * waiting for it, and those will be kept separate from the "type" 3.585 + * messages. 3.586 + */ 3.587 +void * 3.588 +VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ) 3.589 + { DEBUG__printf1(dbgRqstHdlr,"WL: receive type to %d",receiverID[1] ); 3.590 + VSsSemReq reqData; 3.591 + 3.592 + reqData.reqType = receive_type_to; 3.593 + 3.594 + reqData.msgType = type; 3.595 + reqData.receiverID = receiverID; 3.596 + reqData.receiverSlv = receiverSlv; 3.597 + 3.598 + reqData.nextReqInHashEntry = NULL; 3.599 + 3.600 + VMS_WL__send_sem_request( &reqData, receiverSlv ); 3.601 + 3.602 + return receiverSlv->dataRetFromReq; 3.603 + } 3.604 + 3.605 + 3.606 + 3.607 +/*Call this at the point a receiving task wants in-coming data. 3.608 + * Use this from-to form when know senderID -- it makes a direct channel 3.609 + * between sender and receiver. 3.610 + */ 3.611 +void * 3.612 +VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ) 3.613 + { 3.614 + VSsSemReq reqData; 3.615 + 3.616 + reqData.reqType = receive_from_to; 3.617 + 3.618 + reqData.senderID = senderID; 3.619 + reqData.receiverID = receiverID; 3.620 + reqData.receiverSlv = receiverSlv; 3.621 + 3.622 + reqData.nextReqInHashEntry = NULL; 3.623 + DEBUG__printf2(dbgRqstHdlr,"WL: receive from %d to: %d", reqData.senderID[1], reqData.receiverID[1]); 3.624 + 3.625 + VMS_WL__send_sem_request( &reqData, receiverSlv ); 3.626 + 3.627 + return receiverSlv->dataRetFromReq; 3.628 + } 3.629 + 3.630 + 3.631 + 3.632 + 3.633 +//========================================================================== 3.634 +// 3.635 +/*A function singleton is a function whose body executes exactly once, on a 3.636 + * single core, no matter how many times the fuction is called and no 3.637 + * matter how many cores or the timing of cores calling it. 3.638 + * 3.639 + *A data singleton is a ticket attached to data. That ticket can be used 3.640 + * to get the data through the function exactly once, no matter how many 3.641 + * times the data is given to the function, and no matter the timing of 3.642 + * trying to get the data through from different cores. 3.643 + */ 3.644 + 3.645 +/*asm function declarations*/ 3.646 +void asm_save_ret_to_singleton(VSsSingleton *singletonPtrAddr); 3.647 +void asm_write_ret_from_singleton(VSsSingleton *singletonPtrAddr); 3.648 + 3.649 +/*Fn singleton uses ID as index into array of singleton structs held in the 3.650 + * semantic environment. 3.651 + */ 3.652 +void 3.653 +VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ) 3.654 + { 3.655 + VSsSemReq reqData; 3.656 + 3.657 + // 3.658 + reqData.reqType = singleton_fn_start; 3.659 + reqData.singletonID = singletonID; 3.660 + 3.661 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.662 + if( animSlv->dataRetFromReq ) //will be 0 or addr of label in end singleton 3.663 + { 3.664 + VSsSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); 3.665 + asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); 3.666 + } 3.667 + } 3.668 + 3.669 +/*Data singleton hands addr of loc holding a pointer to a singleton struct. 3.670 + * The start_data_singleton makes the structure and puts its addr into the 3.671 + * location. 3.672 + */ 3.673 +void 3.674 +VSs__start_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv ) 3.675 + { 3.676 + VSsSemReq reqData; 3.677 + 3.678 + if( *singletonAddr && (*singletonAddr)->hasFinished ) 3.679 + goto JmpToEndSingleton; 3.680 + 3.681 + reqData.reqType = singleton_data_start; 3.682 + reqData.singletonPtrAddr = singletonAddr; 3.683 + 3.684 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.685 + if( animSlv->dataRetFromReq ) //either 0 or end singleton's return addr 3.686 + { //Assembly code changes the return addr on the stack to the one 3.687 + // saved into the singleton by the end-singleton-fn 3.688 + //The return addr is at 0x4(%%ebp) 3.689 + JmpToEndSingleton: 3.690 + asm_write_ret_from_singleton(*singletonAddr); 3.691 + } 3.692 + //now, simply return 3.693 + //will exit either from the start singleton call or the end-singleton call 3.694 + } 3.695 + 3.696 +/*Uses ID as index into array of flags. If flag already set, resumes from 3.697 + * end-label. Else, sets flag and resumes normally. 3.698 + * 3.699 + *Note, this call cannot be inlined because the instr addr at the label 3.700 + * inside is shared by all invocations of a given singleton ID. 3.701 + */ 3.702 +void 3.703 +VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ) 3.704 + { 3.705 + VSsSemReq reqData; 3.706 + 3.707 + //don't need this addr until after at least one singleton has reached 3.708 + // this function 3.709 + VSsSemEnv *semEnv = VMS_int__give_sem_env_for( animSlv ); 3.710 + asm_write_ret_from_singleton(&(semEnv->fnSingletons[ singletonID])); 3.711 + 3.712 + reqData.reqType = singleton_fn_end; 3.713 + reqData.singletonID = singletonID; 3.714 + 3.715 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.716 + 3.717 +EndSingletonInstrAddr: 3.718 + return; 3.719 + } 3.720 + 3.721 +void 3.722 +VSs__end_data_singleton( VSsSingleton **singletonPtrAddr, SlaveVP *animSlv ) 3.723 + { 3.724 + VSsSemReq reqData; 3.725 + 3.726 + //don't need this addr until after singleton struct has reached 3.727 + // this function for first time 3.728 + //do assembly that saves the return addr of this fn call into the 3.729 + // data singleton -- that data-singleton can only be given to exactly 3.730 + // one instance in the code of this function. However, can use this 3.731 + // function in different places for different data-singletons. 3.732 +// (*(singletonAddr))->endInstrAddr = &&EndDataSingletonInstrAddr; 3.733 + 3.734 + 3.735 + asm_save_ret_to_singleton(*singletonPtrAddr); 3.736 + 3.737 + reqData.reqType = singleton_data_end; 3.738 + reqData.singletonPtrAddr = singletonPtrAddr; 3.739 + 3.740 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.741 + } 3.742 + 3.743 +/*This executes the function in the masterVP, so it executes in isolation 3.744 + * from any other copies -- only one copy of the function can ever execute 3.745 + * at a time. 3.746 + * 3.747 + *It suspends to the master, and the request handler takes the function 3.748 + * pointer out of the request and calls it, then resumes the VP. 3.749 + *Only very short functions should be called this way -- for longer-running 3.750 + * isolation, use transaction-start and transaction-end, which run the code 3.751 + * between as work-code. 3.752 + */ 3.753 +void 3.754 +VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 3.755 + void *data, SlaveVP *animSlv ) 3.756 + { 3.757 + VSsSemReq reqData; 3.758 + 3.759 + // 3.760 + reqData.reqType = atomic; 3.761 + reqData.fnToExecInMaster = ptrToFnToExecInMaster; 3.762 + reqData.dataForFn = data; 3.763 + 3.764 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.765 + } 3.766 + 3.767 + 3.768 +/*This suspends to the master. 3.769 + *First, it looks at the VP's data, to see the highest transactionID that VP 3.770 + * already has entered. If the current ID is not larger, it throws an 3.771 + * exception stating a bug in the code. Otherwise it puts the current ID 3.772 + * there, and adds the ID to a linked list of IDs entered -- the list is 3.773 + * used to check that exits are properly ordered. 3.774 + *Next it is uses transactionID as index into an array of transaction 3.775 + * structures. 3.776 + *If the "VP_currently_executing" field is non-null, then put requesting VP 3.777 + * into queue in the struct. (At some point a holder will request 3.778 + * end-transaction, which will take this VP from the queue and resume it.) 3.779 + *If NULL, then write requesting into the field and resume. 3.780 + */ 3.781 +void 3.782 +VSs__start_transaction( int32 transactionID, SlaveVP *animSlv ) 3.783 + { 3.784 + VSsSemReq reqData; 3.785 + 3.786 + // 3.787 + reqData.callingSlv = animSlv; 3.788 + reqData.reqType = trans_start; 3.789 + reqData.transID = transactionID; 3.790 + 3.791 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.792 + } 3.793 + 3.794 +/*This suspends to the master, then uses transactionID as index into an 3.795 + * array of transaction structures. 3.796 + *It looks at VP_currently_executing to be sure it's same as requesting VP. 3.797 + * If different, throws an exception, stating there's a bug in the code. 3.798 + *Next it looks at the queue in the structure. 3.799 + *If it's empty, it sets VP_currently_executing field to NULL and resumes. 3.800 + *If something in, gets it, sets VP_currently_executing to that VP, then 3.801 + * resumes both. 3.802 + */ 3.803 +void 3.804 +VSs__end_transaction( int32 transactionID, SlaveVP *animSlv ) 3.805 + { 3.806 + VSsSemReq reqData; 3.807 + 3.808 + // 3.809 + reqData.callingSlv = animSlv; 3.810 + reqData.reqType = trans_end; 3.811 + reqData.transID = transactionID; 3.812 + 3.813 + VMS_WL__send_sem_request( &reqData, animSlv ); 3.814 + } 3.815 + 3.816 +//======================== Internal ================================== 3.817 +/* 3.818 + */ 3.819 +SlaveVP * 3.820 +VSs__create_slave_with( TopLevelFnPtr fnPtr, void *initData, 3.821 + SlaveVP *creatingSlv ) 3.822 + { VSsSemReq reqData; 3.823 + 3.824 + //the semantic request data is on the stack and disappears when this 3.825 + // call returns -- it's guaranteed to remain in the VP's stack for as 3.826 + // long as the VP is suspended. 3.827 + reqData.reqType = 0; //know type because in a VMS create req 3.828 + reqData.coreToAssignOnto = -1; //means round-robin assign 3.829 + reqData.fnPtr = fnPtr; 3.830 + reqData.initData = initData; 3.831 + reqData.callingSlv = creatingSlv; 3.832 + 3.833 + VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv ); 3.834 + 3.835 + return creatingSlv->dataRetFromReq; 3.836 + } 3.837 + 3.838 +SlaveVP * 3.839 +VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, 3.840 + SlaveVP *creatingSlv, int32 coreToAssignOnto ) 3.841 + { VSsSemReq reqData; 3.842 + 3.843 + //the semantic request data is on the stack and disappears when this 3.844 + // call returns -- it's guaranteed to remain in the VP's stack for as 3.845 + // long as the VP is suspended. 3.846 + reqData.reqType = create_slave_w_aff; //not used, May 2012 3.847 + reqData.coreToAssignOnto = coreToAssignOnto; 3.848 + reqData.fnPtr = fnPtr; 3.849 + reqData.initData = initData; 3.850 + reqData.callingSlv = creatingSlv; 3.851 + 3.852 + VMS_WL__send_create_slaveVP_req( &reqData, creatingSlv ); 3.853 + 3.854 + return creatingSlv->dataRetFromReq; 3.855 + } 3.856 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/DKU.h Mon Aug 27 02:14:35 2012 -0700 4.3 @@ -0,0 +1,374 @@ 4.4 +/* 4.5 + * Copyright 2009 OpenSourceStewardshipFoundation.org 4.6 + * Licensed under GNU General Public License version 2 4.7 + * 4.8 + * Author: seanhalle@yahoo.com 4.9 + * 4.10 + */ 4.11 + 4.12 +#ifndef _VSs_H 4.13 +#define _VSs_H 4.14 + 4.15 +#include "Queue_impl/PrivateQueue.h" 4.16 +#include "Hash_impl/PrivateHash.h" 4.17 +#include "VMS_impl/VMS.h" 4.18 +#include "Measurement/dependency.h" 4.19 + 4.20 + 4.21 +//=========================================================================== 4.22 +#define NUM_STRUCS_IN_SEM_ENV 1000 4.23 + 4.24 + //This is hardware dependent -- it's the number of cycles of scheduling 4.25 + // overhead -- if a work unit is fewer than this, it is better being 4.26 + // combined sequentially with other work 4.27 + //This value depends on both VMS overhead and VSs's plugin. At some point 4.28 + // it will be derived by perf-counter measurements during init of VSs 4.29 +#define MIN_WORK_UNIT_CYCLES 20000 4.30 + 4.31 +//=========================================================================== 4.32 +/*This header defines everything specific to the VSs semantic plug-in 4.33 + */ 4.34 +typedef struct _VSsSemReq VSsSemReq; 4.35 +typedef void (*VSsTaskFnPtr ) ( void *, SlaveVP *); 4.36 +typedef void (*PtrToAtomicFn ) ( void * ); //executed atomically in master 4.37 +//=========================================================================== 4.38 + 4.39 +#define NONCTLD 0 4.40 +#define IN 1 /*Trick -- READER same as IN*/ 4.41 +#define OUT 2 /*Trick -- WRITER same as OUT and INOUT*/ 4.42 +#define INOUT 2 /*Trick -- WRITER same as OUT and INOUT*/ 4.43 + 4.44 +#define READER 1 /*Trick -- READER same as IN*/ 4.45 +#define WRITER 2 /*Trick -- WRITER same as OUT and INOUT*/ 4.46 + 4.47 +#define IS_A_THREAD NULL 4.48 +#define IS_ENDED NULL 4.49 +#define SEED_SLV NULL 4.50 + 4.51 +typedef struct 4.52 + { 4.53 + VSsTaskFnPtr fn; 4.54 + int32 numTotalArgs;//the number of inputs to function 4.55 + int32 numCtldArgs;//how many of args have dependencies 4.56 + int32 *argTypes; //says reader, writer, or non-ctld 4.57 + int32 *argSizes; //for detecting overlap 4.58 + int32 sizeOfArgs; //for memcpy of args struct 4.59 + } 4.60 +VSsTaskType; 4.61 + 4.62 + 4.63 +typedef struct 4.64 + { 4.65 + bool32 hasEnabledNonFinishedWriter; 4.66 + int32 numEnabledNonDoneReaders; 4.67 + PrivQueueStruc *waitersQ; 4.68 + } 4.69 +VSsPointerEntry; 4.70 + 4.71 +typedef struct 4.72 + { 4.73 + void **args; //ctld args must come first, as ptrs 4.74 + VSsTaskType *taskType; 4.75 + int32 *taskID; 4.76 + int32 numBlockingProp; 4.77 + SlaveVP *slaveAssignedTo; //only valid before end task (thread) 4.78 + VSsPointerEntry **ptrEntries; 4.79 + void* parentTaskStub; 4.80 + int32 numLiveChildTasks; 4.81 + int32 numLiveChildThreads; 4.82 + bool32 isWaitingForChildTasksToEnd; 4.83 + bool32 isWaitingForChildThreadsToEnd; 4.84 + bool32 isEnded; 4.85 + } 4.86 +VSsTaskStub; 4.87 + 4.88 + 4.89 +typedef struct 4.90 + { 4.91 + VSsTaskStub *taskStub; 4.92 + int32 argNum; 4.93 + int32 isReader; 4.94 + } 4.95 +VSsTaskStubCarrier; 4.96 + 4.97 + 4.98 +/*Semantic layer-specific data sent inside a request from lib called in app 4.99 + * to request handler called in AnimationMaster 4.100 + */ 4.101 + 4.102 +typedef struct 4.103 + { 4.104 + SlaveVP *VPCurrentlyExecuting; 4.105 + PrivQueueStruc *waitingVPQ; 4.106 + } 4.107 +VSsTrans; 4.108 + 4.109 +/*WARNING: assembly hard-codes position of endInstrAddr as first field 4.110 + */ 4.111 +typedef struct 4.112 + { 4.113 + void *endInstrAddr; 4.114 + int32 hasBeenStarted; 4.115 + int32 hasFinished; 4.116 + PrivQueueStruc *waitQ; 4.117 + } 4.118 +VSsSingleton; 4.119 + 4.120 +enum VSsReqType 4.121 + { 4.122 + submit_task = 1, 4.123 + end_task, 4.124 + create_slave, 4.125 + create_slave_w_aff, 4.126 + dissipate_slave, 4.127 + //=============================== 4.128 + send_type_to, 4.129 + receive_type_to, 4.130 + send_from_to, 4.131 + receive_from_to, 4.132 + //=============================== 4.133 + taskwait, 4.134 + malloc_req, 4.135 + free_req, 4.136 + singleton_fn_start, 4.137 + singleton_fn_end, 4.138 + singleton_data_start, 4.139 + singleton_data_end, 4.140 + atomic, 4.141 + trans_start, 4.142 + trans_end 4.143 + }; 4.144 + 4.145 +struct _VSsSemReq 4.146 + { enum VSsReqType reqType; 4.147 + SlaveVP *callingSlv; 4.148 + VSsTaskType *taskType; 4.149 + void *args; 4.150 + VSsTaskStub *taskStub; 4.151 + 4.152 + SlaveVP *senderSlv; 4.153 + SlaveVP *receiverSlv; 4.154 + int32 *senderID; 4.155 + int32 *receiverID; 4.156 + int32 msgType; 4.157 + void *msg; 4.158 + VSsSemReq *nextReqInHashEntry; 4.159 + int32 *taskID; 4.160 + 4.161 + TopLevelFnPtr fnPtr; 4.162 + void *initData; 4.163 + int32 coreToAssignOnto; 4.164 + 4.165 + int32 sizeToMalloc; 4.166 + void *ptrToFree; 4.167 + 4.168 + int32 singletonID; 4.169 + VSsSingleton **singletonPtrAddr; 4.170 + 4.171 + PtrToAtomicFn fnToExecInMaster; 4.172 + void *dataForFn; 4.173 + 4.174 + int32 transID; 4.175 + } 4.176 +/* VSsSemReq */; 4.177 + 4.178 + 4.179 +typedef struct 4.180 + { 4.181 + PrivQueueStruc *slavesReadyToResumeQ; //Shared (slaves not pinned) 4.182 + PrivQueueStruc *freeExtraTaskSlvQ; //Shared 4.183 + PrivQueueStruc *taskReadyQ; //Shared (tasks not pinned) 4.184 + SlaveVP *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS]; 4.185 + HashTable *argPtrHashTbl; 4.186 + HashTable *commHashTbl; 4.187 + int32 numLiveExtraTaskSlvs; 4.188 + int32 numLiveThreadSlvs; 4.189 + int32 nextCoreToGetNewSlv; 4.190 + int32 primitiveStartTime; 4.191 + 4.192 + //fix limit on num with dynArray 4.193 + VSsSingleton fnSingletons[NUM_STRUCS_IN_SEM_ENV]; 4.194 + VSsTrans transactionStrucs[NUM_STRUCS_IN_SEM_ENV]; 4.195 + 4.196 + bool32 *coreIsDone; 4.197 + int32 numCoresDone; 4.198 + 4.199 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 4.200 + ListOfArrays* unitList; 4.201 + ListOfArrays* ctlDependenciesList; 4.202 + ListOfArrays* commDependenciesList; 4.203 + NtoN** ntonGroups; 4.204 + PrivDynArrayInfo* ntonGroupsInfo; 4.205 + ListOfArrays* dynDependenciesList; 4.206 + Unit last_in_slot[NUM_CORES * NUM_ANIM_SLOTS]; 4.207 + ListOfArrays* hwArcs; 4.208 + #endif 4.209 + 4.210 + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 4.211 + ListOfArrays* counterList[NUM_CORES]; 4.212 + #endif 4.213 + SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS]; 4.214 + int shutdownInitiated; 4.215 + } 4.216 +VSsSemEnv; 4.217 + 4.218 + 4.219 +typedef struct _TransListElem TransListElem; 4.220 +struct _TransListElem 4.221 + { 4.222 + int32 transID; 4.223 + TransListElem *nextTrans; 4.224 + }; 4.225 +//TransListElem 4.226 + 4.227 +enum VSsSlvType 4.228 + { ExtraTaskSlv = 1, 4.229 + SlotTaskSlv, 4.230 + ThreadSlv 4.231 + }; 4.232 + 4.233 +typedef struct 4.234 + { 4.235 + int32 highestTransEntered; 4.236 + TransListElem *lastTransEntered; 4.237 + bool32 needsTaskAssigned; 4.238 + VSsTaskStub *taskStub; 4.239 + enum VSsSlvType slaveType; 4.240 + } 4.241 +VSsSemData; 4.242 + 4.243 +//=========================================================================== 4.244 + 4.245 +void 4.246 +VSs__create_seed_slave_and_do_work( TopLevelFnPtr fn, void *initData ); 4.247 + 4.248 +int32 4.249 +VSs__giveMinWorkUnitCycles( float32 percentOverhead ); 4.250 + 4.251 +void 4.252 +VSs__start_primitive(); 4.253 + 4.254 +int32 4.255 +VSs__end_primitive_and_give_cycles(); 4.256 + 4.257 +int32 4.258 +VSs__giveIdealNumWorkUnits(); 4.259 + 4.260 +int32 4.261 +VSs__give_number_of_cores_to_schedule_onto(); 4.262 + 4.263 +//======================= 4.264 + 4.265 +void 4.266 +VSs__init(); 4.267 + 4.268 +void 4.269 +VSs__cleanup_after_shutdown(); 4.270 + 4.271 +//======================= 4.272 + 4.273 +SlaveVP * 4.274 +VSs__create_thread( TopLevelFnPtr fnPtr, void *initData, 4.275 + SlaveVP *creatingThd ); 4.276 + 4.277 +void 4.278 +VSs__end_thread( SlaveVP *thdToEnd ); 4.279 + 4.280 +//======================= 4.281 + 4.282 +#define VSs__malloc( numBytes, callingSlave ) VMS_App__malloc( numBytes, callingSlave) 4.283 + 4.284 +#define VSs__free(ptrToFree, callingSlave ) VMS_App__free( ptrToFree, callingSlave ) 4.285 + 4.286 + 4.287 +//======================= 4.288 +void 4.289 +VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv); 4.290 + 4.291 +inline int32 * 4.292 +VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv ); 4.293 + 4.294 +void 4.295 +VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, 4.296 + SlaveVP *animSlv); 4.297 + 4.298 +void 4.299 +VSs__end_task( SlaveVP *animSlv ); 4.300 + 4.301 +//========================= 4.302 +void 4.303 +VSs__taskwait(SlaveVP *animSlv); 4.304 + 4.305 + 4.306 +inline int32 * 4.307 +VSs__give_self_taskID( SlaveVP *animSlv ); 4.308 + 4.309 +void 4.310 +VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID, 4.311 + SlaveVP *senderSlv ); 4.312 + 4.313 +void 4.314 +VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv ); 4.315 + 4.316 +void * 4.317 +VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv ); 4.318 + 4.319 +void * 4.320 +VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv ); 4.321 + 4.322 +//======================= Concurrency Stuff ====================== 4.323 +void 4.324 +VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv ); 4.325 + 4.326 +void 4.327 +VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv ); 4.328 + 4.329 +void 4.330 +VSs__start_data_singleton( VSsSingleton **singeltonAddr, SlaveVP *animSlv ); 4.331 + 4.332 +void 4.333 +VSs__end_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv ); 4.334 + 4.335 +void 4.336 +VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster, 4.337 + void *data, SlaveVP *animSlv ); 4.338 + 4.339 +void 4.340 +VSs__start_transaction( int32 transactionID, SlaveVP *animSlv ); 4.341 + 4.342 +void 4.343 +VSs__end_transaction( int32 transactionID, SlaveVP *animSlv ); 4.344 + 4.345 + 4.346 +//========================= Internal use only ============================= 4.347 +void 4.348 +VSs__Request_Handler( SlaveVP *requestingSlv, void *_semEnv ); 4.349 + 4.350 +SlaveVP * 4.351 +VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot ); 4.352 + 4.353 +SlaveVP* 4.354 +VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData, 4.355 + VSsSemEnv *semEnv, int32 coreToAssignOnto ); 4.356 + 4.357 +VSsTaskStub * 4.358 +create_thread_task_stub( void *initData ); 4.359 + 4.360 + 4.361 +SlaveVP * 4.362 +VSs__create_slave_with( TopLevelFnPtr fnPtr, void *initData, 4.363 + SlaveVP *creatingSlv ); 4.364 + 4.365 +SlaveVP * 4.366 +VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr, void *initData, 4.367 + SlaveVP *creatingSlv, int32 coreToAssignOnto); 4.368 + 4.369 +void 4.370 +idle_fn(void* data, SlaveVP *animatingSlv); 4.371 + 4.372 +//===================== Measurement of Lang Overheads ===================== 4.373 +#include "Measurement/VSs_Measurement.h" 4.374 + 4.375 +//=========================================================================== 4.376 +#endif /* _VSs_H */ 4.377 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/DKU_PluginFns.c Mon Aug 27 02:14:35 2012 -0700 5.3 @@ -0,0 +1,505 @@ 5.4 +/* 5.5 + * Copyright 2010 OpenSourceCodeStewardshipFoundation 5.6 + * 5.7 + * Licensed under BSD 5.8 + */ 5.9 + 5.10 +#include <stdio.h> 5.11 +#include <stdlib.h> 5.12 + 5.13 +#include "Queue_impl/PrivateQueue.h" 5.14 +#include "VSs.h" 5.15 +#include "VSs_Request_Handlers.h" 5.16 + 5.17 +//=========================== Local Fn Prototypes =========================== 5.18 +void 5.19 +resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv ); 5.20 + 5.21 +inline void 5.22 +handleSemReq( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); 5.23 + 5.24 +inline void 5.25 +handleDissipate( SlaveVP *requestingSlv, VSsSemEnv *semEnv ); 5.26 + 5.27 +inline void 5.28 +handleCreate( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); 5.29 + 5.30 +//============================== Assigner ================================== 5.31 +// 5.32 +/*The assigner is complicated by having both tasks and explicitly created 5.33 + * VPs, and by tasks being able to suspend. 5.34 + *It can't use an explicit slave to animate a task because of stack 5.35 + * pollution. So, it has to keep the two kinds separate. 5.36 + *Simplest way for the assigner logic is with a Q for extra empty task 5.37 + * slaves, and another Q for slaves of both types that are ready to resume. 5.38 + * 5.39 + *Keep a current task slave for each anim slot. The request handler manages 5.40 + * it by pulling from the extraTaskSlvQ when a task suspends, or else 5.41 + * creating a new task slave if taskSlvQ empty. 5.42 + *Assigner only assigns a task to the current task slave for the slot. 5.43 + *If no more tasks, then takes a ready to resume slave, if also none of them 5.44 + * then dissipates extra task slaves (one per invocation). 5.45 + *Shutdown condition is: must have no suspended tasks, and no suspended 5.46 + * explicit slaves and no more tasks in taskQ. Will only have the masters 5.47 + * plus a current task slave for each slot.. detects this condition. 5.48 + * 5.49 + *Having the two types of slave is part of having communications directly 5.50 + * between tasks, and tasks to explicit slaves, which requires the ability 5.51 + * to suspend both kinds, but also to keep explicit slave stacks clean from 5.52 + * the junk tasks are allowed to leave behind. 5.53 + */ 5.54 +SlaveVP * 5.55 +VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot ) 5.56 + { SlaveVP *returnSlv; 5.57 + VSsSemEnv *semEnv; 5.58 + VSsSemData *semData; 5.59 + int32 coreNum, slotNum; 5.60 + VSsTaskStub *newTaskStub; 5.61 + SlaveVP *extraSlv; 5.62 + 5.63 + coreNum = slot->coreSlotIsOn; 5.64 + slotNum = slot->slotIdx; 5.65 + 5.66 + semEnv = (VSsSemEnv *)_semEnv; 5.67 + 5.68 + //Check for suspended slaves that are ready to resume 5.69 + returnSlv = readPrivQ( semEnv->slavesReadyToResumeQ ); 5.70 + if( returnSlv != NULL ) //Yes, have a slave, so return it. 5.71 + { returnSlv->coreAnimatedBy = coreNum; 5.72 + 5.73 + //have work, so reset Done flag (when work generated on other core) 5.74 + if( semEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf 5.75 + semEnv->coreIsDone[coreNum] = FALSE; //don't just write always 5.76 + goto ReturnTheSlv; 5.77 + } 5.78 + 5.79 + //If none, speculate will have a task, so get the slot slave 5.80 + //TODO: false sharing ? (think not bad cause mostly read..) 5.81 + returnSlv = semEnv->slotTaskSlvs[coreNum][slotNum]; 5.82 + 5.83 + semData = (VSsSemData *)returnSlv->semanticData; 5.84 + 5.85 + //There is always a curr task slave, and it always needs a task 5.86 + // (task slaves that are resuming are in resumeQ) 5.87 + newTaskStub = readPrivQ( semEnv->taskReadyQ ); 5.88 + if( newTaskStub != NULL ) 5.89 + { //point slave to task's function, and mark slave as having task 5.90 + VMS_int__reset_slaveVP_to_TopLvlFn( returnSlv, 5.91 + newTaskStub->taskType->fn, newTaskStub->args ); 5.92 + semData->taskStub = newTaskStub; 5.93 + newTaskStub->slaveAssignedTo = returnSlv; 5.94 + semData->needsTaskAssigned = FALSE; 5.95 + 5.96 + //have work, so reset Done flag, if was set 5.97 + if( semEnv->coreIsDone[coreNum] == TRUE ) //reads are higher perf 5.98 + semEnv->coreIsDone[coreNum] = FALSE; //don't just write always 5.99 + goto ReturnTheSlv; 5.100 + } 5.101 + else 5.102 + { //no task, so try to clean up unused extra task slaves 5.103 + extraSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); 5.104 + if( extraSlv != NULL ) 5.105 + { //have two slaves need tasks, so delete one 5.106 + //This both bounds the num extras, and delivers shutdown cond 5.107 + handleDissipate( extraSlv, semEnv ); 5.108 + //then return NULL 5.109 + returnSlv = NULL; 5.110 + goto ReturnTheSlv; 5.111 + } 5.112 + else 5.113 + { //candidate for shutdown.. if all extras dissipated, and no tasks 5.114 + // and no ready to resume slaves, then no way to generate 5.115 + // more tasks (on this core -- other core might have task still) 5.116 + if( semEnv->numLiveExtraTaskSlvs == 0 && 5.117 + semEnv->numLiveThreadSlvs == 0 ) 5.118 + { //This core sees no way to generate more tasks, so say it 5.119 + if( semEnv->coreIsDone[coreNum] == FALSE ) 5.120 + { semEnv->numCoresDone += 1; 5.121 + semEnv->coreIsDone[coreNum] = TRUE; 5.122 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 5.123 + semEnv->shutdownInitiated = TRUE; 5.124 + 5.125 + #else 5.126 + if( semEnv->numCoresDone == NUM_CORES ) 5.127 + { //means no cores have work, and none can generate more 5.128 + semEnv->shutdownInitiated = TRUE; 5.129 + } 5.130 + #endif 5.131 + } 5.132 + } 5.133 + //return NULL.. no task and none to resume 5.134 + returnSlv = NULL; 5.135 + //except if shutdown has been initiated by this or other core 5.136 + if(semEnv->shutdownInitiated) 5.137 + { returnSlv = VMS_SS__create_shutdown_slave(); 5.138 + } 5.139 + goto ReturnTheSlv; //don't need, but completes pattern 5.140 + } //if( extraSlv != NULL ) 5.141 + } //if( newTaskStub == NULL ) 5.142 + //outcome: 1)slave was just pointed to task, 2)no tasks, so slave NULL 5.143 + 5.144 +ReturnTheSlv: //Nina, doing gotos to here should help with holistic.. 5.145 + 5.146 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 5.147 + if( returnSlv == NULL ) 5.148 + { returnSlv = semEnv->idleSlv[coreNum][slotNum]; 5.149 + 5.150 + //things that would normally happen in resume(), but these VPs 5.151 + // never go there 5.152 + returnSlv->assignCount++; //Somewhere here! 5.153 + Unit newu; 5.154 + newu.vp = returnSlv->slaveID; 5.155 + newu.task = returnSlv->assignCount; 5.156 + addToListOfArrays(Unit,newu,semEnv->unitList); 5.157 + 5.158 + if (returnSlv->assignCount > 1) 5.159 + { Dependency newd; 5.160 + newd.from_vp = returnSlv->slaveID; 5.161 + newd.from_task = returnSlv->assignCount - 1; 5.162 + newd.to_vp = returnSlv->slaveID; 5.163 + newd.to_task = returnSlv->assignCount; 5.164 + addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList); 5.165 + } 5.166 + } 5.167 + #endif 5.168 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 5.169 + if( returnSlv != NULL ) 5.170 + { //assignSlv->numTimesAssigned++; 5.171 + Unit prev_in_slot = 5.172 + semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum]; 5.173 + if(prev_in_slot.vp != 0) 5.174 + { Dependency newd; 5.175 + newd.from_vp = prev_in_slot.vp; 5.176 + newd.from_task = prev_in_slot.task; 5.177 + newd.to_vp = returnSlv->slaveID; 5.178 + newd.to_task = returnSlv->assignCount; 5.179 + addToListOfArrays(Dependency,newd,semEnv->hwArcs); 5.180 + } 5.181 + prev_in_slot.vp = returnSlv->slaveID; 5.182 + prev_in_slot.task = returnSlv->assignCount; 5.183 + semEnv->last_in_slot[coreNum * NUM_ANIM_SLOTS + slotNum] = 5.184 + prev_in_slot; 5.185 + } 5.186 + #endif 5.187 + return( returnSlv ); 5.188 + } 5.189 + 5.190 + 5.191 +//=========================== Request Handler ============================ 5.192 +// 5.193 +/* 5.194 + * (BTW not inline because invoked indirectly via a pointer) 5.195 + */ 5.196 +void 5.197 +VSs__Request_Handler( SlaveVP *requestingSlv, void *_semEnv ) 5.198 + { VSsSemEnv *semEnv; 5.199 + VMSReqst *req; 5.200 + 5.201 + semEnv = (VSsSemEnv *)_semEnv; 5.202 + 5.203 + req = VMS_PI__take_next_request_out_of( requestingSlv ); 5.204 + 5.205 + while( req != NULL ) 5.206 + { 5.207 + switch( req->reqType ) 5.208 + { case semantic: handleSemReq( req, requestingSlv, semEnv); 5.209 + break; 5.210 + case createReq: handleCreate( req, requestingSlv, semEnv); 5.211 + break; 5.212 + case dissipate: handleDissipate( requestingSlv, semEnv); 5.213 + break; 5.214 + case VMSSemantic: VMS_PI__handle_VMSSemReq(req, requestingSlv, semEnv, 5.215 + (ResumeSlvFnPtr) &resume_slaveVP); 5.216 + break; 5.217 + default: 5.218 + break; 5.219 + } 5.220 + 5.221 + req = VMS_PI__take_next_request_out_of( requestingSlv ); 5.222 + } //while( req != NULL ) 5.223 + 5.224 + } 5.225 + 5.226 + 5.227 +inline void 5.228 +handleSemReq( VMSReqst *req, SlaveVP *reqSlv, VSsSemEnv *semEnv ) 5.229 + { VSsSemReq *semReq; 5.230 + 5.231 + semReq = VMS_PI__take_sem_reqst_from(req); 5.232 + if( semReq == NULL ) return; 5.233 + switch( semReq->reqType ) //sem handlers are all in other file 5.234 + { 5.235 + case submit_task: handleSubmitTask( semReq, semEnv); 5.236 + break; 5.237 + case end_task: handleEndTask( semReq, semEnv); 5.238 + break; 5.239 + case send_type_to: handleSendTypeTo( semReq, semEnv); 5.240 + break; 5.241 + case send_from_to: handleSendFromTo( semReq, semEnv); 5.242 + break; 5.243 + case receive_type_to: handleReceiveTypeTo(semReq, semEnv); 5.244 + break; 5.245 + case receive_from_to: handleReceiveFromTo(semReq, semEnv); 5.246 + break; 5.247 + case taskwait: handleTaskwait( semReq, reqSlv, semEnv); 5.248 + break; 5.249 + 5.250 + //==================================================================== 5.251 + case malloc_req: handleMalloc( semReq, reqSlv, semEnv); 5.252 + break; 5.253 + case free_req: handleFree( semReq, reqSlv, semEnv); 5.254 + break; 5.255 + case singleton_fn_start: handleStartFnSingleton(semReq, reqSlv, semEnv); 5.256 + break; 5.257 + case singleton_fn_end: handleEndFnSingleton( semReq, reqSlv, semEnv); 5.258 + break; 5.259 + case singleton_data_start:handleStartDataSingleton(semReq,reqSlv,semEnv); 5.260 + break; 5.261 + case singleton_data_end: handleEndDataSingleton(semReq, reqSlv, semEnv); 5.262 + break; 5.263 + case atomic: handleAtomic( semReq, reqSlv, semEnv); 5.264 + break; 5.265 + case trans_start: handleTransStart( semReq, reqSlv, semEnv); 5.266 + break; 5.267 + case trans_end: handleTransEnd( semReq, reqSlv, semEnv); 5.268 + break; 5.269 + } 5.270 + } 5.271 + 5.272 + 5.273 + 5.274 +//=========================== VMS Request Handlers ============================== 5.275 +/*SlaveVP dissipate -- this is NOT task-end!, only call this to get rid of 5.276 + * extra task slaves, and to end explicitly created threads 5.277 + */ 5.278 +inline void 5.279 +handleDissipate( SlaveVP *requestingSlv, VSsSemEnv *semEnv ) 5.280 + { VSsSemData *semData; 5.281 + VSsTaskStub *parentTaskStub, *ownTaskStub; 5.282 + 5.283 + DEBUG__printf1(dbgRqstHdlr,"Dissipate request from processor %d", 5.284 + requestingSlv->slaveID) 5.285 + semData = (VSsSemData *)requestingSlv->semanticData; 5.286 + 5.287 + if( semData->slaveType == ExtraTaskSlv ) 5.288 + { semEnv->numLiveExtraTaskSlvs -= 1; //for detecting shutdown condition 5.289 + //Has no task assigned, so no parents and no children, so free self 5.290 + goto FreeSlaveStateAndReturn; 5.291 + } 5.292 + 5.293 + if( semData->slaveType == SlotTaskSlv ) 5.294 + { //should never call dissipate on a slot assigned slave 5.295 + VMS_PI__throw_exception( "dissipate a slot-assigned slave", requestingSlv, NULL ); 5.296 + } 5.297 + 5.298 + //if make it to here, then is a thread slave ending 5.299 + semEnv->numLiveThreadSlvs -= 1; //for detecting shutdown condition 5.300 + 5.301 + ownTaskStub = semData->taskStub; 5.302 + parentTaskStub = ownTaskStub->parentTaskStub; 5.303 + parentTaskStub->numLiveChildThreads -= 1; //not freed, even if ended 5.304 + 5.305 + //if all children ended, then free this task's stub 5.306 + // else, keep stub around, and last child will free it (below) 5.307 + if( ownTaskStub->numLiveChildTasks == 0 && 5.308 + ownTaskStub->numLiveChildThreads == 0 ) 5.309 + free_task_stub( ownTaskStub ); 5.310 + else 5.311 + ownTaskStub->isEnded = TRUE; //for children to see when they end 5.312 + 5.313 + //Now, check on parents waiting on child threads to end 5.314 + if( parentTaskStub->isWaitingForChildThreadsToEnd && 5.315 + parentTaskStub->numLiveChildThreads == 0 ) 5.316 + { parentTaskStub->isWaitingForChildThreadsToEnd = FALSE; 5.317 + if( parentTaskStub->isWaitingForChildTasksToEnd ) 5.318 + return; //still waiting on tasks (should be impossible) 5.319 + else //parent free to resume 5.320 + resume_slaveVP( parentTaskStub->slaveAssignedTo, semEnv ); 5.321 + } 5.322 + 5.323 + //check if this is last child of ended parent (note, not possible to 5.324 + // have more than one level of ancestor waiting to be freed) 5.325 + if( parentTaskStub->isEnded ) 5.326 + { if( parentTaskStub->numLiveChildTasks == 0 && 5.327 + parentTaskStub->numLiveChildThreads == 0 ) 5.328 + free_task_stub( parentTaskStub ); //just stub, semData already freed 5.329 + } 5.330 + 5.331 + //Free the semData and requesting slave's base state for all cases 5.332 + FreeSlaveStateAndReturn: 5.333 + VMS_PI__free( semData ); 5.334 + VMS_PI__dissipate_slaveVP( requestingSlv ); 5.335 + return; 5.336 + //Note, this is not a location to check for shutdown because doesn't 5.337 + // say anything about work availability here.. check for shutdown in 5.338 + // places try to get work for the core (in the assigner) 5.339 + } 5.340 + 5.341 + 5.342 + 5.343 +/*Re-use this in the entry-point fn 5.344 + */ 5.345 +inline SlaveVP * 5.346 +VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData, 5.347 + VSsSemEnv *semEnv, int32 coreToAssignOnto ) 5.348 + { SlaveVP *newSlv; 5.349 + VSsSemData *semData; 5.350 + 5.351 + //This is running in master, so use internal version 5.352 + newSlv = VMS_PI__create_slaveVP( fnPtr, initData ); 5.353 + 5.354 + //task slaves differ from thread slaves by the settings in the taskStub 5.355 + //so, don't create task stub here, only create semData, which is same 5.356 + // for all kinds of slaves 5.357 + semData = VMS_PI__malloc( sizeof(VSsSemData) ); 5.358 + semData->highestTransEntered = -1; 5.359 + semData->lastTransEntered = NULL; 5.360 + semData->needsTaskAssigned = TRUE; 5.361 + semData->taskStub = NULL; 5.362 + 5.363 + newSlv->semanticData = semData; 5.364 + 5.365 + //=================== Assign new processor to a core ===================== 5.366 + #ifdef DEBUG__TURN_ON_SEQUENTIAL_MODE 5.367 + newSlv->coreAnimatedBy = 0; 5.368 + 5.369 + #else 5.370 + //Assigning slaves to cores is part of SSR code.. 5.371 + if(coreToAssignOnto < 0 || coreToAssignOnto >= NUM_CORES ) 5.372 + { //out-of-range, so round-robin assignment 5.373 + newSlv->coreAnimatedBy = semEnv->nextCoreToGetNewSlv; 5.374 + 5.375 + if( semEnv->nextCoreToGetNewSlv >= NUM_CORES - 1 ) 5.376 + semEnv->nextCoreToGetNewSlv = 0; 5.377 + else 5.378 + semEnv->nextCoreToGetNewSlv += 1; 5.379 + } 5.380 + else //core num in-range, so use it 5.381 + { newSlv->coreAnimatedBy = coreToAssignOnto; 5.382 + } 5.383 + #endif 5.384 + //======================================================================== 5.385 + 5.386 + return newSlv; 5.387 + } 5.388 + 5.389 +VSsTaskStub * 5.390 +create_thread_task_stub( void *initData ) 5.391 + { VSsTaskStub *newStub; 5.392 + 5.393 + newStub = VMS_PI__malloc( sizeof(VSsTaskStub) ); 5.394 + newStub->numBlockingProp = 0; 5.395 + newStub->slaveAssignedTo = NULL; //set later 5.396 + newStub->taskType = IS_A_THREAD; 5.397 + newStub->ptrEntries = NULL; 5.398 + newStub->args = initData; 5.399 + newStub->numLiveChildTasks = 0; 5.400 + newStub->numLiveChildThreads = 0; 5.401 + newStub->parentTaskStub = NULL; 5.402 + newStub->isWaitingForChildTasksToEnd = FALSE; 5.403 + newStub->isWaitingForChildThreadsToEnd = FALSE; 5.404 + newStub->taskID = NULL; 5.405 + 5.406 + return newStub; 5.407 + } 5.408 + 5.409 +/*Application invokes this when it explicitly creates a thread via the 5.410 + * "VSs__create_thread()" command. 5.411 + * 5.412 + *The request handlers create new task slaves directly, not via this hdlr. 5.413 + * 5.414 + *Make everything in VSs be a task. An explicitly created VP is just a 5.415 + * suspendable task, and the seedVP is also a suspendable task. 5.416 + *So, here, create a task Stub. 5.417 + * Then, see if there are any extra slaveVPs hanging around, and if not, 5.418 + * call the helper to make a new one. 5.419 + * Then, put the task stub into the slave's semantic Data. 5.420 + *When the slave calls dissipate, have to recycle the task stub. 5.421 + */ 5.422 +inline void 5.423 +handleCreate( VMSReqst *req, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) 5.424 + { VSsSemReq *semReq; 5.425 + SlaveVP *newSlv; 5.426 + VSsSemData *semData, *parentSemData; 5.427 + 5.428 + semReq = VMS_PI__take_sem_reqst_from( req ); 5.429 + 5.430 + semEnv->numLiveThreadSlvs += 1; 5.431 + 5.432 + //Deceptive -- must work when creator is a normal task, or seed, 5.433 + // or another thd.. think have valid sem data and task stub for all 5.434 + //This hdlr is NOT called when creating the seed slave 5.435 + parentSemData = (VSsSemData *)semReq->callingSlv->semanticData; 5.436 + parentSemData->taskStub->numLiveChildThreads += 1; 5.437 + 5.438 + //use an idle "extra" slave, if have one 5.439 + newSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); 5.440 + if( newSlv != NULL ) //got an idle one, so reset it 5.441 + { semData = (VSsSemData *)newSlv->semanticData; 5.442 + semData->highestTransEntered = -1; 5.443 + semData->lastTransEntered = NULL; 5.444 + VMS_int__reset_slaveVP_to_TopLvlFn( newSlv, semReq->fnPtr, 5.445 + semReq->initData ); 5.446 + } 5.447 + else //no idle ones, create a new 5.448 + { newSlv = VSs__create_slave_helper( semReq->fnPtr, semReq->initData, 5.449 + semEnv, semReq->coreToAssignOnto ); 5.450 + semData = (VSsSemData *)newSlv->semanticData; 5.451 + } 5.452 + 5.453 + //now, create a new task and assign to the thread 5.454 + semData->needsTaskAssigned = FALSE; //thread has a permanent task 5.455 + semData->taskStub = create_thread_task_stub( semReq->initData ); 5.456 + semData->taskStub->parentTaskStub = parentSemData->taskStub; 5.457 + semData->slaveType = ThreadSlv; //this hdlr only creates thread slvs 5.458 + 5.459 + DEBUG__printf2(dbgRqstHdlr,"Create from: %d, new VP: %d", 5.460 + requestingSlv->slaveID, newSlv->slaveID) 5.461 + 5.462 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 5.463 + Dependency newd; 5.464 + newd.from_vp = requestingSlv->slaveID; 5.465 + newd.from_task = requestingSlv->assignCount; 5.466 + newd.to_vp = newSlv->slaveID; 5.467 + newd.to_task = 1; 5.468 + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); 5.469 + #endif 5.470 + 5.471 + //For VSs, caller needs ptr to created thread returned to it 5.472 + requestingSlv->dataRetFromReq = newSlv; 5.473 + resume_slaveVP(requestingSlv , semEnv ); 5.474 + resume_slaveVP( newSlv, semEnv ); 5.475 + } 5.476 + 5.477 + 5.478 +//=========================== Helper ============================== 5.479 +void 5.480 +resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv ) 5.481 + { 5.482 + //both suspended tasks and suspended explicit slaves resumed with this 5.483 + writePrivQ( slave, semEnv->slavesReadyToResumeQ ); 5.484 + 5.485 + #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 5.486 +/* 5.487 + int lastRecordIdx = slave->counter_history_array_info->numInArray -1; 5.488 + CounterRecord* lastRecord = slave->counter_history[lastRecordIdx]; 5.489 + saveLowTimeStampCountInto(lastRecord->unblocked_timestamp); 5.490 +*/ 5.491 + #endif 5.492 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 5.493 + slave->assignCount++; //Somewhere here! 5.494 + Unit newu; 5.495 + newu.vp = slave->slaveID; 5.496 + newu.task = slave->assignCount; 5.497 + addToListOfArrays(Unit,newu,semEnv->unitList); 5.498 + 5.499 + if (slave->assignCount > 1){ 5.500 + Dependency newd; 5.501 + newd.from_vp = slave->slaveID; 5.502 + newd.from_task = slave->assignCount - 1; 5.503 + newd.to_vp = slave->slaveID; 5.504 + newd.to_task = slave->assignCount; 5.505 + addToListOfArrays(Dependency, newd ,semEnv->ctlDependenciesList); 5.506 + } 5.507 + #endif 5.508 + }
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/DKU_Request_Handlers.c Mon Aug 27 02:14:35 2012 -0700 6.3 @@ -0,0 +1,1213 @@ 6.4 +/* 6.5 + * Copyright 2010 OpenSourceCodeStewardshipFoundation 6.6 + * 6.7 + * Licensed under BSD 6.8 + */ 6.9 + 6.10 +#include <stdio.h> 6.11 +#include <stdlib.h> 6.12 + 6.13 +#include "VMS_impl/VMS.h" 6.14 +#include "Queue_impl/PrivateQueue.h" 6.15 +#include "Hash_impl/PrivateHash.h" 6.16 +#include "VSs.h" 6.17 +#include "VSs_Request_Handlers.h" 6.18 + 6.19 + 6.20 + 6.21 + 6.22 +//=========================== Local Fn Prototypes =========================== 6.23 +void 6.24 +resume_slaveVP( SlaveVP *slave, VSsSemEnv *semEnv ); 6.25 + 6.26 + 6.27 + 6.28 +//========================================================================== 6.29 +// Helpers 6.30 +// 6.31 + 6.32 +/*Only clone the elements of req used in these reqst handlers 6.33 + */ 6.34 +VSsSemReq * 6.35 +cloneReq( VSsSemReq *semReq ) 6.36 + { VSsSemReq *clonedReq; 6.37 + 6.38 + clonedReq = VMS_PI__malloc( sizeof(VSsSemReq) ); 6.39 + clonedReq->reqType = semReq->reqType; 6.40 + clonedReq->senderSlv = semReq->senderSlv; 6.41 + clonedReq->receiverSlv= semReq->receiverSlv; 6.42 + clonedReq->msg = semReq->msg; 6.43 + clonedReq->nextReqInHashEntry = NULL; 6.44 + 6.45 + return clonedReq; 6.46 + } 6.47 + 6.48 + 6.49 + 6.50 +HashEntry * 6.51 +giveEntryElseInsertReqst32( int32 *key, VSsSemReq *semReq, 6.52 + HashTable *commHashTbl ) 6.53 + { HashEntry *entry; 6.54 + VSsSemReq *waitingReq; 6.55 + 6.56 + entry = getEntryFromTable32( key, commHashTbl ); 6.57 + if( entry == NULL ) 6.58 + { //no waiting sends or receives, so add this request and exit 6.59 + // note: have to clone the request because it's on stack of sender 6.60 + addValueIntoTable32( key, cloneReq( semReq ), commHashTbl ); 6.61 + return NULL; 6.62 + } 6.63 + waitingReq = (VSsSemReq *)entry->content; 6.64 + if( waitingReq == NULL ) //might happen when last waiting gets paired 6.65 + { //no waiting sends or receives, so add this request and exit 6.66 + entry->content = semReq; 6.67 + return NULL; 6.68 + } 6.69 + return entry; 6.70 + } 6.71 + 6.72 + 6.73 +inline VSsPointerEntry * 6.74 +create_pointer_entry( ) 6.75 + { VSsPointerEntry *newEntry; 6.76 + 6.77 + newEntry = VMS_PI__malloc( sizeof(VSsPointerEntry) ); 6.78 + newEntry->hasEnabledNonFinishedWriter = FALSE; 6.79 + newEntry->numEnabledNonDoneReaders = 0; 6.80 + newEntry->waitersQ = makePrivQ(); 6.81 + 6.82 + return newEntry; 6.83 + } 6.84 + 6.85 +/*malloc's space and initializes fields -- and COPIES the arg values 6.86 + * to new space 6.87 + */ 6.88 +inline VSsTaskStub * 6.89 +create_task_stub( VSsTaskType *taskType, void **args ) 6.90 + { void **newArgs; 6.91 + VSsTaskStub* newStub = VMS_int__malloc( sizeof(VSsTaskStub) + taskType->sizeOfArgs ); 6.92 + newStub->numBlockingProp = taskType->numCtldArgs; 6.93 + newStub->slaveAssignedTo = NULL; 6.94 + newStub->taskType = taskType; 6.95 + newStub->ptrEntries = 6.96 + VMS_int__malloc( taskType->numCtldArgs * sizeof(VSsPointerEntry *) ); 6.97 + newArgs = (void **)( (uint8 *)newStub + sizeof(VSsTaskStub) ); 6.98 + newStub->args = newArgs; 6.99 + newStub->numLiveChildTasks = 0; 6.100 + newStub->numLiveChildThreads = 0; 6.101 + newStub->isEnded = FALSE; 6.102 + 6.103 + //Copy the arg-pointers.. can be more arguments than just the ones 6.104 + // that StarSs uses to control ordering of task execution. 6.105 + memcpy( newArgs, args, taskType->sizeOfArgs ); 6.106 + 6.107 + return newStub; 6.108 + } 6.109 + 6.110 +inline VSsTaskStubCarrier * 6.111 +create_task_carrier( VSsTaskStub *taskStub, int32 argNum, int32 rdOrWrite ) 6.112 + { VSsTaskStubCarrier *newCarrier; 6.113 + 6.114 + newCarrier = VMS_PI__malloc( sizeof(VSsTaskStubCarrier) ); 6.115 + newCarrier->taskStub = taskStub; 6.116 + newCarrier->argNum = argNum; 6.117 + newCarrier->isReader = rdOrWrite == READER; 6.118 + } 6.119 + 6.120 +//========================================================================== 6.121 +// 6.122 +// 6.123 +/*Submit Task 6.124 + * 6.125 + *Uses a hash table to match the arg-pointers to each other. So, an 6.126 + * argument-pointer is one-to-one with a hash-table entry. 6.127 + * 6.128 + *If overlapping region detection is enabled, then a hash entry is one 6.129 + * link in a ring of all entries that overlap each other. For example, 6.130 + * say region A shared common addresses with region B, but the pointers 6.131 + * to them are different, then the hash entries for the two would be 6.132 + * linked in a ring. When a pointer is processed, all the pointers in 6.133 + * the ring are processed (Doesn't differentiate independent siblings 6.134 + * from parent-child or conjoined twins overlap..) 6.135 + * NOT ENABLED AS OF MAY 25 2012 6.136 + * 6.137 + *A hash entry has a queue of tasks that are waiting to access the 6.138 + * pointed-to region. The queue goes in the order of creation of 6.139 + * the tasks. Each entry in the queue has a pointer to the task-stub 6.140 + * and whether the task reads-only vs writes to the hash-entry's region. 6.141 + * 6.142 + *A hash entry also has a count of the enabled but not yet finished readers 6.143 + * of the region. It also has a flag that says whether a writer has been 6.144 + * enabled and is not yet finished. 6.145 + * 6.146 + *There are two kinds of events that access a hash entry: creation of a 6.147 + * task and end of a task. 6.148 + * 6.149 + * 6.150 + * ========================== creation ========================== 6.151 + * 6.152 + *At creation, make a task-stub. Set the count of blocking propendents 6.153 + * to the number of controlled arguments (a task can have 6.154 + * arguments that are not controlled by the language, like simple integer 6.155 + * inputs from the sequential portion. Note that all controlled arguments 6.156 + * are pointers, and marked as controlled in the application code). 6.157 + * 6.158 + *The controlled arguments are then processed one by one. 6.159 + *Processing an argument means getting the hash of the pointer. Then, 6.160 + * looking up the hash entry. (If none, create one). 6.161 + *With the hash entry: 6.162 + * 6.163 + *If the arg is a reader, and the entry does not have an enabled 6.164 + * non-finished writer, and the queue is empty (could be prev readers, 6.165 + * then a writer that got queued and now new readers that have to also be 6.166 + * queued). 6.167 + *The reader is free. So, decrement the blocking-propendent count in 6.168 + * the task-stub. If the count is zero, then put the task-stub into the 6.169 + * readyQ. 6.170 + *At the same time, increment the hash-entry's count of enabled and 6.171 + * non-finished readers. 6.172 + * 6.173 + *Otherwise, the reader is put into the hash-entry's Q of waiters 6.174 + * 6.175 + *If the arg is a writer, plus the entry does not have a current writer, 6.176 + * plus the number of enabled non-finished readers is zero, plus the Q is 6.177 + * empty, then the writer is free. Mark the entry has having an 6.178 + * enabled and non-finished writer. Decrement the blocking-propendent 6.179 + * count in the writer's task-stub. If the count is zero, then put the 6.180 + * task-stub into the readyQ. 6.181 + * 6.182 + *Otherwise, put the writer into the entry's Q of waiters. 6.183 + * 6.184 + *No matter what, if the hash entry was chained, put it at the start of 6.185 + * the chain. (Means no-longer-used pointers accumulate at end of chain, 6.186 + * decide garbage collection of no-longer-used pointers later) 6.187 + * 6.188 + * 6.189 + * ========================== end of task =========================== 6.190 + * 6.191 + *At the end of a task, 6.192 + *The task's controlled arguments are processed one by one. 6.193 + *Processing an argument means getting the hash of the pointer. Then, 6.194 + * looking up the hash entry (and putting the entry at the start of the 6.195 + * chain, if there was a chain). 6.196 + *With the hash entry: 6.197 + * 6.198 + *If the arg is a reader, then decrement the enabled and non-finished 6.199 + * reader-count in the hash-entry. If the count becomes zero, then take 6.200 + * the next entry from the Q. It should be a writer, or else there's a 6.201 + * bug in this algorithm. 6.202 + *Set the hash-entry to have an enabled non-finished writer. Decrement 6.203 + * the blocking-propendent-count of the writer's task-stub. If the count 6.204 + * has reached zero, then put the task-stub into the readyQ. 6.205 + * 6.206 + *If the arg is a writer, then clear the enabled non-finished writer flag 6.207 + * of the hash-entry. Take the next entry from the Q. 6.208 + *If it is a writer, then turn the flag back on. Decrement the writer's 6.209 + * blocking-propendent-count in its task-stub. If it becomes zero, then 6.210 + * put the task-stub into the readyQ. 6.211 + * 6.212 + *If it is a reader, then increment the hash-entry's count of enabled 6.213 + * non-finished readers. Decrement the blocking propendents count of the 6.214 + * reader's task-stub. If it reaches zero, then put the task-stub into the 6.215 + * readyQ. 6.216 + *Then repeat until encounter a writer -- put that writer back into the Q. 6.217 + * 6.218 + *That should be it -- that should work. 6.219 + */ 6.220 +inline void 6.221 +handleSubmitTask( VSsSemReq *semReq, VSsSemEnv *semEnv ) 6.222 + { uint32 key[3]; 6.223 + HashEntry *rawHashEntry; //has char *, but use with uint32 * 6.224 + VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer 6.225 + void **args; 6.226 + VSsTaskStub *taskStub; 6.227 + VSsTaskType *taskType; 6.228 + VSsTaskStubCarrier *taskCarrier; 6.229 + 6.230 + HashTable * 6.231 + argPtrHashTbl = semEnv->argPtrHashTbl; 6.232 + 6.233 + //suspending a task always makes the slave into an extra slot slave, 6.234 + // because it ends up in the resumeQ, even when resumes immediately. 6.235 + //Eventually task_end will put the slave into the freeExtraTaskSlvQ 6.236 + replaceWithNewSlotSlvIfNeeded( semReq->callingSlv, semEnv ); 6.237 + 6.238 + /* ========================== creation ========================== 6.239 + * 6.240 + *At creation, make a task-stub. Set the count of blocking propendents 6.241 + * to the number of controlled arguments (a task can have 6.242 + * arguments that are not controlled by the language, like simple integer 6.243 + * inputs from the sequential portion. Note that all controlled arguments 6.244 + * are pointers, and marked as controlled in the application code). 6.245 + */ 6.246 + args = semReq->args; 6.247 + taskType = semReq->taskType; 6.248 + taskStub = create_task_stub( taskType, args );//copies arg ptrs 6.249 + taskStub->numBlockingProp = taskType->numCtldArgs; 6.250 + taskStub->taskID = semReq->taskID; //may be NULL 6.251 + 6.252 + VSsSemData* 6.253 + parentSemData = (VSsSemData*) semReq->callingSlv->semanticData; 6.254 + taskStub->parentTaskStub = (void*) parentSemData->taskStub; 6.255 + parentSemData->taskStub->numLiveChildTasks += 1; 6.256 + 6.257 + //DEBUG__printf3(dbgRqstHdlr,"Submit req from slaveID: %d, from task: %d, for task: %d", semReq->callingSlv->slaveID, parentSemData->taskStub->taskID[1], taskStub->taskID[1]) 6.258 + DEBUG__printf2(dbgRqstHdlr,"Submit req from slaveID: %d, for task: %d", semReq->callingSlv->slaveID, taskStub->taskID[1]) 6.259 + 6.260 + /*The controlled arguments are then processed one by one. 6.261 + *Processing an argument means getting the hash of the pointer. Then, 6.262 + * looking up the hash entry. (If none, create one). 6.263 + */ 6.264 + int32 argNum; 6.265 + for( argNum = 0; argNum < taskType->numCtldArgs; argNum++ ) 6.266 + { 6.267 + key[0] = 2; //two 32b values in key 6.268 + *( (uint64*)&key[1]) = (uint64)args[argNum]; //write 64b into two 32b 6.269 + 6.270 + /*If the hash entry was chained, put it at the 6.271 + * start of the chain. (Means no-longer-used pointers accumulate 6.272 + * at end of chain, decide garbage collection later) */ 6.273 + rawHashEntry = getEntryFromTable32( key, argPtrHashTbl ); 6.274 + if( rawHashEntry == NULL ) 6.275 + { //adding a value auto-creates the hash-entry 6.276 + ptrEntry = create_pointer_entry(); 6.277 + rawHashEntry = addValueIntoTable32( key, ptrEntry, argPtrHashTbl ); 6.278 + } 6.279 + else 6.280 + { ptrEntry = (VSsPointerEntry *)rawHashEntry->content; 6.281 + if( ptrEntry == NULL ) 6.282 + { ptrEntry = create_pointer_entry(); 6.283 + rawHashEntry = addValueIntoTable32(key, ptrEntry, argPtrHashTbl); 6.284 + } 6.285 + } 6.286 + taskStub->ptrEntries[argNum] = ptrEntry; 6.287 + 6.288 + /*Have the hash entry. 6.289 + *If the arg is a reader and the entry does not have an enabled 6.290 + * non-finished writer, and the queue is empty. */ 6.291 + if( taskType->argTypes[argNum] == READER ) 6.292 + { if( !ptrEntry->hasEnabledNonFinishedWriter && 6.293 + isEmptyPrivQ( ptrEntry->waitersQ ) ) 6.294 + { /*The reader is free. So, decrement the blocking-propendent 6.295 + * count in the task-stub. If the count is zero, then put the 6.296 + * task-stub into the readyQ. At the same time, increment 6.297 + * the hash-entry's count of enabled and non-finished readers.*/ 6.298 + taskStub->numBlockingProp -= 1; 6.299 + if( taskStub->numBlockingProp == 0 ) 6.300 + { writePrivQ( taskStub, semEnv->taskReadyQ ); 6.301 + } 6.302 + ptrEntry->numEnabledNonDoneReaders += 1; 6.303 + } 6.304 + else 6.305 + { /*Otherwise, the reader is put into the hash-entry's Q of 6.306 + * waiters*/ 6.307 + taskCarrier = create_task_carrier( taskStub, argNum, READER ); 6.308 + writePrivQ( taskCarrier, ptrEntry->waitersQ ); 6.309 + } 6.310 + } 6.311 + else //arg is a writer 6.312 + { /*the arg is a writer, plus the entry does not have a current 6.313 + * writer, plus the number of enabled non-finished readers is 6.314 + * zero, (the Q must be empty, else bug!) then the writer is free*/ 6.315 + if( !ptrEntry->hasEnabledNonFinishedWriter && 6.316 + ptrEntry->numEnabledNonDoneReaders == 0 ) 6.317 + { /*Mark the entry has having a enabled and non-finished writer. 6.318 + * Decrement the blocking-propenden count in the writer's 6.319 + * task-stub. If the count is zero, then put the task-stub 6.320 + * into the readyQ.*/ 6.321 + taskStub->numBlockingProp -= 1; 6.322 + if( taskStub->numBlockingProp == 0 ) 6.323 + { writePrivQ( taskStub, semEnv->taskReadyQ ); 6.324 + } 6.325 + ptrEntry->hasEnabledNonFinishedWriter = TRUE; 6.326 + } 6.327 + else 6.328 + {/*Otherwise, put the writer into the entry's Q of waiters.*/ 6.329 + taskCarrier = create_task_carrier( taskStub, argNum, WRITER ); 6.330 + writePrivQ( taskCarrier, ptrEntry->waitersQ ); 6.331 + } 6.332 + } 6.333 + } //for argNum 6.334 + 6.335 + 6.336 + resume_slaveVP( semReq->callingSlv, semEnv ); 6.337 + 6.338 + return; 6.339 + } 6.340 + 6.341 + 6.342 +/* ========================== end of task =========================== 6.343 + * 6.344 + *At the end of a task, 6.345 + *The task's controlled arguments are processed one by one. 6.346 + *Processing an argument means getting the hash of the pointer. Then, 6.347 + * looking up the hash entry (and putting the entry at the start of the 6.348 + * chain, if there was a chain). 6.349 + *With the hash entry: 6.350 + * 6.351 + *If the arg is a reader, then decrement the enabled and non-finished 6.352 + * reader-count in the hash-entry. If the count becomes zero, then take 6.353 + * the next entry from the Q. It should be a writer, or else there's a 6.354 + * bug in this algorithm. 6.355 + *Set the hash-entry to have an enabled non-finished writer. Decrement 6.356 + * the blocking-propendent-count of the writer's task-stub. If the count 6.357 + * has reached zero, then put the task-stub into the readyQ. 6.358 + * 6.359 + *If the arg is a writer, then clear the enabled non-finished writer flag 6.360 + * of the hash-entry. Take the next entry from the waiters Q. 6.361 + *If it is a writer, then turn the flag back on. Decrement the writer's 6.362 + * blocking-propendent-count in its task-stub. If it becomes zero, then 6.363 + * put the task-stub into the readyQ. 6.364 + * 6.365 + *If waiter is a reader, then do a loop, getting all waiting readers. 6.366 + * For each, increment the hash-entry's count of enabled 6.367 + * non-finished readers. Decrement the blocking propendents count of the 6.368 + * reader's task-stub. If it reaches zero, then put the task-stub into the 6.369 + * readyQ. 6.370 + *Repeat until encounter a writer -- put that writer back into the Q. 6.371 + * 6.372 + *May 2012 -- not keeping track of how many references to a given ptrEntry 6.373 + * exist, so no way to garbage collect.. 6.374 + *TODO: Might be safe to delete an entry when task ends and waiterQ empty 6.375 + * and no readers and no writers.. 6.376 + */ 6.377 +inline void 6.378 +handleEndTask( VSsSemReq *semReq, VSsSemEnv *semEnv ) 6.379 + { VSsPointerEntry *ptrEntry; //contents of hash table entry for an arg pointer 6.380 + void **args; 6.381 + VSsSemData *endingSlvSemData; 6.382 + VSsTaskStub *endingTaskStub, *waitingTaskStub, *parent; 6.383 + VSsTaskType *endingTaskType; 6.384 + VSsTaskStubCarrier *waitingTaskCarrier; 6.385 + VSsPointerEntry **ptrEntries; 6.386 + 6.387 + 6.388 + endingSlvSemData = (VSsSemData *)semReq->callingSlv->semanticData; 6.389 + endingTaskStub = endingSlvSemData->taskStub; 6.390 + args = endingTaskStub->args; 6.391 + endingTaskType = endingTaskStub->taskType; 6.392 + ptrEntries = endingTaskStub->ptrEntries; //saved in stub when create 6.393 + 6.394 + DEBUG__printf2(dbgRqstHdlr,"EndTask req from slaveID: %d, task: %d",semReq->callingSlv->slaveID, endingTaskStub->taskID[1]) 6.395 + 6.396 + //Check if parent was waiting on this task 6.397 + parent = (VSsTaskStub *) endingTaskStub->parentTaskStub; 6.398 + parent->numLiveChildTasks -= 1; 6.399 + if( parent->isWaitingForChildTasksToEnd && parent->numLiveChildTasks == 0) 6.400 + { 6.401 + parent->isWaitingForChildTasksToEnd = FALSE; 6.402 + resume_slaveVP( parent->slaveAssignedTo, semEnv ); 6.403 + } 6.404 + 6.405 + //Check if parent ended, and this was last descendent, then free it 6.406 + if( parent->isEnded && parent->numLiveChildTasks == 0 ) 6.407 + { VMS_PI__free( parent ); 6.408 + } 6.409 + 6.410 + 6.411 + //Now, update state of dependents and start ready tasks 6.412 + /*The task's controlled arguments are processed one by one. 6.413 + *Processing an argument means getting arg-pointer's entry. 6.414 + */ 6.415 + int32 argNum; 6.416 + for( argNum = 0; argNum < endingTaskType->numCtldArgs; argNum++ ) 6.417 + { 6.418 + /* commented out 'cause remembering entry ptr when create stub 6.419 + key[0] = 2; //says are 2 32b values in key 6.420 + *( (uint64*)&key[1] ) = args[argNum]; //write 64b ptr into two 32b 6.421 + 6.422 + /*If the hash entry was chained, put it at the 6.423 + * start of the chain. (Means no-longer-used pointers accumulate 6.424 + * at end of chain, decide garbage collection later) 6.425 + */ 6.426 + /*NOTE: don't do hash lookups here, instead, have a pointer to the 6.427 + * hash entry inside task-stub, put there during task creation. 6.428 + rawHashEntry = getEntryFromTable32( key, ptrHashTbl ); 6.429 + ptrEntry = (VSsPointerEntry *)rawHashEntry->content; 6.430 + if( ptrEntry == NULL ) 6.431 + VMS_App__throw_exception("hash entry NULL", NULL, NULL); 6.432 + */ 6.433 + 6.434 + ptrEntry = ptrEntries[argNum]; 6.435 + /*check if the ending task was reader of this arg*/ 6.436 + if( endingTaskType->argTypes[argNum] == READER ) 6.437 + { /*then decrement the enabled and non-finished reader-count in 6.438 + * the hash-entry. */ 6.439 + ptrEntry->numEnabledNonDoneReaders -= 1; 6.440 + 6.441 + /*If the count becomes zero, then take the next entry from the Q. 6.442 + *It should be a writer, or else there's a bug in this algorithm.*/ 6.443 + if( ptrEntry->numEnabledNonDoneReaders == 0 ) 6.444 + { waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); 6.445 + if( waitingTaskCarrier == NULL ) 6.446 + { //TODO: looks safe to delete the ptr entry at this point 6.447 + continue; //next iter of loop 6.448 + } 6.449 + if( waitingTaskCarrier->isReader ) 6.450 + VMS_App__throw_exception("READER waiting", NULL, NULL); 6.451 + 6.452 + waitingTaskStub = waitingTaskCarrier->taskStub; 6.453 + 6.454 + /*Set the hash-entry to have an enabled non-finished writer.*/ 6.455 + ptrEntry->hasEnabledNonFinishedWriter = TRUE; 6.456 + 6.457 + /* Decrement the blocking-propendent-count of the writer's 6.458 + * task-stub. If the count has reached zero, then put the 6.459 + * task-stub into the readyQ.*/ 6.460 + waitingTaskStub->numBlockingProp -= 1; 6.461 + if( waitingTaskStub->numBlockingProp == 0 ) 6.462 + { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); 6.463 + } 6.464 + } 6.465 + } 6.466 + else /*the ending task is a writer of this arg*/ 6.467 + { /*clear the enabled non-finished writer flag of the hash-entry.*/ 6.468 + ptrEntry->hasEnabledNonFinishedWriter = FALSE; 6.469 + 6.470 + /*Take the next waiter from the hash-entry's Q.*/ 6.471 + waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); 6.472 + if( waitingTaskCarrier == NULL ) 6.473 + { //TODO: looks safe to delete ptr entry at this point 6.474 + continue; //go to next iter of loop, done here. 6.475 + } 6.476 + waitingTaskStub = waitingTaskCarrier->taskStub; 6.477 + 6.478 + /*If task is a writer of this hash-entry's pointer*/ 6.479 + if( !waitingTaskCarrier->isReader ) 6.480 + { /* then turn the flag back on.*/ 6.481 + ptrEntry->hasEnabledNonFinishedWriter = TRUE; 6.482 + /*Decrement the writer's blocking-propendent-count in task-stub 6.483 + * If it becomes zero, then put the task-stub into the readyQ.*/ 6.484 + waitingTaskStub->numBlockingProp -= 1; 6.485 + if( waitingTaskStub->numBlockingProp == 0 ) 6.486 + { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); 6.487 + } 6.488 + } 6.489 + else 6.490 + { /*Waiting task is a reader, so do a loop, of all waiting readers 6.491 + * until encounter a writer or waitersQ is empty*/ 6.492 + while( TRUE ) /*The checks guarantee have a waiting reader*/ 6.493 + { /*Increment the hash-entry's count of enabled non-finished 6.494 + * readers.*/ 6.495 + ptrEntry->numEnabledNonDoneReaders += 1; 6.496 + 6.497 + /*Decrement the blocking propendents count of the reader's 6.498 + * task-stub. If it reaches zero, then put the task-stub 6.499 + * into the readyQ.*/ 6.500 + waitingTaskStub->numBlockingProp -= 1; 6.501 + if( waitingTaskStub->numBlockingProp == 0 ) 6.502 + { writePrivQ( waitingTaskStub, semEnv->taskReadyQ ); 6.503 + } 6.504 + /*Get next waiting task*/ 6.505 + waitingTaskCarrier = peekPrivQ( ptrEntry->waitersQ ); 6.506 + if( waitingTaskCarrier == NULL ) break; 6.507 + if( !waitingTaskCarrier->isReader ) break; 6.508 + waitingTaskCarrier = readPrivQ( ptrEntry->waitersQ ); 6.509 + waitingTaskStub = waitingTaskCarrier->taskStub; 6.510 + }//while waiter is a reader 6.511 + }//if-else, first waiting task is a reader 6.512 + }//if-else, check of ending task, whether writer or reader 6.513 + }//for argnum in ending task 6.514 + 6.515 + 6.516 + //done ending the task, now free the stub + args copy 6.517 + // if still has live children, then keep stub around 6.518 + if( endingTaskStub->numLiveChildTasks == 0 && 6.519 + endingTaskStub->numLiveChildThreads == 0 ) 6.520 + { free_task_stub( endingTaskStub ); 6.521 + } 6.522 + 6.523 + 6.524 + endingSlvSemData->needsTaskAssigned = TRUE; 6.525 + 6.526 + //Check if the slave is an extra task slave, and put into free Q 6.527 + if( endingSlvSemData->slaveType == ExtraTaskSlv ) 6.528 + { writePrivQ( semReq->callingSlv, semEnv->freeExtraTaskSlvQ ); 6.529 + } 6.530 + 6.531 + //otherwise, it's a slot slave, so it will get used from matrix 6.532 + // so, do nothing with it, just return 6.533 + return; 6.534 + } 6.535 + 6.536 +inline void 6.537 +free_task_stub( VSsTaskStub *stubToFree ) 6.538 + { if(stubToFree->ptrEntries != NULL ) //a thread stub has NULL entry 6.539 + { VMS_PI__free( stubToFree->ptrEntries ); 6.540 + } 6.541 + VMS_PI__free( stubToFree ); 6.542 + } 6.543 + 6.544 +//========================== Task Comm handlers =========================== 6.545 + 6.546 + 6.547 + 6.548 +//============================ Send Handlers ============================== 6.549 +/*Send of Type -- The semantic request has the receiving task ID and Type 6.550 + * 6.551 + *Messages of a given Type have to be kept separate.. so need a separate 6.552 + * entry in the hash table for each pair: receiverID, Type 6.553 + * 6.554 + *Also, if same sender sends multiple before any get received, then need to 6.555 + * stack the sends up -- even if a send waits until it's paired, several 6.556 + * separate tasks can send to the same receiver, and doing hash on the 6.557 + * receive task, so they will stack up. 6.558 + */ 6.559 +inline void 6.560 +handleSendTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv ) 6.561 + { SlaveVP *senderSlv, *receiverSlv; 6.562 + int32 *senderID, *receiverID; 6.563 + int32 *key, keySz, receiverIDNumInt; 6.564 + VSsSemReq *waitingReq; 6.565 + HashEntry *entry; 6.566 + HashTable *commHashTbl = semEnv->commHashTbl; 6.567 + 6.568 + receiverID = semReq->receiverID; //For "send", know both send & recv procrs 6.569 + senderSlv = semReq->senderSlv; 6.570 + 6.571 + DEBUG__printf2(dbgRqstHdlr,"SendType req from sender slaveID: %d, recTask: %d", senderSlv->slaveID, receiverID[1]) 6.572 + 6.573 + //suspending a task always makes the slave into an extra slot slave, 6.574 + // because it ends up in the resumeQ, even when resumes immediately. 6.575 + //Eventually task_end will put the slave into the freeExtraTaskSlvQ 6.576 + replaceWithNewSlotSlvIfNeeded( senderSlv, semEnv ); 6.577 + 6.578 + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself 6.579 + keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); 6.580 + key = VMS_PI__malloc( keySz ); 6.581 + key[0] = receiverIDNumInt + 1; //loc 0 is num int32 in key 6.582 + memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 6.583 + key[ 1 + receiverIDNumInt ] = semReq->msgType; 6.584 + 6.585 + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); 6.586 + if( entry == NULL ) //was just inserted, means task has to wait 6.587 + { return; 6.588 + } 6.589 + 6.590 + //if here, found a waiting request with same key 6.591 + waitingReq = (VSsSemReq *)entry->content; 6.592 + 6.593 + //At this point, know have waiting request(s) -- either sends or recv 6.594 + //Note, can only have max of one receive waiting, and cannot have both 6.595 + // sends and receives waiting (they would have paired off) 6.596 + // but can have multiple sends from diff sending VPs, all same msg-type 6.597 + if( waitingReq->reqType == send_type_to ) 6.598 + { //waiting request is another send, so stack this up on list 6.599 + // but first clone the sending request so it persists. 6.600 + VSsSemReq *clonedReq = cloneReq( semReq ); 6.601 + clonedReq-> nextReqInHashEntry = waitingReq->nextReqInHashEntry; 6.602 + waitingReq->nextReqInHashEntry = clonedReq; 6.603 + DEBUG__printf2( dbgRqstHdlr, "linked requests: %p, %p ", clonedReq,\ 6.604 + waitingReq ) 6.605 + return; 6.606 + } 6.607 + else 6.608 + { 6.609 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 6.610 + Dependency newd; 6.611 + newd.from_vp = senderID->slaveID; 6.612 + newd.from_task = senderID->assignCount; 6.613 + newd.to_vp = receiverID->slaveID; 6.614 + newd.to_task = receiverID->assignCount +1; 6.615 + //(newd,semEnv->commDependenciesList); 6.616 + addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); 6.617 + int32 groupId = semReq->msgType; 6.618 + if(semEnv->ntonGroupsInfo->numInArray <= groupId){ 6.619 + makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); 6.620 + } 6.621 + if(semEnv->ntonGroups[groupId] == NULL){ 6.622 + semEnv->ntonGroups[groupId] = new_NtoN(groupId); 6.623 + } 6.624 + Unit u; 6.625 + u.vp = senderID->slaveID; 6.626 + u.task = senderID->assignCount; 6.627 + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); 6.628 + u.vp = receiverID->slaveID; 6.629 + u.task = receiverID->assignCount +1; 6.630 + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); 6.631 + #endif 6.632 + 6.633 + //set receiver slave, from the waiting request 6.634 + receiverSlv = waitingReq->receiverSlv; 6.635 + 6.636 + //waiting request is a receive_type_to, so it pairs to this send 6.637 + //First, remove the waiting receive request from the entry 6.638 + entry->content = waitingReq->nextReqInHashEntry; 6.639 + VMS_PI__free( waitingReq ); //Don't use contents -- so free it 6.640 + 6.641 + if( entry->content == NULL ) 6.642 + { //TODO: mod hash table to double-link, so can delete entry from 6.643 + // table without hashing the key and looking it up again 6.644 + deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees hashEntry 6.645 + } 6.646 + 6.647 + //attach msg that's in this send request to receiving task's Slv 6.648 + // when comes back from suspend will have msg in dataRetFromReq 6.649 + receiverSlv->dataRetFromReq = semReq->msg; 6.650 + 6.651 + //bring both processors back from suspend 6.652 + resume_slaveVP( senderSlv, semEnv ); 6.653 + resume_slaveVP( receiverSlv, semEnv ); 6.654 + 6.655 + return; 6.656 + } 6.657 + } 6.658 + 6.659 + 6.660 +/*Looks like can make single handler for both sends.. 6.661 + */ 6.662 +//TODO: combine both send handlers into single handler 6.663 +inline void 6.664 +handleSendFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv) 6.665 + { SlaveVP *senderSlv, *receiverSlv; 6.666 + int32 *senderID, *receiverID; 6.667 + int32 *key, keySz, receiverIDNumInt, senderIDNumInt; 6.668 + VSsSemReq *waitingReq; 6.669 + HashEntry *entry; 6.670 + HashTable *commHashTbl = semEnv->commHashTbl; 6.671 + 6.672 + DEBUG__printf2(dbgRqstHdlr,"SendFromTo req from task %d to %d", 6.673 + semReq->senderID[1],semReq->receiverID[1]) 6.674 + 6.675 + receiverID = semReq->receiverID; //For "send", know both send & recv procrs 6.676 + senderID = semReq->senderID; 6.677 + senderSlv = semReq->senderSlv; 6.678 + 6.679 + //suspending a task always makes the slave into an extra slot slave, 6.680 + // because it ends up in the resumeQ, even when resumes immediately. 6.681 + //Eventually task_end will put the slave into the freeExtraTaskSlvQ 6.682 + replaceWithNewSlotSlvIfNeeded( senderSlv, semEnv ); 6.683 + 6.684 + receiverIDNumInt = receiverID[0] + 1; //include the count in the key 6.685 + senderIDNumInt = senderID[0] + 1; 6.686 + keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); 6.687 + key = VMS_PI__malloc( keySz ); 6.688 + key[0] = receiverIDNumInt + senderIDNumInt; 6.689 + memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 6.690 + memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32) ); 6.691 + 6.692 + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); 6.693 + if( entry == NULL ) //was just inserted, means task has to wait 6.694 + { return; 6.695 + } 6.696 + 6.697 + waitingReq = (VSsSemReq *)entry->content; 6.698 + 6.699 + //At this point, know have waiting request(s) -- either sends or recv 6.700 + if( waitingReq->reqType == send_from_to ) 6.701 + { printf("\n ERROR: shouldn't be two send-from-tos waiting \n"); 6.702 + } 6.703 + else 6.704 + { //waiting request is a receive, so it completes pair with this send 6.705 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 6.706 + Dependency newd; 6.707 + newd.from_vp = sendPr->slaveID; 6.708 + newd.from_task = sendPr->assignCount; 6.709 + newd.to_vp = receivePr->slaveID; 6.710 + newd.to_task = receivePr->assignCount +1; 6.711 + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); 6.712 + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); 6.713 + #endif 6.714 + 6.715 + //set receiver slave, from the waiting request 6.716 + receiverSlv = waitingReq->receiverSlv; 6.717 + 6.718 + //First, remove the waiting receive request from the entry 6.719 + entry->content = waitingReq->nextReqInHashEntry; 6.720 + VMS_PI__free( waitingReq ); //Don't use contents -- so free it 6.721 + 6.722 + //can only be one waiting req for "from-to" semantics 6.723 + if( entry->content != NULL ) 6.724 + { 6.725 + printf("\nERROR in handleSendFromTo\n"); 6.726 + } 6.727 + deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry 6.728 + 6.729 + //attach msg that's in this send request to receiving procr 6.730 + // when comes back from suspend, will have msg in dataRetFromReq 6.731 + receiverSlv->dataRetFromReq = semReq->msg; 6.732 + 6.733 + //bring both processors back from suspend 6.734 + resume_slaveVP( senderSlv, semEnv ); 6.735 + resume_slaveVP( receiverSlv, semEnv ); 6.736 + 6.737 + return; 6.738 + } 6.739 + } 6.740 + 6.741 + 6.742 + 6.743 +//============================== Receives =========================== 6.744 +// 6.745 + 6.746 + 6.747 +inline void 6.748 +handleReceiveTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv) 6.749 + { SlaveVP *senderSlv, *receiverSlv; 6.750 + int32 *receiverID; 6.751 + int32 *key, keySz, receiverIDNumInt; 6.752 + VSsSemReq *waitingReq; 6.753 + HashEntry *entry; 6.754 + HashTable *commHashTbl = semEnv->commHashTbl; 6.755 + 6.756 + DEBUG__printf2(dbgRqstHdlr,"ReceiveType req to ID: %d type: %d",semReq->receiverID[1], semReq->msgType) 6.757 + 6.758 + receiverID = semReq->receiverID; //For "send", know both send & recv procrs 6.759 + receiverSlv = semReq->receiverSlv; 6.760 + 6.761 + //suspending a task always makes the slave into an extra slot slave, 6.762 + // because it ends up in the resumeQ, even when resumes immediately. 6.763 + //Eventually task_end will put the slave into the freeExtraTaskSlvQ 6.764 + replaceWithNewSlotSlvIfNeeded( receiverSlv, semEnv ); 6.765 + 6.766 + //key is the receiverID plus the type -- have to copy them into key 6.767 + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself 6.768 + keySz = receiverIDNumInt * sizeof(int32) + 2 * sizeof(int32); 6.769 + key = VMS_PI__malloc( keySz ); 6.770 + key[0] = receiverIDNumInt + 1; //loc 0 is num int32s in key 6.771 + memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 6.772 + key[ 1 + receiverIDNumInt ] = semReq->msgType; 6.773 + 6.774 + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl );//clones 6.775 + if( entry == NULL ) //was just inserted, means task has to wait 6.776 + { return; 6.777 + } 6.778 + 6.779 + waitingReq = (VSsSemReq *)entry->content; //previously cloned by insert 6.780 + 6.781 + //At this point, know have waiting request(s) -- should be send(s) 6.782 + if( waitingReq->reqType == send_type_to ) 6.783 + { 6.784 + //set sending slave from the request 6.785 + senderSlv = waitingReq->senderSlv; 6.786 + 6.787 + //waiting request is a send, so pair it with this receive 6.788 + //first, remove the waiting send request from the list in entry 6.789 + entry->content = waitingReq->nextReqInHashEntry; 6.790 + if( entry->content == NULL ) 6.791 + { deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees HashEntry 6.792 + } 6.793 + 6.794 + //attach msg that's in the send request to receiving procr 6.795 + // when comes back from suspend, will have msg in dataRetFromReq 6.796 + receiverSlv->dataRetFromReq = waitingReq->msg; 6.797 + 6.798 + //bring both processors back from suspend 6.799 + VMS_PI__free( waitingReq ); 6.800 + 6.801 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 6.802 + Dependency newd; 6.803 + newd.from_vp = sendPr->slaveID; 6.804 + newd.from_task = sendPr->assignCount; 6.805 + newd.to_vp = receivePr->slaveID; 6.806 + newd.to_task = receivePr->assignCount +1; 6.807 + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); 6.808 + addToListOfArrays(Dependency,newd,semEnv->dynDependenciesList); 6.809 + int32 groupId = semReq->msgType; 6.810 + if(semEnv->ntonGroupsInfo->numInArray <= groupId){ 6.811 + makeHighestDynArrayIndexBeAtLeast(semEnv->ntonGroupsInfo, groupId); 6.812 + } 6.813 + if(semEnv->ntonGroups[groupId] == NULL){ 6.814 + semEnv->ntonGroups[groupId] = new_NtoN(groupId); 6.815 + } 6.816 + Unit u; 6.817 + u.vp = sendPr->slaveID; 6.818 + u.task = sendPr->assignCount; 6.819 + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->senders); 6.820 + u.vp = receivePr->slaveID; 6.821 + u.task = receivePr->assignCount +1; 6.822 + addToListOfArrays(Unit,u,semEnv->ntonGroups[groupId]->receivers); 6.823 + #endif 6.824 + 6.825 + resume_slaveVP( senderSlv, semEnv ); 6.826 + resume_slaveVP( receiverSlv, semEnv ); 6.827 + 6.828 + return; 6.829 + } 6.830 + printf("\nLang Impl Error: Should never be two waiting receives!\n"); 6.831 + } 6.832 + 6.833 + 6.834 +/* 6.835 + */ 6.836 +inline void 6.837 +handleReceiveFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv) 6.838 + { SlaveVP *senderSlv, *receiverSlv; 6.839 + int32 *senderID, *receiverID; 6.840 + int32 *key, keySz, receiverIDNumInt, senderIDNumInt; 6.841 + VSsSemReq *waitingReq; 6.842 + HashEntry *entry; 6.843 + HashTable *commHashTbl = semEnv->commHashTbl; 6.844 + 6.845 + DEBUG__printf2(dbgRqstHdlr,"RecFromTo req from ID: %d to ID: %d",semReq->senderID[1],semReq->receiverID[1]) 6.846 + 6.847 + receiverID = semReq->receiverID; //For "send", know both send & recv procrs 6.848 + senderID = semReq->senderID; 6.849 + receiverSlv = semReq->receiverSlv; 6.850 + 6.851 + //suspending a task always makes the slave into an extra slot slave, 6.852 + // because it ends up in the resumeQ, even when resumes immediately. 6.853 + //Eventually task_end will put the slave into the freeExtraTaskSlvQ 6.854 + replaceWithNewSlotSlvIfNeeded( receiverSlv, semEnv ); 6.855 + 6.856 + receiverIDNumInt = receiverID[0] + 1; //pos 0 doesn't include itself 6.857 + senderIDNumInt = senderID[0] + 1; 6.858 + keySz = (receiverIDNumInt + senderIDNumInt) * sizeof(int32) + sizeof(int32); 6.859 + key = VMS_PI__malloc( keySz ); 6.860 + key[0] = receiverIDNumInt + senderIDNumInt; //loc 0 is num int32s in key 6.861 + memcpy( &key[1], receiverID, receiverIDNumInt * sizeof(int32) ); 6.862 + memcpy( &key[1 + receiverIDNumInt], senderID, senderIDNumInt * sizeof(int32)); 6.863 + 6.864 + entry = giveEntryElseInsertReqst32( key, semReq, commHashTbl ); 6.865 + if( entry == NULL ) //was just inserted, means task has to wait 6.866 + { return; 6.867 + } 6.868 + 6.869 + waitingReq = (VSsSemReq *)entry->content; 6.870 + 6.871 + //At this point, know have a request to rendez-vous -- should be send 6.872 + if( waitingReq->reqType == send_from_to ) 6.873 + { //waiting request is a send, so pair it with this receive 6.874 + #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC 6.875 + Dependency newd; 6.876 + newd.from_vp = sendPr->slaveID; 6.877 + newd.from_task = sendPr->assignCount; 6.878 + newd.to_vp = receivePr->slaveID; 6.879 + newd.to_task = receivePr->assignCount +1; 6.880 + //addToListOfArraysDependency(newd,semEnv->commDependenciesList); 6.881 + addToListOfArrays(Dependency,newd,semEnv->commDependenciesList); 6.882 + #endif 6.883 + 6.884 + //have receiver slave, now set sender slave 6.885 + senderSlv = waitingReq->senderSlv; 6.886 + 6.887 + //For from-to, should only ever be a single reqst waiting tobe paird 6.888 + entry->content = waitingReq->nextReqInHashEntry; 6.889 + if( entry->content != NULL ) printf("\nERROR in handleRecvFromTo\n"); 6.890 + deleteEntryFromTable32( (uint32*)entry->key, commHashTbl ); //frees entry too 6.891 + 6.892 + //attach msg that's in the send request to receiving procr 6.893 + // when comes back from suspend, will have msg in dataRetFromReq 6.894 + receiverSlv->dataRetFromReq = waitingReq->msg; 6.895 + 6.896 + //bring both processors back from suspend 6.897 + VMS_PI__free( waitingReq ); 6.898 + 6.899 + resume_slaveVP( senderSlv, semEnv ); 6.900 + resume_slaveVP( receiverSlv, semEnv ); 6.901 + 6.902 + return; 6.903 + } 6.904 + printf("\nLang Impl Error: Should never be two waiting receives!\n"); 6.905 + } 6.906 + 6.907 +//========================================================================== 6.908 +inline void 6.909 +replaceWithNewSlotSlvIfNeeded( SlaveVP *requestingSlv, VSsSemEnv *semEnv ) 6.910 + { SlaveVP *newSlotSlv; 6.911 + VSsSemData *semData, *reqSemData; 6.912 + 6.913 + reqSemData = (VSsSemData *)requestingSlv->semanticData; 6.914 + if( reqSemData->slaveType != SlotTaskSlv ) 6.915 + return; //already replaced, so just return 6.916 + 6.917 + //get a new slave to be the slot slave 6.918 + newSlotSlv = readPrivQ( semEnv->freeExtraTaskSlvQ ); 6.919 + if( newSlotSlv == NULL ) 6.920 + { newSlotSlv = VSs__create_slave_helper( &idle_fn, NULL, semEnv, 0); 6.921 + //just made a new extra task slave, so count it 6.922 + semEnv->numLiveExtraTaskSlvs += 1; 6.923 + } 6.924 + 6.925 + //set slave values to make it the slot slave 6.926 + semData = newSlotSlv->semanticData; 6.927 + semData->taskStub = NULL; 6.928 + semData->slaveType = SlotTaskSlv; 6.929 + semData->needsTaskAssigned = TRUE; 6.930 + 6.931 + //a slot slave is pinned to a particular slot on a particular core 6.932 + newSlotSlv->animSlotAssignedTo = requestingSlv->animSlotAssignedTo; 6.933 + newSlotSlv->coreAnimatedBy = requestingSlv->coreAnimatedBy; 6.934 + 6.935 + //put it into the slot slave matrix 6.936 + int32 slotNum = requestingSlv->animSlotAssignedTo->slotIdx; 6.937 + int32 coreNum = requestingSlv->coreAnimatedBy; 6.938 + semEnv->slotTaskSlvs[coreNum][slotNum] = newSlotSlv; 6.939 + 6.940 + //Fix up requester, to be an extra slave now (but not a free one) 6.941 + // because it's not free, doesn't go into freeExtraTaskSlvQ 6.942 + semData = requestingSlv->semanticData; 6.943 + semData->slaveType = ExtraTaskSlv; 6.944 + } 6.945 + 6.946 +inline void 6.947 +handleTaskwait( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv) 6.948 + { VSsTaskStub* requestingTaskStub; 6.949 + VSsSemData* semData; 6.950 + DEBUG__printf1(dbgRqstHdlr,"Taskwait request from processor %d", 6.951 + requestingSlv->slaveID) 6.952 + 6.953 + semData = (VSsSemData *)semReq->callingSlv->semanticData; 6.954 + requestingTaskStub = semData->taskStub; 6.955 + 6.956 + if( semData->taskStub->numLiveChildTasks == 0 ) 6.957 + { //nobody to wait for, resume 6.958 + resume_slaveVP( requestingSlv, semEnv ); 6.959 + } 6.960 + else //have to wait, replace requester with new slot slv & mark waiting 6.961 + { 6.962 + if(semData->slaveType == SlotTaskSlv){ 6.963 + replaceWithNewSlotSlvIfNeeded( requestingSlv, semEnv ); 6.964 + } 6.965 + 6.966 + requestingTaskStub->isWaitingForChildTasksToEnd = TRUE; 6.967 + } 6.968 + } 6.969 + 6.970 + 6.971 +//========================================================================== 6.972 +/* 6.973 + */ 6.974 +void 6.975 +handleMalloc( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) 6.976 + { void *ptr; 6.977 + 6.978 + DEBUG__printf1(dbgRqstHdlr,"Malloc request from processor %d",requestingSlv->slaveID) 6.979 + 6.980 + ptr = VMS_PI__malloc( semReq->sizeToMalloc ); 6.981 + requestingSlv->dataRetFromReq = ptr; 6.982 + resume_slaveVP( requestingSlv, semEnv ); 6.983 + } 6.984 + 6.985 +/* 6.986 + */ 6.987 +void 6.988 +handleFree( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) 6.989 + { 6.990 + DEBUG__printf1(dbgRqstHdlr,"Free request from processor %d",requestingSlv->slaveID) 6.991 + VMS_PI__free( semReq->ptrToFree ); 6.992 + resume_slaveVP( requestingSlv, semEnv ); 6.993 + } 6.994 + 6.995 + 6.996 +//=========================================================================== 6.997 +// 6.998 +/*Uses ID as index into array of flags. If flag already set, resumes from 6.999 + * end-label. Else, sets flag and resumes normally. 6.1000 + */ 6.1001 +void inline 6.1002 +handleStartSingleton_helper( VSsSingleton *singleton, SlaveVP *reqstingSlv, 6.1003 + VSsSemEnv *semEnv ) 6.1004 + { 6.1005 + if( singleton->hasFinished ) 6.1006 + { //the code that sets the flag to true first sets the end instr addr 6.1007 + reqstingSlv->dataRetFromReq = singleton->endInstrAddr; 6.1008 + resume_slaveVP( reqstingSlv, semEnv ); 6.1009 + return; 6.1010 + } 6.1011 + else if( singleton->hasBeenStarted ) 6.1012 + { //singleton is in-progress in a diff slave, so wait for it to finish 6.1013 + writePrivQ(reqstingSlv, singleton->waitQ ); 6.1014 + return; 6.1015 + } 6.1016 + else 6.1017 + { //hasn't been started, so this is the first attempt at the singleton 6.1018 + singleton->hasBeenStarted = TRUE; 6.1019 + reqstingSlv->dataRetFromReq = 0x0; 6.1020 + resume_slaveVP( reqstingSlv, semEnv ); 6.1021 + return; 6.1022 + } 6.1023 + } 6.1024 +void inline 6.1025 +handleStartFnSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, 6.1026 + VSsSemEnv *semEnv ) 6.1027 + { VSsSingleton *singleton; 6.1028 + DEBUG__printf1(dbgRqstHdlr,"StartFnSingleton request from processor %d",requestingSlv->slaveID) 6.1029 + 6.1030 + singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); 6.1031 + handleStartSingleton_helper( singleton, requestingSlv, semEnv ); 6.1032 + } 6.1033 +void inline 6.1034 +handleStartDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, 6.1035 + VSsSemEnv *semEnv ) 6.1036 + { VSsSingleton *singleton; 6.1037 + 6.1038 + DEBUG__printf1(dbgRqstHdlr,"StartDataSingleton request from processor %d",requestingSlv->slaveID) 6.1039 + if( *(semReq->singletonPtrAddr) == NULL ) 6.1040 + { singleton = VMS_PI__malloc( sizeof(VSsSingleton) ); 6.1041 + singleton->waitQ = makeVMSQ(); 6.1042 + singleton->endInstrAddr = 0x0; 6.1043 + singleton->hasBeenStarted = FALSE; 6.1044 + singleton->hasFinished = FALSE; 6.1045 + *(semReq->singletonPtrAddr) = singleton; 6.1046 + } 6.1047 + else 6.1048 + singleton = *(semReq->singletonPtrAddr); 6.1049 + handleStartSingleton_helper( singleton, requestingSlv, semEnv ); 6.1050 + } 6.1051 + 6.1052 + 6.1053 +void inline 6.1054 +handleEndSingleton_helper( VSsSingleton *singleton, SlaveVP *requestingSlv, 6.1055 + VSsSemEnv *semEnv ) 6.1056 + { PrivQueueStruc *waitQ; 6.1057 + int32 numWaiting, i; 6.1058 + SlaveVP *resumingSlv; 6.1059 + 6.1060 + if( singleton->hasFinished ) 6.1061 + { //by definition, only one slave should ever be able to run end singleton 6.1062 + // so if this is true, is an error 6.1063 + ERROR1( "singleton code ran twice", requestingSlv ); 6.1064 + } 6.1065 + 6.1066 + singleton->hasFinished = TRUE; 6.1067 + waitQ = singleton->waitQ; 6.1068 + numWaiting = numInPrivQ( waitQ ); 6.1069 + for( i = 0; i < numWaiting; i++ ) 6.1070 + { //they will resume inside start singleton, then jmp to end singleton 6.1071 + resumingSlv = readPrivQ( waitQ ); 6.1072 + resumingSlv->dataRetFromReq = singleton->endInstrAddr; 6.1073 + resume_slaveVP( resumingSlv, semEnv ); 6.1074 + } 6.1075 + 6.1076 + resume_slaveVP( requestingSlv, semEnv ); 6.1077 + 6.1078 +} 6.1079 +void inline 6.1080 +handleEndFnSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, 6.1081 + VSsSemEnv *semEnv ) 6.1082 + { 6.1083 + VSsSingleton *singleton; 6.1084 + 6.1085 + DEBUG__printf1(dbgRqstHdlr,"EndFnSingleton request from processor %d",requestingSlv->slaveID) 6.1086 + 6.1087 + singleton = &(semEnv->fnSingletons[ semReq->singletonID ]); 6.1088 + handleEndSingleton_helper( singleton, requestingSlv, semEnv ); 6.1089 + } 6.1090 +void inline 6.1091 +handleEndDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, 6.1092 + VSsSemEnv *semEnv ) 6.1093 + { 6.1094 + VSsSingleton *singleton; 6.1095 + 6.1096 + DEBUG__printf1(dbgRqstHdlr,"EndDataSingleton request from processor %d",requestingSlv->slaveID) 6.1097 + 6.1098 + singleton = *(semReq->singletonPtrAddr); 6.1099 + handleEndSingleton_helper( singleton, requestingSlv, semEnv ); 6.1100 + } 6.1101 + 6.1102 + 6.1103 +/*This executes the function in the masterVP, take the function 6.1104 + * pointer out of the request and call it, then resume the VP. 6.1105 + */ 6.1106 +void 6.1107 +handleAtomic( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv ) 6.1108 + { 6.1109 + DEBUG__printf1(dbgRqstHdlr,"Atomic request from processor %d",requestingSlv->slaveID) 6.1110 + semReq->fnToExecInMaster( semReq->dataForFn ); 6.1111 + resume_slaveVP( requestingSlv, semEnv ); 6.1112 + } 6.1113 + 6.1114 +/*First, it looks at the VP's semantic data, to see the highest transactionID 6.1115 + * that VP 6.1116 + * already has entered. If the current ID is not larger, it throws an 6.1117 + * exception stating a bug in the code. 6.1118 + *Otherwise it puts the current ID 6.1119 + * there, and adds the ID to a linked list of IDs entered -- the list is 6.1120 + * used to check that exits are properly ordered. 6.1121 + *Next it is uses transactionID as index into an array of transaction 6.1122 + * structures. 6.1123 + *If the "VP_currently_executing" field is non-null, then put requesting VP 6.1124 + * into queue in the struct. (At some point a holder will request 6.1125 + * end-transaction, which will take this VP from the queue and resume it.) 6.1126 + *If NULL, then write requesting into the field and resume. 6.1127 + */ 6.1128 +void 6.1129 +handleTransStart( VSsSemReq *semReq, SlaveVP *requestingSlv, 6.1130 + VSsSemEnv *semEnv ) 6.1131 + { VSsSemData *semData; 6.1132 + TransListElem *nextTransElem; 6.1133 + 6.1134 + DEBUG__printf1(dbgRqstHdlr,"TransStart request from processor %d",requestingSlv->slaveID) 6.1135 + 6.1136 + //check ordering of entering transactions is correct 6.1137 + semData = requestingSlv->semanticData; 6.1138 + if( semData->highestTransEntered > semReq->transID ) 6.1139 + { //throw VMS exception, which shuts down VMS. 6.1140 + VMS_PI__throw_exception( "transID smaller than prev", requestingSlv, NULL); 6.1141 + } 6.1142 + //add this trans ID to the list of transactions entered -- check when 6.1143 + // end a transaction 6.1144 + semData->highestTransEntered = semReq->transID; 6.1145 + nextTransElem = VMS_PI__malloc( sizeof(TransListElem) ); 6.1146 + nextTransElem->transID = semReq->transID; 6.1147 + nextTransElem->nextTrans = semData->lastTransEntered; 6.1148 + semData->lastTransEntered = nextTransElem; 6.1149 + 6.1150 + //get the structure for this transaction ID 6.1151 + VSsTrans * 6.1152 + transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 6.1153 + 6.1154 + if( transStruc->VPCurrentlyExecuting == NULL ) 6.1155 + { 6.1156 + transStruc->VPCurrentlyExecuting = requestingSlv; 6.1157 + resume_slaveVP( requestingSlv, semEnv ); 6.1158 + } 6.1159 + else 6.1160 + { //note, might make future things cleaner if save request with VP and 6.1161 + // add this trans ID to the linked list when gets out of queue. 6.1162 + // but don't need for now, and lazy.. 6.1163 + writePrivQ( requestingSlv, transStruc->waitingVPQ ); 6.1164 + } 6.1165 + } 6.1166 + 6.1167 + 6.1168 +/*Use the trans ID to get the transaction structure from the array. 6.1169 + *Look at VP_currently_executing to be sure it's same as requesting VP. 6.1170 + * If different, throw an exception, stating there's a bug in the code. 6.1171 + *Next, take the first element off the list of entered transactions. 6.1172 + * Check to be sure the ending transaction is the same ID as the next on 6.1173 + * the list. If not, incorrectly nested so throw an exception. 6.1174 + * 6.1175 + *Next, get from the queue in the structure. 6.1176 + *If it's empty, set VP_currently_executing field to NULL and resume 6.1177 + * requesting VP. 6.1178 + *If get somethine, set VP_currently_executing to the VP from the queue, then 6.1179 + * resume both. 6.1180 + */ 6.1181 +void 6.1182 +handleTransEnd(VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv) 6.1183 + { VSsSemData *semData; 6.1184 + SlaveVP *waitingSlv; 6.1185 + VSsTrans *transStruc; 6.1186 + TransListElem *lastTrans; 6.1187 + 6.1188 + DEBUG__printf1(dbgRqstHdlr,"TransEnd request from processor %d",requestingSlv->slaveID) 6.1189 + 6.1190 + transStruc = &(semEnv->transactionStrucs[ semReq->transID ]); 6.1191 + 6.1192 + //make sure transaction ended in same VP as started it. 6.1193 + if( transStruc->VPCurrentlyExecuting != requestingSlv ) 6.1194 + { 6.1195 + VMS_PI__throw_exception( "trans ended in diff VP", requestingSlv, NULL ); 6.1196 + } 6.1197 + 6.1198 + //make sure nesting is correct -- last ID entered should == this ID 6.1199 + semData = requestingSlv->semanticData; 6.1200 + lastTrans = semData->lastTransEntered; 6.1201 + if( lastTrans->transID != semReq->transID ) 6.1202 + { 6.1203 + VMS_PI__throw_exception( "trans incorrectly nested", requestingSlv, NULL ); 6.1204 + } 6.1205 + 6.1206 + semData->lastTransEntered = semData->lastTransEntered->nextTrans; 6.1207 + 6.1208 + 6.1209 + waitingSlv = readPrivQ( transStruc->waitingVPQ ); 6.1210 + transStruc->VPCurrentlyExecuting = waitingSlv; 6.1211 + 6.1212 + if( waitingSlv != NULL ) 6.1213 + resume_slaveVP( waitingSlv, semEnv ); 6.1214 + 6.1215 + resume_slaveVP( requestingSlv, semEnv ); 6.1216 + }
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/DKU_Request_Handlers.h Mon Aug 27 02:14:35 2012 -0700 7.3 @@ -0,0 +1,62 @@ 7.4 +/* 7.5 + * Copyright 2009 OpenSourceStewardshipFoundation.org 7.6 + * Licensed under GNU General Public License version 2 7.7 + * 7.8 + * Author: seanhalle@yahoo.com 7.9 + * 7.10 + */ 7.11 + 7.12 +#ifndef _VSs_REQ_H 7.13 +#define _VSs_REQ_H 7.14 + 7.15 +#include "VSs.h" 7.16 + 7.17 +/*This header defines everything specific to the VSs semantic plug-in 7.18 + */ 7.19 + 7.20 +inline void 7.21 +handleSubmitTask( VSsSemReq *semReq, VSsSemEnv *semEnv); 7.22 +inline void 7.23 +handleEndTask( VSsSemReq *semReq, VSsSemEnv *semEnv); 7.24 +inline void 7.25 +handleSendTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv); 7.26 +inline void 7.27 +handleSendFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv); 7.28 +inline void 7.29 +handleReceiveTypeTo( VSsSemReq *semReq, VSsSemEnv *semEnv); 7.30 +inline void 7.31 +handleReceiveFromTo( VSsSemReq *semReq, VSsSemEnv *semEnv); 7.32 +inline void 7.33 +handleTaskwait(VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv); 7.34 + 7.35 +inline void 7.36 +handleMalloc( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv); 7.37 +inline void 7.38 +handleFree( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv ); 7.39 +inline void 7.40 +handleTransEnd(VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv*semEnv); 7.41 +inline void 7.42 +handleTransStart( VSsSemReq *semReq, SlaveVP *requestingSlv, 7.43 + VSsSemEnv *semEnv ); 7.44 +inline void 7.45 +handleAtomic( VSsSemReq *semReq, SlaveVP *requestingSlv, VSsSemEnv *semEnv); 7.46 +inline void 7.47 +handleStartFnSingleton( VSsSemReq *semReq, SlaveVP *reqstingSlv, 7.48 + VSsSemEnv *semEnv ); 7.49 +inline void 7.50 +handleEndFnSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, 7.51 + VSsSemEnv *semEnv ); 7.52 +inline void 7.53 +handleStartDataSingleton( VSsSemReq *semReq, SlaveVP *reqstingSlv, 7.54 + VSsSemEnv *semEnv ); 7.55 +inline void 7.56 +handleEndDataSingleton( VSsSemReq *semReq, SlaveVP *requestingSlv, 7.57 + VSsSemEnv *semEnv ); 7.58 +inline void 7.59 +free_task_stub( VSsTaskStub *stubToFree ); 7.60 +inline void 7.61 +replaceWithNewSlotSlvIfNeeded( SlaveVP *requestingSlv, VSsSemEnv *semEnv ); 7.62 + 7.63 + 7.64 +#endif /* _VSs_REQ_H */ 7.65 +
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/DKU_singleton_asm.s Mon Aug 27 02:14:35 2012 -0700 8.3 @@ -0,0 +1,21 @@ 8.4 + 8.5 +//Assembly code takes the return addr off the stack and saves 8.6 +// into the singleton. The first field in the singleton is the 8.7 +// "endInstrAddr" field, and the return addr is at 0x4(%ebp) 8.8 +.globl asm_save_ret_to_singleton 8.9 +asm_save_ret_to_singleton: 8.10 + movq 0x8(%rbp), %rax #get ret address, ebp is the same as in the calling function 8.11 + movq %rax, (%rdi) #write ret addr to endInstrAddr field 8.12 + ret 8.13 + 8.14 + 8.15 +//Assembly code changes the return addr on the stack to the one 8.16 +// saved into the singleton by the end-singleton-fn 8.17 +//The stack's return addr is at 0x4(%%ebp) 8.18 +.globl asm_write_ret_from_singleton 8.19 +asm_write_ret_from_singleton: 8.20 + movq (%rdi), %rax #get endInstrAddr field 8.21 + movq %rax, 0x8(%rbp) #write return addr to the stack of the caller 8.22 + ret 8.23 + 8.24 +
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/Measurement/DKU_Counter_Recording.c Mon Aug 27 02:14:35 2012 -0700 9.3 @@ -0,0 +1,121 @@ 9.4 +/* 9.5 + * 9.6 + * author: Nina Engelhardt 9.7 + */ 9.8 + 9.9 +#include "VSs_Counter_Recording.h" 9.10 +#include "VMS_impl/VMS.h" 9.11 +#include "VSs_impl/VSs.h" 9.12 + 9.13 +#ifdef HOLISTIC__TURN_ON_PERF_COUNTERS 9.14 + 9.15 +void VSs__init_counter_data_structs(){ 9.16 + VSsSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv; 9.17 + int i; 9.18 + for(i=0;i<NUM_CORES;i++){ 9.19 + semanticEnv->counterList[i] = makeListOfArrays(sizeof(CounterEvent), 128); 9.20 + } 9.21 +} 9.22 + 9.23 +void addToListOfArraysCounterEvent(CounterEvent value, ListOfArrays* list){ 9.24 + int offset_in_fragment = list->next_free_index % list->num_entries_per_fragment; 9.25 + if(offset_in_fragment == 0){ 9.26 + void* newBlock = malloc(list->entry_size * list->num_entries_per_fragment); 9.27 + addToDynArray(newBlock,list->dim1info); 9.28 + } 9.29 + CounterEvent* typedFragment = (CounterEvent*) ((list->dim1)[list->dim1info->numInArray -1]); 9.30 + typedFragment[offset_in_fragment] = value; 9.31 + list->next_free_index++; 9.32 +} 9.33 + 9.34 +void VSs__counter_handler(int evt_type, int vpid, int task, SlaveVP* pr, uint64 cycles, uint64 instrs) 9.35 +{ 9.36 + 9.37 + if (pr->typeOfVP == Master || pr->typeOfVP == Shutdown) 9.38 + { //Only save values for application work, done in a SlaveVP 9.39 + return; 9.40 + } 9.41 + 9.42 + VSsSemEnv *semanticEnv = _VMSMasterEnv->semanticEnv; 9.43 + 9.44 + CounterEvent e; 9.45 + e.event_type = evt_type; 9.46 + e.vp = vpid; 9.47 + e.task = task; 9.48 + 9.49 + e.cycles = cycles; 9.50 + e.instrs = instrs; 9.51 + 9.52 + if(pr){ 9.53 + e.coreID = pr->coreAnimatedBy; 9.54 + e.slot = pr->animSlotAssignedTo; 9.55 + } else { 9.56 + e.coreID = -1; 9.57 + e.slot = NULL; 9.58 + } 9.59 + 9.60 + int corenum; 9.61 + 9.62 + if(pr) corenum = pr->coreAnimatedBy; else return; 9.63 + 9.64 + if(evt_type==Work_start || evt_type==Work_end || evt_type==AppResponderInvocation_start){ 9.65 + addToListOfArrays_ext(CounterEvent,e,semanticEnv->counterList[corenum]); 9.66 + } else { 9.67 + addToListOfArraysCounterEvent(e,semanticEnv->counterList[corenum]); 9.68 + } 9.69 +} 9.70 + 9.71 +void set_counter_file(FILE* f){ 9.72 + counterfile = f; 9.73 +} 9.74 + 9.75 +void print_counter_events_to_file(void* _e){ 9.76 + CounterEvent* e = (CounterEvent*) _e; 9.77 + fprintf(counterfile, "event, "); 9.78 + switch(e->event_type){ 9.79 + case AppResponderInvocation_start: 9.80 + fprintf(counterfile, "AppResponderInvocation_start"); 9.81 + break; 9.82 + case AppResponder_start: 9.83 + fprintf(counterfile, "AppResponder_start"); 9.84 + break; 9.85 + case AppResponder_end: 9.86 + fprintf(counterfile, "AppResponder_end"); 9.87 + break; 9.88 + case AssignerInvocation_start: 9.89 + fprintf(counterfile, "AssignerInvocation_start"); 9.90 + break; 9.91 + case NextAssigner_start: 9.92 + fprintf(counterfile, "NextAssigner_start"); 9.93 + break; 9.94 + case Assigner_start: 9.95 + fprintf(counterfile, "Assigner_start"); 9.96 + break; 9.97 + case Assigner_end: 9.98 + fprintf(counterfile, "Assigner_end"); 9.99 + break; 9.100 + case Work_end: 9.101 + fprintf(counterfile, "Work_end"); 9.102 + break; 9.103 + case Work_start: 9.104 + fprintf(counterfile, "Work_start"); 9.105 + break; 9.106 + case HwResponderInvocation_start: 9.107 + fprintf(counterfile, "HwResponderInvocation_start"); 9.108 + break; 9.109 + case Timestamp_start: 9.110 + fprintf(counterfile, "Timestamp_start"); 9.111 + break; 9.112 + case Timestamp_end: 9.113 + fprintf(counterfile, "Timestamp_end"); 9.114 + break; 9.115 + default: 9.116 + fprintf(counterfile, "unknown event"); 9.117 + } 9.118 + fprintf(counterfile,", %d, %d, %llu, %llu",e->vp,e->task,e->cycles,e->instrs); 9.119 + if(e->coreID >=0) 9.120 + fprintf(counterfile,", %d",e->coreID); 9.121 + fprintf(counterfile,"\n"); 9.122 + fflush(counterfile); 9.123 +} 9.124 +#endif
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/Measurement/DKU_Counter_Recording.h Mon Aug 27 02:14:35 2012 -0700 10.3 @@ -0,0 +1,33 @@ 10.4 +/* 10.5 + * File: VSs_Counter_Recording.h 10.6 + * Author: nengel 10.7 + * 10.8 + * Created on January 11, 2012, 3:03 PM 10.9 + */ 10.10 + 10.11 +#ifndef VSs_COUNTER_RECORDING_H 10.12 +#define VSs_COUNTER_RECORDING_H 10.13 + 10.14 +#include "VMS_impl/VMS.h" 10.15 + 10.16 +typedef struct { 10.17 + int event_type; 10.18 + int coreID; 10.19 + AnimSlot* slot; 10.20 + int vp; 10.21 + int task; 10.22 + uint64 cycles; 10.23 + uint64 instrs; 10.24 +} CounterEvent; 10.25 + 10.26 +FILE* counterfile; 10.27 + 10.28 +void VSs__init_counter_data_structs(); 10.29 + 10.30 +void VSs__counter_handler(int evt_type, int vpid, int task, SlaveVP* pr, uint64 cycles, uint64 instrs); 10.31 + 10.32 +void set_counter_file(FILE* f); 10.33 + 10.34 +void print_counter_events_to_file(void* _e); 10.35 +#endif /* VSs_COUNTER_RECORDING_H */ 10.36 +
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/Measurement/DKU_Measurement.h Mon Aug 27 02:14:35 2012 -0700 11.3 @@ -0,0 +1,87 @@ 11.4 +/* 11.5 + * Copyright 2009 OpenSourceStewardshipFoundation.org 11.6 + * Licensed under GNU General Public License version 2 11.7 + * 11.8 + * Author: seanhalle@yahoo.com 11.9 + * 11.10 + */ 11.11 + 11.12 +#ifndef _VSs_MEAS_H 11.13 +#define _VSs_MEAS_H 11.14 + 11.15 + 11.16 +#ifdef MEAS__TURN_ON_LANG_MEAS 11.17 + 11.18 + #ifdef MEAS__Make_Meas_Hists_for_Language 11.19 + #undef MEAS__Make_Meas_Hists_for_Language 11.20 + #endif 11.21 + 11.22 + 11.23 +//=================== Language-specific Measurement Stuff =================== 11.24 +// 11.25 +// 11.26 + #define SendFromToHistIdx 1 //note: starts at 1 11.27 + #define SendOfTypeHistIdx 2 11.28 + #define ReceiveFromToHistIdx 3 11.29 + #define ReceiveOfTypeHistIdx 4 11.30 + 11.31 + #define MEAS__Make_Meas_Hists_for_Language \ 11.32 + _VMSMasterEnv->measHistsInfo = \ 11.33 + makePrivDynArrayOfSize( (void***)&(_VMSMasterEnv->measHists), 200); \ 11.34 + makeAMeasHist( SendFromToHistIdx, "SendFromTo", 50, 0, 100 ) \ 11.35 + makeAMeasHist( SendOfTypeHistIdx, "SendOfType", 50, 0, 100 ) \ 11.36 + makeAMeasHist( ReceiveFromToHistIdx,"ReceiveFromTo", 50, 0, 100 ) \ 11.37 + makeAMeasHist( ReceiveOfTypeHistIdx,"ReceiveOfType", 50, 0, 100 ) 11.38 + 11.39 + #define Meas_startSendFromTo \ 11.40 + int32 startStamp, endStamp; \ 11.41 + saveLowTimeStampCountInto( startStamp ); \ 11.42 + 11.43 + #define Meas_endSendFromTo \ 11.44 + saveLowTimeStampCountInto( endStamp ); \ 11.45 + addIntervalToHist( startStamp, endStamp, \ 11.46 + _VMSMasterEnv->measHists[ SendFromToHistIdx ] ); 11.47 + 11.48 + #define Meas_startSendOfType \ 11.49 + int32 startStamp, endStamp; \ 11.50 + saveLowTimeStampCountInto( startStamp ); \ 11.51 + 11.52 + #define Meas_endSendOfType \ 11.53 + saveLowTimeStampCountInto( endStamp ); \ 11.54 + addIntervalToHist( startStamp, endStamp, \ 11.55 + _VMSMasterEnv->measHists[ SendOfTypeHistIdx ] ); 11.56 + 11.57 + #define Meas_startReceiveFromTo \ 11.58 + int32 startStamp, endStamp; \ 11.59 + saveLowTimeStampCountInto( startStamp ); \ 11.60 + 11.61 + #define Meas_endReceiveFromTo \ 11.62 + saveLowTimeStampCountInto( endStamp ); \ 11.63 + addIntervalToHist( startStamp, endStamp, \ 11.64 + _VMSMasterEnv->measHists[ ReceiveFromToHistIdx ] ); 11.65 + 11.66 + #define Meas_startReceiveOfType \ 11.67 + int32 startStamp, endStamp; \ 11.68 + saveLowTimeStampCountInto( startStamp ); \ 11.69 + 11.70 + #define Meas_endReceiveOfType \ 11.71 + saveLowTimeStampCountInto( endStamp ); \ 11.72 + addIntervalToHist( startStamp, endStamp, \ 11.73 + _VMSMasterEnv->measHists[ReceiveOfTypeHistIdx ] ); 11.74 + 11.75 +#else //===================== turned off ========================== 11.76 + 11.77 + #define MEAS__Make_Meas_Hists_for_Language 11.78 + #define Meas_startSendFromTo 11.79 + #define Meas_endSendFromTo 11.80 + #define Meas_startSendOfType 11.81 + #define Meas_endSendOfType 11.82 + #define Meas_startReceiveFromTo 11.83 + #define Meas_endReceiveFromTo 11.84 + #define Meas_startReceiveOfType 11.85 + #define Meas_endReceiveOfType 11.86 + 11.87 +#endif /* MEAS__TURN_ON_LANG_MEAS */ 11.88 + 11.89 +#endif /* */ 11.90 +
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/Measurement/dependency.c Mon Aug 27 02:14:35 2012 -0700 12.3 @@ -0,0 +1,78 @@ 12.4 +#include "dependency.h" 12.5 +#include "VMS_impl/VMS.h" 12.6 + 12.7 +Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task){ 12.8 + Dependency* newDep = (Dependency*) VMS_int__malloc(sizeof(Dependency)); 12.9 + if (newDep!=NULL){ 12.10 + newDep->from_vp = from_vp; 12.11 + newDep->from_task = from_task; 12.12 + newDep->to_vp = to_vp; 12.13 + newDep->to_task = to_task; 12.14 + } 12.15 + return newDep; 12.16 +} 12.17 + 12.18 +NtoN* new_NtoN(int id){ 12.19 + NtoN* newn = (NtoN*) VMS_int__malloc(sizeof(NtoN)); 12.20 + newn->id = id; 12.21 + newn->senders = makeListOfArrays(sizeof(Unit), 64); 12.22 + newn->receivers = makeListOfArrays(sizeof(Unit), 64); 12.23 + return newn; 12.24 +} 12.25 + 12.26 +int set_dependency_file(FILE* file){ 12.27 + dependency_file = file; 12.28 +} 12.29 + 12.30 +void print_ctl_dependency_to_file(void* _dep){ 12.31 + Dependency* dep = (Dependency*) _dep; 12.32 + if(!dep) return; 12.33 + fprintf(dependency_file,"ctlDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); 12.34 +} 12.35 + 12.36 +void print_comm_dependency_to_file(void* _dep){ 12.37 + Dependency* dep = (Dependency*) _dep; 12.38 + if(!dep) return; 12.39 + fprintf(dependency_file,"commDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); 12.40 +} 12.41 + 12.42 +void print_dyn_dependency_to_file(void* _dep){ 12.43 + Dependency* dep = (Dependency*) _dep; 12.44 + if(!dep) return; 12.45 + fprintf(dependency_file,"dynDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); 12.46 +} 12.47 + 12.48 +void print_hw_dependency_to_file(void* _dep){ 12.49 + Dependency* dep = (Dependency*) _dep; 12.50 + if(!dep) return; 12.51 + fprintf(dependency_file,"hwDep,%d,%d,%d,%d\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); 12.52 +} 12.53 + 12.54 +void print_dependency_to_file(void* _dep){ 12.55 + Dependency* dep = (Dependency*) _dep; 12.56 + if(!dep) return; 12.57 + fprintf(dependency_file,"VP_%d_%d -> VP_%d_%d;\n",dep->from_vp,dep->from_task,dep->to_vp,dep->to_task); 12.58 +} 12.59 + 12.60 +void print_unit_to_file(void* _unit){ 12.61 + Unit* unit = (Unit*) _unit; 12.62 + if(!unit) return; 12.63 + fprintf(dependency_file,"unit,%d,%d\n",unit->vp,unit->task); 12.64 +} 12.65 + 12.66 +void print_nton_set_helper(void* _u){ 12.67 + Unit* u = (Unit*) _u; 12.68 + if(!u) return; 12.69 + fprintf(dependency_file,",%d,%d",u->vp,u->task); 12.70 +} 12.71 + 12.72 +void print_nton_to_file(void* _nton){ 12.73 + NtoN* nton = (NtoN*) _nton; 12.74 + if(!nton) return; 12.75 + //assert(nton->senders->next_free_index==nton->receivers->next_free_index); 12.76 + int numInSet = nton->senders->next_free_index; 12.77 + fprintf(dependency_file,"NtoN,%d",numInSet); 12.78 + forAllInListOfArraysDo(nton->senders,&print_nton_set_helper); 12.79 + forAllInListOfArraysDo(nton->receivers,&print_nton_set_helper); 12.80 + fprintf(dependency_file,"\n"); 12.81 +} 12.82 \ No newline at end of file
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/Measurement/dependency.h Mon Aug 27 02:14:35 2012 -0700 13.3 @@ -0,0 +1,56 @@ 13.4 +/* 13.5 + * File: dependency.h 13.6 + * Author: Nina Engelhardt 13.7 + * 13.8 + * Created on 29. August 2011, 17:41 13.9 + */ 13.10 + 13.11 +#ifndef _DEPENDENCY_H 13.12 +#define _DEPENDENCY_H 13.13 + 13.14 + 13.15 +#include <stdio.h> 13.16 +#include "ListOfArrays/ListOfArrays.h" 13.17 + 13.18 +typedef struct { 13.19 + int vp; 13.20 + int task; 13.21 +} Unit; 13.22 + 13.23 +typedef struct { 13.24 + int from_vp; 13.25 + int from_task; 13.26 + int to_vp; 13.27 + int to_task; 13.28 +} Dependency; 13.29 + 13.30 +typedef struct { 13.31 + int32 id; 13.32 + ListOfArrays* senders; 13.33 + ListOfArrays* receivers; 13.34 +} NtoN; 13.35 + 13.36 +FILE* dependency_file; 13.37 + 13.38 +Dependency* new_dependency(int from_vp, int from_task, int to_vp, int to_task); 13.39 + 13.40 +NtoN* new_NtoN(int id); 13.41 + 13.42 +int set_dependency_file(FILE* file); 13.43 + 13.44 +void print_ctl_dependency_to_file(void* _dep); 13.45 + 13.46 +void print_comm_dependency_to_file(void* _dep); 13.47 + 13.48 +void print_dyn_dependency_to_file(void* _dep); 13.49 + 13.50 +void print_hw_dependency_to_file(void* _dep); 13.51 + 13.52 +void print_dependency_to_file(void* dep); 13.53 + 13.54 +void print_unit_to_file(void* unit); 13.55 + 13.56 +void print_nton_to_file(void* _nton); 13.57 + 13.58 +#endif /* DEPENDENCY_H */ 13.59 +
