191 lines
5.7 KiB
C
191 lines
5.7 KiB
C
/**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;
|
|
|
|
}
|
|
|