Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!cbatt!ihnp4!inuxc!pur-ee!uiucdcs!uxc.cso.uiuc.edu!uicsg!rick From: rick@uicsg.UUCP Newsgroups: comp.arch Subject: New Benchmark Message-ID: <500001@uicsg> Date: Sat, 14-Feb-87 18:01:00 EST Article-I.D.: uicsg.500001 Posted: Sat Feb 14 18:01:00 1987 Date-Received: Sun, 15-Feb-87 22:38:35 EST Lines: 570 Nf-ID: #N:uicsg:500001:000:16783 Nf-From: uicsg.UUCP!rick Feb 14 17:01:00 1987 New Benchmark A new benchmark has been written to overcome some of the deficiencies of Dhrystone. This benchmark, Dhampstone (written in C), was designed primarily for evaluation of multiple-register-set architectures (such as RISC), but is useful for general types of architectures as well. The benchmark is a modification of Dhrystone designed to incorporate several important statistics that were not used in the design of Dhrystone. For multiple-register-set architectures, the number of local variables and number of parameters are very important. Statistics for these distributions were included. Running Dhrystone on RISC would cause no overflow of the register file; the depth of nesting is too shallow. Dhampstone has overflow characteristics which are derived from measurements of several C programs (nroff, pi, sort, tbl, ccom, etc.). Other statistics useful for evaluating general architectures were also included. The distribution of register declarations was included in Dhampstone. Dhampstone also includes a representation of I/O processing overhead. No actual I/O is performed but the movement of data to an I/O buffer is included. I/O measurements were made in several programs and Dhampstone has a typical number of bytes of I/O per instruction executed. Other program statistics of Dhampstone are similar to those in Dhrystone. Neither synthetic benchmark uses statistics relevant for cache evaluation or code optimization evaluation. The code of Dhampstone follows. Rick Eickemeyer ihnp4!uiucdcs!uicsg!rick -------------------------------------------------------------------------- /* * DHAMPSTONE * * Synthetic Systems Program Benchmark for * Multiple Register Set Architectures * * AUTHORS: Richard J. Eickemeyer and Janak H. Patel * Computer Systems Group * Coordinated Science Laboratory * University of Illinois at Urbana-Champaign * 1101 W. Springfield * Urbana, IL 61801 * * DATE: September 1985 * * DHAMPSTONE is a synthetic benchmark program designed to match dynamic * program statistics of systems programs. The program is useful for * evaluating performance of general purpose computers. In designing * the program, a special emphasis was made in making the program * suitable for evaluating processors with multiple register sets. * Dhampstone, written in C, was created by modifying Dhrystone, * originally written in Ada, as described below. (Dhrystone is * described in: "Dhrystone: A Synthetic Systems Programming Benchmark" * by R. P. Weicker in _Communications_of_the_ACM_ Vol. 27, pp. 1013- * 1030.) Two copies of a C version of Dhrystone were used as a starting * point. This allowed greater precision in adjusting the number of * local variables and parameters. The two versions are the functions * Proc0 and Proc0a, which call each other in the proper sequence to * achieve the desired overflow statistics. As in Dhrystone, start and * stop marks are given to separate the initialization section from the * part of the program that meets the specified statistics. Measurements * should include only parts of the program executed between these two * points. The type names in the original have been preserved. * Dhampstone incorporates statistics on number of parameters and number * of local variables per procedure; multiple register set overflow; I/O; * and register declarations in addition to the statement and operand * type and locality distributions of Dhrystone. * * I/O is implemented with function "string_io" using a string of length 22. * No actual I/O is done, only the memory operations necessary for the * I/O. I/O is to blocks of memory. The input is the string * "DHAMPSTONE PROG INPUT" repeated 10 times (without intervening blanks * or new-lines) * * COMPILE Dhampstone as: * cc -o Dhampstone Dhampstone.c * If it is desired to run the program in a loop, compile as: * cc -DLOOP=n -o Dhampstone Dhampstone.c * with n the number of iterations. * Dhampstone was not designed with statistics relevant for optimization. * Results obtained using an optimizing compiler may not be indicative * of behavior of real programs. * * For each execution of both Proc0 and Proc0a all functions are * executed 2 times, unless indicated otherwise. */ /* definitions similar to those in stdio.h */ struct _iobuf { int _cnt; char *_ptr; char *_base; int _bufsiz }; # define FILE struct _iobuf # define NULL 0 # define getc(p) \ (--(p)->_cnt>=0? *(p)->_ptr++&0377:printf("I/O ERROR\n")) # define putc(x,p) \ (--(p)->_cnt>=0?((int)(*(p)->_ptr++=(unsigned)(x))):printf("I/O ERROR\n")) # define FALSE 0 # define TRUE 1 # define SLEN 22 /* I/O string length */ # define IOLEN 210 /* = 10 * (SLEN - 1) */ typedef enum {Id1, Id2, Id3, Id4, Id5} Enumeration; typedef int OneToThirty, OneToFifty; typedef char CapitalLetter; typedef char String30[30]; typedef int Array1DimInteger[50]; typedef int Array2DimInteger[50][50]; typedef int boolean; typedef struct RecordExample { Enumeration Discr; struct RecordExample *PtrComp; Enumeration EnumComp; OneToFifty IntComp; String30 StringComp; } RecordType, *RecordPtr; boolean BoolG; char CharG1, CharG2, CharG3; Array1DimInteger ArrG1; Array2DimInteger ArrG2; String30 StringG1; RecordPtr PtrG1, PtrG2; int IntG1, IntG2, IntG3, IntG4; FILE *File_In, *File_Out; char input[IOLEN+1] = "DHAMPSTONE PROG INPUTDHAMPSTONE PROG INPUT\ DHAMPSTONE PROG INPUTDHAMPSTONE PROG INPUTDHAMPSTONE PROG INPUT\ DHAMPSTONE PROG INPUTDHAMPSTONE PROG INPUTDHAMPSTONE PROG INPUT\ DHAMPSTONE PROG INPUTDHAMPSTONE PROG INPUT"; char output[IOLEN+1]; int Proc0_Flag; /* indicates if in Proc0 or Proc0a */ Enumeration Func1(), Func1a(); boolean Func2(), Func3(); char *malloc(); main () { #ifdef LOOP int loop; #endif LOOP PtrG2 = (RecordPtr) malloc (sizeof (RecordType)); PtrG1 = (RecordPtr) malloc (sizeof (RecordType)); PtrG1->Discr = Id1; PtrG1->PtrComp = PtrG2; PtrG1->EnumComp = Id3; PtrG1->IntComp = 40; strcpy (PtrG1->StringComp, "DHAMPSTONE PROGRAM ONE STRING"); strcpy (StringG1, "DHAMPSTONE PROGRAM 3RD STRING"); File_In = (FILE *) malloc (sizeof (FILE)); File_Out = (FILE *) malloc (sizeof (FILE)); File_In->_ptr = File_In->_base = input; File_Out->_ptr = File_Out->_base = output; File_In->_cnt = File_Out->_cnt = IOLEN; File_In->_bufsiz = File_Out->_bufsiz = IOLEN; ArrG2[6][5] = 47; ArrG2[10][9] = 32; CharG3 = 'C'; IntG4 = 8; /* *------- Start Timer ------- */ #ifdef LOOP for (loop = 1; loop <= LOOP; loop++) { #endif LOOP Proc0a(2); Proc0(9); Proc0a(2); Proc0a(3); Proc0(2); Proc0a(2); #ifdef LOOP File_In->_ptr = File_In->_base; File_In->_cnt = File_In->_bufsiz; File_Out->_ptr = File_Out->_base; File_Out->_cnt = File_Out->_bufsiz; } #endif LOOP /* *------- Stop Timer -------* */ } Proc0 (IntParI) register int IntParI; /* IntParI is a no. to control calling depth (called from main and Proc0a) */ { register OneToFifty IntL1, IntL2; OneToFifty IntL3; char CharIndex; Enumeration EnumL; String30 StringL1, StringL2; if (IntParI >= 2) Proc0a (IntParI - 1); Proc0_Flag = 1; IntL1 = 2; IntL2 = 3; string_io (StringL1, SLEN); strcpy (StringL2, "DHAMPSTONE PROGRAM 2ND STRING"); EnumL = Id2; BoolG = ! Func2 ('E', &CharG3, 'R', StringL2, StringL1); while (IntL1 < IntL2) { /* body executed once */ IntL3 = 5 * IntL1 - IntL2; Proc7 (); IntL1 = IntL1 + 1; } Proc8 (ArrG1, ArrG2, IntL1, IntL3 - 5); Proc1 (PtrG1); for (CharIndex = 'A'; CharIndex <= CharG2; CharIndex++) if (EnumL == Func1a(Id1, CharIndex, 'Z')) /* body executed twice */ Proc6 (&EnumL, Id1, 20, IntL2); /* not executed */ IntL3 = IntL2 * IntL3; IntL2 = IntL3 / IntL1; IntL2 = 7 * (IntL3 - IntL2) - IntL1; Proc2 (&IntL3, 'C'); } Proc0a (IntParI) int IntParI; /* IntParI is a no. to control calling depth (called from main and Proc0a) */ { register OneToFifty IntL1, IntL2, IntL3; OneToFifty IntL4; char CharIndex, CharL1, CharL2; Enumeration EnumL1; String30 StringL; IntL1 = 2; IntL2 = 5; CharL2 = 'A'; CharL1 = 'C'; if (IntParI > 1) Proc0(IntParI - 1); Proc0_Flag = 0; Proc4 (CharL2); strcpy (StringL, "DHAMPSTONE PROGRAM 1ST STRING"); EnumL1 = Id2; BoolG = ! Func2 (CharL1, &CharL2, CharG1, StringG1, StringL); while (IntL1 < IntL2) { /* body executed 3 times */ if (IntL1 == 2) { IntL3 = 5 * IntL1 - IntL2; /* executed 1 time */ Proc7a (); } IntL1 = IntL1 + 1; } Proc8a (IntL1, ArrG1, ArrG2, IntL3, IntL2, &IntL4); Proc1 (PtrG1); for (CharIndex = 'A'; CharIndex <= CharG2; CharIndex++) if (EnumL1 == Func1a (Id1, CharIndex, 'Z')) { /* body executed twice */ EnumL1 = Id3; /* not executed */ Proc6 (&EnumL1, Id1, 4, 5); } IntL2 = IntL4 * IntL3; IntL3 = IntL3 / IntL4; IntL2 = 7 * (IntL4 - IntL3) - IntL2; Proc2 (&IntL4, CharL1); /* CharL1 & CharG3 are both 'C' */ } Proc1 (PtrParI) RecordPtr PtrParI; /* argument is PtrG1 (called from Proc0 and Proc0a) */ { # define NextRecord (*(PtrParI->PtrComp)) register RecordPtr PtrL; register int IntL; NextRecord = *PtrG1; PtrParI->IntComp = 5; NextRecord.IntComp = PtrParI->IntComp; PtrL = PtrParI->PtrComp; NextRecord.PtrComp = PtrL; Proc3 (&NextRecord.PtrComp); if (NextRecord.Discr == Id1) { /* executed */ Proc6 (&NextRecord.EnumComp, PtrParI->EnumComp, PtrParI->IntComp, 10); NextRecord.IntComp = 6; Proc7 (); NextRecord.PtrComp = PtrG1->PtrComp; } else { *PtrParI = NextRecord; /* not executed */ if (PtrL == NULL) IntL = 10; else { IntL = 1; PtrParI->IntComp = IntL; } } # undef NextRecord } Proc2 (IntParIO, CharParI) register OneToFifty *IntParIO; char CharParI; /* arguments are 21 and 'C' (called from Proc0). Returns 50 as IntParIO arguments are 7 and 'C' (called from Proc0a). Returns 22 as IntParIO */ { register OneToFifty IntL1, IntL2, IntL3; Enumeration EnumL1, EnumL2; IntL2 = *IntParIO + 10; do /* body executed once */ if (CharG3 == CharParI) { IntL3 = IntL2 - 2; /* executed */ *IntParIO = *IntParIO + IntL3 - IntG3; EnumL2 = Id1; } else { IntL1 = IntL2 + 4; /* not executed */ *IntParIO = IntL1 - IntG3; EnumL1 = Id1; EnumL2 = EnumL1; } while (EnumL2 != Id1); } Proc3 (PtrParO) RecordPtr *PtrParO; /* (called from Proc1). Returns address of PtrG2 as PtrParO */ { if (PtrG1 != NULL) *PtrParO = PtrG1->PtrComp; /* executed */ else IntG1 = 100; /* not executed */ Proc7a (); } Proc4 (CharParI) char CharParI; /* argument is 'C' (called from Proc8--from Proc0) argument is 'A' (called from Proc0a) */ { register boolean BoolL; if (Proc0_Flag) Proc5 (); BoolL = CharG1 == CharParI; BoolL = BoolL || BoolG; CharG2 = 'B'; } Proc5 () { /* executed 3 times per Proc0--Proc0a pair */ CharG1 = 'A'; BoolG = FALSE; } Proc6 (EnumParO, EnumParI, IntParI1, IntParI2) Enumeration *EnumParO; Enumeration EnumParI; OneToFifty IntParI1, IntParI2; /* arguments are address, Id3, 5, 10 (called from Proc1). Returns Id2 for EnumParO */ { if (IntParI1 > 10) IntG1 = 4; /* not executed */ else if (! Func3(EnumParI)) *EnumParO = Id4; /* not executed */ switch (EnumParI) { case Id1 : *EnumParO = Id1; IntG2 = IntParI2 + 2; IntG3 = IntParI1 + IntParI2; break; case Id2 : if (IntG3 > IntParI1) *EnumParO = Id1; else *EnumParO = Id4; break; case Id3 : *EnumParO = Id2; /* executed */ break; case Id4 : break; case Id5 : *EnumParO = Id3; break; } } Proc7 () { /* executed 3 times per Proc0--Proc0a pair */ register OneToFifty IntL; IntL = IntG1 + 2; IntG2 = IntG1 + IntL; } Proc7a () { /* executed 3 times per Proc0--Proc0a pair */ if (! Proc0_Flag) Proc5 (); if (IntG4 > 4) IntG2 = IntG3 + 2; /* executed */ else IntG2 = IntG3 + 1; /* not executed */ } Proc8 (ArrParIO1, ArrParIO2, IntParI1, IntParI2) Array1DimInteger ArrParIO1; Array2DimInteger ArrParIO2; register int IntParI1; int IntParI2; /* arguments are 2 arrays, 3, 2 (called from Proc0) */ { /* executed 1 time per Proc0--Proc0a pair */ OneToFifty IntL1; register OneToFifty IntL2; OneToFifty IntL3; register OneToFifty IntIndex; OneToFifty IntL4, IntL5; Proc4 ('C'); IntL1 = IntParI1 + 5; IntL2 = IntL1 + 1; if (IntParI2 == 2) { IntL5 = IntL1; /* executed */ IntL4 = IntL1 + 1 - IntParI1; } else { IntL3 = IntL2; /* not executed */ IntL5 = IntL3 + 3; IntL4 = IntL3 + 2 - IntParI1; } ArrParIO1[IntL5] = IntParI2; ArrParIO1[IntL1 + 1] = ArrParIO1[IntL1]; ArrParIO1[IntL1 + 30] = IntL4; for (IntIndex = IntL1; IntIndex <= IntL2; IntIndex++) ArrParIO2[IntL2][IntIndex] = IntParI1; /* body executed twice */ ArrParIO2[IntL4][IntL2 - 1] = ArrParIO2[IntL4][IntL4 - 1] + 1; ArrParIO2[IntL5 + 20][IntL5] = ArrParIO1[IntL1]; if (IntParI2 != 2) IntL3 = IntL3 + 4; /* not executed */ IntG1 = 5; } Proc8a (IntParI1, ArrParIO1, ArrParIO2, IntParI2, IntParI3, IntParO) OneToFifty IntParI1; register OneToFifty IntParI2; OneToFifty IntParI3, *IntParO; Array1DimInteger ArrParIO1; Array2DimInteger ArrParIO2; /* arguments are 5, two arrays, 5, 5, address (called from Proc0a). Returns 7 for IntParO */ { /* executed 1 time per Proc0--Proc0a pair */ register OneToFifty IntL1; OneToFifty IntL2; register OneToFifty IntIndex; OneToFifty IntL3, IntL4; IntL2 = IntParI1 + 5; IntL1 = IntL2 + 1; if (IntParI3 <= 23) IntL3 = IntL2; /* executed */ else { IntL4 = IntL2; /* not executed */ IntL3 = IntL4 + 3; } ArrParIO1[IntL3] = IntParI2; ArrParIO1[IntL2 + 1] = ArrParIO1[IntL2]; ArrParIO1[IntL3 + 30] = IntParI3; for (IntIndex = IntL2; IntIndex <= IntL1; IntIndex++) ArrParIO2[IntL1][IntIndex] = IntParI2; /* body executed twice */ ArrParIO2[IntL1][IntL2 - 1] = ArrParIO2[IntL3][IntL2 - 1] + 1; if (IntParI3 > 17) IntL4 = IntL4 + 4; /* not executed */ else ArrParIO2[IntL3 + 20][IntL3] = ArrParIO1[IntL2];/* executed */ *IntParO = IntParI2 + IntParI3 + 2 - IntParI1; } Enumeration Func1 (CharParI1, CharParI2) CapitalLetter CharParI1, CharParI2; /* arguments are 'M', 'M' (called from Func2). Returns Id1 */ { /* executed 2 times per Proc0--Proc0a pair */ CapitalLetter CharL1, CharL2; Enumeration EnumL; CharL1 = CharParI1; CharL2 = CharL1; if (CharL2 != CharParI2) { EnumL = Id2; /* not executed */ return (EnumL); } else return (Id1); /* executed */ } Enumeration Func1a (EnumParI, CharParI1, CharParI2) Enumeration EnumParI; CapitalLetter CharParI1, CharParI2; /* arguments are Id1, 'A' or 'B', 'Z' (called from Proc0 and Proc0a) Returns Id1 */ { /* executed 4 times per Proc0--Proc0a pair */ CapitalLetter CharL1, CharL2; CharL1 = CharParI1; CharL2 = CharL1; if (CharL2 != CharParI2) return (EnumParI); /* executed */ else return (Id3); /* not executed */ } boolean Func2 (CharParI1, CharParIO, CharParI2, StringParI1, StringParI2) char CharParI1; register char *CharParIO; char CharParI2; String30 StringParI1, StringParI2; /* arguments are 'E', 'C', 'R', 2 strings (called from Proc0) arguments are 'C', 'C', 'A', 2 strings (called from Proc0a) Returns FALSE, CharParIO is not changed */ { register OneToThirty IntL1, IntL2; CapitalLetter CharL1, CharL2; IntL1 = 2; CharG1 = StringParI1[IntL1]; while (IntL1 <= 2) /* body executed once */ if (Func1 (StringParI2[IntL1 + 1], 'M') == Id1) { CharL1 = 'A'; /* executed */ IntL1 = IntL1 + 1; } if (CharL1 >= 'W' && CharL1 < 'Z') { CharL2 = CharParI1; /* not executed */ IntL2 = 3; } if (CharL1 == 'X') { CharL2 = *CharParIO; /* not executed */ *CharParIO = 'J'; return TRUE; } else if (strcmp (StringParI2, StringParI1) > 0) { IntL2 = IntG3; /* not executed */ IntL2 = IntL1 + IntL2; CharL2 = CharParI2; CharL1 = CharL2; return TRUE; } else return FALSE; /* executed */ } boolean Func3 (EnumParI) Enumeration EnumParI; /* argument is Id3 (called from Proc6). Returns TRUE */ { Enumeration EnumL; EnumL = EnumParI; if (EnumL == Id3) return TRUE; /* executed */ return FALSE; /* not executed */ } string_io(string, length) register char *string; int length; /* arguments are string, SLEN (called from Proc0) */ { /* executed 1 time per Proc0--Proc0a pair */ register int index; --length; for (index = 0; index < length; index++) { string[index] = getc(File_In); /* body executed 21 times */ putc(string[index],File_Out); } string[length] = '\0'; }