Phil Merkey
Introduction
The website http://www.99-bottles-of-beer.net holds a collection
of programs that generate the song 99 Bottles of Beer.
The collection has programs in more than 990 different languages. The
follow is my humble submission to the collection.
<99bottles.c>=
/*
* UPC (Unified Parallel C: www.upcworld.org) by Phil Merkey
* To run as C program compile: gcc 99bottles.c
* To run as UPC program on a Cray X1
* compile: cc -hupc -hssp 99bottles.c
* run: aprun -n <THREADS> ./a.out
* Other versions of UPC will require the appropriate syntax changes
* for 'fetch_and_minus'
*/
#include <stdio.h>
#include <time.h>
#define ROUNDS 100
#define VERSE_LEN 132
#if __UPC__
#include <upc.h>
#include <intrinsics.h>
shared long counter;
#define fetch_and_minus(A) _amo_afadd((volatile long *)(A), -1)
shared [] char song[ROUNDS*VERSE_LEN];
#else
#define upc_barrier
#define MYTHREAD 0
#define upc_memput memcpy
long counter;
#define fetch_and_minus(A) serial_fetch_and_add((long *)(A), -1)
char song[ROUNDS*VERSE_LEN];
#endif
main()
{
int cnt, offset;
char verse_buf[VERSE_LEN];
srand48(33);
if(MYTHREAD == 0) counter = ROUNDS-1;
upc_barrier;
while(1){
cnt = fetch_and_minus( &counter );
if( cnt < 0 )
break;
offset = build_verse( cnt , verse_buf );
upc_memput( &song[offset], verse_buf, VERSE_LEN );
}
upc_barrier;
if(MYTHREAD == 0 ) printf("%s", (char *) song);
}
/*
* Note that build_verse pulls the bottles off the wall in
* order, takes a random amount of time to complete the task of
* building the verse, then writes it into the correct location
* in the song. This allows each thread to contribute to the
* construction of the song while handling issues of
* load-balancing and synchronization in a trivial way.
*/
int build_verse(int cnt, char *verse)
{
char stash_str[60];
struct timespec surfeiting;
report_stash_str(1, cnt, stash_str );
sprintf(verse,"\n\n%s on the wall, ", stash_str);
report_stash_str(0, cnt, stash_str );
sprintf(verse+strlen(verse),"%s.", stash_str);
surfeiting.tv_sec = 0;
surfeiting.tv_nsec = (ROUNDS-cnt)*(lrand48() % 100000);
nanosleep(&surfeiting, NULL);
if ( cnt == 0 ){
sprintf(verse+strlen(verse), "\nGo to the store and buy some more, ");
report_stash_str(0, ROUNDS-1, stash_str );
sprintf(verse+strlen(verse), "%s on the wall.\n", stash_str);
} else {
sprintf(verse+strlen(verse), "\nTake one down and pass it around, ");
report_stash_str(0, cnt-1, stash_str );
sprintf(verse+strlen(verse), "%s on the wall. ", stash_str);
}
return( (ROUNDS-1-cnt) * VERSE_LEN );
}
report_stash_str(int cap, int nb, char *stash_str )
{
if( nb == 0 )
sprintf(stash_str, "%co more bottles of beer", (cap)?'N':'n' );
else
sprintf(stash_str, "%d bottle%s of beer", nb, (nb>1)?"s":"");
}
int serial_fetch_and_add( long *cntr, int val )
{
int ret;
ret = *cntr;
*cntr += val;
return(ret);
}