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