changeset 0:b456b67cddd0

Initial add -- works, with vmalloc + probes version of VMS
author Me
date Sat, 30 Oct 2010 20:51:40 -0700
parents
children b6ce47a0909b
files VCilk.h VCilk_PluginFns.c VCilk__DESIGN_NOTES.txt VCilk_lib.c
diffstat 4 files changed, 775 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/VCilk.h	Sat Oct 30 20:51:40 2010 -0700
     1.3 @@ -0,0 +1,121 @@
     1.4 +/*
     1.5 + *  Copyright 2009 OpenSourceStewardshipFoundation.org
     1.6 + *  Licensed under GNU General Public License version 2
     1.7 + *
     1.8 + * Author: seanhalle@yahoo.com
     1.9 + *
    1.10 + */
    1.11 +
    1.12 +#ifndef _VCilk_H
    1.13 +#define	_VCilk_H
    1.14 +
    1.15 +#include "VMS/Queue_impl/PrivateQueue.h"
    1.16 +#include "VMS/Hash_impl/PrivateHash.h"
    1.17 +#include "VMS/VMS.h"
    1.18 +
    1.19 +/*This header defines everything specific to the VCilk semantic plug-in
    1.20 + */
    1.21 +typedef struct _VCilkSemReq   VCilkSemReq;
    1.22 +
    1.23 +
    1.24 +/*Semantic layer-specific data sent inside a request from lib called in app
    1.25 + * to request handler called in MasterLoop
    1.26 + */
    1.27 +enum VCilkReqType
    1.28 + {
    1.29 +   syncReq = 1,
    1.30 +   mallocReq,
    1.31 +   freeReq
    1.32 + };
    1.33 +
    1.34 +struct _VCilkSemReq
    1.35 + { enum VCilkReqType    reqType;
    1.36 +   VirtProcr           *requestingPr;
    1.37 +   int32                sizeToMalloc;
    1.38 +   void                *ptrToFree;
    1.39 +   VirtProcrFnPtr       fnPtr;
    1.40 +   void                *initData;
    1.41 +   int32                coreToSpawnOnto;
    1.42 + }
    1.43 +/* VCilkSemReq */;
    1.44 +
    1.45 +typedef struct
    1.46 + {
    1.47 +   PrivQueueStruc **readyVPQs;
    1.48 +   HashTable       *commHashTbl;
    1.49 +   int32            numVirtPr;
    1.50 +   int32            nextCoreToGetNewPr;
    1.51 +   int32            primitiveStartTime;
    1.52 + }
    1.53 +VCilkSemEnv;
    1.54 +
    1.55 +typedef struct
    1.56 + {
    1.57 +   int32 syncPending;
    1.58 +   int32 numLiveChildren;
    1.59 +   VirtProcr *parentPr;
    1.60 + }
    1.61 +VCilkSemData;
    1.62 +
    1.63 +//===========================================================================
    1.64 +
    1.65 +void
    1.66 +VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fn, void *initData );
    1.67 +
    1.68 +int32
    1.69 +VCilk__giveMinWorkUnitCycles( float32 percentOverhead );
    1.70 +
    1.71 +void inline
    1.72 +VCilk__start_primitive();
    1.73 +
    1.74 +int32 inline
    1.75 +VCilk__end_primitive_and_give_cycles();
    1.76 +
    1.77 +int32
    1.78 +VCilk__giveIdealNumWorkUnits();
    1.79 +
    1.80 +//=======================
    1.81 +
    1.82 +void
    1.83 +VCilk__init();
    1.84 +
    1.85 +void
    1.86 +VCilk__cleanup_after_shutdown();
    1.87 +
    1.88 +//=======================
    1.89 +
    1.90 +void inline
    1.91 +VCilk__spawn( int32  coreToSpawnOnto, VirtProcrFnPtr  fnPtr,
    1.92 +              void  *initData,        VirtProcr      *creatingPr );
    1.93 +
    1.94 +int32
    1.95 +VCilk__give_number_of_cores_to_spawn_onto();
    1.96 +
    1.97 +void
    1.98 +VCilk__sync( VirtProcr *animatingPr );
    1.99 +
   1.100 +void *
   1.101 +VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr );
   1.102 +
   1.103 +void
   1.104 +VCilk__free( void *ptrToFree, VirtProcr *animPr );
   1.105 +
   1.106 +void
   1.107 +VCilk__dissipate_procr( VirtProcr *procrToDissipate );
   1.108 +
   1.109 +//=======================
   1.110 +
   1.111 +void
   1.112 +VCilk__free_semantic_request( VCilkSemReq *semReq );
   1.113 +
   1.114 +
   1.115 +//=========================  Internal use only  =============================
   1.116 +void
   1.117 +VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv );
   1.118 +
   1.119 +VirtProcr *
   1.120 +VCilk__schedule_virt_procr( void *_semEnv, int coreNum );
   1.121 +
   1.122 +
   1.123 +#endif	/* _VCilk_H */
   1.124 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/VCilk_PluginFns.c	Sat Oct 30 20:51:40 2010 -0700
     2.3 @@ -0,0 +1,285 @@
     2.4 +/*
     2.5 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
     2.6 + *
     2.7 + * Licensed under BSD
     2.8 + */
     2.9 +
    2.10 +#include <stdio.h>
    2.11 +#include <stdlib.h>
    2.12 +#include <malloc.h>
    2.13 +
    2.14 +#include "VMS/Queue_impl/PrivateQueue.h"
    2.15 +#include "VCilk.h"
    2.16 +
    2.17 +
    2.18 +
    2.19 +//===========================================================================
    2.20 +void inline
    2.21 +handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv );
    2.22 +
    2.23 +void inline
    2.24 +handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.25 +              VCilkSemEnv *semEnv );
    2.26 +void inline
    2.27 +handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.28 +            VCilkSemEnv *semEnv );
    2.29 +void inline
    2.30 +handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv );
    2.31 +
    2.32 +void inline
    2.33 +handleSpawn( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.34 +             VCilkSemEnv *semEnv  );
    2.35 +
    2.36 +void inline
    2.37 +dispatchSemReq( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.38 +                VCilkSemEnv *semEnv );
    2.39 +
    2.40 +void inline
    2.41 +resumePr( VirtProcr *procr, VCilkSemEnv *semEnv );
    2.42 +
    2.43 +//===========================================================================
    2.44 +
    2.45 +
    2.46 +/*Will get requests to send, to receive, and to create new processors.
    2.47 + * Upon send, check the hash to see if a receive is waiting.
    2.48 + * Upon receive, check hash to see if a send has already happened.
    2.49 + * When other is not there, put in.  When other is there, the comm.
    2.50 + *  completes, which means the receiver P gets scheduled and
    2.51 + *  picks up right after the receive request.  So make the work-unit
    2.52 + *  and put it into the queue of work-units ready to go.
    2.53 + * Other request is create a new Processor, with the function to run in the
    2.54 + *  Processor, and initial data.
    2.55 + */
    2.56 +void
    2.57 +VCilk__Request_Handler( VirtProcr *requestingPr, void *_semEnv )
    2.58 + { VCilkSemEnv *semEnv;
    2.59 +   VMSReqst    *req;
    2.60 +   VCilkSemReq *semReq;
    2.61 + 
    2.62 +   semEnv = (VCilkSemEnv *)_semEnv;
    2.63 +
    2.64 +   req = VMS__take_next_request_out_of( requestingPr );
    2.65 +   
    2.66 +   while( req != NULL )
    2.67 +    {
    2.68 +      switch( req->reqType )
    2.69 +       { case semantic:     dispatchSemReq( VMS__take_sem_reqst_from(req),
    2.70 +                                            requestingPr, semEnv );
    2.71 +            break;
    2.72 +         case createReq:    //create request has to come as a VMS request,
    2.73 +                            // to allow MasterLoop to do stuff before gets
    2.74 +                            // here, and maybe also stuff after all requests
    2.75 +                            // done -- however, can still attach semantic
    2.76 +                            // req data to req.
    2.77 +                            semReq = VMS__take_sem_reqst_from( req );
    2.78 +                            handleSpawn( semReq, requestingPr, semEnv );
    2.79 +            break;
    2.80 +         case dissipate:    handleDissipate( requestingPr, semEnv );
    2.81 +            break;
    2.82 +         case VMSSemantic:  VMS__handle_VMSSemReq(req, requestingPr, semEnv,
    2.83 +                                                  &resumePr );
    2.84 +            break;
    2.85 +         default:
    2.86 +            break;
    2.87 +       }
    2.88 +      
    2.89 +      DoneHandlingReqst:
    2.90 +
    2.91 +      req = VMS__take_next_request_out_of( requestingPr );
    2.92 +    } //while( req != NULL )
    2.93 +
    2.94 + }
    2.95 +
    2.96 +void inline
    2.97 +dispatchSemReq( VCilkSemReq *semReq, VirtProcr *requestingPr,
    2.98 +                VCilkSemEnv *semEnv )
    2.99 + {
   2.100 +   if( semReq == NULL ) return;
   2.101 +   switch( semReq->reqType )
   2.102 +    {
   2.103 +      case syncReq:       handleSync(           requestingPr, semEnv );
   2.104 +         break;
   2.105 +      case mallocReq:     handleMalloc( semReq, requestingPr, semEnv );
   2.106 +         break;
   2.107 +      case freeReq:       handleFree(   semReq, requestingPr, semEnv );
   2.108 +         break;
   2.109 +    }
   2.110 +   //NOTE: semantic request data strucs allocated on stack in VCilk Lib calls
   2.111 + }
   2.112 +
   2.113 +
   2.114 +//============================== Scheduler ==================================
   2.115 +
   2.116 +
   2.117 +/*For VCilk, scheduling a slave simply takes the next work-unit off the
   2.118 + * ready-to-go work-unit queue and assigns it to the slaveToSched.
   2.119 + *If the ready-to-go work-unit queue is empty, then nothing to schedule
   2.120 + * to the slave -- return FALSE to let Master loop know scheduling that
   2.121 + * slave failed.
   2.122 + */
   2.123 +VirtProcr *
   2.124 +VCilk__schedule_virt_procr( void *_semEnv, int coreNum )
   2.125 + { VirtProcr   *schedPr;
   2.126 +   VCilkSemEnv *semEnv;
   2.127 +
   2.128 +   semEnv = (VCilkSemEnv *)_semEnv;
   2.129 +
   2.130 +   schedPr = readPrivQ( semEnv->readyVPQs[coreNum] );
   2.131 +      //Note, using a non-blocking queue -- it returns NULL if queue empty
   2.132 +
   2.133 +   return( schedPr );
   2.134 + }
   2.135 +
   2.136 +
   2.137 +//=========================== Request Handlers ==============================
   2.138 +void inline
   2.139 +resumePr( VirtProcr *procr, VCilkSemEnv *semEnv )
   2.140 + {
   2.141 +   writePrivQ( procr, semEnv->readyVPQs[ procr->coreAnimatedBy] );
   2.142 + }
   2.143 +
   2.144 +
   2.145 +
   2.146 +
   2.147 +/* check if list of live children is empty.
   2.148 + * If yes, then resume.
   2.149 + * If no, then set sync-pending flag.
   2.150 + */
   2.151 +void
   2.152 +handleSync( VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.153 + {
   2.154 +   if(((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren  == 0 )
   2.155 +    { //no live children to wait for
   2.156 +      resumePr( requestingPr, semEnv );
   2.157 +    }
   2.158 +   else
   2.159 +    {
   2.160 +      ((VCilkSemData *)(requestingPr->semanticData))->syncPending = TRUE;
   2.161 +    }
   2.162 + }
   2.163 +
   2.164 +/*
   2.165 + */
   2.166 +void
   2.167 +handleMalloc( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.168 +              VCilkSemEnv *semEnv )
   2.169 + { void *ptr;
   2.170 +   
   2.171 +   ptr = VMS__malloc( semReq->sizeToMalloc );
   2.172 +   requestingPr->dataReturnedFromReq = ptr;
   2.173 +   resumePr( requestingPr, semEnv );
   2.174 + }
   2.175 +
   2.176 +/*
   2.177 + */
   2.178 +void inline
   2.179 +handleFree( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.180 +            VCilkSemEnv *semEnv )
   2.181 + {
   2.182 +   VMS__free( semReq->ptrToFree );
   2.183 +   resumePr( requestingPr, semEnv );
   2.184 + }
   2.185 +
   2.186 +
   2.187 +
   2.188 +
   2.189 +/* 
   2.190 + */
   2.191 +void inline
   2.192 +handleSpawn( VCilkSemReq *semReq, VirtProcr *requestingPr,
   2.193 +             VCilkSemEnv *semEnv  )
   2.194 + {
   2.195 +   VirtProcr    *newPr;
   2.196 +   VCilkSemData *semanticData;
   2.197 +
   2.198 +      //This is running in master, so use internal version
   2.199 +   newPr = VMS__create_procr( semReq->fnPtr, semReq->initData );
   2.200 +
   2.201 +   semanticData = VMS__malloc( sizeof(VCilkSemData) );
   2.202 +
   2.203 +   semanticData->numLiveChildren = 0;
   2.204 +   semanticData->parentPr        = NULL;
   2.205 +   semanticData->syncPending     = FALSE;
   2.206 +
   2.207 +   newPr->semanticData = semanticData;
   2.208 +
   2.209 +   /* add newly created to the list of live children of requester.
   2.210 +    * In newly created, add pointer to VP requesting, as the parentVP
   2.211 +    */
   2.212 +   ((VCilkSemData *)(requestingPr->semanticData))->numLiveChildren +=1;
   2.213 +   ((VCilkSemData *)(newPr->semanticData))->parentPr = requestingPr;
   2.214 +
   2.215 +   semEnv->numVirtPr += 1;
   2.216 +
   2.217 +      //Assign new processor to a core & transition it to ready
   2.218 +   #ifdef SEQUENTIAL
   2.219 +   newPr->coreAnimatedBy = 0;
   2.220 +
   2.221 +   #else
   2.222 +   int32
   2.223 +   coreToSpawnOnto = semReq->coreToSpawnOnto;
   2.224 +
   2.225 +   if(coreToSpawnOnto < 0 || coreToSpawnOnto >= NUM_CORES )
   2.226 +    {    //out-of-range, so round-robin assignment
   2.227 +      newPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr;
   2.228 +      if( semEnv->nextCoreToGetNewPr >= NUM_CORES - 1 )
   2.229 +          semEnv->nextCoreToGetNewPr  = 0;
   2.230 +      else
   2.231 +          semEnv->nextCoreToGetNewPr += 1;
   2.232 +    }
   2.233 +   else //core num in-range, so use it
   2.234 +    { newPr->coreAnimatedBy = coreToSpawnOnto;
   2.235 +    }
   2.236 +   #endif
   2.237 +
   2.238 +   resumePr( newPr,        semEnv );
   2.239 +   resumePr( requestingPr, semEnv );
   2.240 + }
   2.241 +
   2.242 +
   2.243 +/*get parentVP & remove dissipator from parent's live children.
   2.244 + *If this was last live child, check "sync pending" flag
   2.245 + *-- if set, then resume the parentVP.
   2.246 + */
   2.247 +void inline
   2.248 +handleDissipate( VirtProcr *requestingPr, VCilkSemEnv *semEnv )
   2.249 + {
   2.250 +   VirtProcr *
   2.251 +   parentPr = ((VCilkSemData *)
   2.252 +               (requestingPr->semanticData))->parentPr;
   2.253 +   if( parentPr == NULL ) //means this is seed processor being dissipated
   2.254 +    { //Just act normally, except don't deal with parent
   2.255 +      // VMS__Free is implemented to ignore requests to free data from
   2.256 +      // outside VMS, so all this processor's non-VMS allocated data will
   2.257 +      // remain and be cleaned up outside
   2.258 +    }
   2.259 +   else
   2.260 +    {
   2.261 +      ((VCilkSemData *)(parentPr->semanticData))->numLiveChildren -= 1;
   2.262 +      if( ((VCilkSemData *)
   2.263 +           (parentPr->semanticData))->numLiveChildren <= 0 )
   2.264 +       { //this was last live child of parent
   2.265 +         if( ((VCilkSemData *)
   2.266 +              (parentPr->semanticData))->syncPending == TRUE )
   2.267 +          { //was waiting for last child to dissipate, so resume it
   2.268 +            ((VCilkSemData *)
   2.269 +             (parentPr->semanticData))->syncPending = FALSE;
   2.270 +            resumePr( parentPr, semEnv );
   2.271 +          }
   2.272 +       }
   2.273 +    }
   2.274 +
   2.275 +   VMS__free( requestingPr->semanticData );
   2.276 +   
   2.277 +       //Now do normal dissipate
   2.278 +   
   2.279 +       //call VMS to free_all AppVP state -- stack and so on
   2.280 +   VMS__handle_dissipate_reqst( requestingPr );
   2.281 +
   2.282 +   semEnv->numVirtPr -= 1;
   2.283 +   if( semEnv->numVirtPr == 0 )
   2.284 +    {    //no more work, so shutdown
   2.285 +      VMS__handle_shutdown_reqst( requestingPr );
   2.286 +    }
   2.287 + }
   2.288 +
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/VCilk__DESIGN_NOTES.txt	Sat Oct 30 20:51:40 2010 -0700
     3.3 @@ -0,0 +1,28 @@
     3.4 +
     3.5 +
     3.6 +
     3.7 + the design:
     3.8 +
     3.9 +Only has the spawn and sync calls, nothing else.
    3.10 +
    3.11 +For spawn, creates a new VP
    3.12 +
    3.13 +For sync, waits for all VPs created by itself to dissipate.
    3.14 +
    3.15 +To implement these, in request handler:
    3.16 +For spawn:
    3.17 + create new virtual processor
    3.18 + In requester, add newly created to the list of live children
    3.19 + In newly created, add pointer to requester, as the parentVP
    3.20 +
    3.21 +For Dissipate:
    3.22 + remove dissipator from its parent's list of live children.
    3.23 + If this was last in list, check "sync pending" flag 
    3.24 + -- if set, then resume the parentVP.
    3.25 +
    3.26 +For Sync:
    3.27 + check if list of live of children is empty.  
    3.28 + If yes, then resume.  
    3.29 + If no, then set sync-pending flag and remain suspended
    3.30 +
    3.31 +That's it.  Quick and simple,
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/VCilk_lib.c	Sat Oct 30 20:51:40 2010 -0700
     4.3 @@ -0,0 +1,341 @@
     4.4 +/*
     4.5 + * Copyright 2010  OpenSourceCodeStewardshipFoundation
     4.6 + *
     4.7 + * Licensed under BSD
     4.8 + */
     4.9 +
    4.10 +#include <stdio.h>
    4.11 +#include <stdlib.h>
    4.12 +#include <malloc.h>
    4.13 +
    4.14 +#include "VMS/VMS.h"
    4.15 +#include "VCilk.h"
    4.16 +#include "VMS/Queue_impl/PrivateQueue.h"
    4.17 +#include "VMS/Hash_impl/PrivateHash.h"
    4.18 +
    4.19 +
    4.20 +//==========================================================================
    4.21 +
    4.22 +void
    4.23 +VCilk__init();
    4.24 +
    4.25 +void
    4.26 +VCilk__init_Seq();
    4.27 +
    4.28 +void
    4.29 +VCilk__init_Helper();
    4.30 +//==========================================================================
    4.31 +
    4.32 +
    4.33 +/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR
    4.34 + * (still want to do FoR, with time-lines as syntax, could be super cool)
    4.35 + * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate
    4.36 + * among library, DKU, WT, FoR -- all the patterns in terms of virtual
    4.37 + * processors (or equivalently work-units), so Master picks which virt procr
    4.38 + * from which portions of app (DKU, WT, FoR) onto which sched slots
    4.39 + *Might even do hierarchy of masters -- group of sched slots for each core
    4.40 + * has its own master, that keeps generated work local
    4.41 + * single-reader-single-writer sync everywhere -- no atomic primitives (but
    4.42 + * memory fences on architectures that need them)
    4.43 + * Might have the different schedulers talk to each other, to negotiate
    4.44 + * larger-grain sharing of resources, according to predicted critical
    4.45 + * path, and expansion of work
    4.46 + */
    4.47 +
    4.48 +
    4.49 +
    4.50 +//===========================================================================
    4.51 +
    4.52 +
    4.53 +/*These are the library functions *called in the application*
    4.54 + * 
    4.55 + *There's a pattern for the outside sequential code to interact with the
    4.56 + * VMS_HW code.
    4.57 + *The VMS_HW system is inside a boundary..  every VCilk system is in its
    4.58 + * own directory that contains the functions for each of the processor types.
    4.59 + * One of the processor types is the "seed" processor that starts the
    4.60 + * cascade of creating all the processors that do the work.
    4.61 + *So, in the directory is a file called "EntryPoint.c" that contains the
    4.62 + * function, named appropriately to the work performed, that the outside
    4.63 + * sequential code calls.  This function follows a pattern:
    4.64 + *1) it calls VCilk__init()
    4.65 + *2) it creates the initial data for the seed processor, which is passed
    4.66 + *    in to the function
    4.67 + *3) it creates the seed VCilk processor, with the data to start it with.
    4.68 + *4) it calls startVCilkThenWaitUntilWorkDone
    4.69 + *5) it gets the returnValue from the transfer struc and returns that
    4.70 + *    from the function
    4.71 + *
    4.72 + *For now, a new VCilk system has to be created via VCilk__init every
    4.73 + * time an entry point function is called -- later, might add letting the
    4.74 + * VCilk system be created once, and let all the entry points just reuse
    4.75 + * it -- want to be as simple as possible now, and see by using what makes
    4.76 + * sense for later..
    4.77 + */
    4.78 +
    4.79 +
    4.80 +
    4.81 +//===========================================================================
    4.82 +
    4.83 +/*This is the "border crossing" function -- the thing that crosses from the
    4.84 + * outside world, into the VMS_HW world.  It initializes and starts up the
    4.85 + * VMS system, then creates one processor from the specified function and
    4.86 + * puts it into the readyQ.  From that point, that one function is resp.
    4.87 + * for creating all the other processors, that then create others, and so
    4.88 + * forth.
    4.89 + *When all the processors, including the seed, have dissipated, then this
    4.90 + * function returns.  The results will have been written by side-effect via
    4.91 + * pointers read from, or written into initData.
    4.92 + *
    4.93 + *NOTE: no Threads should exist in the outside program that might touch
    4.94 + * any of the data reachable from initData passed in to here
    4.95 + */
    4.96 +void
    4.97 +VCilk__create_seed_procr_and_do_work( VirtProcrFnPtr fnPtr, void *initData )
    4.98 + { VCilkSemEnv *semEnv;
    4.99 +   VirtProcr *seedPr;
   4.100 +
   4.101 +   #ifdef SEQUENTIAL
   4.102 +   VCilk__init_Seq();  //debug sequential exe
   4.103 +   #else
   4.104 +   VCilk__init();      //normal multi-thd
   4.105 +   #endif
   4.106 +   semEnv = _VMSMasterEnv->semanticEnv;
   4.107 +
   4.108 +      //VCilk starts with one processor, which is put into initial environ,
   4.109 +      // and which then calls create() to create more, thereby expanding work
   4.110 +      //Note, have to use external version of VMS__create_procr because
   4.111 +      // internal version uses VMS__malloc, which hasn't been set up by here
   4.112 +   seedPr = VMS_ext__create_procr( fnPtr, initData );
   4.113 +   VCilkSemData *
   4.114 +   semanticData = malloc( sizeof(VCilkSemData) );
   4.115 +
   4.116 +   semanticData->numLiveChildren = 0;
   4.117 +   semanticData->parentPr        = NULL;
   4.118 +   semanticData->syncPending     = FALSE;
   4.119 +
   4.120 +   seedPr->semanticData = semanticData;
   4.121 +   seedPr->coreAnimatedBy = semEnv->nextCoreToGetNewPr++;
   4.122 +
   4.123 +   writePrivQ( seedPr, semEnv->readyVPQs[seedPr->coreAnimatedBy] );
   4.124 +   semEnv->numVirtPr = 1;
   4.125 +
   4.126 +   #ifdef SEQUENTIAL
   4.127 +   VMS__start_the_work_then_wait_until_done_Seq();  //debug sequential exe
   4.128 +   #else
   4.129 +   VMS__start_the_work_then_wait_until_done();      //normal multi-thd
   4.130 +   #endif
   4.131 +
   4.132 +   VCilk__cleanup_after_shutdown();
   4.133 + }
   4.134 +
   4.135 +
   4.136 +int32 inline
   4.137 +VCilk__giveMinWorkUnitCycles( float32 percentOverhead )
   4.138 + {
   4.139 +   return MIN_WORK_UNIT_CYCLES;
   4.140 + }
   4.141 +
   4.142 +int32
   4.143 +VCilk__giveIdealNumWorkUnits()
   4.144 + {
   4.145 +   return NUM_SCHED_SLOTS * NUM_CORES;
   4.146 + }
   4.147 +
   4.148 +/*To measure how long a primitive operation takes, when calculating number of
   4.149 + * sub-tasks to divide into.
   4.150 + * For now, use TSC -- later, make these two macros with assembly that first
   4.151 + * saves jump point, and second jumps back several times to get reliable time
   4.152 + */
   4.153 +void inline
   4.154 +VCilk__start_primitive()
   4.155 + { //int32 *saveAddr;
   4.156 +   //saveAddr = &(((VCilkSemEnv *)(_VMSMasterEnv->semanticEnv))->primitiveStartTime);
   4.157 +   saveLowTimeStampCountInto( (((VCilkSemEnv *)
   4.158 +                        (_VMSMasterEnv->semanticEnv))->primitiveStartTime) );
   4.159 + }
   4.160 +
   4.161 +/*Just quick and dirty for now -- make reliable later
   4.162 + * will want this to jump back several times -- to be sure cache is warm
   4.163 + * because don't want comm time included in calc-time measurement -- and
   4.164 + * also to throw out any "weird" values due to OS interrupt or TSC rollover
   4.165 + */
   4.166 +int32 inline
   4.167 +VCilk__end_primitive_and_give_cycles()
   4.168 + { int32 endTime, startTime;
   4.169 +   //TODO: fix by repeating time-measurement
   4.170 +   saveLowTimeStampCountInto( endTime );
   4.171 +   startTime = ((VCilkSemEnv *)(_VMSMasterEnv->semanticEnv))->primitiveStartTime;
   4.172 +   return (endTime - startTime);
   4.173 + }
   4.174 +
   4.175 +//===========================================================================
   4.176 +//
   4.177 +/*Initializes all the data-structures for a VCilk system -- but doesn't
   4.178 + * start it running yet!
   4.179 + *
   4.180 + *This and its callees run in main thread outside VMS
   4.181 + * 
   4.182 + *This sets up the semantic layer over the VMS system
   4.183 + *
   4.184 + *First, calls VMS_Setup, then creates own environment, making it ready
   4.185 + * for creating the seed processor and then starting the work.
   4.186 + */
   4.187 +void
   4.188 +VCilk__init()
   4.189 + {
   4.190 +   VMS__init();
   4.191 +      //masterEnv, a global var, now is partially set up by init_VMS
   4.192 +
   4.193 +   VCilk__init_Helper();
   4.194 + }
   4.195 +
   4.196 +void
   4.197 +VCilk__init_Seq()
   4.198 + {
   4.199 +   VMS__init_Seq();
   4.200 +      //masterEnv, a global var, now is partially set up by init_VMS
   4.201 +
   4.202 +   VCilk__init_Helper();
   4.203 + }
   4.204 +
   4.205 +/*Runs in main thread before VMS system starts
   4.206 + */
   4.207 +void
   4.208 +VCilk__init_Helper()
   4.209 + { VCilkSemEnv     *semanticEnv;
   4.210 +   PrivQueueStruc **readyVPQs;
   4.211 +   int              coreIdx;
   4.212 + 
   4.213 +      //Hook up the semantic layer's plug-ins to the Master virt procr
   4.214 +   _VMSMasterEnv->requestHandler = &VCilk__Request_Handler;
   4.215 +   _VMSMasterEnv->slaveScheduler = &VCilk__schedule_virt_procr;
   4.216 +
   4.217 +      //create the semantic layer's environment (all its data) and add to
   4.218 +      // the master environment
   4.219 +   semanticEnv = malloc( sizeof( VCilkSemEnv ) );
   4.220 +   _VMSMasterEnv->semanticEnv = semanticEnv;
   4.221 +
   4.222 +      //create the ready queue, hash tables used for pairing send to receive
   4.223 +      // and so forth
   4.224 +      //TODO: add hash tables for pairing sends with receives, and
   4.225 +      // initialize the data ownership system
   4.226 +   readyVPQs = malloc( NUM_CORES * sizeof(PrivQueueStruc *) );
   4.227 +
   4.228 +   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   4.229 +    {
   4.230 +      readyVPQs[ coreIdx ] = makePrivQ();
   4.231 +    }
   4.232 +   
   4.233 +   semanticEnv->readyVPQs = readyVPQs;
   4.234 +   
   4.235 +   semanticEnv->nextCoreToGetNewPr = 0;
   4.236 + }
   4.237 +
   4.238 +
   4.239 +/*Runs in main thread, outside VMS
   4.240 + *Frees any memory allocated by VCilk__init() then calls VMS's cleanup
   4.241 + */
   4.242 +void
   4.243 +VCilk__cleanup_after_shutdown()
   4.244 + { VCilkSemEnv *semanticEnv;
   4.245 +   int coreIdx;
   4.246 + 
   4.247 +   semanticEnv = _VMSMasterEnv->semanticEnv;
   4.248 +
   4.249 +//TODO: double check all sem env locations freed
   4.250 +
   4.251 +   for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   4.252 +    {
   4.253 +      free( semanticEnv->readyVPQs[coreIdx]->startOfData );
   4.254 +      free( semanticEnv->readyVPQs[coreIdx] );
   4.255 +    }
   4.256 +   free( semanticEnv->readyVPQs );
   4.257 +   
   4.258 +   free( _VMSMasterEnv->semanticEnv );
   4.259 +   VMS__cleanup_after_shutdown();
   4.260 + }
   4.261 +
   4.262 +
   4.263 +//===========================================================================
   4.264 +
   4.265 +
   4.266 +/*Spawn involves allocating mem as well as creating processor which itself
   4.267 + * allocates, so has to be done inside master
   4.268 + */
   4.269 +void inline
   4.270 +VCilk__spawn( int32  coreToSpawnOnto, VirtProcrFnPtr  fnPtr,
   4.271 +              void  *initData,        VirtProcr      *requestingPr )
   4.272 + { VCilkSemReq reqData;
   4.273 +
   4.274 +      //the semantic request data is on the stack and disappears when this
   4.275 +      // call returns -- it's guaranteed to remain in the VP's stack for as
   4.276 +      // long as the VP is suspended.
   4.277 +   reqData.reqType         = 0; //know it's type because in a VMS create req
   4.278 +   reqData.coreToSpawnOnto = coreToSpawnOnto;
   4.279 +   reqData.fnPtr           = fnPtr;
   4.280 +   reqData.initData        = initData;
   4.281 +   reqData.requestingPr    = requestingPr;
   4.282 +
   4.283 +   VMS__send_create_procr_req( &reqData, requestingPr );
   4.284 + } 
   4.285 +
   4.286 +
   4.287 +int32
   4.288 +VCilk__give_number_of_cores_to_spawn_onto()
   4.289 + {
   4.290 +   return NUM_CORES;
   4.291 + }
   4.292 +
   4.293 +
   4.294 +
   4.295 +/*This runs inside slave VP, so can't do any freeing -- have to do in plugin
   4.296 + */
   4.297 +void inline
   4.298 +VCilk__dissipate_procr( VirtProcr *procrToDissipate )
   4.299 + { 
   4.300 +
   4.301 +   VMS__dissipate_procr( procrToDissipate );
   4.302 + }
   4.303 +
   4.304 +//===========================================================================
   4.305 +
   4.306 +void
   4.307 +VCilk__sync( VirtProcr *animPr )
   4.308 + { VCilkSemReq reqData;
   4.309 + 
   4.310 +   reqData.reqType      = syncReq;
   4.311 +   reqData.requestingPr = animPr;
   4.312 +
   4.313 +   VMS__send_sem_request( &reqData, animPr );
   4.314 + }
   4.315 +
   4.316 +
   4.317 +
   4.318 +void *
   4.319 +VCilk__malloc( int32 sizeToMalloc, VirtProcr *animPr )
   4.320 + { VCilkSemReq reqData;
   4.321 +
   4.322 +   reqData.reqType      = mallocReq;
   4.323 +   reqData.requestingPr = animPr;
   4.324 +   reqData.sizeToMalloc = sizeToMalloc;
   4.325 +
   4.326 +   VMS__send_sem_request( &reqData, animPr );
   4.327 +
   4.328 +   return animPr->dataReturnedFromReq;
   4.329 + }
   4.330 +
   4.331 +
   4.332 +/*Sends request to Master, which does the work of freeing
   4.333 + */
   4.334 +void
   4.335 +VCilk__free( void *ptrToFree, VirtProcr *animPr )
   4.336 + { VCilkSemReq reqData;
   4.337 +
   4.338 +   reqData.reqType      = freeReq;
   4.339 +   reqData.requestingPr = animPr;
   4.340 +   reqData.ptrToFree    = ptrToFree;
   4.341 +
   4.342 +   VMS__send_sem_request( &reqData, animPr );
   4.343 + }
   4.344 +