| /**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; |
| |
| } |
| |