| |
| /* |
| ** 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 |
| ** 10/95 -- Added memory array & alignment; moved memory |
| ** allocation out of LU Decomposition -- RG |
| ** |
| ** DISCLAIMER |
| ** The source, executable, and documentation files that comprise |
| ** the BYTEmark benchmarks are made available on an "as is" basis. |
| ** This means that we at BYTE Magazine have made every reasonable |
| ** effort to verify that the there are no errors in the source and |
| ** executable code. We cannot, however, guarantee that the programs |
| ** are error-free. Consequently, McGraw-HIll and BYTE Magazine make |
| ** no claims in regard to the fitness of the source code, executable |
| ** code, and documentation of the BYTEmark. |
| ** Furthermore, BYTE Magazine, McGraw-Hill, and all employees |
| ** of McGraw-Hill cannot be held responsible for any damages resulting |
| ** from the use of this code or the results obtained from using |
| ** this code. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <time.h> |
| #include <math.h> |
| #include "nmglobal.h" |
| #include "nbench0.h" |
| #include "hardware.h" |
| |
| #ifndef N_ITERATIONS |
| #define N_ITERATIONS 1 |
| #endif |
| |
| /************* |
| **** main **** |
| *************/ |
| #ifdef MAC |
| void main(void) |
| #else |
| int main(int argc, char *argv[]) |
| #endif |
| { |
| int i; /* Index */ |
| int iter; |
| time_t time_and_date; /* Self-explanatory */ |
| struct tm *loctime; |
| double bmean; /* Benchmark mean */ |
| double bstdev; /* Benchmark stdev */ |
| double lx_memindex; /* Linux memory index (mainly integer operations)*/ |
| double lx_intindex; /* Linux integer index */ |
| double lx_fpindex; /* Linux floating-point index */ |
| 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; |
| global_align=8; |
| write_to_file=0; |
| lx_memindex=(double)1.0; /* set for geometric mean computations */ |
| lx_intindex=(double)1.0; |
| lx_fpindex=(double)1.0; |
| intindex=(double)1.0; |
| fpindex=(double)1.0; |
| mem_array_ents=0; /* Nothing in mem array */ |
| |
| /* |
| ** We presume all tests will be run unless told |
| ** otherwise |
| */ |
| for(i=0;i<NUMTESTS;i++) |
| tests_to_do[i]=1; |
| |
| /* |
| ** Initialize test data structures to default |
| ** values. |
| */ |
| set_request_secs(); /* Set all request_secs fields */ |
| global_numsortstruct.adjust=0; |
| global_numsortstruct.arraysize=NUMARRAYSIZE; |
| |
| global_strsortstruct.adjust=0; |
| global_strsortstruct.arraysize=STRINGARRAYSIZE; |
| |
| global_bitopstruct.adjust=0; |
| global_bitopstruct.bitfieldarraysize=BITFARRAYSIZE; |
| |
| global_emfloatstruct.adjust=0; |
| global_emfloatstruct.arraysize=EMFARRAYSIZE; |
| |
| global_fourierstruct.adjust=0; |
| |
| global_assignstruct.adjust=0; |
| |
| global_ideastruct.adjust=0; |
| global_ideastruct.arraysize=IDEAARRAYSIZE; |
| |
| global_huffstruct.adjust=0; |
| global_huffstruct.arraysize=HUFFARRAYSIZE; |
| |
| global_nnetstruct.adjust=0; |
| |
| global_lustruct.adjust=0; |
| |
| /* |
| ** For Macintosh -- read the command line. |
| */ |
| #ifdef MAC |
| UCommandLine(); |
| #endif |
| |
| /* |
| ** Handle any command-line arguments. |
| */ |
| if(argc>1) |
| for(i=1;i<argc;i++) |
| if(parse_arg(argv[i])==-1) |
| { display_help(argv[0]); |
| exit(0); |
| } |
| /* |
| ** Output header |
| */ |
| #ifdef LINUX |
| output_string("\nBYTEmark* Native Mode Benchmark ver. 2 (10/95)\n"); |
| output_string("Index-split by Andrew D. Balsa (11/97)\n"); |
| output_string("Linux/Unix* port by Uwe F. Mayer (12/96,11/97)\n"); |
| #else |
| output_string("BBBBBB YYY Y TTTTTTT EEEEEEE\n"); |
| output_string("BBB B YYY Y TTT EEE\n"); |
| output_string("BBB B YYY Y TTT EEE\n"); |
| output_string("BBBBBB YYY Y TTT EEEEEEE\n"); |
| output_string("BBB B YYY TTT EEE\n"); |
| output_string("BBB B YYY TTT EEE\n"); |
| output_string("BBBBBB YYY TTT EEEEEEE\n\n"); |
| output_string("\nBYTEmark (tm) Native Mode Benchmark ver. 2 (10/95)\n"); |
| #endif |
| /* |
| ** See if the user wants all stats. Output heading info |
| ** if so. |
| */ |
| if(global_allstats) |
| { |
| output_string("\n"); |
| output_string("============================== ALL STATISTICS ===============================\n"); |
| time(&time_and_date); |
| loctime=localtime(&time_and_date); |
| sprintf(buffer,"**Date and time of benchmark run: %s",asctime(loctime)); |
| output_string(buffer); |
| sprintf(buffer,"**Sizeof: char:%u short:%u int:%u long:%u u8:%u u16:%u u32:%u int32:%u\n", |
| (unsigned int)sizeof(char), |
| (unsigned int)sizeof(short), |
| (unsigned int)sizeof(int), |
| (unsigned int)sizeof(long), |
| (unsigned int)sizeof(u8), |
| (unsigned int)sizeof(u16), |
| (unsigned int)sizeof(u32), |
| (unsigned int)sizeof(int32)); |
| output_string(buffer); |
| #ifdef LINUX |
| #include "sysinfo.c" |
| #else |
| sprintf(buffer,"**%s\n",sysname); |
| output_string(buffer); |
| sprintf(buffer,"**%s\n",compilername); |
| output_string(buffer); |
| sprintf(buffer,"**%s\n",compilerversion); |
| output_string(buffer); |
| #endif |
| output_string("=============================================================================\n"); |
| } |
| |
| /* |
| ** Execute the tests. |
| */ |
| output_string("\nNOTE!!! Iteration display disabled to prevent diffs from failing!\n"); |
| #ifdef LINUX |
| output_string("\nTEST : Iterations/sec. : Old Index : New Index\n"); |
| output_string(" : : Pentium 90* : AMD K6/233*\n"); |
| output_string("--------------------:------------------:-------------:------------\n"); |
| #endif |
| |
| for(i=0;i<NUMTESTS;i++) |
| { |
| if(tests_to_do[i]) |
| { sprintf(buffer,"%s :",ftestnames[i]); |
| output_string(buffer); |
| #if 0 |
| if (0!=bench_with_confidence(i, |
| &bmean, |
| &bstdev, |
| &bnumrun)){ |
| output_string("\n** WARNING: The current test result is NOT 95 % statistically certain.\n"); |
| output_string("** WARNING: The variation among the individual results is too large.\n"); |
| output_string(" :"); |
| } |
| #endif |
| for (iter = 0; iter < N_ITERATIONS; ++iter) { |
| (*funcpointer[i])(); |
| } |
| #ifdef LINUX |
| sprintf(buffer," %15.5g : %9.2f : %9.2f\n", |
| bmean,bmean/bindex[i],bmean/lx_bindex[i]); |
| #else |
| sprintf(buffer," Iterations/sec.: %13.2f Index: %6.2f\n", |
| /*bmean,bmean/bindex[i],*/ 0.0, 0.0); |
| #endif |
| output_string(buffer); |
| /* |
| ** Gather integer or FP indexes |
| */ |
| if((i==4)||(i==8)||(i==9)){ |
| /* FP index */ |
| fpindex=fpindex*(bmean/bindex[i]); |
| /* Linux FP index */ |
| lx_fpindex=lx_fpindex*(bmean/lx_bindex[i]); |
| } |
| else{ |
| /* Integer index */ |
| intindex=intindex*(bmean/bindex[i]); |
| if((i==0)||(i==3)||(i==6)||(i==7)) |
| /* Linux integer index */ |
| lx_intindex=lx_intindex*(bmean/lx_bindex[i]); |
| else |
| /* Linux memory index */ |
| lx_memindex=lx_memindex*(bmean/lx_bindex[i]); |
| } |
| |
| if(global_allstats) |
| { |
| sprintf(buffer," Absolute standard deviation: %g\n",bstdev); |
| output_string(buffer); |
| if (bmean>(double)1e-100){ |
| /* avoid division by zero */ |
| sprintf(buffer," Relative standard deviation: %g %%\n", |
| (double)100*bstdev/bmean); |
| output_string(buffer); |
| } |
| sprintf(buffer," Number of runs: %lu\n",bnumrun); |
| output_string(buffer); |
| show_stats(i); |
| sprintf(buffer,"Done with %s\n\n",ftestnames[i]); |
| output_string(buffer); |
| } |
| } |
| } |
| /* printf("...done...\n"); */ |
| |
| /* |
| ** Output the total indexes |
| */ |
| if(global_custrun==0) |
| { |
| output_string("==========================ORIGINAL BYTEMARK RESULTS==========================\n"); |
| sprintf(buffer,"INTEGER INDEX : %.3f\n", |
| /*pow(intindex,(double).142857)*/ 0.0); |
| output_string(buffer); |
| sprintf(buffer,"FLOATING-POINT INDEX: %.3f\n", |
| /*pow(fpindex,(double).33333)*/ 0.0); |
| output_string(buffer); |
| output_string("Baseline (MSDOS*) : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0\n"); |
| #ifdef LINUX |
| output_string("==============================LINUX DATA BELOW===============================\n"); |
| hardware(write_to_file, global_ofile); |
| #include "sysinfoc.c" |
| sprintf(buffer,"MEMORY INDEX : %.3f\n", |
| pow(lx_memindex,(double).3333333333)); |
| output_string(buffer); |
| sprintf(buffer,"INTEGER INDEX : %.3f\n", |
| pow(lx_intindex,(double).25)); |
| output_string(buffer); |
| sprintf(buffer,"FLOATING-POINT INDEX: %.3f\n", |
| pow(lx_fpindex,(double).3333333333)); |
| output_string(buffer); |
| output_string("Baseline (LINUX) : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38\n"); |
| #endif |
| output_string("* Trademarks are property of their respective holder.\n"); |
| } |
| |
| exit(0); |
| } |
| |
| /************** |
| ** parse_arg ** |
| *************** |
| ** Given a pointer to a string, we assume that's an argument. |
| ** Parse that argument and act accordingly. |
| ** Return 0 if ok, else return -1. |
| */ |
| static int parse_arg(char *argptr) |
| { |
| int i; /* Index */ |
| FILE *cfile; /* Command file identifier */ |
| |
| /* |
| ** First character has got to be a hyphen. |
| */ |
| if(*argptr++!='-') return(-1); |
| |
| /* |
| ** Convert the rest of the argument to upper case |
| ** so there's little chance of confusion. |
| */ |
| for(i=0;i<strlen(argptr);i++) |
| argptr[i]=(char)toupper((int)argptr[i]); |
| |
| /* |
| ** Next character picks the action. |
| */ |
| switch(*argptr++) |
| { |
| case '?': return(-1); /* Will display help */ |
| |
| case 'V': global_allstats=1; return(0); /* verbose mode */ |
| |
| case 'C': /* Command file name */ |
| /* |
| ** First try to open the file for reading. |
| */ |
| cfile=fopen(argptr,"r"); |
| if(cfile==(FILE *)NULL) |
| { printf("**Error opening file: %s\n",argptr); |
| return(-1); |
| } |
| read_comfile(cfile); /* Read commands */ |
| fclose(cfile); |
| break; |
| default: |
| return(-1); |
| } |
| return(0); |
| } |
| |
| /******************* |
| ** display_help() ** |
| ******************** |
| ** Display a help message showing argument requirements and such. |
| ** Exit when you're done...I mean, REALLY exit. |
| */ |
| void display_help(char *progname) |
| { |
| printf("Usage: %s [-v] [-c<FILE>]\n",progname); |
| printf(" -v = verbose\n"); |
| printf(" -c = input parameters thru command file <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<NUMTESTS;i++) |
| tests_to_do[i]=1-global_custrun; |
| break; |
| |
| case PF_DONUM: /* DONUMSORT */ |
| tests_to_do[TF_NUMSORT]=getflag(eptr); |
| break; |
| |
| case PF_NUMNUMA: /* NUMNUMARRAYS */ |
| global_numsortstruct.numarrays= |
| (ushort)atoi(eptr); |
| global_numsortstruct.adjust=1; |
| break; |
| |
| case PF_NUMASIZE: /* NUMARRAYSIZE */ |
| global_numsortstruct.arraysize= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_NUMMINS: /* NUMMINSECONDS */ |
| global_numsortstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOSTR: /* DOSTRINGSORT */ |
| tests_to_do[TF_SSORT]=getflag(eptr); |
| break; |
| |
| case PF_STRASIZE: /* STRARRAYSIZE */ |
| global_strsortstruct.arraysize= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_NUMSTRA: /* NUMSTRARRAYS */ |
| global_strsortstruct.numarrays= |
| (ushort)atoi(eptr); |
| global_strsortstruct.adjust=1; |
| break; |
| |
| case PF_STRMINS: /* STRMINSECONDS */ |
| global_strsortstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOBITF: /* DOBITFIELD */ |
| tests_to_do[TF_BITOP]=getflag(eptr); |
| break; |
| |
| case PF_NUMBITOPS: /* NUMBITOPS */ |
| global_bitopstruct.bitoparraysize= |
| (ulong)atol(eptr); |
| global_bitopstruct.adjust=1; |
| break; |
| |
| case PF_BITFSIZE: /* BITFIELDSIZE */ |
| global_bitopstruct.bitfieldarraysize= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_BITMINS: /* BITMINSECONDS */ |
| global_bitopstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOEMF: /* DOEMF */ |
| tests_to_do[TF_FPEMU]=getflag(eptr); |
| break; |
| |
| case PF_EMFASIZE: /* EMFARRAYSIZE */ |
| global_emfloatstruct.arraysize= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_EMFLOOPS: /* EMFLOOPS */ |
| global_emfloatstruct.loops= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_EMFMINS: /* EMFMINSECOND */ |
| global_emfloatstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOFOUR: /* DOFOUR */ |
| tests_to_do[TF_FFPU]=getflag(eptr); |
| break; |
| |
| case PF_FOURASIZE: /* FOURASIZE */ |
| global_fourierstruct.arraysize= |
| (ulong)atol(eptr); |
| global_fourierstruct.adjust=1; |
| break; |
| |
| case PF_FOURMINS: /* FOURMINSECONDS */ |
| global_fourierstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOASSIGN: /* DOASSIGN */ |
| tests_to_do[TF_ASSIGN]=getflag(eptr); |
| break; |
| |
| case PF_AARRAYS: /* ASSIGNARRAYS */ |
| global_assignstruct.numarrays= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_ASSIGNMINS: /* ASSIGNMINSECONDS */ |
| global_assignstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOIDEA: /* DOIDEA */ |
| tests_to_do[TF_IDEA]=getflag(eptr); |
| break; |
| |
| case PF_IDEAASIZE: /* IDEAARRAYSIZE */ |
| global_ideastruct.arraysize= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_IDEALOOPS: /* IDEALOOPS */ |
| global_ideastruct.loops= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_IDEAMINS: /* IDEAMINSECONDS */ |
| global_ideastruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOHUFF: /* DOHUFF */ |
| tests_to_do[TF_HUFF]=getflag(eptr); |
| break; |
| |
| case PF_HUFFASIZE: /* HUFFARRAYSIZE */ |
| global_huffstruct.arraysize= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_HUFFLOOPS: /* HUFFLOOPS */ |
| global_huffstruct.loops= |
| (ulong)atol(eptr); |
| global_huffstruct.adjust=1; |
| break; |
| |
| case PF_HUFFMINS: /* HUFFMINSECONDS */ |
| global_huffstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DONNET: /* DONNET */ |
| tests_to_do[TF_NNET]=getflag(eptr); |
| break; |
| |
| case PF_NNETLOOPS: /* NNETLOOPS */ |
| global_nnetstruct.loops= |
| (ulong)atol(eptr); |
| global_nnetstruct.adjust=1; |
| break; |
| |
| case PF_NNETMINS: /* NNETMINSECONDS */ |
| global_nnetstruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_DOLU: /* DOLU */ |
| tests_to_do[TF_LU]=getflag(eptr); |
| break; |
| |
| case PF_LUNARRAYS: /* LUNUMARRAYS */ |
| global_lustruct.numarrays= |
| (ulong)atol(eptr); |
| global_lustruct.adjust=1; |
| break; |
| |
| case PF_LUMINS: /* LUMINSECONDS */ |
| global_lustruct.request_secs= |
| (ulong)atol(eptr); |
| break; |
| |
| case PF_ALIGN: /* ALIGN */ |
| global_align=atoi(eptr); |
| break; |
| } |
| skipswitch: |
| continue; |
| } /* End while */ |
| |
| return; |
| } |
| |
| /************ |
| ** getflag ** |
| ************* |
| ** Return 1 if cptr points to "T"; 0 otherwise. |
| */ |
| static int getflag(char *cptr) |
| { |
| if(toupper((int)*cptr)=='T') return(1); |
| return(0); |
| } |
| |
| /*************** |
| ** strtoupper ** |
| **************** |
| ** Convert's a string to upper case. The string is presumed |
| ** to consist only of alphabetic characters, and to be terminated |
| ** with a null. |
| */ |
| static void strtoupper(char *s) |
| { |
| |
| do { |
| /* |
| ** Oddly enough, the following line did not work under THINK C. |
| ** So, I modified it....hmmmm. --RG |
| *s++=(char)toupper((int)*s); |
| */ |
| *s=(char)toupper((int)*s); |
| s++; |
| } while(*s!=(char)'\0'); |
| return; |
| } |
| |
| /********************* |
| ** set_request_secs ** |
| ********************** |
| ** Set everyone's "request_secs" entry to whatever |
| ** value is in global_min_secs. This is done |
| ** at the beginning, and possibly later if the |
| ** user redefines global_min_secs in the command file. |
| */ |
| static void set_request_secs(void) |
| { |
| |
| global_numsortstruct.request_secs=global_min_seconds; |
| global_strsortstruct.request_secs=global_min_seconds; |
| global_bitopstruct.request_secs=global_min_seconds; |
| global_emfloatstruct.request_secs=global_min_seconds; |
| global_fourierstruct.request_secs=global_min_seconds; |
| global_assignstruct.request_secs=global_min_seconds; |
| global_ideastruct.request_secs=global_min_seconds; |
| global_huffstruct.request_secs=global_min_seconds; |
| global_nnetstruct.request_secs=global_min_seconds; |
| global_lustruct.request_secs=global_min_seconds; |
| |
| return; |
| } |
| |
| |
| /************************** |
| ** bench_with_confidence ** |
| *************************** |
| ** Given a benchmark id that indicates a function, this routine |
| ** repeatedly calls that benchmark, seeking to collect and replace |
| ** scores to get 5 that meet the confidence criteria. |
| ** |
| ** The above is mathematically questionable, as the statistical theory |
| ** depends on independent observations, and if we exchange data points |
| ** depending on what we already have then this certainly violates |
| ** independence of the observations. Hence I changed this so that at |
| ** most 30 observations are done, but none are deleted as we go |
| ** along. We simply do more runs and hope to get a big enough sample |
| ** size so that things stabilize. Uwe F. Mayer |
| ** |
| ** Return 0 if ok, -1 if failure. Returns mean |
| ** and std. deviation of results if successful. |
| */ |
| static int bench_with_confidence(int fid, /* Function id */ |
| double *mean, /* Mean of scores */ |
| double *stdev, /* Standard deviation */ |
| ulong *numtries) /* # of attempts */ |
| { |
| double myscores[30]; /* Need at least 5 scores, use at most 30 */ |
| double c_half_interval; /* Confidence half interval */ |
| int i; /* Index */ |
| /* double newscore; */ /* For improving confidence interval */ |
| |
| /* |
| ** Get first 5 scores. Then begin confidence testing. |
| */ |
| for (i=0;i<5;i++) |
| { (*funcpointer[fid])(); |
| myscores[i]=getscore(fid); |
| #ifdef DEBUG |
| printf("score # %d = %g\n", i, myscores[i]); |
| #endif |
| } |
| *numtries=5; /* Show 5 attempts */ |
| |
| /* |
| ** The system allows a maximum of 30 tries before it gives |
| ** up. Since we've done 5 already, we'll allow 25 more. |
| */ |
| |
| /* |
| ** Enter loop to test for confidence criteria. |
| */ |
| while(1) |
| { |
| /* |
| ** Calculate confidence. Should always return 0. |
| */ |
| if (0!=calc_confidence(myscores, |
| *numtries, |
| &c_half_interval, |
| mean, |
| stdev)) return(-1); |
| |
| /* |
| ** Is the length of the half interval 5% or less of mean? |
| ** If so, we can go home. Otherwise, we have to continue. |
| */ |
| if(c_half_interval/ (*mean) <= (double)0.05) |
| break; |
| |
| #ifdef OLDCODE |
| #undef OLDCODE |
| #endif |
| #ifdef OLDCODE |
| /* this code is no longer valid, we now do not replace but add new scores */ |
| /* Uwe F. Mayer */ |
| /* |
| ** Go get a new score and see if it |
| ** improves existing scores. |
| */ |
| do { |
| if(*numtries==10) |
| return(-1); |
| (*funcpointer[fid])(); |
| *numtries+=1; |
| newscore=getscore(fid); |
| } while(seek_confidence(myscores,&newscore, |
| &c_half_interval,mean,stdev)==0); |
| #endif |
| /* We now simply add a new test run and hope that the runs |
| finally stabilize, Uwe F. Mayer */ |
| if(*numtries==30) return(-1); |
| (*funcpointer[fid])(); |
| myscores[*numtries]=getscore(fid); |
| #ifdef DEBUG |
| printf("score # %ld = %g\n", *numtries, myscores[*numtries]); |
| #endif |
| *numtries+=1; |
| } |
| |
| return(0); |
| } |
| |
| #ifdef OLDCODE |
| /* this procecdure is no longer needed, Uwe F. Mayer */ |
| /******************** |
| ** seek_confidence ** |
| ********************* |
| ** Pass this routine an array of 5 scores PLUS a new score. |
| ** This routine tries the new score in place of each of |
| ** the other five scores to determine if the new score, |
| ** when replacing one of the others, improves the confidence |
| ** half-interval. |
| ** Return 0 if failure. Original 5 scores unchanged. |
| ** Return -1 if success. Also returns new half-interval, |
| ** mean, and standard deviation of the sample. |
| */ |
| static int seek_confidence( double scores[5], |
| double *newscore, |
| double *c_half_interval, |
| double *smean, |
| double *sdev) |
| { |
| double sdev_to_beat; /* Original sdev to be beaten */ |
| double temp; /* For doing a swap */ |
| int is_beaten; /* Indicates original was beaten */ |
| int i; /* Index */ |
| |
| /* |
| ** First calculate original standard deviation |
| */ |
| calc_confidence(scores,c_half_interval,smean,sdev); |
| sdev_to_beat=*sdev; |
| is_beaten=-1; |
| |
| /* |
| ** Try to beat original score. We'll come out of this |
| ** loop with a flag. |
| */ |
| for(i=0;i<5;i++) |
| { |
| temp=scores[i]; |
| scores[i]=*newscore; |
| calc_confidence(scores,c_half_interval,smean,sdev); |
| scores[i]=temp; |
| if(sdev_to_beat>*sdev) |
| { is_beaten=i; |
| sdev_to_beat=*sdev; |
| } |
| } |
| |
| if(is_beaten!=-1) |
| { scores[is_beaten]=*newscore; |
| return(-1); |
| } |
| return(0); |
| } |
| #endif |
| |
| /******************** |
| ** calc_confidence ** |
| ********************* |
| ** Given a set of numtries scores, calculate the confidence |
| ** half-interval. We'll also return the sample mean and sample |
| ** standard deviation. |
| ** NOTE: This routines presumes a confidence of 95% and |
| ** a confidence coefficient of .95 |
| ** returns 0 if there is an error, otherwise -1 |
| */ |
| static int calc_confidence(double scores[], /* Array of scores */ |
| int num_scores, /* number of scores in array */ |
| double *c_half_interval, /* Confidence half-int */ |
| double *smean, /* Standard mean */ |
| double *sdev) /* Sample stand dev */ |
| { |
| /* Here is a list of the student-t distribution up to 29 degrees of |
| freedom. The value at 0 is bogus, as there is no value for zero |
| degrees of freedom. */ |
| double student_t[30]={0.0 , 12.706 , 4.303 , 3.182 , 2.776 , 2.571 , |
| 2.447 , 2.365 , 2.306 , 2.262 , 2.228 , |
| 2.201 , 2.179 , 2.160 , 2.145 , 2.131 , |
| 2.120 , 2.110 , 2.101 , 2.093 , 2.086 , |
| 2.080 , 2.074 , 2.069 , 2.064 , 2.060 , |
| 2.056 , 2.052 , 2.048 , 2.045 }; |
| int i; /* Index */ |
| if ((num_scores<2) || (num_scores>30)) { |
| output_string("Internal error: calc_confidence called with an illegal number of scores\n"); |
| return(-1); |
| } |
| /* |
| ** First calculate mean. |
| */ |
| *smean=(double)0.0; |
| for(i=0;i<num_scores;i++){ |
| *smean+=scores[i]; |
| } |
| *smean/=(double)num_scores; |
| |
| /* Get standard deviation */ |
| *sdev=(double)0.0; |
| for(i=0;i<num_scores;i++) { |
| *sdev+=(scores[i]-(*smean))*(scores[i]-(*smean)); |
| } |
| *sdev/=(double)(num_scores-1); |
| *sdev=sqrt(*sdev); |
| |
| /* Now calculate the length of the confidence half-interval. For a |
| ** confidence level of 95% our confidence coefficient gives us a |
| ** multiplying factor of the upper .025 quartile of a t distribution |
| ** with num_scores-1 degrees of freedom, and dividing by sqrt(number of |
| ** observations). See any introduction to statistics. |
| */ |
| *c_half_interval=student_t[num_scores-1] * (*sdev) / sqrt((double)num_scores); |
| return(0); |
| } |
| |
| /************* |
| ** 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 |