Wednesday, November 25, 2009

blackscholes Perforated Loops

The experimental results show that it is possible to perforate the outer loop in main() without changing the output at all. Further investigation reveals that this loop is superfluous --- it simply repeats the same computation multiple times and was apparently added to the benchmark to increase the workload.

// This function is the main function in the threaded version of blackscholes.  
// It is found in blackscholes.cpp in the blackscholes source code
int bs_thread(void *tid_ptr) {
int i, j, k;
fptype price;
fptype priceDelta;
int tid = *(int *)tid_ptr;
int start = tid * (numOptions / nThreads);
int end = start + (numOptions / nThreads);

#ifdef ENABLE_THREADS
BARRIER(barrier);
#endif

// This loop is perforated, changing j++ to j+=2
for (j=0; j<NUM_RUNS; j++) {
for (i=start; i<end; i++) {
/* Calling main function to calculate option value based on
* Black & Sholes's equation.
*/

if(i%25000 == 0)
heartbeat(&heart);

price = BlkSchlsEqEuroNoDiv( sptprice[i], strike[i],
rate[i], volatility[i], otime[i],
otype[i], 0);

prices[i] = price;

#ifdef ERR_CHK
priceDelta = data[i].DGrefval - price;
if( fabs(priceDelta) >= 1e-5 ){
printf("Error on %d. Computed=%.5f, Ref=%.5f, Delta=%.5f\n",
i, price, data[i].DGrefval, priceDelta);
numError ++;
}
#endif
}
}

return 0;
}


int main (int argc, char **argv)
{
#ifdef PARSEC_VERSION
#define __PARSEC_STRING(x) #x
#define __PARSEC_XSTRING(x) __PARSEC_STRING(x)
printf("PARSEC Benchmark Suite Version "__PARSEC_XSTRING(PARSEC_VERSION)"\n");
fflush(NULL);
#else
printf("PARSEC Benchmark Suite\n");
fflush(NULL);
#endif //PARSEC_VERSION
#ifdef ENABLE_PARSEC_HOOKS
__parsec_bench_begin(__parsec_blackscholes);
#endif

if (argc != 3)
{
printf("Usage:\n\t%s <nthreads> <numOptions>\n", argv[0]);
exit(1);
}
nThreads = atoi(argv[1]);
#ifndef ENABLE_THREADS
if(nThreads != 1) {
printf("Error: <nthreads> must be 1 (serial version)\n");
exit(1);
}
#endif

int i, j;
init_heartbeat(&heart, 0, 100, 20, "heartbeat.log");
numOptions = atoi(argv[2]);
fptype * buffer;
int * buffer2;
// alloc spaces for the option data
data = new OptionData[numOptions];
prices = new fptype[numOptions];
FILE* output=fopen("prices.txt", "w");

// initialize the data array
int initOptionNum = ( (sizeof(data_init)) / sizeof(OptionData) );
for ( int loopnum = 0; loopnum < numOptions; ++ loopnum )
{
OptionData *temp = data_init + loopnum%initOptionNum;
data[loopnum].OptionType = new char[strlen(temp->OptionType)];
strcpy(data[loopnum].OptionType, temp->OptionType);
data[loopnum].s = temp->s;
data[loopnum].strike = temp->strike;
data[loopnum].r = temp->r;
data[loopnum].divq = temp->divq;
data[loopnum].v = temp->v;
data[loopnum].t = temp->t;
data[loopnum].divs = temp->divs;
data[loopnum].DGrefval = temp->DGrefval;
}
#ifdef ENABLE_THREADS
MAIN_INITENV(,8000000,nThreads);
BARINIT(barrier);
#endif
printf("Num of Options: %d\n", numOptions);
printf("Num of Runs: %d\n", NUM_RUNS);

#define PAD 256
#define LINESIZE 64

buffer = (fptype *) malloc(5 * numOptions * sizeof(fptype) + PAD);
sptprice = (fptype *) (((unsigned long long)buffer + PAD) & ~(LINESIZE - 1));
strike = sptprice + numOptions;
rate = strike + numOptions;
volatility = rate + numOptions;
otime = volatility + numOptions;

buffer2 = (int *) malloc(numOptions * sizeof(fptype) + PAD);
otype = (int *) (((unsigned long long)buffer2 + PAD) & ~(LINESIZE - 1));

for (i=0; i<numOptions; i++) {
otype[i] = (data[i].OptionType == "P") ? 1 : 0;
// printf("Option %d, type = %s, otype = %d\n", i, data[i].OptionType, otype[i]);
sptprice[i] = data[i].s;
strike[i] = data[i].strike;
rate[i] = data[i].r;
volatility[i] = data[i].v;
otime[i] = data[i].t;
}

printf("Size of data: %d\n", sizeof(data) + sizeof(otype));

#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_begin();
#endif
#ifdef ENABLE_THREADS
int tids[nThreads];
for(i=0; i<nThreads; i++) {
tids[i]=i;
CREATE_WITH_ARG(bs_thread, &tids[i]);
}
WAIT_FOR_END(nThreads);
#else
int tid=0;
bs_thread(&tid);
#endif //ENABLE_THREADS
#ifdef ENABLE_PARSEC_HOOKS
__parsec_roi_end();
#endif

#ifdef ERR_CHK
printf("Num Errors: %d\n", numError);
#endif
for( int noptions = 0; noptions < numOptions; noptions++) {
fprintf(output, "%f\n", prices[noptions]);
}

for (int loopnum = 0; loopnum < numOptions; ++ loopnum)
{
delete []data[loopnum].OptionType;
}
delete []data;

#ifdef ENABLE_PARSEC_HOOKS
__parsec_bench_end();
#endif
finalize_heartbeat(&heart);

return 1;
}