    /***********************************************************************
                   Copyright (c) 2007 SKY Computers, Inc.
    
     Redistribution and use in source and binary forms are permitted
     provided that this notice is preserved and that due credit is given to
     SKY Computers, Inc. The name of SKY Computers, Inc. may not be used to
     endorse or promote products derived from this software without
     specific prior written permission. This software is provided ``as is''
     without express or implied warranty.
    ************************************************************************/

/*
 *--------------------------------------------------------------------------
 *
 >++
 *
 *   File: in_compute.c
 *
 *   Function: To provide a series of computations as directed by the main
 *       thread.
 *
 *   Calling Sequence: See below. 
 *  
 *   Implementation Details:
 *       1. Allocate buffer space, initialize variables.
 *       2. In a loop, wait for commands from the main thread, then execute
 *          those commands.
 *
 *   Restrictions:
 *       1. None.
 *
 >**
 *   Revision Information:
 *    Date       By   Rev    Changes Made...
 *    10/26/07   bwj  0.0    New Module.
 *
 >--
 *--------------------------------------------------------------------------
 */

#include "sky_ex_inc.h"
#include "in_tcb.h"

/*
 *  TimeTrac Externals -- 
 *      Do the following if you want the TimeTrac variables to
 *      disappear when the TimeTrac function calls disappear
 *      (see the Makefile).
 */
#ifdef TIME_TRAC
extern TTHandle Trace_Log[NUM_THREADS];

extern TTEventHandle tt_hello_bgn[NUM_THREADS], tt_hello_end[NUM_THREADS];
extern TTEventHandle tt_vran_bgn[NUM_THREADS], tt_vran_end[NUM_THREADS];
extern TTEventHandle tt_vadd_bgn[NUM_THREADS], tt_vadd_end[NUM_THREADS];
extern TTEventHandle tt_vmul_bgn[NUM_THREADS], tt_vmul_end[NUM_THREADS];
extern TTEventHandle tt_vsub_bgn[NUM_THREADS], tt_vsub_end[NUM_THREADS];
#endif

/* ---------------------------------------------------------------------- */ 

/*
 >++
 *
 *   int compute_main (TCB *tcb):
 *       TCB *t: Task block defining this thread.
 *
 *       This is the compute thread entry point for the multiple child threads.
 *       After startup, it waits for commands from the main thread.
 *   
 *       Returns: Does not.
 >--
 */

int compute_main (TCB *tcb)
{
  int pass = -1;
  float *src1, *src2;
  float *sum1, *mult;
  float *dst0;
    
  /* The TimeTrac parameters were set up in th_main(). */
    
  printf ("%2d -- Thread starting.\n", tcb->Rank);
  
  /* Allocate storage for the arrays. */
  src1 = (float *) ex_mem_alloc (tcb->Rank, V_SIZE * sizeof (float), 64, "Array Src_1");
  src2 = (float *) ex_mem_alloc (tcb->Rank, V_SIZE * sizeof (float), 64, "Array Src_2");
  sum1 = (float *) ex_mem_alloc (tcb->Rank, V_SIZE * sizeof (float), 64, "Array Sum_1");
  mult = (float *) ex_mem_alloc (tcb->Rank, V_SIZE * sizeof (float), 64, "Array Mult");
  dst0 = (float *) ex_mem_alloc (tcb->Rank, V_SIZE * sizeof (float), 64, "Array Dst_X");
  
  /* Wait for the master thread to tell us to go. */
  tcb->Status = STAT_WAIT;
  while (tcb->Comm == COMM_NONE)
    {
#ifdef BETTER
      sched_yield ();
#else
      usleep (100);
#endif
    }
    
  tcb->Status = STAT_RUN;
    
  /* 
   *  Process commands from the main thread. Stay in this loop until
   *  the master thread tells us to exit.
   */
  while (FOREVER)
    {
      /* Wait for the next command to run or exit. */
      while (tcb->Comm == COMM_NONE)
	{
#ifdef BETTER
	  sched_yield ();
#else
	  usleep (100);
#endif
	}

      if (tcb->Comm == COMM_EXIT)
	break;

      pass = tcb->Pass;
      
      time_trac_record (Trace_Log[tcb->Rank], tt_hello_bgn[tcb->Rank], (float)pass);
      //printf ("%2d -- Hello World -- %d\n", tcb->Rank, pass);
      time_trac_record (Trace_Log[tcb->Rank], tt_hello_end[tcb->Rank], (float)pass);
      
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_bgn[tcb->Rank], (float)pass);
      vinput (src1, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_end[tcb->Rank], (float)pass);
	
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_bgn[tcb->Rank], (float)pass);
      vinput (src2, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_end[tcb->Rank], (float)pass);
	
      time_trac_record (Trace_Log[tcb->Rank], tt_vadd_bgn[tcb->Rank], (float)pass);
      vadd (src1, src2, sum1, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vadd_end[tcb->Rank], (float)pass);
      
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_bgn[tcb->Rank], (float)pass);
      vinput (src1, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_end[tcb->Rank], (float)pass);
      
      time_trac_record (Trace_Log[tcb->Rank], tt_vmul_bgn[tcb->Rank], (float)pass);
      vmul (src1, sum1, dst0, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vmul_end[tcb->Rank], (float)pass);
      
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_bgn[tcb->Rank], (float)pass);
      vinput (src2, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vran_end[tcb->Rank], (float)pass);
	
      time_trac_record (Trace_Log[tcb->Rank], tt_vsub_bgn[tcb->Rank], (float)pass);
      vsub (dst0, src2, dst0, V_SIZE);
      time_trac_record (Trace_Log[tcb->Rank], tt_vsub_end[tcb->Rank], (float)pass);
	
      /* Reset the control command and status flag. */
      tcb->Comm = COMM_NONE;
      tcb->Status = STAT_DONE;
    }

  /* Save the events and exit */
  tcb->Status = STAT_DONE;
    
  /* Thread is done, exit when parent exits. */
  printf ("%2d -- Thread waiting for exit.\n", tcb->Rank);
  while (1)
    sleep (1);
}

/* --------------------------- End of Module ---------------------------- */

