starter.c 5.71 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
/**CFile****************************************************************

  FileName    [starter.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Wrapper for calling ABC.]

  Synopsis    [A demo program illustrating parallel execution of ABC.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - October 22, 2009.]

  Revision    [$Id: starter.c,v 1.00 2009/10/22 00:00:00 alanmi Exp $]

***********************************************************************/

// To compile on Linux run:  gcc -pthread -o starter starter.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef WIN32
#include "pthread.h"
#else
#include <pthread.h>
#include <unistd.h>
#endif

// the max number of commands to execute from the input file
#define MAX_COMM_NUM 1000

// time printing
#define ABC_PRT(a,t)    (printf("%s = ", (a)), printf("%7.2f sec\n", (float)(t)/(float)(CLOCKS_PER_SEC)))

// the number of currently running threads
static int nThreadsRunning = 0;

// mutext to control access to the number of threads
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// procedure for duplicating strings
char * Abc_UtilStrsav( char * s )   { return s ? strcpy(malloc(strlen(s)+1), s) : NULL;  }

/**Function*************************************************************

  Synopsis    [This procedures executes one call to system().]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void * Abc_RunThread( void * Command )
{
    // perform the call
    if ( system( (char *)Command ) )
    {
        assert(pthread_mutex_lock(&mutex) == 0);
        fprintf( stderr, "The following command has returned non-zero exit status:\n" );
        fprintf( stderr, "\"%s\"\n", (char *)Command );
        fprintf( stderr, "Sorry for the inconvenience.\n" );
        fflush( stdout );
        assert(pthread_mutex_unlock(&mutex) == 0);
    }

    // decrement the number of threads runining 
    assert(pthread_mutex_lock(&mutex) == 0);
    nThreadsRunning--;
    assert(pthread_mutex_unlock(&mutex) == 0);

    // quit this thread
    //printf("...Finishing %s\n", (char *)Command);
    free( Command );
    pthread_exit( NULL );
    assert(0);
    return NULL;
}

/**Function*************************************************************

  Synopsis    [Takes file with commands to be executed and the number of CPUs.]

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int main( int argc, char * argv[] )
{
    FILE * pFile, * pOutput = stdout;
    pthread_t ThreadIds[MAX_COMM_NUM];
    char * pBufferCopy, Buffer[MAX_COMM_NUM];
    int i, nCPUs = 0, nLines = 0, Counter;
    clock_t clk = clock();
    
    // check command line arguments
    if ( argc != 3 )
        { fprintf( stderr, "Wrong number of command line arguments.\n" ); goto usage; }

    // get the number of CPUs
    nCPUs = atoi( argv[1] );
    if ( nCPUs <= 0 )
        { fprintf( pOutput, "Cannot read an integer represting the number of CPUs.\n" ); goto usage; }

    // open the file and make sure it is available
    pFile = fopen( argv[2], "r" );
    if ( pFile == NULL )
        { fprintf( pOutput, "Input file \"%s\" cannot be opened.\n", argv[2] ); goto usage; }

    // read commands and execute at most <num> of them at a time
//    assert(mutex == PTHREAD_MUTEX_INITIALIZER);
    while ( fgets( Buffer, MAX_COMM_NUM, pFile ) != NULL )
    {
        // get the command from the file
        if ( Buffer[0] == '\n' || Buffer[0] == '\r' || Buffer[0] == '\t' || 
             Buffer[0] == ' ' || Buffer[0] == '#')
        {
            continue;
        }

        if ( Buffer[strlen(Buffer)-1] == '\n' )
            Buffer[strlen(Buffer)-1] = 0;
        if ( Buffer[strlen(Buffer)-1] == '\r' )
            Buffer[strlen(Buffer)-1] = 0;

        // wait till there is an empty thread
        while ( 1 )
        {
            assert(pthread_mutex_lock(&mutex) == 0);
            Counter = nThreadsRunning;
            assert(pthread_mutex_unlock(&mutex) == 0);
            if ( Counter < nCPUs - 1 )
                break;
//            Sleep( 100 );
        }

        // increament the number of threads running
        assert(pthread_mutex_lock(&mutex) == 0);
        nThreadsRunning++;
        printf( "Calling:  %s\n", (char *)Buffer );  
        fflush( stdout );
        assert(pthread_mutex_unlock(&mutex) == 0);

        // create thread to execute this command
        pBufferCopy = Abc_UtilStrsav( Buffer );
        assert(pthread_create( &ThreadIds[nLines], NULL, Abc_RunThread, (void *)pBufferCopy ) == 0);
        if ( ++nLines == MAX_COMM_NUM )
            { fprintf( pOutput, "Cannot execute more than %d commands from file \"%s\".\n", nLines, argv[2] ); break; }
    }

    // wait for all the threads to finish
    while ( 1 )
    {
        assert(pthread_mutex_lock(&mutex) == 0);
        Counter = nThreadsRunning;
        assert(pthread_mutex_unlock(&mutex) == 0);
        if ( Counter == 0 )
            break;
    }

    // cleanup
    assert(pthread_mutex_destroy(&mutex) == 0);
//    assert(mutex == NULL);
    fclose( pFile );
    printf( "Finished processing commands in file \"%s\".  ", argv[2] );
    ABC_PRT( "Total time", clock() - clk );
    return 0;

usage: 
    // skip the path name till the binary name
    for ( i = strlen(argv[0]) - 1; i > 0; i-- )
        if ( argv[0][i-1] == '\\' || argv[0][i-1] == '/' )
            break;
    // print usage message
    fprintf( pOutput, "usage: %s <num> <file>\n", argv[0]+i );
    fprintf( pOutput, "       executes command listed in <file> in parallel on <num> CPUs\n" );
    fprintf( pOutput, "\n" );
    return 1;

}