1 /* dhrystone - benchmark program */ 2 3 #define REGISTER 4 /* 5 * 6 * "DHRYSTONE" Benchmark Program 7 * 8 * Version: C/1.1, 12/01/84 9 * 10 * Date: PROGRAM updated 01/06/86, COMMENTS changed 01/31/87 11 * 12 * Author: Reinhold P. Weicker, CACM Vol 27, No 10, 10/84 pg.1013 13 * Translated from ADA by Rick Richardson 14 * Every method to preserve ADA-likeness has been used, 15 * at the expense of C-ness. 16 * 17 * Compile: cc -O dry.c -o drynr : No registers 18 * cc -O -DREG=register dry.c -o dryr : Registers 19 * 20 * Defines: Defines are provided for old C compiler's 21 * which don't have enums, and can't assign structures. 22 * The time(2) function is library dependant; Most 23 * return the time in seconds, but beware of some, like 24 * Aztec C, which return other units. 25 * The LOOPS define is initially set for 50000 loops. 26 * If you have a machine with large integers and is 27 * very fast, please change this number to 500000 to 28 * get better accuracy. Please select the way to 29 * measure the execution time using the TIME define. 30 * For single user machines, time(2) is adequate. For 31 * multi-user machines where you cannot get single-user 32 * access, use the times(2) function. Be careful to 33 * adjust the HZ parameter below for the units which 34 * are returned by your times(2) function. You can 35 * sometimes find this in <sys/param.h>. If you have 36 * neither time(2) nor times(2), use a stopwatch in 37 * the dead of the night. 38 * Use a "printf" at the point marked "start timer" 39 * to begin your timings. DO NOT use the UNIX "time(1)" 40 * command, as this will measure the total time to 41 * run this program, which will (erroneously) include 42 * the time to malloc(3) storage and to compute the 43 * time it takes to do nothing. 44 * 45 * Run: drynr; dryr 46 * 47 * Results: If you get any new machine/OS results, please send to: 48 * 49 * ihnp4!castor!pcrat!rick 50 * 51 * and thanks to all that do. 52 * 53 * Note: I order the list in increasing performance of the 54 * "with registers" benchmark. If the compiler doesn't 55 * provide register variables, then the benchmark 56 * is the same for both REG and NOREG. 57 * 58 * PLEASE: Send complete information about the machine type, 59 * clock speed, OS and C manufacturer/version. If 60 * the machine is modified, tell me what was done. 61 * On UNIX, execute uname -a and cc -V to get this info. 62 * 63 * 80x8x NOTE: 80x8x benchers: please try to do all memory models 64 * for a particular compiler. 65 * 66 * 67 * The following program contains statements of a high-level programming 68 * language (C) in a distribution considered representative: 69 * 70 * assignments 53% 71 * control statements 32% 72 * procedure, function calls 15% 73 * 74 * 100 statements are dynamically executed. The program is balanced with 75 * respect to the three aspects: 76 * - statement type 77 * - operand type (for simple data types) 78 * - operand access 79 * operand global, local, parameter, or constant. 80 * 81 * The combination of these three aspects is balanced only approximately. 82 * 83 * The program does not compute anything meaningfull, but it is 84 * syntactically and semantically correct. 85 * 86 */ 87 88 89 #include <sys/types.h> 90 #include <stdlib.h> 91 #include <string.h> 92 #include <time.h> 93 #include <stdio.h> 94 #include <signal.h> 95 #include <unistd.h> 96 97 /* Accuracy of timings and human fatigue controlled by next two lines */ 98 /*#define LOOPS 50000 */ /* Use this for slow or 16 bit machines */ 99 /*#define LOOPS 500000 */ /* Use this for faster machines */ 100 /*#define LOOPS (sizeof(int) == 2 ? 50000 : 1000000)*/ 101 102 /* Seconds to run */ 103 #define SECONDS 15 104 105 /* Compiler dependent options */ 106 #define NOENUM /* Define if compiler has no enum's */ 107 /* #define NOSTRUCTASSIGN */ /* Define if compiler can't assign structures*/ 108 109 110 /* Define only one of the next two defines */ 111 #define TIMES /* Use times(2) time function */ 112 /*#define TIME */ /* Use time(2) time function */ 113 114 115 #ifdef TIME 116 /* Ganularity of time(2) is of course 1 second */ 117 #define HZ 1 118 #endif 119 120 #ifdef TIMES 121 /* Define the granularity of your times(2) function */ 122 /*#define HZ 50 */ /* times(2) returns 1/50 second (europe?) */ 123 /*#define HZ 60 */ /* times(2) returns 1/60 second (most) */ 124 /*#define HZ 100 */ /* times(2) returns 1/100 second (WECo) */ 125 #endif 126 127 /* For compatibility with goofed up version */ 128 /*#undef GOOF */ /* Define if you want the goofed up version */ 129 130 131 #ifdef GOOF 132 char Version[] = "1.0"; 133 #else 134 char Version[] = "1.1"; 135 #endif 136 137 138 #ifdef NOSTRUCTASSIGN 139 #define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) 140 #else 141 #define structassign(d, s) d = s 142 #endif 143 144 145 #ifdef NOENUM 146 #define Ident1 1 147 #define Ident2 2 148 #define Ident3 3 149 #define Ident4 4 150 #define Ident5 5 151 typedef int Enumeration; 152 #else 153 typedef enum { 154 Ident1, Ident2, Ident3, Ident4, Ident5 155 } Enumeration; 156 #endif 157 158 typedef int OneToThirty; 159 typedef int OneToFifty; 160 typedef char CapitalLetter; 161 typedef char String30[31]; 162 typedef int Array1Dim[51]; 163 typedef int Array2Dim[51][51]; 164 165 struct Record { 166 struct Record *PtrComp; 167 Enumeration Discr; 168 Enumeration EnumComp; 169 OneToFifty IntComp; 170 String30 StringComp; 171 }; 172 173 typedef struct Record RecordType; 174 typedef RecordType *RecordPtr; 175 typedef int boolean; 176 177 #ifdef NULL 178 #undef NULL 179 #endif 180 181 #define NULL 0 182 #define TRUE 1 183 #define FALSE 0 184 185 #ifndef REG 186 #define REG 187 #endif 188 189 190 #ifdef TIMES 191 #include <sys/times.h> 192 #endif 193 194 int main(void); 195 void prep_timer(void); 196 void timeout(int sig); 197 void Proc0(void); 198 void Proc1(RecordPtr PtrParIn); 199 void Proc2(OneToFifty *IntParIO); 200 void Proc3(RecordPtr *PtrParOut); 201 void Proc4(void); 202 void Proc5(void); 203 void Proc6(Enumeration EnumParIn, Enumeration *EnumParOut); 204 void Proc7(OneToFifty IntParI1, OneToFifty IntParI2, OneToFifty 205 *IntParOut); 206 void Proc8(Array1Dim Array1Par, Array2Dim Array2Par, OneToFifty 207 IntParI1, OneToFifty IntParI2); 208 boolean Func2(String30 StrParI1, String30 StrParI2); 209 boolean Func3(Enumeration EnumParIn); 210 211 Enumeration Func1(int CharPar1, int CharPar2); 212 213 214 int main() 215 { 216 Proc0(); 217 return(0); 218 } 219 220 221 #if __STDC__ 222 volatile int done; 223 #else 224 int done; 225 #endif 226 227 void prep_timer() 228 { 229 signal(SIGALRM, timeout); 230 done = 0; 231 } 232 233 void timeout(sig) 234 int sig; 235 { 236 done = 1; 237 } 238 239 /* Package 1 */ 240 int IntGlob; 241 boolean BoolGlob; 242 char Char1Glob; 243 char Char2Glob; 244 Array1Dim Array1Glob; 245 Array2Dim Array2Glob; 246 RecordPtr PtrGlb; 247 RecordPtr PtrGlbNext; 248 249 250 void Proc0() 251 { 252 OneToFifty IntLoc1; 253 REG OneToFifty IntLoc2; 254 OneToFifty IntLoc3; 255 REG char CharIndex; 256 Enumeration EnumLoc; 257 String30 String1Loc; 258 String30 String2Loc; 259 register unsigned long i; 260 unsigned long starttime; 261 unsigned long benchtime; 262 unsigned long nulltime; 263 unsigned long nullloops; 264 unsigned long benchloops; 265 unsigned long ticks_per_sec; 266 #ifdef TIMES 267 struct tms tms; 268 #endif 269 270 #ifdef HZ 271 #define ticks_per_sec HZ 272 #else 273 ticks_per_sec = sysconf(_SC_CLK_TCK); 274 #endif 275 276 i = 0; 277 prep_timer(); 278 279 #ifdef TIME 280 starttime = time((long *) 0); 281 #endif 282 283 #ifdef TIMES 284 times(&tms); 285 starttime = tms.tms_utime; 286 #endif 287 288 alarm(1); 289 while (!done) i++; 290 291 #ifdef TIME 292 nulltime = time((long *) 0) - starttime; /* Computes o'head of loop */ 293 #endif 294 295 #ifdef TIMES 296 times(&tms); 297 nulltime = tms.tms_utime - starttime; /* Computes overhead of looping */ 298 #endif 299 300 nullloops = i; 301 302 303 PtrGlbNext = (RecordPtr) malloc(sizeof(RecordType)); 304 PtrGlb = (RecordPtr) malloc(sizeof(RecordType)); 305 PtrGlb->PtrComp = PtrGlbNext; 306 PtrGlb->Discr = Ident1; 307 PtrGlb->EnumComp = Ident3; 308 PtrGlb->IntComp = 40; 309 strcpy(PtrGlb->StringComp, "DHRYSTONE PROGRAM, SOME STRING"); 310 #ifndef GOOF 311 strcpy(String1Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); /* GOOF */ 312 #endif 313 314 Array2Glob[8][7] = 10; /* Was missing in published program */ 315 316 317 /***************** 318 -- Start Timer -- 319 *****************/ 320 i = 0; 321 prep_timer(); 322 323 #ifdef TIME 324 starttime = time((long *) 0); 325 #endif 326 327 #ifdef TIMES 328 times(&tms); 329 starttime = tms.tms_utime; 330 #endif 331 332 alarm(SECONDS); 333 while (!done) { 334 i++; 335 Proc5(); 336 Proc4(); 337 IntLoc1 = 2; 338 IntLoc2 = 3; 339 strcpy(String2Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); 340 EnumLoc = Ident2; 341 BoolGlob = !Func2(String1Loc, String2Loc); 342 while (IntLoc1 < IntLoc2) { 343 IntLoc3 = 5 * IntLoc1 - IntLoc2; 344 Proc7(IntLoc1, IntLoc2, &IntLoc3); 345 ++IntLoc1; 346 } 347 Proc8(Array1Glob, Array2Glob, IntLoc1, IntLoc3); 348 Proc1(PtrGlb); 349 for (CharIndex = 'A'; CharIndex <= Char2Glob; ++CharIndex) 350 if (EnumLoc == Func1(CharIndex, 'C')) 351 Proc6(Ident1, &EnumLoc); 352 IntLoc3 = IntLoc2 * IntLoc1; 353 IntLoc2 = IntLoc3 / IntLoc1; 354 IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1; 355 Proc2(&IntLoc1); 356 } 357 358 359 /***************** 360 -- Stop Timer -- 361 *****************/ 362 363 364 #ifdef TIME 365 benchtime = time((long *) 0) - starttime; 366 #endif 367 368 #ifdef TIMES 369 times(&tms); 370 benchtime = tms.tms_utime - starttime; 371 #endif 372 benchloops = i; 373 374 /* Approximately correct benchtime to the nulltime. */ 375 benchtime -= nulltime / (nullloops / benchloops); 376 377 printf("Dhrystone(%s) time for %lu passes = %lu.%02lu\n", 378 Version, 379 benchloops, benchtime / ticks_per_sec, 380 benchtime % ticks_per_sec * 100 / ticks_per_sec); 381 printf("This machine benchmarks at %lu dhrystones/second\n", 382 benchloops * ticks_per_sec / benchtime); 383 } 384 385 386 void Proc1(PtrParIn) 387 REG RecordPtr PtrParIn; 388 { 389 #define NextRecord (*(PtrParIn->PtrComp)) 390 391 392 structassign(NextRecord, *PtrGlb); 393 PtrParIn->IntComp = 5; 394 NextRecord.IntComp = PtrParIn->IntComp; 395 NextRecord.PtrComp = PtrParIn->PtrComp; 396 Proc3((RecordPtr *)NextRecord.PtrComp); 397 if (NextRecord.Discr == Ident1) { 398 NextRecord.IntComp = 6; 399 Proc6(PtrParIn->EnumComp, &NextRecord.EnumComp); 400 NextRecord.PtrComp = PtrGlb->PtrComp; 401 Proc7(NextRecord.IntComp, 10, &NextRecord.IntComp); 402 } else 403 structassign(*PtrParIn, NextRecord); 404 405 406 #undef NextRecord 407 } 408 409 410 void Proc2(IntParIO) 411 OneToFifty *IntParIO; 412 { 413 REG OneToFifty IntLoc; 414 REG Enumeration EnumLoc; 415 416 417 IntLoc = *IntParIO + 10; 418 for (;;) { 419 if (Char1Glob == 'A') { 420 --IntLoc; 421 *IntParIO = IntLoc - IntGlob; 422 EnumLoc = Ident1; 423 } 424 if (EnumLoc == Ident1) break; 425 } 426 } 427 428 429 void Proc3(PtrParOut) 430 RecordPtr *PtrParOut; 431 { 432 if (PtrGlb != NULL) 433 *PtrParOut = PtrGlb->PtrComp; 434 else 435 IntGlob = 100; 436 Proc7(10, IntGlob, &PtrGlb->IntComp); 437 } 438 439 440 void Proc4() 441 { 442 REG boolean BoolLoc; 443 444 445 BoolLoc = Char1Glob == 'A'; 446 BoolLoc |= BoolGlob; 447 Char2Glob = 'B'; 448 } 449 450 451 void Proc5() 452 { 453 Char1Glob = 'A'; 454 BoolGlob = FALSE; 455 } 456 457 458 void Proc6(EnumParIn, EnumParOut) 459 REG Enumeration EnumParIn; 460 REG Enumeration *EnumParOut; 461 { 462 *EnumParOut = EnumParIn; 463 if (!Func3(EnumParIn)) *EnumParOut = Ident4; 464 switch (EnumParIn) { 465 case Ident1: *EnumParOut = Ident1; break; 466 case Ident2: 467 if (IntGlob > 100) 468 *EnumParOut = Ident1; 469 else 470 *EnumParOut = Ident4; 471 break; 472 case Ident3: *EnumParOut = Ident2; break; 473 case Ident4: 474 break; 475 case Ident5: *EnumParOut = Ident3; 476 } 477 } 478 479 480 void Proc7(IntParI1, IntParI2, IntParOut) 481 OneToFifty IntParI1; 482 OneToFifty IntParI2; 483 OneToFifty *IntParOut; 484 { 485 REG OneToFifty IntLoc; 486 487 488 IntLoc = IntParI1 + 2; 489 *IntParOut = IntParI2 + IntLoc; 490 } 491 492 493 void Proc8(Array1Par, Array2Par, IntParI1, IntParI2) 494 Array1Dim Array1Par; 495 Array2Dim Array2Par; 496 OneToFifty IntParI1; 497 OneToFifty IntParI2; 498 { 499 REG OneToFifty IntLoc; 500 REG OneToFifty IntIndex; 501 502 503 IntLoc = IntParI1 + 5; 504 Array1Par[IntLoc] = IntParI2; 505 Array1Par[IntLoc + 1] = Array1Par[IntLoc]; 506 Array1Par[IntLoc + 30] = IntLoc; 507 for (IntIndex = IntLoc; IntIndex <= (IntLoc + 1); ++IntIndex) 508 Array2Par[IntLoc][IntIndex] = IntLoc; 509 ++Array2Par[IntLoc][IntLoc - 1]; 510 Array2Par[IntLoc + 20][IntLoc] = Array1Par[IntLoc]; 511 IntGlob = 5; 512 } 513 514 515 Enumeration Func1(CharPar1, CharPar2) 516 CapitalLetter CharPar1; 517 CapitalLetter CharPar2; 518 { 519 REG CapitalLetter CharLoc1; 520 REG CapitalLetter CharLoc2; 521 522 523 CharLoc1 = CharPar1; 524 CharLoc2 = CharLoc1; 525 if (CharLoc2 != CharPar2) 526 return(Ident1); 527 else 528 return(Ident2); 529 } 530 531 532 boolean Func2(StrParI1, StrParI2) 533 String30 StrParI1; 534 String30 StrParI2; 535 { 536 REG OneToThirty IntLoc; 537 REG CapitalLetter CharLoc; 538 539 540 IntLoc = 1; 541 while (IntLoc <= 1) 542 if (Func1(StrParI1[IntLoc], StrParI2[IntLoc + 1]) == Ident1) { 543 CharLoc = 'A'; 544 ++IntLoc; 545 } 546 if (CharLoc >= 'W' && CharLoc <= 'Z') IntLoc = 7; 547 if (CharLoc == 'X') 548 return(TRUE); 549 else { 550 if (strcmp(StrParI1, StrParI2) > 0) { 551 IntLoc += 7; 552 return(TRUE); 553 } else 554 return(FALSE); 555 } 556 } 557 558 559 boolean Func3(EnumParIn) 560 REG Enumeration EnumParIn; 561 { 562 REG Enumeration EnumLoc; 563 564 565 EnumLoc = EnumParIn; 566 if (EnumLoc == Ident3) return(TRUE); 567 return(FALSE); 568 } 569 570 571 #ifdef NOSTRUCTASSIGN 572 memcpy(d, s, l) 573 register char *d; 574 register char *s; 575 register int l; 576 { 577 while (l--) *d++ = *s++; 578 } 579 580 #endif 581