/* ** nbench0.c */ /******************************************* ** BYTEmark (tm) ** ** BYTE MAGAZINE'S NATIVE MODE BENCHMARKS ** ** FOR CPU/FPU ** ** ver 2.0 ** ** Rick Grehan, BYTE Magazine ** ******************************************** ** NOTE: These benchmarks do NOT check for the presence ** of an FPU. You have to find that out manually. ** ** REVISION HISTORY FOR BENCHMARKS ** 9/94 -- First beta. --RG ** 12/94 -- Bug discovered in some of the integer routines ** (IDEA, Huffman,...). Routines were not accurately counting ** the number of loops. Fixed. --RG (Thanks to Steve A.) ** 12/94 -- Added routines to calculate and display index ** values. Indexes based on DELL XPS 90 (90 MHz Pentium). ** 1/95 -- Added Mac time manager routines for more accurate ** timing on Macintosh (said to be good to 20 usecs) -- RG ** 1/95 -- Re-did all the #defines so they made more ** sense. See NMGLOBAL.H -- RG ** 3/95 -- Fixed memory leak in LU decomposition. Did not ** invalidate previous results, just made it easier to run.--RG ** 3/95 -- Added TOOLHELP.DLL timing routine to Windows timer. --RG */ #include #include #include #include #include #include #include "nmglobal.h" #include "nbench0.h" /************* **** main **** *************/ #ifdef MAC void main(void) #else void main(int argc, char **argv) #endif { int i; /* Index */ time_t time_and_date; /* Self-explanatory */ struct tm *loctime; double bmean; /* Benchmark mean */ double bstdev; /* Benchmark stdev */ double intindex; /* Integer index */ double fpindex; /* Floating-point index */ ulong bnumrun; /* # of runs */ #ifdef MAC MaxApplZone(); #endif #ifdef MACTIMEMGR /* Set up high res timer */ MacHSTdelay=600*1000*1000; /* Delay is 10 minutes */ memset((char *)&myTMTask,0,sizeof(TMTask)); /* Prime and remove the task, calculating overhead */ PrimeTime((QElemPtr)&myTMTask,-MacHSTdelay); RmvTime((QElemPtr)&myTMTask); MacHSTohead=MacHSTdelay+myTMTask.tmCount; #endif #ifdef WIN31TIMER /* Set up the size of the timer info structure */ win31tinfo.dwSize=(DWORD)sizeof(TIMERINFO); /* Load library */ if((hThlp=LoadLibrary("TOOLHELP.DLL"))<32) { printf("Error loading TOOLHELP\n"); exit(0); } if(!(lpfn=GetProcAddress(hThlp,"TimerCount"))) { printf("TOOLHELP error\n"); exit(0); } #endif /* ** Set global parameters to default. */ global_min_ticks=MINIMUM_TICKS; global_min_seconds=MINIMUM_SECONDS; global_allstats=0; global_custrun=0; write_to_file=0; intindex=(double)1.0; fpindex=(double)1.0; /* ** We presume all tests will be run unless told ** otherwise */ for(i=0;i1) for(i=1;i]\n",progname); printf(" -c = Input parameters thru command file \n"); exit(0); } /***************** ** read_comfile ** ****************** ** Read the command file. Set global parameters as ** specified. This routine assumes that the command file ** is already open. */ static void read_comfile(FILE *cfile) { char inbuf[40]; char *eptr; /* Offset to "=" sign */ int i; /* Index */ /* ** Sit in a big loop, reading a line from the file at each ** pass. Terminate on EOF. */ while(fgets(inbuf,39,cfile)!=(char *)NULL) { /* Overwrite the CR character */ if(strlen(inbuf)>0) inbuf[strlen(inbuf)-1]='\0'; /* ** Parse up to the "=" sign. If we don't find an ** "=", then flag an error. */ if((eptr=strchr(inbuf,(int)'='))==(char *)NULL) { printf("**COMMAND FILE ERROR at LINE:\n %s\n", inbuf); goto skipswitch; /* A GOTO!!!! */ } /* ** Insert a null where the "=" was, then convert ** the substring to uppercase. That will enable ** us to perform the match. */ *eptr++='\0'; strtoupper((char *)&inbuf[0]); i=MAXPARAM; do { if(strcmp(inbuf,paramnames[i])==0) break; } while(--i>=0); if(i<0) { printf("**COMMAND FILE ERROR -- UNKNOWN PARAM: %s", inbuf); goto skipswitch; } /* ** Advance eptr to the next field...which should be ** the value assigned to the parameter. */ switch(i) { case PF_GMTICKS: /* GLOBALMINTICKS */ global_min_ticks=(ulong)atol(eptr); break; case PF_MINSECONDS: /* MINSECONDS */ global_min_seconds=(ulong)atol(eptr); set_request_secs(); break; case PF_ALLSTATS: /* ALLSTATS */ global_allstats=getflag(eptr); break; case PF_OUTFILE: /* OUTFILE */ strcpy(global_ofile_name,eptr); global_ofile=fopen(global_ofile_name,"a"); /* ** Open the output file. */ if(global_ofile==(FILE *)NULL) { printf("**Error opening output file: %s\n", global_ofile_name); ErrorExit(); } write_to_file=-1; break; case PF_CUSTOMRUN: /* CUSTOMRUN */ global_custrun=getflag(eptr); for(i=0;i*sdev) { is_beaten=i; sdev_to_beat=*sdev; } } if(is_beaten!=-1) { scores[is_beaten]=*newscore; return(-1); } return(0); } /******************** ** calc_confidence ** ********************* ** Given a set of 5 scores, calculate the confidence ** half-interval. We'l also return the sample mean and sample ** standard deviation. ** NOTE: This routines presumes a confidence of 95% and ** a confidence coefficient of .95 */ static void calc_confidence( double scores[], /* Array of scores */ double *c_half_interval, /* Confidence half-int */ double *smean, /* Standard mean */ double *sdev) /* Sample stand dev */ { int i; /* Index */ /* ** First calculate mean. */ *smean=(scores[0]+scores[1]+scores[2]+scores[3]+scores[4])/ (double)5.0; /* ** Get standard deviation - first get variance */ *sdev=(double)0.0; for(i=0;i<5;i++) { *sdev+=(scores[i]-(*smean))*(scores[i]-(*smean)); } *sdev/=(double)4.0; *sdev=sqrt(*sdev)/sqrt(5.0); /* ** Now calculate the confidence half-interval. ** For a confidence level of 95% our confidence coefficient ** gives us a multiplying factor of 2.776 ** (The upper .025 quartile of a t distribution with 4 degrees ** of freedom.) */ *c_half_interval=(double)2.776 * (*sdev); return; } /************* ** getscore ** ************** ** Return the score for a particular benchmark. */ static double getscore(int fid) { /* ** Fid tells us the function. This is really a matter of ** doing the proper coercion. */ switch(fid) { case TF_NUMSORT: return(global_numsortstruct.sortspersec); case TF_SSORT: return(global_strsortstruct.sortspersec); case TF_BITOP: return(global_bitopstruct.bitopspersec); case TF_FPEMU: return(global_emfloatstruct.emflops); case TF_FFPU: return(global_fourierstruct.fflops); case TF_ASSIGN: return(global_assignstruct.iterspersec); case TF_IDEA: return(global_ideastruct.iterspersec); case TF_HUFF: return(global_huffstruct.iterspersec); case TF_NNET: return(global_nnetstruct.iterspersec); case TF_LU: return(global_lustruct.iterspersec); } return((double)0.0); } /****************** ** output_string ** ******************* ** Displays a string on the screen. Also, if the flag ** write_to_file is set, outputs the string to the output file. ** Note, this routine presumes that you've included a carriage ** return at the end of the buffer. */ static void output_string(char *buffer) { printf("%s",buffer); if(write_to_file!=0) fprintf(global_ofile,"%s",buffer); return; } /*************** ** show_stats ** **************** ** This routine displays statistics for a particular benchmark. ** The benchmark is identified by its id. */ static void show_stats (int bid) { char buffer[80]; /* Display buffer */ switch(bid) { case TF_NUMSORT: /* Numeric sort */ sprintf(buffer," Number of arrays: %d\n", global_numsortstruct.numarrays); output_string(buffer); sprintf(buffer," Array size: %ld\n", global_numsortstruct.arraysize); output_string(buffer); break; case TF_SSORT: /* String sort */ sprintf(buffer," Number of arrays: %d\n", global_strsortstruct.numarrays); output_string(buffer); sprintf(buffer," Array size: %ld\n", global_strsortstruct.arraysize); output_string(buffer); break; case TF_BITOP: /* Bitmap operation */ sprintf(buffer," Operations array size: %ld\n", global_bitopstruct.bitoparraysize); output_string(buffer); sprintf(buffer," Bitfield array size: %ld\n", global_bitopstruct.bitfieldarraysize); output_string(buffer); break; case TF_FPEMU: /* Floating-point emulation */ sprintf(buffer," Number of loops: %lu\n", global_emfloatstruct.loops); output_string(buffer); sprintf(buffer," Array size: %lu\n", global_emfloatstruct.arraysize); output_string(buffer); break; case TF_FFPU: /* Fourier test */ sprintf(buffer," Number of coefficients: %lu\n", global_fourierstruct.arraysize); output_string(buffer); break; case TF_ASSIGN: sprintf(buffer," Number of arrays: %lu\n", global_assignstruct.numarrays); output_string(buffer); break; case TF_IDEA: sprintf(buffer," Array size: %lu\n", global_ideastruct.arraysize); output_string(buffer); sprintf(buffer," Number of loops: %lu\n", global_ideastruct.loops); output_string(buffer); break; case TF_HUFF: sprintf(buffer," Array size: %lu\n", global_huffstruct.arraysize); output_string(buffer); sprintf(buffer," Number of loops: %lu\n", global_huffstruct.loops); output_string(buffer); break; case TF_NNET: sprintf(buffer," Number of loops: %lu\n", global_nnetstruct.loops); output_string(buffer); break; case TF_LU: sprintf(buffer," Number of arrays: %lu\n", global_lustruct.numarrays); output_string(buffer); break; } return; } /* ** Following code added for Mac stuff, so that we can emulate command ** lines. */ #ifdef MAC /***************** ** UCommandLine ** ****************** ** Reads in a command line, and sets up argc and argv appropriately. ** Note that this routine uses gets() to read in the line. This means ** you'd better not enter more than 128 characters on a command line, or ** things will overflow, and oh boy... */ void UCommandLine(void) { printf("Enter command line\n:"); gets((char *)Uargbuff); UParse(); return; } /*********** ** UParse ** ************ ** Parse the pseudo command-line. This code appeared as part of the ** Small-C library in Dr. Dobb's ToolBook of C. ** It expects the following globals: ** argc = arg count ** argv = Pointer to array of char pointers ** Uargbuff = Character array that holds the arguments. Should be 129 bytes long. ** Udummy1 = This is a 2-byte buffer that holds a "*", and acts as the first ** argument in the argument list. This maintains compatibility with other ** C's, though it does not provide access to the executable filename. ** This routine allows for up to 20 individual command-line arguments. ** Also note that this routine does NOT allow for redirection. */ void UParse(void) { unsigned char *ptr; argc=0; /* Start arg count */ Udummy[0]='*'; /* Set dummy first argument */ Udummy[1]='\0'; argv[argc++]=(char *)Udummy; ptr=Uargbuff; /* Start pointer */ while(*ptr) { if(isspace(*ptr)) { ++ptr; continue; } if(argc<20) argv[argc++]=(char *)ptr; ptr=UField(ptr); } return; } /*********** ** UField ** ************ ** Isolate the next command-line field. */ unsigned char *UField(unsigned char *ptr) { while(*ptr) { if(isspace(*ptr)) { *ptr=(unsigned char)NULL; return(++ptr); } ++ptr; } return(ptr); } #endif