changeset 0:35b53e6de714

Initial add -- up on sourceforge now
author Me
date Sat, 22 May 2010 19:33:11 -0700
parents
children 06ca89bafbb8
files VMSHW.h VMSHW_PluginFns.c VMSHW_lib.c
diffstat 3 files changed, 417 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/VMSHW.h	Sat May 22 19:33:11 2010 -0700
     1.3 @@ -0,0 +1,46 @@
     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 _VMSHW_H
    1.13 +#define	_VMSHW_H
    1.14 +
    1.15 +#include "VMS/VMS_primitive_data_types.h"
    1.16 +#include "VMS/Queue_impl/BlockingQueue.h"
    1.17 +
    1.18 +/*This header defines everything specific to the VMSHW semantic plug-in
    1.19 + */
    1.20 +typedef struct VMSHWReqData VMSHWReqData;
    1.21 +
    1.22 +typedef struct
    1.23 + {
    1.24 + }
    1.25 +VMSHWProcr;
    1.26 +
    1.27 +/*Semantic layer-specific data sent inside a request from lib called in app
    1.28 + * to request handler called in MasterLoop
    1.29 + */
    1.30 +enum VMSHW_ReqType
    1.31 + {
    1.32 +   receive,
    1.33 +   send,
    1.34 +   create
    1.35 + };
    1.36 +
    1.37 +struct VMSHWReqData
    1.38 + { VMSHW_ReqType   reqType;
    1.39 +   
    1.40 + };
    1.41 +
    1.42 +typedef struct
    1.43 + {
    1.44 +
    1.45 + }
    1.46 +VMSHWSemanticEnv;
    1.47 +
    1.48 +#endif	/* _VMSHW_H */
    1.49 +
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/VMSHW_PluginFns.c	Sat May 22 19:33:11 2010 -0700
     2.3 @@ -0,0 +1,141 @@
     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/VMS.h"
    2.15 +#include "VMS/Queue_impl/PrivateQueue.h"
    2.16 +#include "VMSHW.h"
    2.17 +
    2.18 +
    2.19 +/*Will get requests to send, to receive, and to create new processors.
    2.20 + * Upon send, check the hash to see if a receive is waiting.
    2.21 + * Upon receive, check hash to see if a send has already happened.
    2.22 + * When other is not there, put in.  When other is there, the comm.
    2.23 + *  completes, which means the receiver P gets a new work-unit generated
    2.24 + *  that picks up right after the receive request.  So make the work-unit
    2.25 + *  and put it into the queue of work-units ready to go.
    2.26 + * Other request is create a new Processor, with the function to run in the
    2.27 + *  Processor, and initial data.
    2.28 + */
    2.29 +
    2.30 +/*Old idea, but want to keep around:
    2.31 + * give pointer to initialization function to create-processor call, in
    2.32 + *  addition to the work-function and initial data
    2.33 + * Then, make the initialization be a work-unit, that places the created
    2.34 + *  processor-struc, and an initial work-unit for that processor in a
    2.35 + *  request that comes to the req handler when done.  The initial work-unit
    2.36 + *  has the pointer to a special VMS code snippet that
    2.37 + * the function to run in the Processor is pointed to by the work-unit
    2.38 + *  code pointer, and the initial data as the work-unit's data-pointer.
    2.39 + * Another request is the result of create-processor request.  It has a new
    2.40 + *  Processor, and the processor's inital work-unit.  Add the Processor to
    2.41 + *  the data-structures that track Processors, and put the work-unit into the
    2.42 + *  queue of ready-to-go work-units.
    2.43 + * The reason to make the create-processor work-unit return the new
    2.44 + *  processor and its initial work unit, is that only the MasterLoop
    2.45 + *  work-unit owns the semantic environment, with the Processor-tracking
    2.46 + *  data-structures, and only it can put work-units into or take out of
    2.47 + *  the ready-to-go work-unit queue.
    2.48 + */
    2.49 +void
    2.50 +VMSHW__Request_Handler( VMSProcr *slave, void *semanticEnv )
    2.51 + { VMSHWEnviron semEnv;
    2.52 + 
    2.53 +   semEnv = (VMSHWEnviron *)semanticEnv;
    2.54 +
    2.55 +   req = slave->requestsToMaster;
    2.56 +   while( req != NULL )
    2.57 +    {
    2.58 +      //TODO: figure out better separation -- maybe MasterLoop gives
    2.59 +      // request payloads one at a time to this handler
    2.60 +      if( req->type == VMSInternal ) /*do something*/;
    2.61 +      else //request is to be handled by VMSHW
    2.62 +       {
    2.63 +         semanticReq = req->reqPayload; //TODO: make sure not NULL in creator
    2.64 +         switch( semanticReq->type )
    2.65 +          {
    2.66 +            case sendFromName:    handleSendFromName(   semanticReq, semEnv);
    2.67 +               break;
    2.68 +            case sendToPort:      handleSendToPort(     semanticReq, semEnv);
    2.69 +               break;
    2.70 +            case receiveFromName: handleReceiveFromName(semanticReq, semEnv);
    2.71 +               break;
    2.72 +            case receiveOnPort:   handleReceiveOnPort(  semanticReq, semEnv);
    2.73 +               break;
    2.74 +            case create:          handleCreate(         semanticReq, semEnv);
    2.75 +               break;
    2.76 +          }
    2.77 +       }
    2.78 +      req = req->next;
    2.79 +    }
    2.80 + }
    2.81 +
    2.82 +/*The payload has the receiving processor and its port
    2.83 + *
    2.84 + *Note one value in this approach: without the extra (VMS) virtual layer,
    2.85 + * the send and receive would happen in real time instead of virtual time,
    2.86 + * which would waste real time while one of them waited for other
    2.87 + */
    2.88 + void
    2.89 +handleSendToPort( VMSHWRequest *reqPayload, VMSHWEnviron *semEnv )
    2.90 + {
    2.91 +   reqProcr  = reqPayload->reqProcr;
    2.92 +   receivePr = reqPayload->receivePr;
    2.93 +
    2.94 +   key = receivePr->keys[ reqPayload->portNum ];
    2.95 +   value = getValueFromTable( key, semEnv->commHash );
    2.96 +   if( value == NULL )
    2.97 +    {
    2.98 +      //TODO: is hash entry really just a flag -- empty?  Want work-unit? No
    2.99 +      // 'cause want to make an entry when only a send, no receive yet
   2.100 +      value = malloc( sizeof(CommHashFlag) );
   2.101 +      putValueIntoTable( key, value, semEnv->commHash );
   2.102 +    }
   2.103 +   else //receive waiting for this send
   2.104 +    {
   2.105 +      workUPayload = malloc( sizeof(VMSHWWorkUnit) );
   2.106 +      workUPayload->owningProcr = receivePr;
   2.107 +      newWorkUnit  = VMS__create_workUnit( workUPayload );
   2.108 +
   2.109 +      writePrivQ( newWorkUnit, semEnv->readyWorkUnitQ );
   2.110 +      
   2.111 +      //NOTE: this is sequential!  Don't have to worry about sharing or syncs
   2.112 +      //in semantic environment -- even though shared by work units, slaves,
   2.113 +      // and virtual processors -- all the sharing is in virtual time, and
   2.114 +      // mapped onto safe sequence in physical time by VMS
   2.115 +      
   2.116 +    }
   2.117 + }
   2.118 +
   2.119 +
   2.120 +/*For VMSHW, scheduling a slave simply takes the next work-unit off the
   2.121 + * ready-to-go work-unit queue and assigns it to the slaveToSched.
   2.122 + *If the ready-to-go work-unit queue is empty, then nothing to schedule
   2.123 + * to the slave -- return FALSE to let Master loop know scheduling that
   2.124 + * slave failed.
   2.125 + */
   2.126 +bool8
   2.127 +VMSHW__schedule_slave( VMSProcr *slaveToSched, void *semanticEnv )
   2.128 + { PrivQueueStruc    *readyWorkUnitQ;
   2.129 +   WorkUnit          *workUnitToSched;
   2.130 +   VMSHWSemanticEnv *semEnv;
   2.131 +
   2.132 +   semEnv = (VMSHWSemanticEnv *)semanticEnv;
   2.133 +
   2.134 +      //Note, using a non-blocking queue -- it returns NULL if queue empty
   2.135 +   readyWorkUnitQ = semEnv->readyWorkUnitQ;
   2.136 +
   2.137 +   workUnitToSched = readPrivQ( readyWorkUnitQ );
   2.138 +   if( readQ == NULL ) return FALSE;
   2.139 +
   2.140 +   slaveToSched->workUnitToDo = workUnitToSched;
   2.141 +   workUnitToSched->slaveAssignedTo = slaveToSched;
   2.142 +
   2.143 +   return TRUE;
   2.144 + }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/VMSHW_lib.c	Sat May 22 19:33:11 2010 -0700
     3.3 @@ -0,0 +1,230 @@
     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 "../VMS/VMS.h"
    3.15 +#include "VMSHW.h"
    3.16 +#include "../VMS/Queue_impl/NonBlockingQueue.h"
    3.17 +
    3.18 +
    3.19 +/*These are the library functions *called in the application*
    3.20 + *They all run in the virtual slaves, never in the virtual master.
    3.21 + * 
    3.22 + *There's a pattern for the outside sequential code to interact with the
    3.23 + * VMSHW code.
    3.24 + *The VMSHW system is inside a boundary..  every VMSHW system is in its
    3.25 + * own directory that contains the functions for each of the processor types.
    3.26 + * One of the processor types is the "seed" processor that starts the
    3.27 + * cascade of creating all the processors that do the work.
    3.28 + *So, in the directory is a file called "EntryPoint.c" that contains the
    3.29 + * function, named appropriately to the work performed, that the outside
    3.30 + * sequential code calls.  This function follows a pattern:
    3.31 + *1) it calls VMSHW__init()
    3.32 + *2) it creates the initial data for the seed processor, which is passed
    3.33 + *    in to the function
    3.34 + *3) it creates the seed VMSHW processor, with the data to start it with.
    3.35 + *4) it calls startVMSHWThenWaitUntilWorkDone
    3.36 + *5) it gets the returnValue from the transfer struc and returns that
    3.37 + *    from the function
    3.38 + *
    3.39 + *For now, a new VMSHW system has to be created via VMSHW__init every
    3.40 + * time an entry point function is called -- later, might add letting the
    3.41 + * VMSHW system be created once, and let all the entry points just reuse
    3.42 + * it -- want to be as simple as possible now, and see by using what makes
    3.43 + * sense for later..
    3.44 + */
    3.45 +
    3.46 +
    3.47 +/*Initializes all the data-structures for a VMSHW system -- but doesn't
    3.48 + * start it running yet!
    3.49 + *
    3.50 + * 
    3.51 + *This sets up the semantic layer over the VMS system
    3.52 + *
    3.53 + *First, calls VMS_Setup, then creates own environment, making it ready
    3.54 + * for creating the seed processor.
    3.55 + */
    3.56 + void
    3.57 +VMSHW__init()
    3.58 + { VMSHWEnv *semanticEnv;
    3.59 +
    3.60 +   init_VMS();
    3.61 +
    3.62 +      //masterEnv, a global var, now is partially set up by init_VMS
    3.63 +   semanticEnv = malloc( sizeof( VMSHWEnv ) );
    3.64 +   masterEnv->semanticEnv = semanticEnv;
    3.65 +
    3.66 +   semanticEnv->readyWorkUnitsQ = mareadyWorkUnitsQkePrivQ();
    3.67 + }
    3.68 +
    3.69 +
    3.70 +/*This is the entry point to the VMSHW system from the sequential part of
    3.71 + * the app..
    3.72 + *
    3.73 + *Calling this starts the VMS system, passing it the input data given to
    3.74 + * this, then waits for the work to finish, and returns whatever pointer
    3.75 + * the final VMSHW call said to return to the outside via the
    3.76 + * VMSHW__transfer_out_as_result call
    3.77 + */
    3.78 +
    3.79 +VMSHW__start_then_wait_until_work_done()
    3.80 + {
    3.81 +   VMS__start();
    3.82 +    
    3.83 +      //Wait for work to complete
    3.84 +      //Use PThreads to put the main thread to sleep until something executes
    3.85 +      // a notify(), which is the last thing VMS does when work is done
    3.86 +
    3.87 +
    3.88 +      //This will suspend the main PThread until all VMSHW processors have
    3.89 +      // performed dissipate_self(), at which point the VMSHW system will
    3.90 +      // shut itself down, then shut VMS down then call notify to make this
    3.91 +      // wait wake up the main thread again.
    3.92 +      status =
    3.93 +   pthread_cond_wait( &VMS_Environ->doneCondition/*,&VMS_Environ->doneLock*/);
    3.94 +      if (status != 0){perror("Error waiting for work to finish\n"); exit(1);}
    3.95 +
    3.96 +      //signal like this: pthread_cond_signal( &VMS_Environ->doneCondition );
    3.97 +
    3.98 + }
    3.99 +
   3.100 +/*TODO: Q: dealing with library f()s and DKU vs WT vs FoR
   3.101 + * (still want to do FoR, with time-lines as syntax, could be super cool)
   3.102 + * A: thinking pin the coreLoops for all of BLIS -- let Master arbitrate
   3.103 + * among library, DKU, WT, FoR -- all the patterns in terms of work-units,
   3.104 + * so Master picks which work-units from which portions of app onto which
   3.105 + * Slaves
   3.106 + *Might even do one master plus several slaves for each core -- allows
   3.107 + * single-reader-single-writer sync everywhere -- no atomic primitives
   3.108 + * Might have the different schedulers talk to each other, to negotiate
   3.109 + * larger-grain sharing of resources, according to predicted critical
   3.110 + * path, and expansion of work
   3.111 + */
   3.112 +
   3.113 +
   3.114 +
   3.115 +/*Causes the VMSHW system to remove internal ownership, so data won't be
   3.116 + * freed when VMSHW shuts down, and will persist in the external program.
   3.117 + */
   3.118 +void
   3.119 +VMSHW__transfer_to_external( void *data )
   3.120 + {
   3.121 +
   3.122 + }
   3.123 +
   3.124 +void
   3.125 +VMSHW__create_seed_processor_then_wait_until_work_done
   3.126 +                                           ( VMSHWProcrFnPtr fn, void *data )
   3.127 + { VMSHWEnviron semEnv;
   3.128 +
   3.129 +   VMSHW__init();
   3.130 +   semEnv = masterEnv->semanticEnv;
   3.131 +   
   3.132 +      //VMSHW starts with one processor, which is put into initial environ,
   3.133 +      // and, which then calls create() to create more thereby expanding work
   3.134 +   firstVirtProcr = VMSHW__create_processor(  );
   3.135 +
   3.136 +   firstWorkUnit  = 
   3.137 +
   3.138 +   writePrivQ( firstWorkUnit, semEnv->readyWorkUnitsQ );
   3.139 +
   3.140 +   //start the VMSHW system then wait for work to end
   3.141 +   //NOTE: no Threads should exist in the outside program that might touch
   3.142 +   // any of the data reachable from the params given to the seed procr
   3.143 +   VMSHW__start_then_wait_until_work_done();
   3.144 + }
   3.145 +
   3.146 +void
   3.147 +VMSHW__create_processor( )
   3.148 + {
   3.149 +   firstWorkUnit  = firstVirtProcr->latestWorkUnit;
   3.150 +
   3.151 +   writePrivQ( firstWorkUnit, semanticEnv->readyWorkUnitsQ );
   3.152 +
   3.153 +   return firstVirtProcr;
   3.154 + }
   3.155 +
   3.156 +VMSHWProcrFnPtr
   3.157 +   VMSHWProcr * VMSHW__create_processor( &calcVector, vectParams );
   3.158 +   void * VMSHW__malloc( sizeof( VectorParams ) );
   3.159 +   VMSHW__transfer_to_outside( resultMatrix );
   3.160 +   VMSHW__dissipate_self();   //all processors have to dissipate self at end
   3.161 +   VMSHW__send( result, resultPr );
   3.162 +   resultsParams->dividerPr = VMSHW__self();
   3.163 +   VMSHW__start_then_wait_until_work_done();
   3.164 +   VMSHW__create_seed_processor( &divideIntoVectors, dividerParams );
   3.165 +VMSHWProcr
   3.166 +
   3.167 +   void * VMSHW__receive_from( self, resultPr );
   3.168 +   void * VMSHW__receive_from_any_but( self, dividerPr );
   3.169 +   void * VMSHW__receive_on_port( self, VECTOR_PORT );
   3.170 +   
   3.171 +   VMSHW__transfer_ownership_from_to( resultMatrix, self, dividerPr );
   3.172 +
   3.173 +void *
   3.174 +VMSHW__receive_from( VMSHWProcr *callingPr, VMSHWProcr *sendingPr )
   3.175 + { VMSRequest *req;
   3.176 +   VMSHWReq reqPayload;
   3.177 +
   3.178 +      //hash on the caller, 'cause always know it, but sometimes want to
   3.179 +      // receive from anonymous sender
   3.180 +      //Q: what happens if no "receive" is outstanding for one sender, but
   3.181 +      //   do have an outstanding for a different sender?
   3.182 +      //need to treat each "from" as a separate port in the hash table
   3.183 +
   3.184 +   reqPayload = malloc( sizeof(VMSHWReq) );
   3.185 +   reqPayload->type = receive_from;
   3.186 +   reqPayload->key = callingPr->ID ^ sendingPr->ID << 16; //65K max procrs
   3.187 +   reqPayload->procr = callingPr;
   3.188 +   
   3.189 +   req = VMS__create_request( reqPayload );
   3.190 +   VMS__add_request_to_slave( req, callingPr );
   3.191 +   VMS__save_ret_and_jump_to_CoreLoop( callingPr );
   3.192 + }
   3.193 +
   3.194 +
   3.195 +
   3.196 +//===========================================================================
   3.197 + void
   3.198 +freeParamStruc( ParamStruc * param )
   3.199 + { if( param->type == STRING_PARAM_TYPE ) free( param->strValue );
   3.200 +   free( param );
   3.201 + }
   3.202 +
   3.203 +
   3.204 + ParamStruc *
   3.205 +makeParamStruc()
   3.206 + { ParamStruc *retStruc;
   3.207 +   retStruc = malloc( sizeof( ParamStruc ) );
   3.208 +   retStruc->floatValue = 0.0;
   3.209 +   retStruc->intValue   = 0;
   3.210 +   retStruc->strValue   = NULL;
   3.211 + }
   3.212 +
   3.213 + ParamStruc *
   3.214 +makeParamFromStrs( char * type, char *value )
   3.215 + { ParamStruc *retParam;
   3.216 +   retParam = makeParamStruc();
   3.217 +   switch(*type)
   3.218 +    { case 'i':
   3.219 +       { retParam->type = INT_PARAM_TYPE;
   3.220 +         retParam->intValue = atoi( value );
   3.221 +       } break;
   3.222 +      case 's':
   3.223 +       { retParam->type = STRING_PARAM_TYPE;
   3.224 +         retParam->strValue = malloc( strlen(value) + 1);
   3.225 +         strcpy( retParam->strValue, value );
   3.226 +       } break;
   3.227 +      case 'f':
   3.228 +       { retParam->type = FLOAT_PARAM_TYPE;
   3.229 +         retParam->floatValue = atof( value );
   3.230 +       } break;
   3.231 +    }
   3.232 +   return retParam;
   3.233 + }