1
2 /*
3 ** nbench0.c
4 */
5
6 /*******************************************
7 ** BYTEmark (tm) **
8 ** BYTE MAGAZINE'S NATIVE MODE BENCHMARKS **
9 ** FOR CPU/FPU **
10 ** ver 2.0 **
11 ** Rick Grehan, BYTE Magazine **
12 ********************************************
13 ** NOTE: These benchmarks do NOT check for the presence
14 ** of an FPU. You have to find that out manually.
15 **
16 ** REVISION HISTORY FOR BENCHMARKS
17 ** 9/94 -- First beta. --RG
18 ** 12/94 -- Bug discovered in some of the integer routines
19 ** (IDEA, Huffman,...). Routines were not accurately counting
20 ** the number of loops. Fixed. --RG (Thanks to Steve A.)
21 ** 12/94 -- Added routines to calculate and display index
22 ** values. Indexes based on DELL XPS 90 (90 MHz Pentium).
23 ** 1/95 -- Added Mac time manager routines for more accurate
24 ** timing on Macintosh (said to be good to 20 usecs) -- RG
25 ** 1/95 -- Re-did all the #defines so they made more
26 ** sense. See NMGLOBAL.H -- RG
27 ** 3/95 -- Fixed memory leak in LU decomposition. Did not
28 ** invalidate previous results, just made it easier to run.--RG
29 ** 3/95 -- Added TOOLHELP.DLL timing routine to Windows timer. --RG
30 ** 10/95 -- Added memory array & alignment; moved memory
31 ** allocation out of LU Decomposition -- RG
32 **
33 ** DISCLAIMER
34 ** The source, executable, and documentation files that comprise
35 ** the BYTEmark benchmarks are made available on an "as is" basis.
36 ** This means that we at BYTE Magazine have made every reasonable
37 ** effort to verify that the there are no errors in the source and
38 ** executable code. We cannot, however, guarantee that the programs
39 ** are error-free. Consequently, McGraw-HIll and BYTE Magazine make
40 ** no claims in regard to the fitness of the source code, executable
41 ** code, and documentation of the BYTEmark.
42 ** Furthermore, BYTE Magazine, McGraw-Hill, and all employees
43 ** of McGraw-Hill cannot be held responsible for any damages resulting
44 ** from the use of this code or the results obtained from using
45 ** this code.
46 */
47
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <ctype.h>
51 #include <string.h>
52 #include <time.h>
53 #include <math.h>
54 #include "nmglobal.h"
55 #include "nbench0.h"
56 #include "hardware.h"
57
58 /*************
59 **** main ****
60 *************/
61 #ifdef MAC
main(void)62 void main(void)
63 #else
64 int main(int argc, char *argv[])
65 #endif
66 {
67 int i; /* Index */
68 time_t time_and_date; /* Self-explanatory */
69 struct tm *loctime;
70 double bmean; /* Benchmark mean */
71 double bstdev; /* Benchmark stdev */
72 double lx_memindex; /* Linux memory index (mainly integer operations)*/
73 double lx_intindex; /* Linux integer index */
74 double lx_fpindex; /* Linux floating-point index */
75 double intindex; /* Integer index */
76 double fpindex; /* Floating-point index */
77 ulong bnumrun; /* # of runs */
78
79 #ifdef MAC
80 MaxApplZone();
81 #endif
82
83 #ifdef MACTIMEMGR
84 /* Set up high res timer */
85 MacHSTdelay=600*1000*1000; /* Delay is 10 minutes */
86
87 memset((char *)&myTMTask,0,sizeof(TMTask));
88
89 /* Prime and remove the task, calculating overhead */
90 PrimeTime((QElemPtr)&myTMTask,-MacHSTdelay);
91 RmvTime((QElemPtr)&myTMTask);
92 MacHSTohead=MacHSTdelay+myTMTask.tmCount;
93 #endif
94
95 #ifdef WIN31TIMER
96 /* Set up the size of the timer info structure */
97 win31tinfo.dwSize=(DWORD)sizeof(TIMERINFO);
98 /* Load library */
99 if((hThlp=LoadLibrary("TOOLHELP.DLL"))<32)
100 { printf("Error loading TOOLHELP\n");
101 exit(0);
102 }
103 if(!(lpfn=GetProcAddress(hThlp,"TimerCount")))
104 { printf("TOOLHELP error\n");
105 exit(0);
106 }
107 #endif
108
109 /*
110 ** Set global parameters to default.
111 */
112 global_min_ticks=MINIMUM_TICKS;
113 global_min_seconds=MINIMUM_SECONDS;
114 global_allstats=0;
115 global_custrun=0;
116 global_align=8;
117 write_to_file=0;
118 lx_memindex=(double)1.0; /* set for geometric mean computations */
119 lx_intindex=(double)1.0;
120 lx_fpindex=(double)1.0;
121 intindex=(double)1.0;
122 fpindex=(double)1.0;
123 mem_array_ents=0; /* Nothing in mem array */
124
125 /*
126 ** We presume all tests will be run unless told
127 ** otherwise
128 */
129 for(i=0;i<NUMTESTS;i++)
130 tests_to_do[i]=1;
131
132 /*
133 ** Initialize test data structures to default
134 ** values.
135 */
136 set_request_secs(); /* Set all request_secs fields */
137 global_numsortstruct.adjust=0;
138 global_numsortstruct.arraysize=NUMARRAYSIZE;
139
140 global_strsortstruct.adjust=0;
141 global_strsortstruct.arraysize=STRINGARRAYSIZE;
142
143 global_bitopstruct.adjust=0;
144 global_bitopstruct.bitfieldarraysize=BITFARRAYSIZE;
145
146 global_emfloatstruct.adjust=0;
147 global_emfloatstruct.arraysize=EMFARRAYSIZE;
148
149 global_fourierstruct.adjust=0;
150
151 global_assignstruct.adjust=0;
152
153 global_ideastruct.adjust=0;
154 global_ideastruct.arraysize=IDEAARRAYSIZE;
155
156 global_huffstruct.adjust=0;
157 global_huffstruct.arraysize=HUFFARRAYSIZE;
158
159 global_nnetstruct.adjust=0;
160
161 global_lustruct.adjust=0;
162
163 /*
164 ** For Macintosh -- read the command line.
165 */
166 #ifdef MAC
167 UCommandLine();
168 #endif
169
170 /*
171 ** Handle any command-line arguments.
172 */
173 if(argc>1)
174 for(i=1;i<argc;i++)
175 if(parse_arg(argv[i])==-1)
176 { display_help(argv[0]);
177 exit(0);
178 }
179 /*
180 ** Output header
181 */
182 #ifdef LINUX
183 output_string("\nBYTEmark* Native Mode Benchmark ver. 2 (10/95)\n");
184 output_string("Index-split by Andrew D. Balsa (11/97)\n");
185 output_string("Linux/Unix* port by Uwe F. Mayer (12/96,11/97)\n");
186 #else
187 output_string("BBBBBB YYY Y TTTTTTT EEEEEEE\n");
188 output_string("BBB B YYY Y TTT EEE\n");
189 output_string("BBB B YYY Y TTT EEE\n");
190 output_string("BBBBBB YYY Y TTT EEEEEEE\n");
191 output_string("BBB B YYY TTT EEE\n");
192 output_string("BBB B YYY TTT EEE\n");
193 output_string("BBBBBB YYY TTT EEEEEEE\n\n");
194 output_string("\nBYTEmark (tm) Native Mode Benchmark ver. 2 (10/95)\n");
195 #endif
196 /*
197 ** See if the user wants all stats. Output heading info
198 ** if so.
199 */
200 if(global_allstats)
201 {
202 output_string("\n");
203 output_string("============================== ALL STATISTICS ===============================\n");
204 time(&time_and_date);
205 loctime=localtime(&time_and_date);
206 sprintf(buffer,"**Date and time of benchmark run: %s",asctime(loctime));
207 output_string(buffer);
208 sprintf(buffer,"**Sizeof: char:%u short:%u int:%u long:%u u8:%u u16:%u u32:%u int32:%u\n",
209 (unsigned int)sizeof(char),
210 (unsigned int)sizeof(short),
211 (unsigned int)sizeof(int),
212 (unsigned int)sizeof(long),
213 (unsigned int)sizeof(u8),
214 (unsigned int)sizeof(u16),
215 (unsigned int)sizeof(u32),
216 (unsigned int)sizeof(int32));
217 output_string(buffer);
218 #ifdef LINUX
219 #include "sysinfo.c"
220 #else
221 sprintf(buffer,"**%s\n",sysname);
222 output_string(buffer);
223 sprintf(buffer,"**%s\n",compilername);
224 output_string(buffer);
225 sprintf(buffer,"**%s\n",compilerversion);
226 output_string(buffer);
227 #endif
228 output_string("=============================================================================\n");
229 }
230
231 /*
232 ** Execute the tests.
233 */
234 #ifdef LINUX
235 output_string("\nTEST : Iterations/sec. : Old Index : New Index\n");
236 output_string(" : : Pentium 90* : AMD K6/233*\n");
237 output_string("--------------------:------------------:-------------:------------\n");
238 #endif
239
240 for(i=0;i<NUMTESTS;i++)
241 {
242 if(tests_to_do[i])
243 { sprintf(buffer,"%s :",ftestnames[i]);
244 output_string(buffer);
245 if (0!=bench_with_confidence(i,
246 &bmean,
247 &bstdev,
248 &bnumrun)){
249 output_string("\n** WARNING: The current test result is NOT 95 % statistically certain.\n");
250 output_string("** WARNING: The variation among the individual results is too large.\n");
251 output_string(" :");
252 }
253 #ifdef LINUX
254 sprintf(buffer," %15.5g : %9.2f : %9.2f\n",
255 bmean,bmean/bindex[i],bmean/lx_bindex[i]);
256 #else
257 sprintf(buffer," Iterations/sec.: %13.2f Index: %6.2f\n",
258 bmean,bmean/bindex[i]);
259 #endif
260 output_string(buffer);
261 /*
262 ** Gather integer or FP indexes
263 */
264 if((i==4)||(i==8)||(i==9)){
265 /* FP index */
266 fpindex=fpindex*(bmean/bindex[i]);
267 /* Linux FP index */
268 lx_fpindex=lx_fpindex*(bmean/lx_bindex[i]);
269 }
270 else{
271 /* Integer index */
272 intindex=intindex*(bmean/bindex[i]);
273 if((i==0)||(i==3)||(i==6)||(i==7))
274 /* Linux integer index */
275 lx_intindex=lx_intindex*(bmean/lx_bindex[i]);
276 else
277 /* Linux memory index */
278 lx_memindex=lx_memindex*(bmean/lx_bindex[i]);
279 }
280
281 if(global_allstats)
282 {
283 sprintf(buffer," Absolute standard deviation: %g\n",bstdev);
284 output_string(buffer);
285 if (bmean>(double)1e-100){
286 /* avoid division by zero */
287 sprintf(buffer," Relative standard deviation: %g %%\n",
288 (double)100*bstdev/bmean);
289 output_string(buffer);
290 }
291 sprintf(buffer," Number of runs: %lu\n",bnumrun);
292 output_string(buffer);
293 show_stats(i);
294 sprintf(buffer,"Done with %s\n\n",ftestnames[i]);
295 output_string(buffer);
296 }
297 }
298 }
299 /* printf("...done...\n"); */
300
301 /*
302 ** Output the total indexes
303 */
304 if(global_custrun==0)
305 {
306 output_string("==========================ORIGINAL BYTEMARK RESULTS==========================\n");
307 sprintf(buffer,"INTEGER INDEX : %.3f\n",
308 pow(intindex,(double).142857));
309 output_string(buffer);
310 sprintf(buffer,"FLOATING-POINT INDEX: %.3f\n",
311 pow(fpindex,(double).33333));
312 output_string(buffer);
313 output_string("Baseline (MSDOS*) : Pentium* 90, 256 KB L2-cache, Watcom* compiler 10.0\n");
314 #ifdef LINUX
315 output_string("==============================LINUX DATA BELOW===============================\n");
316 hardware(write_to_file, global_ofile);
317 #include "sysinfoc.c"
318 sprintf(buffer,"MEMORY INDEX : %.3f\n",
319 pow(lx_memindex,(double).3333333333));
320 output_string(buffer);
321 sprintf(buffer,"INTEGER INDEX : %.3f\n",
322 pow(lx_intindex,(double).25));
323 output_string(buffer);
324 sprintf(buffer,"FLOATING-POINT INDEX: %.3f\n",
325 pow(lx_fpindex,(double).3333333333));
326 output_string(buffer);
327 output_string("Baseline (LINUX) : AMD K6/233*, 512 KB L2-cache, gcc 2.7.2.3, libc-5.4.38\n");
328 #endif
329 output_string("* Trademarks are property of their respective holder.\n");
330 }
331
332 exit(0);
333 }
334
335 /**************
336 ** parse_arg **
337 ***************
338 ** Given a pointer to a string, we assume that's an argument.
339 ** Parse that argument and act accordingly.
340 ** Return 0 if ok, else return -1.
341 */
parse_arg(char * argptr)342 static int parse_arg(char *argptr)
343 {
344 int i; /* Index */
345 FILE *cfile; /* Command file identifier */
346
347 /*
348 ** First character has got to be a hyphen.
349 */
350 if(*argptr++!='-') return(-1);
351
352 /*
353 ** Convert the rest of the argument to upper case
354 ** so there's little chance of confusion.
355 */
356 for(i=0;i<strlen(argptr);i++)
357 argptr[i]=(char)toupper((int)argptr[i]);
358
359 /*
360 ** Next character picks the action.
361 */
362 switch(*argptr++)
363 {
364 case '?': return(-1); /* Will display help */
365
366 case 'V': global_allstats=1; return(0); /* verbose mode */
367
368 case 'C': /* Command file name */
369 /*
370 ** First try to open the file for reading.
371 */
372 cfile=fopen(argptr,"r");
373 if(cfile==(FILE *)NULL)
374 { printf("**Error opening file: %s\n",argptr);
375 return(-1);
376 }
377 read_comfile(cfile); /* Read commands */
378 fclose(cfile);
379 break;
380 default:
381 return(-1);
382 }
383 return(0);
384 }
385
386 /*******************
387 ** display_help() **
388 ********************
389 ** Display a help message showing argument requirements and such.
390 ** Exit when you're done...I mean, REALLY exit.
391 */
display_help(char * progname)392 void display_help(char *progname)
393 {
394 printf("Usage: %s [-v] [-c<FILE>]\n",progname);
395 printf(" -v = verbose\n");
396 printf(" -c = input parameters thru command file <FILE>\n");
397 exit(0);
398 }
399
400
401 /*****************
402 ** read_comfile **
403 ******************
404 ** Read the command file. Set global parameters as
405 ** specified. This routine assumes that the command file
406 ** is already open.
407 */
read_comfile(FILE * cfile)408 static void read_comfile(FILE *cfile)
409 {
410 char inbuf[40];
411 char *eptr; /* Offset to "=" sign */
412 int i; /* Index */
413
414 /*
415 ** Sit in a big loop, reading a line from the file at each
416 ** pass. Terminate on EOF.
417 */
418 while(fgets(inbuf,39,cfile)!=(char *)NULL)
419 {
420 /* Overwrite the CR character */
421 if(strlen(inbuf)>0)
422 inbuf[strlen(inbuf)-1]='\0';
423
424 /*
425 ** Parse up to the "=" sign. If we don't find an
426 ** "=", then flag an error.
427 */
428 if((eptr=strchr(inbuf,(int)'='))==(char *)NULL)
429 { printf("**COMMAND FILE ERROR at LINE:\n %s\n",
430 inbuf);
431 goto skipswitch; /* A GOTO!!!! */
432 }
433
434 /*
435 ** Insert a null where the "=" was, then convert
436 ** the substring to uppercase. That will enable
437 ** us to perform the match.
438 */
439 *eptr++='\0';
440 strtoupper((char *)&inbuf[0]);
441 i=MAXPARAM;
442 do {
443 if(strcmp(inbuf,paramnames[i])==0)
444 break;
445 } while(--i>=0);
446
447 if(i<0)
448 { printf("**COMMAND FILE ERROR -- UNKNOWN PARAM: %s",
449 inbuf);
450 goto skipswitch;
451 }
452
453 /*
454 ** Advance eptr to the next field...which should be
455 ** the value assigned to the parameter.
456 */
457 switch(i)
458 {
459 case PF_GMTICKS: /* GLOBALMINTICKS */
460 global_min_ticks=(ulong)atol(eptr);
461 break;
462
463 case PF_MINSECONDS: /* MINSECONDS */
464 global_min_seconds=(ulong)atol(eptr);
465 set_request_secs();
466 break;
467
468 case PF_ALLSTATS: /* ALLSTATS */
469 global_allstats=getflag(eptr);
470 break;
471
472 case PF_OUTFILE: /* OUTFILE */
473 strcpy(global_ofile_name,eptr);
474 global_ofile=fopen(global_ofile_name,"a");
475 /*
476 ** Open the output file.
477 */
478 if(global_ofile==(FILE *)NULL)
479 { printf("**Error opening output file: %s\n",
480 global_ofile_name);
481 ErrorExit();
482 }
483 write_to_file=-1;
484 break;
485
486 case PF_CUSTOMRUN: /* CUSTOMRUN */
487 global_custrun=getflag(eptr);
488 for(i=0;i<NUMTESTS;i++)
489 tests_to_do[i]=1-global_custrun;
490 break;
491
492 case PF_DONUM: /* DONUMSORT */
493 tests_to_do[TF_NUMSORT]=getflag(eptr);
494 break;
495
496 case PF_NUMNUMA: /* NUMNUMARRAYS */
497 global_numsortstruct.numarrays=
498 (ushort)atoi(eptr);
499 global_numsortstruct.adjust=1;
500 break;
501
502 case PF_NUMASIZE: /* NUMARRAYSIZE */
503 global_numsortstruct.arraysize=
504 (ulong)atol(eptr);
505 break;
506
507 case PF_NUMMINS: /* NUMMINSECONDS */
508 global_numsortstruct.request_secs=
509 (ulong)atol(eptr);
510 break;
511
512 case PF_DOSTR: /* DOSTRINGSORT */
513 tests_to_do[TF_SSORT]=getflag(eptr);
514 break;
515
516 case PF_STRASIZE: /* STRARRAYSIZE */
517 global_strsortstruct.arraysize=
518 (ulong)atol(eptr);
519 break;
520
521 case PF_NUMSTRA: /* NUMSTRARRAYS */
522 global_strsortstruct.numarrays=
523 (ushort)atoi(eptr);
524 global_strsortstruct.adjust=1;
525 break;
526
527 case PF_STRMINS: /* STRMINSECONDS */
528 global_strsortstruct.request_secs=
529 (ulong)atol(eptr);
530 break;
531
532 case PF_DOBITF: /* DOBITFIELD */
533 tests_to_do[TF_BITOP]=getflag(eptr);
534 break;
535
536 case PF_NUMBITOPS: /* NUMBITOPS */
537 global_bitopstruct.bitoparraysize=
538 (ulong)atol(eptr);
539 global_bitopstruct.adjust=1;
540 break;
541
542 case PF_BITFSIZE: /* BITFIELDSIZE */
543 global_bitopstruct.bitfieldarraysize=
544 (ulong)atol(eptr);
545 break;
546
547 case PF_BITMINS: /* BITMINSECONDS */
548 global_bitopstruct.request_secs=
549 (ulong)atol(eptr);
550 break;
551
552 case PF_DOEMF: /* DOEMF */
553 tests_to_do[TF_FPEMU]=getflag(eptr);
554 break;
555
556 case PF_EMFASIZE: /* EMFARRAYSIZE */
557 global_emfloatstruct.arraysize=
558 (ulong)atol(eptr);
559 break;
560
561 case PF_EMFLOOPS: /* EMFLOOPS */
562 global_emfloatstruct.loops=
563 (ulong)atol(eptr);
564 break;
565
566 case PF_EMFMINS: /* EMFMINSECOND */
567 global_emfloatstruct.request_secs=
568 (ulong)atol(eptr);
569 break;
570
571 case PF_DOFOUR: /* DOFOUR */
572 tests_to_do[TF_FFPU]=getflag(eptr);
573 break;
574
575 case PF_FOURASIZE: /* FOURASIZE */
576 global_fourierstruct.arraysize=
577 (ulong)atol(eptr);
578 global_fourierstruct.adjust=1;
579 break;
580
581 case PF_FOURMINS: /* FOURMINSECONDS */
582 global_fourierstruct.request_secs=
583 (ulong)atol(eptr);
584 break;
585
586 case PF_DOASSIGN: /* DOASSIGN */
587 tests_to_do[TF_ASSIGN]=getflag(eptr);
588 break;
589
590 case PF_AARRAYS: /* ASSIGNARRAYS */
591 global_assignstruct.numarrays=
592 (ulong)atol(eptr);
593 break;
594
595 case PF_ASSIGNMINS: /* ASSIGNMINSECONDS */
596 global_assignstruct.request_secs=
597 (ulong)atol(eptr);
598 break;
599
600 case PF_DOIDEA: /* DOIDEA */
601 tests_to_do[TF_IDEA]=getflag(eptr);
602 break;
603
604 case PF_IDEAASIZE: /* IDEAARRAYSIZE */
605 global_ideastruct.arraysize=
606 (ulong)atol(eptr);
607 break;
608
609 case PF_IDEALOOPS: /* IDEALOOPS */
610 global_ideastruct.loops=
611 (ulong)atol(eptr);
612 break;
613
614 case PF_IDEAMINS: /* IDEAMINSECONDS */
615 global_ideastruct.request_secs=
616 (ulong)atol(eptr);
617 break;
618
619 case PF_DOHUFF: /* DOHUFF */
620 tests_to_do[TF_HUFF]=getflag(eptr);
621 break;
622
623 case PF_HUFFASIZE: /* HUFFARRAYSIZE */
624 global_huffstruct.arraysize=
625 (ulong)atol(eptr);
626 break;
627
628 case PF_HUFFLOOPS: /* HUFFLOOPS */
629 global_huffstruct.loops=
630 (ulong)atol(eptr);
631 global_huffstruct.adjust=1;
632 break;
633
634 case PF_HUFFMINS: /* HUFFMINSECONDS */
635 global_huffstruct.request_secs=
636 (ulong)atol(eptr);
637 break;
638
639 case PF_DONNET: /* DONNET */
640 tests_to_do[TF_NNET]=getflag(eptr);
641 break;
642
643 case PF_NNETLOOPS: /* NNETLOOPS */
644 global_nnetstruct.loops=
645 (ulong)atol(eptr);
646 global_nnetstruct.adjust=1;
647 break;
648
649 case PF_NNETMINS: /* NNETMINSECONDS */
650 global_nnetstruct.request_secs=
651 (ulong)atol(eptr);
652 break;
653
654 case PF_DOLU: /* DOLU */
655 tests_to_do[TF_LU]=getflag(eptr);
656 break;
657
658 case PF_LUNARRAYS: /* LUNUMARRAYS */
659 global_lustruct.numarrays=
660 (ulong)atol(eptr);
661 global_lustruct.adjust=1;
662 break;
663
664 case PF_LUMINS: /* LUMINSECONDS */
665 global_lustruct.request_secs=
666 (ulong)atol(eptr);
667 break;
668
669 case PF_ALIGN: /* ALIGN */
670 global_align=atoi(eptr);
671 break;
672 }
673 skipswitch:
674 continue;
675 } /* End while */
676
677 return;
678 }
679
680 /************
681 ** getflag **
682 *************
683 ** Return 1 if cptr points to "T"; 0 otherwise.
684 */
getflag(char * cptr)685 static int getflag(char *cptr)
686 {
687 if(toupper((int)*cptr)=='T') return(1);
688 return(0);
689 }
690
691 /***************
692 ** strtoupper **
693 ****************
694 ** Convert's a string to upper case. The string is presumed
695 ** to consist only of alphabetic characters, and to be terminated
696 ** with a null.
697 */
strtoupper(char * s)698 static void strtoupper(char *s)
699 {
700
701 do {
702 /*
703 ** Oddly enough, the following line did not work under THINK C.
704 ** So, I modified it....hmmmm. --RG
705 *s++=(char)toupper((int)*s);
706 */
707 *s=(char)toupper((int)*s);
708 s++;
709 } while(*s!=(char)'\0');
710 return;
711 }
712
713 /*********************
714 ** set_request_secs **
715 **********************
716 ** Set everyone's "request_secs" entry to whatever
717 ** value is in global_min_secs. This is done
718 ** at the beginning, and possibly later if the
719 ** user redefines global_min_secs in the command file.
720 */
set_request_secs(void)721 static void set_request_secs(void)
722 {
723
724 global_numsortstruct.request_secs=global_min_seconds;
725 global_strsortstruct.request_secs=global_min_seconds;
726 global_bitopstruct.request_secs=global_min_seconds;
727 global_emfloatstruct.request_secs=global_min_seconds;
728 global_fourierstruct.request_secs=global_min_seconds;
729 global_assignstruct.request_secs=global_min_seconds;
730 global_ideastruct.request_secs=global_min_seconds;
731 global_huffstruct.request_secs=global_min_seconds;
732 global_nnetstruct.request_secs=global_min_seconds;
733 global_lustruct.request_secs=global_min_seconds;
734
735 return;
736 }
737
738
739 /**************************
740 ** bench_with_confidence **
741 ***************************
742 ** Given a benchmark id that indicates a function, this routine
743 ** repeatedly calls that benchmark, seeking to collect and replace
744 ** scores to get 5 that meet the confidence criteria.
745 **
746 ** The above is mathematically questionable, as the statistical theory
747 ** depends on independent observations, and if we exchange data points
748 ** depending on what we already have then this certainly violates
749 ** independence of the observations. Hence I changed this so that at
750 ** most 30 observations are done, but none are deleted as we go
751 ** along. We simply do more runs and hope to get a big enough sample
752 ** size so that things stabilize. Uwe F. Mayer
753 **
754 ** Return 0 if ok, -1 if failure. Returns mean
755 ** and std. deviation of results if successful.
756 */
bench_with_confidence(int fid,double * mean,double * stdev,ulong * numtries)757 static int bench_with_confidence(int fid, /* Function id */
758 double *mean, /* Mean of scores */
759 double *stdev, /* Standard deviation */
760 ulong *numtries) /* # of attempts */
761 {
762 double myscores[30]; /* Need at least 5 scores, use at most 30 */
763 double c_half_interval; /* Confidence half interval */
764 int i; /* Index */
765 /* double newscore; */ /* For improving confidence interval */
766
767 /*
768 ** Get first 5 scores. Then begin confidence testing.
769 */
770 for (i=0;i<5;i++)
771 { (*funcpointer[fid])();
772 myscores[i]=getscore(fid);
773 #ifdef DEBUG
774 printf("score # %d = %g\n", i, myscores[i]);
775 #endif
776 }
777 *numtries=5; /* Show 5 attempts */
778
779 /*
780 ** The system allows a maximum of 30 tries before it gives
781 ** up. Since we've done 5 already, we'll allow 25 more.
782 */
783
784 /*
785 ** Enter loop to test for confidence criteria.
786 */
787 while(1)
788 {
789 /*
790 ** Calculate confidence. Should always return 0.
791 */
792 if (0!=calc_confidence(myscores,
793 *numtries,
794 &c_half_interval,
795 mean,
796 stdev)) return(-1);
797
798 /*
799 ** Is the length of the half interval 5% or less of mean?
800 ** If so, we can go home. Otherwise, we have to continue.
801 */
802 if(c_half_interval/ (*mean) <= (double)0.05)
803 break;
804
805 #ifdef OLDCODE
806 #undef OLDCODE
807 #endif
808 #ifdef OLDCODE
809 /* this code is no longer valid, we now do not replace but add new scores */
810 /* Uwe F. Mayer */
811 /*
812 ** Go get a new score and see if it
813 ** improves existing scores.
814 */
815 do {
816 if(*numtries==10)
817 return(-1);
818 (*funcpointer[fid])();
819 *numtries+=1;
820 newscore=getscore(fid);
821 } while(seek_confidence(myscores,&newscore,
822 &c_half_interval,mean,stdev)==0);
823 #endif
824 /* We now simply add a new test run and hope that the runs
825 finally stabilize, Uwe F. Mayer */
826 if(*numtries==30) return(-1);
827 (*funcpointer[fid])();
828 myscores[*numtries]=getscore(fid);
829 #ifdef DEBUG
830 printf("score # %ld = %g\n", *numtries, myscores[*numtries]);
831 #endif
832 *numtries+=1;
833 }
834
835 return(0);
836 }
837
838 #ifdef OLDCODE
839 /* this procecdure is no longer needed, Uwe F. Mayer */
840 /********************
841 ** seek_confidence **
842 *********************
843 ** Pass this routine an array of 5 scores PLUS a new score.
844 ** This routine tries the new score in place of each of
845 ** the other five scores to determine if the new score,
846 ** when replacing one of the others, improves the confidence
847 ** half-interval.
848 ** Return 0 if failure. Original 5 scores unchanged.
849 ** Return -1 if success. Also returns new half-interval,
850 ** mean, and standard deviation of the sample.
851 */
seek_confidence(double scores[5],double * newscore,double * c_half_interval,double * smean,double * sdev)852 static int seek_confidence( double scores[5],
853 double *newscore,
854 double *c_half_interval,
855 double *smean,
856 double *sdev)
857 {
858 double sdev_to_beat; /* Original sdev to be beaten */
859 double temp; /* For doing a swap */
860 int is_beaten; /* Indicates original was beaten */
861 int i; /* Index */
862
863 /*
864 ** First calculate original standard deviation
865 */
866 calc_confidence(scores,c_half_interval,smean,sdev);
867 sdev_to_beat=*sdev;
868 is_beaten=-1;
869
870 /*
871 ** Try to beat original score. We'll come out of this
872 ** loop with a flag.
873 */
874 for(i=0;i<5;i++)
875 {
876 temp=scores[i];
877 scores[i]=*newscore;
878 calc_confidence(scores,c_half_interval,smean,sdev);
879 scores[i]=temp;
880 if(sdev_to_beat>*sdev)
881 { is_beaten=i;
882 sdev_to_beat=*sdev;
883 }
884 }
885
886 if(is_beaten!=-1)
887 { scores[is_beaten]=*newscore;
888 return(-1);
889 }
890 return(0);
891 }
892 #endif
893
894 /********************
895 ** calc_confidence **
896 *********************
897 ** Given a set of numtries scores, calculate the confidence
898 ** half-interval. We'll also return the sample mean and sample
899 ** standard deviation.
900 ** NOTE: This routines presumes a confidence of 95% and
901 ** a confidence coefficient of .95
902 ** returns 0 if there is an error, otherwise -1
903 */
calc_confidence(double scores[],int num_scores,double * c_half_interval,double * smean,double * sdev)904 static int calc_confidence(double scores[], /* Array of scores */
905 int num_scores, /* number of scores in array */
906 double *c_half_interval, /* Confidence half-int */
907 double *smean, /* Standard mean */
908 double *sdev) /* Sample stand dev */
909 {
910 /* Here is a list of the student-t distribution up to 29 degrees of
911 freedom. The value at 0 is bogus, as there is no value for zero
912 degrees of freedom. */
913 double student_t[30]={0.0 , 12.706 , 4.303 , 3.182 , 2.776 , 2.571 ,
914 2.447 , 2.365 , 2.306 , 2.262 , 2.228 ,
915 2.201 , 2.179 , 2.160 , 2.145 , 2.131 ,
916 2.120 , 2.110 , 2.101 , 2.093 , 2.086 ,
917 2.080 , 2.074 , 2.069 , 2.064 , 2.060 ,
918 2.056 , 2.052 , 2.048 , 2.045 };
919 int i; /* Index */
920 if ((num_scores<2) || (num_scores>30)) {
921 output_string("Internal error: calc_confidence called with an illegal number of scores\n");
922 return(-1);
923 }
924 /*
925 ** First calculate mean.
926 */
927 *smean=(double)0.0;
928 for(i=0;i<num_scores;i++){
929 *smean+=scores[i];
930 }
931 *smean/=(double)num_scores;
932
933 /* Get standard deviation */
934 *sdev=(double)0.0;
935 for(i=0;i<num_scores;i++) {
936 *sdev+=(scores[i]-(*smean))*(scores[i]-(*smean));
937 }
938 *sdev/=(double)(num_scores-1);
939 *sdev=sqrt(*sdev);
940
941 /* Now calculate the length of the confidence half-interval. For a
942 ** confidence level of 95% our confidence coefficient gives us a
943 ** multiplying factor of the upper .025 quartile of a t distribution
944 ** with num_scores-1 degrees of freedom, and dividing by sqrt(number of
945 ** observations). See any introduction to statistics.
946 */
947 *c_half_interval=student_t[num_scores-1] * (*sdev) / sqrt((double)num_scores);
948 return(0);
949 }
950
951 /*************
952 ** getscore **
953 **************
954 ** Return the score for a particular benchmark.
955 */
getscore(int fid)956 static double getscore(int fid)
957 {
958
959 /*
960 ** Fid tells us the function. This is really a matter of
961 ** doing the proper coercion.
962 */
963 switch(fid)
964 {
965 case TF_NUMSORT:
966 return(global_numsortstruct.sortspersec);
967 case TF_SSORT:
968 return(global_strsortstruct.sortspersec);
969 case TF_BITOP:
970 return(global_bitopstruct.bitopspersec);
971 case TF_FPEMU:
972 return(global_emfloatstruct.emflops);
973 case TF_FFPU:
974 return(global_fourierstruct.fflops);
975 case TF_ASSIGN:
976 return(global_assignstruct.iterspersec);
977 case TF_IDEA:
978 return(global_ideastruct.iterspersec);
979 case TF_HUFF:
980 return(global_huffstruct.iterspersec);
981 case TF_NNET:
982 return(global_nnetstruct.iterspersec);
983 case TF_LU:
984 return(global_lustruct.iterspersec);
985 }
986 return((double)0.0);
987 }
988
989 /******************
990 ** output_string **
991 *******************
992 ** Displays a string on the screen. Also, if the flag
993 ** write_to_file is set, outputs the string to the output file.
994 ** Note, this routine presumes that you've included a carriage
995 ** return at the end of the buffer.
996 */
output_string(char * buffer)997 static void output_string(char *buffer)
998 {
999
1000 printf("%s",buffer);
1001 if(write_to_file!=0)
1002 fprintf(global_ofile,"%s",buffer);
1003 return;
1004 }
1005
1006 /***************
1007 ** show_stats **
1008 ****************
1009 ** This routine displays statistics for a particular benchmark.
1010 ** The benchmark is identified by its id.
1011 */
show_stats(int bid)1012 static void show_stats (int bid)
1013 {
1014 char buffer[80]; /* Display buffer */
1015
1016 switch(bid)
1017 {
1018 case TF_NUMSORT: /* Numeric sort */
1019 sprintf(buffer," Number of arrays: %d\n",
1020 global_numsortstruct.numarrays);
1021 output_string(buffer);
1022 sprintf(buffer," Array size: %ld\n",
1023 global_numsortstruct.arraysize);
1024 output_string(buffer);
1025 break;
1026
1027 case TF_SSORT: /* String sort */
1028 sprintf(buffer," Number of arrays: %d\n",
1029 global_strsortstruct.numarrays);
1030 output_string(buffer);
1031 sprintf(buffer," Array size: %ld\n",
1032 global_strsortstruct.arraysize);
1033 output_string(buffer);
1034 break;
1035
1036 case TF_BITOP: /* Bitmap operation */
1037 sprintf(buffer," Operations array size: %ld\n",
1038 global_bitopstruct.bitoparraysize);
1039 output_string(buffer);
1040 sprintf(buffer," Bitfield array size: %ld\n",
1041 global_bitopstruct.bitfieldarraysize);
1042 output_string(buffer);
1043 break;
1044
1045 case TF_FPEMU: /* Floating-point emulation */
1046 sprintf(buffer," Number of loops: %lu\n",
1047 global_emfloatstruct.loops);
1048 output_string(buffer);
1049 sprintf(buffer," Array size: %lu\n",
1050 global_emfloatstruct.arraysize);
1051 output_string(buffer);
1052 break;
1053
1054 case TF_FFPU: /* Fourier test */
1055 sprintf(buffer," Number of coefficients: %lu\n",
1056 global_fourierstruct.arraysize);
1057 output_string(buffer);
1058 break;
1059
1060 case TF_ASSIGN:
1061 sprintf(buffer," Number of arrays: %lu\n",
1062 global_assignstruct.numarrays);
1063 output_string(buffer);
1064 break;
1065
1066 case TF_IDEA:
1067 sprintf(buffer," Array size: %lu\n",
1068 global_ideastruct.arraysize);
1069 output_string(buffer);
1070 sprintf(buffer," Number of loops: %lu\n",
1071 global_ideastruct.loops);
1072 output_string(buffer);
1073 break;
1074
1075 case TF_HUFF:
1076 sprintf(buffer," Array size: %lu\n",
1077 global_huffstruct.arraysize);
1078 output_string(buffer);
1079 sprintf(buffer," Number of loops: %lu\n",
1080 global_huffstruct.loops);
1081 output_string(buffer);
1082 break;
1083
1084 case TF_NNET:
1085 sprintf(buffer," Number of loops: %lu\n",
1086 global_nnetstruct.loops);
1087 output_string(buffer);
1088 break;
1089
1090 case TF_LU:
1091 sprintf(buffer," Number of arrays: %lu\n",
1092 global_lustruct.numarrays);
1093 output_string(buffer);
1094 break;
1095 }
1096 return;
1097 }
1098
1099 /*
1100 ** Following code added for Mac stuff, so that we can emulate command
1101 ** lines.
1102 */
1103
1104 #ifdef MAC
1105
1106 /*****************
1107 ** UCommandLine **
1108 ******************
1109 ** Reads in a command line, and sets up argc and argv appropriately.
1110 ** Note that this routine uses gets() to read in the line. This means
1111 ** you'd better not enter more than 128 characters on a command line, or
1112 ** things will overflow, and oh boy...
1113 */
UCommandLine(void)1114 void UCommandLine(void)
1115 {
1116 printf("Enter command line\n:");
1117 gets((char *)Uargbuff);
1118 UParse();
1119 return;
1120 }
1121
1122 /***********
1123 ** UParse **
1124 ************
1125 ** Parse the pseudo command-line. This code appeared as part of the
1126 ** Small-C library in Dr. Dobb's ToolBook of C.
1127 ** It expects the following globals:
1128 ** argc = arg count
1129 ** argv = Pointer to array of char pointers
1130 ** Uargbuff = Character array that holds the arguments. Should be 129 bytes long.
1131 ** Udummy1 = This is a 2-byte buffer that holds a "*", and acts as the first
1132 ** argument in the argument list. This maintains compatibility with other
1133 ** C's, though it does not provide access to the executable filename.
1134 ** This routine allows for up to 20 individual command-line arguments.
1135 ** Also note that this routine does NOT allow for redirection.
1136 */
UParse(void)1137 void UParse(void)
1138 {
1139 unsigned char *ptr;
1140
1141 argc=0; /* Start arg count */
1142 Udummy[0]='*'; /* Set dummy first argument */
1143 Udummy[1]='\0';
1144 argv[argc++]=(char *)Udummy;
1145
1146 ptr=Uargbuff; /* Start pointer */
1147 while(*ptr)
1148 {
1149 if(isspace(*ptr))
1150 { ++ptr;
1151 continue;
1152 }
1153 if(argc<20) argv[argc++]=(char *)ptr;
1154 ptr=UField(ptr);
1155 }
1156 return;
1157 }
1158 /***********
1159 ** UField **
1160 ************
1161 ** Isolate the next command-line field.
1162 */
UField(unsigned char * ptr)1163 unsigned char *UField(unsigned char *ptr)
1164 {
1165 while(*ptr)
1166 { if(isspace(*ptr))
1167 { *ptr=(unsigned char)NULL;
1168 return(++ptr);
1169 }
1170 ++ptr;
1171 }
1172 return(ptr);
1173 }
1174 #endif
1175