Personal tools
You are here: Home Codes ZEUS 3D exemplarthread
Document Actions

exemplarthread

by streeter last modified 2005-09-21 04:18

Click here to get the file

Size 11.7 kB - File type text/plain

File contents

/***********************************************************************
 
Thread Timers

Here are Isom's lightweight, thread-safe wall clock time and 
CPU time routines. They work for compiler based parallelism, 
cpslib, and MPI or regular processes.

Some improvements for pthreads based parallelism are needed.

Compile:
	cc -D_CONVEX_SOURCE -c timers.c
Link:
	cc/f77 *.o -Wl,-aarchive_shared,+FPD -lail -lcnx_syscall
		   ^^^^^^^^^^^^^^^^^^^^^^^^^
                   optional, but recommended 


 ***********************************************************************
 *
 *  cpu_time(ref) - Subroutine intended to be lightweight and 
 *                  thread-safe mechanism to return individual thread 
 *                  cpu time for the Convex SPP.  It does not return 
 *                  system (kernel or time blocked waiting) time, only 
 *
 *                  cpu time spent executing user code.
 *     ARGS:  ref - address containing floating point (real*4) value 
 *                  used to determine whether timer should be reset or 
 *                  not.  0.0 forces the timer to be reset.
 *                  NOTE: *ref != 0.0 is not used by timers, it simply 
 *                  indicates that the timer is not to be reset.
 *
 *    Author: Isom Crawford, HP/Convex
 *
 *    Date: 18 April 1996
 *
 *    Usage:  Mainly intended for use on Convex SPP machines, although
 *            non Convex compilers should compile without a problem 
 *            (and get wrappers for gettimeofdday() and clock()).
 *        
 *            FORTRAN:
 *
 *                      REAL*4  T0, T1, CPU_TIME
 *                      ...
 *
 *                      T0 = 0.0
 *                      t0 = CPU_TIME( T0 )
 *
 *                      ...    Code segment to be timed.
 *
 *                      T1 = CPU_TIME( t0 )
 *
 *             C:
 *
 *                      float t0, t1, cpu_time;
 *                      ...
 *
 *                      t0 = 0.0;
 *                      t0 = cpu_time( &t0 );
 *
 *                      ...     Code segment to be timed
 *
 *                      t1 = cpu_time( &t0 );
 *
 *
 *    Warnings:  When used with fork() and vfork() system calls, the 
 *               user should note the following:
 *
 *               1> If calls are made to cpu_time/wall_time before the 
 *                  fork, then those routines should _NOT_ be called in 
 *                  the child.  Doing so may cause the child 
 *                  process(es) to receive a SIGSEGV.  The parent may 
 *                  make calls before and after the fork without a 
 *                  problem provided the child does not make calls to 
 *                  cpu_time.
 *
 *               2> Calls to cpu_time() and wall_time() may be made by 
 *                  both parent and child subsequent to a fork().
 *
 *               3> SIGSEGV.  The parent may make calls before and after
 *                  the fork without a problem provided the child does 
 *                  not make calls to cpu_time.
 *
 *               When called with *ref != 0.0, this  simply indicates
 *               that the timer is not reset - _THE_VALUE_IS_NOT_USED_!
 *               This was done primarily to protect the user, i.e. to 
 *               guarantee that times are thread-private.
 *
 *               These timers provide _THREAD_SPECIFIC_ info.  Hence,
 *               timing around thread spawns/joins will only return info
 *               for thread 0, and _NOT_ all threads.  Of course, timing
 *               inside the parallel regions will return thread-unique
 *               cpu_time/wall_time for each thread.
 *
 **********************************************************************/

#if !defined( _CONVEX_SOURCE )
#	include <time.h>
#else
#	include <spp_prog_model.h>
#	include <sys/types.h>
#	include <sys/cnx_ail.h>
#endif

#define SECS_PER_MUSEC 0.000001
#define TWO_TO_32 4294967296.0

float cpu_time(ref)
float *ref;
{

#if !defined( _CONVEX_SOURCE )
    double t;
    clock_t clockret;

    if( ref == NULL )
    {
	perror("cpu_time/NULL address");
	exit(-1);
    }
    clockret= clock();
    t= ((double)clockret) / ((double)CLOCKS_PER_SEC) - (double)(*ref);

    return (t);
#else
	/***************************************************************
	 * ttr_per_sec := # of thread timer ticks per second.  
         *                thread_private in anticipation of mixed node 
         *                configurations.
	 **************************************************************/
	static thread_private double ttr_per_sec_recip;

	/***************************************************************
	 * handle := handle used by ttr_enable() and must be thread -
         *           unique.
	 **************************************************************/
	static thread_private unsigned int handle;

	/***************************************************************
	 * flag[0-128] := Array of flags for each thread.  That is, i-th
	 *                entry indicates whether ttr_enable() needs to 
         *                be called.  Declared static as it must be 
         *                retained.
	 **************************************************************/
        static unsigned int flag[128]= {
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
		0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

	/***************************************************************
	 * OTHER VARIABLES:
	 *  ktid := This thread's id #.
	 *  temp_ttr := 64 bit counter temporary.
	 *  ptr := int pointer used to convert temp_ttr to integers
	 *  temp_secs := temporary used to convert ptr[] to floating 
         *               point.
	 **************************************************************/
	int ktid;
        cnx_ttr_t temp_ttr;
        unsigned int *ptr;
        double temp_secs;

        ptr= (unsigned int *)&temp_ttr;

	ktid= cps_ktid();
	if( ktid < 0 )
	{
		perror("cpu_time/ktid");
		exit(-1);
	}
	if( ref == NULL )
	{
		perror("cpu_time/NULL address");
		exit(-1);
	}

	/*************************************************************
	 * If flag[thread id] is not set, then timer must be enabled.
	 ************************************************************/
	if( flag[ktid] == 0 )
	{
		/*****************************************************
		 * Initialize thread timer ticks per second for this
		 * thread.
		 ****************************************************/
		ttr_per_sec_recip= 1.0 / (double)ttr_per_sec_read();
		if( ttr_per_sec_recip <= 0 ) 
		{
			perror("ttr_per_sec_read() in cpu_time");
			exit(-1);
		}
		/*****************************************************
		 * Enable timer for this thread.
		 ****************************************************/
		if (ttr_enable(&handle) == -1)
		{
			perror("ttr_enable() in cpu_time");
			exit(-1);
		}
		/*****************************************************
		 * Mark flag so that thread timer won't be enabled
		 * multiple times.
		 ****************************************************/
		flag[ktid]= 1;
	}

	/*************************************************************
	 * If argument is 0, reset timer.
	 ************************************************************/
        if ( *ref == 0. )
        {
		/*****************************************************
		 * Set 64 bit counter to zero (via pointers).  
		 ****************************************************/
		ptr[0]= ptr[1]= 0;
		/*****************************************************
		 * Hammer timer.
		 ****************************************************/
		ttr_write(handle, temp_ttr);
        }
	/*************************************************************
	 * end if ( *ref == 0.0 )
	 ************************************************************/
	/*************************************************************
	 * Get 64 bit counter from thread timer.  Then convert to
	 * double precision seconds.  Deduct base seconds for correct
	 * time since last initialization.
	 ************************************************************/
        temp_ttr= ttr_read(handle);
        temp_secs=  ( (double)ptr[0] ) * TWO_TO_32 ;
        temp_secs+= ( (double)ptr[1] ) ;
        temp_secs= temp_secs * ttr_per_sec_recip ;

        return( (float)temp_secs );
#endif
}

/***********************************************************************
 *
 *  wall_time(ref) - Subroutine intended to be lightweight and 
 *                   thread-safe mechanism to return individual thread 
 *                   wall time for the Convex SPP.
 *
 *    ARGS:  ref - address containing floating point (real*4) value 
 *                 used to determine whether timer should be reset or 
 *                 not.  0.0 forces the timer to be reset.
 *
 *    Author: Isom Crawford, HP/Convex
 *
 **********************************************************************/
float wall_time(ref)
float *ref;
{
#if !defined( _CONVEX_SOURCE )
    double t;
    static unsigned long base_sec= 0;
    struct timeval buffer;
    struct timezone dummy;

    gettimeofday (&buffer, &dummy);

    if( base_sec <= 0 ) base_sec= buffer.tv_sec;

    buffer.tv_sec -= base_sec;

    if( ref == NULL )
    {
	perror("wall_time/NULL address");
	exit(-1);
    }
    t = (double)buffer.tv_sec + ((double)buffer.tv_usec*1.0e-6) - (double)(*ref);

    return (t);
#else
	/***************************************************************
	 * base_ptr0 := # of seconds at initialization time (*ref = 0).
	 *              This must be static and thread_private to 
         *              maintain retained, separate information for 
         *              each thread.
	 **************************************************************/
        static thread_private unsigned int base_ptr0;
        static thread_private double base_secs;

	/***************************************************************
	 * OTHER VARIABLES:
	 *  temp_toc := 64 bit counter temporary.
	 *  ptr := int pointer used to convert temp_toc to integers
	 *  temp_secs := temporary used to convert ptr[] to floating 
         *  point.
	 **************************************************************/
        cnx_toc_t temp_toc;
        unsigned int *ptr;
        double temp_secs;

	if( ref == NULL )
	{
		perror("wall_time/NULL address");
		exit(-1);
	}
        ptr= (unsigned int *)&temp_toc;

	/***************************************************************
	 * Get time of century.
	 **************************************************************/
        temp_toc= toc_read();

	/***************************************************************
	 * If arg (*ref) is <= 0.0, reset baseline time.  Make second 
         * call to toc_read() to make absolutely sure that return value 
         * is > 0.0.
	 **************************************************************/
        if ( *ref <= 0. )
        {
                /* Reset base_ptr0 */
                base_ptr0= ptr[0];
		base_secs= ( (double)ptr[1] ) * SECS_PER_MUSEC ;
		temp_toc= toc_read();
        }
	ptr[0] -= base_ptr0;

	/***************************************************************
	 * Convert 64 bit counter to double precision.
	 **************************************************************/
        temp_secs=  ( (double)ptr[0] ) * TWO_TO_32 ;
        temp_secs+= ( (double)ptr[1] )  ;
        temp_secs*= SECS_PER_MUSEC ;
	temp_secs= temp_secs - base_secs - (double)(*ref);

        return( (float)temp_secs );
#endif
}



Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: