[comp.lang.pascal] Benchmarks

reeder@reed.UUCP (Doug Reeder) (10/30/89)

This is primarily for Tim Smithers, whom I could not reach by mail, but
others may be interested.

send the following commands as the body of an email message 
to nistlib@cmr.icst.nbs.gov

send doc from info
send index
send index from stones




-- 
Doug Reeder                          USENET: ...!tektronix!reed!reeder
Box 722 Reed College                 BITNET: reeder@reed.BITNET
Portland, OR 97202                from ARPA: tektronix!reed!reeder@berkeley.EDU
(503) 777-1551                  "A blaster can point two ways."  -Salvor Hardin

6600john%ucsbuxa@hub.ucsb.edu (Tazz Man) (02/22/90)

I am sure that there are others out there who are just a curious about
compiler performance as I am.  Here is a suggestion:  We come up with a
benchmark which exercises the language (Pascal or M2) in a way as to
simulate an actual program.  This program should be machine and compiler
independent (meaning, no nifty optimization tricks).  The program should
then be run on as many different machines and different compilers as 
possible (with out any resident programs running, of course).  The 
results should then be posted.  If people find time to undertake this
I will compile all of the results and present them.

John Bernstein
6600john@ucsbuxa.ucsb.edu

bigelow@hpfcso.HP.COM (Jim Bigelow) (02/22/90)

Concerning pascal benchmarks, how about using the drystone benchmark? 
I have included the source incase you don't have it.

Jim Bigelow
S300 Pascal
Colorado Langauge Lab 
HP, Ft. Collins


----
$standard_level 'hp_modcal'$
(*
 ****************************************************************************
 *
 *                   "DHRYSTONE" Benchmark Program
 *                   -----------------------------
 *                                                                            
 *  Version:    Pascal, Version 2.1
 *                                                                            
 *  File:       dhry.p
 *
 *  Date:       May 25, 1988
 *
 *  Author:     Reinhold P. Weicker
 *                      Siemens AG, E STE 35
 *                      Postfach 3240
 *                      8520 Erlangen
 *                      Germany (West)
 *                              Phone:  [xxx-49]-9131-7-20330
 *                                      (8-17 Central European Time)
 *                              Usenet: ..!mcvax!unido!estevax!weicker
 *
 *              Original Version (in Ada) published in
 *              "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
 *              pp. 1013 - 1030, together with the statistics
 *              on which the distribution of statements etc. is based,
 *
 *              This version uses calls to the Pascal runtime library of the
 *              Berkeley UNIX system (4.3 bsd) for time measurement.
 *              For measurements on other systems, these calls need to be
 *              modified.                                
 *             
 *              Slight modifications made for compilation using HP Pascal
 *              Jim Bigelow, S300 HP Pascal, Colorado Language Lab, 
 *              HP, Ft. Collins, Colorado
 *                                                                           
 *  Collection of Results:
 *              Reinhold Weicker (address see above) and
 *              
 *              Rick Richardson
 *              PC Research. Inc.
 *              94 Apple Orchard Drive
 *              Tinton Falls, NJ 07724
 *                      Phone:  (201) 834-1378 (9-17 EST)               
 *                      Usenet: ...!seismo!uunet!pcrat!rick
 *
 *      Please send results to Rick Richardson and/or Reinhold Weicker.
 *      Complete information should be given on hardware and software used.
 *      Hardware information includes: Machine type, CPU, type and size
 *      of caches; for microprocessors: clock frequency, memory speed
 *      (number of wait states).
 *      Software information includes: Compiler (and runtime library)
 *      manufacturer and version, compilation switches, OS version.
 *      The Operating System version may give an indication about the
 *      compiler; Dhrystone itself performs no OS calls in the measurement loop.
 *
 *      The complete output generated by the program should be mailed
 *      such that at least some checks for correctness can be made.
 *
 ****************************************************************************
 *
 *  History:    This version Pascal/2.1 has been made for two reasons:
 *
 *              1) There is a need for a common Pascal version of
 *              Dhrystone. Although translation from the published (Ada)
 *              version to Pascal is straightforward in most aspects,
 *              there are cases where it may not be obvious to everyone.
 *              There should be, as far as possible, only one Pascal version
 *              of Dhrystone such that results can be compared without
 *              restrictions. Also, a Pascal version of Dhrystone has not yet
 *              found a network distribution comparable to the C version
 *              (version 1.1) distributed by Rick Richardson.
 *              
 *              2) As far as it is possible without changes to the Dhrystone
 *              statistics, optimizing compilers should be prevented from
 *              removing significant statements.
 *
 *              This Pascal version 2.1 has been made consistent with the
 *              C version 2.1; therefore the acknowledgments for the C version
 *              are due for the Pascal version as well: I thank
 *              Rick Richardson (Tinton Falls, NJ), Chaim Benedelac (Nat.
 *              Semi.), David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
 *              Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
 *              for their help with comments on earlier versions of the
 *              benchmark.
 *
 *  Changes:    In the initialization part, this version differs 
 *              from the Pascal version previously distributed by Reinhold
 *              Weicker, the number of runs through Dhrystone is obtained
 *              interactively from the terminal. Output of the result 
 *              has been changed to conform to the C version (2.1).
 *              The changes in the initialization part and in the printing
 *              of the result have no impact on performance measurement 
 *              since they are outside the measaurement loop.
 *              
 *              Inside the measurement loop, this version follows the
 *              version previously distributed by Reinhold Weicker.
 *              As a correction to the published version, a statement
 *              initializing Array2Glob [8,7] (outside the measurement
 *              loop) has been added. Otherwise, this array element would
 *              have an undefined value.
 *
 *              At several places in the benchmark, code has been added,
 *              but within the measurement loop only in branches that 
 *              are not executed. The intention is that optimizing compilers
 *              should be prevented from moving code out of the measurement
 *              loop, or from removing code altogether. Since the statements
 *              that are executed within the measurement loop have NOT been
 *              changed, all numbers defining the "Dhrystone distribution"
 *              (distribution of statements, operand types and locality)
 *              still hold. Except for sophisticated optimizing compilers,
 *              execution times for this version should be the same as
 *              for previous versions.
 *
 *              Since it has proven difficult to subtract the time for the
 *              measurement loop overhead in a correct way, the loop check
 *              has been made a part of the benchmark. This does have
 *              an impact - though a very minor one - on the distribution
 *              statistics which have been updated for this version.
 *
 *              All changes within the measurement loop are described
 *              and discussed in the companion paper "Rationale for
 *              Dhrystone version 2".
 *
 *              Because of the self-imposed limitation that the order and
 *              distribution of the executed statements should not be
 *              changed, there are still cases where optimizing compilers
 *              may not generate code for some statements. To a certain
 *              degree, this is unavoidable for small synthetic benchmarks.
 *              Users of the benchmark are advised to check code listings
 *              whether code is generated for all statements of Dhrystone.
 *
 *              Version 2.1 is identical to version 2.0 distributed via
 *              the UNIX network Usenet in March 1988 except that it corrects
 *              some minor deficiencies that were found by users of version 2.0.
 *              The only change within the measurement loop is that a
 *              non-executed "else" part was added to the "if" statement in
 *              Func3, and a non-executed "else" part removed from Proc3.
 *
 ***************************************************************************
 *
 *  Compilation model and measurement (IMPORTANT):
 *
 *  This program contains the Dhrystone program, including measurement setup,
 *  in one file. The original (Ada) program contained three packages,
 *  - a package with global type definitions,
 *  - Pack_1, containing the main program (Proc_0 in Ada) and procedures
 *            Proc_1, ... , Proc_5,
 *  - Pack_2, containing Proc_6, ... , Proc_8, Func_1, ..., Func_3.
 *  Since ISO/ANSI Standard Pascal provides no means to express separate
 *  compilation (although many Pascal implementations provide such a feature),
 *  it is not possible to formulate a portable Pascal version with the program
 *  in several modules, corresponding more closely to the Ada and C versions.
 *  Therefore, no attempt has been made to construct a Pascal version with
 *  the program consisting of several modules.
 *                                                                           
 *  This difference may impact execution time because the compiler can
 *  perform more data flow analysis for a single-module program;
 *  sophisticated compilers may be able to suppress code generation for
 *  some parts of the program.
 *  Users should check machine code listings generated by the compiler
 *  to ensure that code is generated for all parts of the program.
 *
 *  The following "ground rules" apply for measurements:
 *  - No procedure merging
 *  - Otherwise, compiler optimizations are allowed but should be indicated
 *  See the companion paper "Rationale for Dhrystone Version 2" for a more
 *  detailed discussion of these ground rules.
 *
 *  For 16-Bit processors (e.g. 80x86), times for all compilation models
 *  ("small", "medium", "large") should be given if possible, together
 *  with a definition of these models for the compiler system used.
 *
 **************************************************************************
 *
 *  Dhrystone (Pascal version) statistics:
 *
 *  [Comment from the first distribution by Reinhold Weicker,
 *   the distribution statistics have been updated for Version 2.1.
 *   Note that because of language differences, the numbers are different
 *   from the Ada version. The main difference is that the variables that
 *   are local variables of "Proc_0" (Ada) or "main" (C) are global
 *   variables in the Pascal version.]
 *                                                                           
 *  The following program contains statements of a high level programming    
 *  language (here: Pascal) in a distribution considered representative:     
 *                                                                           
 *    assignments                  58
 *    control statements           28
 *    procedure, function calls    15
 *                                                                           
 *  100 statements are dynamically executed. The program is balanced with    
 *  respect to the three aspects:                                            
 *                                                                           
 *    - statement type                                                       
 *    - operand type (for simple data types)                                 
 *    - operand access                                                       
 *         operand global, local, parameter, or constant.                    
 *           There is no static nesting of blocks or procedures,             
 *           therefore all variables are either global or local.             
 *                                                                           
 *  The combination of these three aspects is balanced only approximately.   
 *                                                                           
 *  1. Statement Type:                                                       
 *  -----------------             number
 *                                                                           
 *     V1 := V2                   15                                         
 *     V := Constant              12                                         
 *       (incl. V1 := F(..)                                                  
 *     Assignment,                 7                                         
 *       with array element                                                  
 *     Assignment,                 6                                         
 *       with record component                                               
 *                                --                                       
 *                                40       40                                
 *                                                                           
 *     X := Y +|-|and|or Z         5                                         
 *     X := Y +|-|"=" Constant     6                                         
 *     X := X +|- 1                3                                         
 *     X := Y *|/ Z                2                                         
 *     X := Expression,            1                                         
 *          two operators                                                    
 *     X := Expression,            1                                         
 *          three operators                                                  
 *                                --                                         
 *                                18       18                                
 *                                                                           
 *     if .... then ....          14                                         
 *       with "else"      7                                                  
 *       without "else"   7                                                  
 *           executed        3                                               
 *           not executed    4                                               
 *     for I in 1..N do ...        7  |  counted every time                  
 *     while ... do ...            4  |  the loop condition                  
 *     repeat ... until            1  |  is evaluated                        
 *     case ... end                1                                         
 *     with                        1                                         
 *                                --                                         
 *                                28       28                                
 *                                                                           
 *     P (...)  procedure call    10                                         
 *     X := F (...)                                                          
 *             function  call      5                                         
 *                                --                                         
 *                                15       15                                
 *                                        ---                              
 *                                        101                                
 *                                                                           
 *    22 of the 58 assignments have a variable of a constrained              
 *    (sub-)type as their destination. In general, discriminant checks       
 *    will be necessary in these cases; however, the compiler may            
 *    optimize out some of these checks.                                     
 *                                                                           
 *    The average number of parameters in procedure or function calls        
 *    is 1.80 (not counting the function values as implicit parameters).     
 *                                                                           
 *                                                                           
 *  2. Operators                                                             
 *  ------------                                                             
 *                          number    approximate                            
 *                                    percentage                             
 *                                                                           
 *    Arithmetic             27          52.9                                
 *                                                                           
 *       +                     16          31.4                              
 *       -                      7          13.7                              
 *       *                      3           5.9                              
 *       div                    1           2.0                              
 *                                                                           
 *    Comparison             20           39.2                               
 *                                                                           
 *       =                      9           17.6                             
 *       <>                     4            7.8                             
 *       >                      1            2.0                             
 *       <                      3            5.9                             
 *       >=                     1            2.0                             
 *       <=                     2            3.9                             
 *                                                                           
 *    Logic                   4            7.8                               
 *                                                                           
 *       AND                    1            2.0                             
 *       OR                     1            2.0                             
 *       NOT                    2            3.9                             
 *                                                                           
 *                           --          -----                               
 *                           51           99.9                               
 *                                                                           
 *                                                                           
 *  3. Operand Type (counted once per operand reference):                    
 *  ---------------                                                          
 *                          number    approximate                            
 *                                    percentage                             
 *                                                                           
 *     Integer               135        54.7 %                               
 *     Character              47        19.0 %                               
 *     Enumeration            31        12.6 %                               
 *     Boolean                13         5.3 %                               
 *     Pointer                11         4.5 %                               
 *     String30                6         2.4 %                               
 *     Array                   2         0.8 %                               
 *     Record                  2         0.8 %                               
 *                           ---       -------                               
 *                           247        100.1 %
 *                                                                           
 *  When there is an access path leading to the final operand (e.g. a record 
 *  component), only the final data type on the access path is counted.      
 *                                                                           
 *  There are 16 accesses to components of a record, 9 of them go to         
 *  a component in a variant part. For some of these accesses, the           
 *  compiler may suppress generation of code checking the tag field          
 *  during optimization.                                                     
 *                                                                           
 *                                                                           
 *  3. Operand Locality:                                                     
 *  -------------------                                                      
 *                                                                           
 *     local variable               84        34.0 %                         
 *     global variable              58        23.5 %                         
 *     parameter                    45        18.2 %                         
 *        value                        23         9.3 %                      
 *        reference                    22         8.9 %                      
 *     function result               5         2.0 %                         
 *     constant                     55        22.3 %                         
 *                                 ---       -------                         
 *                                 247       100.0 %                         
 *                                                                           
 *                                                                           
 *  The program des not compute anything meaningful, but it is syntactically
 *  and semantically correct. All variables have a value assigned to them    
 *  before they are used as a source operand.                                
 *                                                                           
 *  There may be cases where a highly optimizing compiler may recognize      
 *  unnecessary statements and may not generate code for them.               
 *                                                                           
 *  There has been no explicit effort to account for the effects of a        
 *  cache, or to balance the use of long or short displacements for code or  
 *  data.                                                                    
 *                                                                           
 ****************************************************************************
 *)

program Dhrystone (input, output);
(***************)

const (* for measurement *)

  MicrosecondsPerClock  = 1000;
  ClocksPerSecond       = 1000;
        (* In Berkeley UNIX Pascal, the function "clock"        *)
        (* returns milliseconds                                 *)
  TooSmallTime          = 2000;
        (* Measurements should last at least 2 seconds          *)

type

  (* Global type definitions *)

  Enumeration           = (Ident1, Ident2, Ident3, Ident4, Ident5);

  OneToThirty           = 1..30;
  OneToFifty            = 1..50;
  CapitalLetter         = 'A'..'Z';

  String30              = packed array [OneToThirty] of char;

  Array1DimInteger      = array [OneToFifty] of integer;
  Array2DimInteger      = array [OneToFifty, OneToFifty] of integer;

  RecordPointer         = ^RecordType;

  RecordType            =
      record
        PointerComp:   RecordPointer;
        case Discr:    Enumeration of
          Ident1:         (* only this variant is used,           *)
                          (* but in some cases discriminant       *)
                          (* checks are necessary                 *)
            (EnumComp:      Enumeration;
             IntComp:       OneToFifty;
             StringComp:    String30);
          Ident2:
            (Enum2Comp:    Enumeration;
             String2Comp:  String30);
          Ident3, Ident4, Ident5:
            (Char1Comp,
             Char2Comp:    char);
      end; (* record *)

var

  (* Ada version: Variables local in Proc_0 *)

  Int1Glob,
  Int2Glob,
  Int3Glob:       OneToFifty;
  CharIndex:      char;
  EnumGlob:       Enumeration;
  String1Glob,
  String2Glob:    String30;

  (* Ada version: Variables global in Pack_1 *)

  PointerGlob,
  NextPointerGlob: RecordPointer;
  IntGlob:         integer;

  BoolGlob:        boolean;
  Char1Glob,
  Char2Glob:       char;
  Array1Glob:      Array1DimInteger;
  Array2Glob:      Array2DimInteger;

  (* Variables for measurement *)

  RunIndex,
  NumberOfRuns,
  BeginClock,
  EndClock,
  SumClocks:            integer;
  Microseconds,         
  DhrystonesPerSecond:  real;
  I:                    integer;

  (* end of variables for measurement *)

function $alias '_clock'$ clock :integer; 		external;

procedure Proc1 (    PointerParVal: RecordPointer);     forward;

procedure Proc2 (var IntParRef:     OneToFifty);        forward;

procedure Proc3 (var PointerParRef: RecordPointer);     forward;

procedure Proc4;                                        forward;
  (* without parameters *)

procedure Proc5;                                        forward;
  (* without parameters *)

procedure Proc6 (    EnumParVal:    Enumeration;
                 var EnumParRef:    Enumeration);       forward;

procedure Proc7 (    Int1ParVal,
                     Int2ParVal:    OneToFifty;
                 var IntParRef:     OneToFifty);        forward;

procedure Proc8 (var Array1ParRef:  Array1DimInteger;
                 var Array2ParRef:  Array2DimInteger;
                     Int1ParVal,
                     Int2ParVal:    integer);            forward;

function Func1  (    Char1ParVal,
                     Char2ParVal:   CapitalLetter): 
                                            Enumeration; forward;

function Func2  (var String1ParRef,
                     String2ParRef: String30): 
                                            boolean;      forward;

function Func3  (    EnumParVal:    Enumeration): 
                                            boolean;      forward;


procedure Proc1; (* (PointerParVal: RecordPointer) *)
    (* executed once *)
begin
  with PointerParVal^.PointerComp^ (* = PointerGlobNext *) do
  begin
    PointerParVal^.PointerComp^ := PointerGlob^;
    PointerParVal^.IntComp := 5;
    IntComp := PointerParVal^.IntComp;
    PointerComp := PointerParVal^.PointerComp;
    Proc3 (PointerComp);
      (* PointerParVal^.PointerComp^.PointerComp = PointerGlob^.PointerComp *)
    if Discr = Ident1
    then (* executed *)
    begin
      IntComp := 6;
      Proc6 (PointerParVal^.EnumComp, EnumComp);
      PointerComp := PointerGlob^.PointerComp;
      Proc7 (IntComp, 10, IntComp);
    end (* then *)
    else (* not executed *)
      PointerParVal^ := PointerParVal^.PointerComp^;
  end; (* with *)
end; (* Proc1 *)


procedure Proc2; (* (var IntParRef: OneToFifty) *)
    (* executed once *)
    (* InParRef = 3, becomes 7 *)
var
  IntLoc:  OneToFifty;
  EnumLoc: Enumeration;
begin
  IntLoc := IntParRef + 10;
  repeat (* executed once *)
    if Char1Glob = 'A'
    then (* executed *)
    begin
      IntLoc := IntLoc - 1;
      IntParRef := IntLoc - IntGlob;
      EnumLoc := Ident1;
    end (* if *)
  until EnumLoc = Ident1; (* true *)
end; (* Proc2 *)


procedure Proc3; (* (var PointerParRef: RecordPointer) *)
    (* executed once *)
    (* PointerParRef becomes PointerGlob *)
begin
  if PointerGlob <> nil
  then (* executed *)
    PointerParRef := PointerGlob^.PointerComp;
  Proc7 (10, IntGlob, PointerGlob^.IntComp);
end; (* Proc3 *)


procedure Proc4; (* without parameters *)
    (* executed once *)
var
  BoolLoc: boolean;
begin
  BoolLoc := Char1Glob = 'A';
  BoolGlob := BoolLoc or BoolGlob;
  Char2Glob := 'B';
end; (* Proc4 *)


procedure Proc5; (* without parameters *)
    (* executed once *)
begin
  Char1Glob := 'A';
  BoolGlob := false;
end; (* Proc5 *)


procedure Proc6; (* (    EnumParVal:     Enumeration;
                     var EnumParRef:     Enumeration) *)
    (* executed once *)
    (* EnumParVal = Ident3, EnumParRef becomes Ident2 *)
begin
  EnumParRef := EnumParVal;
  if not Func3 (EnumParVal)
  then (* not executed *)
    EnumParRef := Ident4;
  case EnumParVal of
    Ident1: EnumParRef := Ident1;
    Ident2: if IntGlob > 100
              then EnumParRef := Ident1
              else EnumParRef := Ident4;
    Ident3: EnumParRef := Ident2;    (* executed *)
    Ident4: ;
    Ident5: EnumParRef := Ident3;
  end; (* case *)
end; (* Proc6 *)


procedure Proc7; (* (    Int1ParVal,
                         Int2ParVal:    OneToFifty;
                     var IntParRef:     OneToFifty) *)
    (* executed three times                               *)
    (* first call:      Int1ParVal = 2, Int2ParVal = 3,   *)
    (*                  IntParRef becomes 7               *)
    (* second call:     Int1ParVal = 10, Int2ParVal = 5,  *)
    (*                  IntParRef becomes 17              *)
    (* third call:      Int1ParVal = 6, Int2ParVal = 10,  *)
    (*                  IntParRef becomes 18              *)
var
  IntLoc: OneToFifty;
begin
  IntLoc := Int1ParVal + 2;
  IntParRef := Int2ParVal + IntLoc;
end; (* Proc7 *)


procedure Proc8; (* (var Array1ParRef: Array1DimInteger;
                     var Array2ParRef: Array2DimInteger;
                         Int1ParVal,
                         Int2ParVal:    integer)          *)
    (* executed once  *)
    (* Int1ParVal = 3 *)
    (* Int2ParVal = 7 *)
var
  IntIndex,
  IntLoc:   OneToFifty;
begin
  IntLoc := Int1ParVal + 5;
  Array1ParRef [IntLoc] := Int2ParVal;
  Array1ParRef [IntLoc+1] := Array1ParRef [IntLoc];
  Array1ParRef [IntLoc+30] := IntLoc;
  for IntIndex := IntLoc to IntLoc+1 do
    Array2ParRef [IntLoc, IntIndex] := IntLoc;
  Array2ParRef [IntLoc, IntLoc-1] := Array2ParRef [IntLoc, IntLoc-1] + 1;
  Array2ParRef [IntLoc+20, IntLoc] := Array1ParRef [IntLoc];
  IntGlob := 5;
end; (* Proc8 *)


function Func1; (* (Char1ParVal,
                    Char2ParVal: CapitalLetter): Enumeration *)
    (* executed three times, returns always Ident1              *)
    (* first call:      Char1ParVal = 'H', Char2ParVal = 'R'    *)
    (* second call:     Char1ParVal = 'A', Char2ParVal = 'C'    *)
    (* third call:      Char1ParVal = 'B', Char2ParVal = 'C'    *)
var
  Char1Loc, Char2Loc: CapitalLetter;
begin
  Char1Loc := Char1ParVal;
  Char2Loc := Char1Loc;
  if Char2Loc <> Char2ParVal
  then  (* executed *)
    Func1 := Ident1
  else  (* not executed *)
  begin
    Char1Glob := Char1Loc;
    Func1 := Ident2;
  end;
end; (* Func1 *)


function Func2; (* (var String1ParRef,
                        String2ParRef: String30): boolean *)
    (* executed once, returns false              *)
    (* String1ParRef = 'DHRYSTONE PROGRAM, 1''ST STRING' *)
    (* String2ParRef = 'DHRYSTONE PROGRAM, 2''ND STRING' *)
var
  IntLoc:  OneToThirty;
  CharLoc: CapitalLetter;
begin
  IntLoc := 2;
  while IntLoc <= 2 do (* loop body executed once *)
    if Func1 (String1ParRef[IntLoc],
              String2ParRef[IntLoc+1]) = Ident1
    then (* executed *)
    begin
      CharLoc := 'A';
      IntLoc := IntLoc + 1;
    end; (* if, while *)
  if (CharLoc >= 'W') and (CharLoc < 'Z')
  then (* not executed *)
    IntLoc := 7;
  if CharLoc = 'R'
  then (* not executed *)
    Func2 := true
  else (* executed *)
  begin
    if String1ParRef > String2ParRef
    then (* not executed *)
    begin
      IntLoc := IntLoc + 7;
      IntGlob := IntLoc;
      Func2 := true
    end
    else (* executed *)
      Func2 := false;
  end; (* if CharLoc *)
end; (* Func2 *)


function Func3; (* (EnumParVal: Enumeration): boolean *)
    (* executed once, returns true      *)
    (* EnumParVal = Ident3              *)
var
  EnumLoc:  Enumeration;
begin
  EnumLoc := EnumParVal;
  if EnumLoc = Ident3
  then (* executed *)
    Func3 := true
  else (* not executed *)
    Func3 := false;
end; (* Func3 *)


begin (* main program, corresponds to procedures        *)
      (* Main and Proc_0 in the Ada version             *)

  (* Initializations *)

  new (NextPointerGlob);

  new (PointerGlob);

  PointerGlob^.PointerComp := NextPointerGlob;
  PointerGlob^.Discr       := Ident1;
  PointerGlob^.EnumComp    := Ident3;
  PointerGlob^.IntComp     := 40;
  PointerGlob^.StringComp  := 'DHRYSTONE PROGRAM, SOME STRING';

  String1Glob := 'DHRYSTONE PROGRAM, 1''ST STRING';

  Array2Glob [8,7] := 10;

  writeln;
  writeln ('Dhrystone Benchmark, Version 2.1 (Language: Pascal)');
  writeln;
  writeln ('Please give the number of runs through the benchmark: ');
  readln (NumberOfRuns);
  writeln;
  writeln ('Execution starts, ', NumberOfRuns : 7, ' runs through Dhrystone');

  BeginClock := clock;

  (***************)
  (* Start timer *)
  (***************)
  
  for RunIndex := 1 to NumberOfRuns do
  begin

    Proc5;
    Proc4;
      (* Char1Glob = 'A', Char2Glob = 'B', BoolGlob = false *)
    Int1Glob := 2;
    Int2Glob := 3;
    String2Glob := 'DHRYSTONE PROGRAM, 2''ND STRING';
    EnumGlob := Ident2;
    BoolGlob := not Func2 (String1Glob, String2Glob);
      (* BoolGlob = true *)
    while Int1Glob < Int2Glob do  (* loop body executed once *)
    begin
      Int3Glob := 5 * Int1Glob - Int2Glob;
        (* Int3Glob = 7 *)
      Proc7 (Int1Glob, Int2Glob, Int3Glob);
        (* Int3Glob = 7 *)
      Int1Glob := Int1Glob + 1;
    end; (* while *)
      (* Int1Glob = 3 *)
    Proc8 (Array1Glob, Array2Glob, Int1Glob, Int3Glob);
      (* IntGlob = 5 *)
    Proc1 (PointerGlob);
    for CharIndex := 'A' to Char2Glob do   (* loop body executed twice *)
      if EnumGlob = Func1 (CharIndex, 'C')
        then (* not executed *)
        begin
          Proc6 (Ident1, EnumGlob);
          String2Glob := 'DHRYSTONE PROGRAM, 3''RD STRING';
          Int2Glob := RunIndex;
          IntGlob := RunIndex;
        end;
    (* Int1Glob = 3, Int2Glob = 3, Int3Glob = 7 *)
    Int2Glob := Int2Glob * Int1Glob;
    Int1Glob := Int2Glob div Int3Glob;
    Int2Glob := 7 * (Int2Glob - Int3Glob) - Int1Glob;
      (* Int1Glob = 1, Int2Glob = 13, Int3Glob = 7 *)
    Proc2 (Int1Glob);
      (* Int1Glob = 5 *)

  end; (* for RunIndex *)

  EndClock := clock;

  (**************)
  (* Stop timer *)
  (**************)

  writeln ('Execution ends');
  writeln;
  writeln ('Final values of the variables used in the benchmark:');
  writeln;

  writeln ('IntGlob:                      ', IntGlob : 5);
  writeln ('        should be:                5');
  write ('BoolGlob:                      ');
  if BoolGlob = true
  then
    writeln ('TRUE')
  else
    writeln ('FALSE');
  writeln ('        should be:             TRUE');
  writeln ('Char1Glob:                        ', Char1Glob);
  writeln ('        should be:                A');
  writeln ('Char2Glob:                        ', Char2Glob);
  writeln ('        should be:                B');
  writeln ('Array1Glob [8]:               ', Array1Glob [8] : 5);
  writeln ('        should be:                7');
  writeln ('Array2Glob [8,7]:             ', Array2Glob [8,7] : 5);
  writeln ('        should be:                NumberOfRuns + 10');
  writeln ('PointerGlob^.Discr:           ', ord (PointerGlob^.Discr) : 5);
  writeln ('        should be:                0');
  writeln ('PointerGlob^.EnumComp:        ', ord (PointerGlob^.EnumComp) : 5);
  writeln ('        should be:                2');
  writeln ('PointerGlob^.IntComp  :       ', PointerGlob^.IntComp : 5);
  writeln ('        should be:               17');
  write   ('PointerGlob^.StringComp:     ');
  for I := 1 to 30 do
    write (PointerGlob^.StringComp [I]);
  writeln;
  writeln ('        should be:           DHRYSTONE PROGRAM, SOME STRING');
  writeln ('NextPointerGlob^.Discr:       ', ord (NextPointerGlob^.Discr) : 5);
  writeln ('        should be:                0');
  writeln ('NextPointerGlob^.EnumComp:    ',
                    ord (NextPointerGlob^.EnumComp) : 5);
  writeln ('        should be:                1');
  writeln ('NextPointerGlob^.IntComp:     ', NextPointerGlob^.IntComp : 5);
  writeln ('        should be:               18');
  write   ('NextPointerGlob^.StringComp: ');
  for I := 1 to 30 do
    write (NextPointerGlob^.StringComp [I]);
  writeln;
  writeln ('        should be:           DHRYSTONE PROGRAM, SOME STRING');
  writeln ('Int1Glob:                     ', Int1Glob : 5);
  writeln ('        should be:                5');
  writeln ('Int2Glob:                     ', Int2Glob : 5);
  writeln ('        should be:               13');
  writeln ('Int3Glob:                     ', Int3Glob : 5);
  writeln ('        should be:                7');
  writeln ('EnumGlob:                     ', ord (EnumGlob) : 5);
  writeln ('        should be:                1');
  write   ('String1Glob:                 ');
  for I := 1 to 30 do
    write (String1Glob [I]);
  writeln;
  writeln ('        should be:           DHRYSTONE PROGRAM, 1''ST STRING');
  write   ('String2Glob:                 ');
  for I := 1 to 30 do
    write (String2Glob [I]);
  writeln;
  writeln ('        should be:           DHRYSTONE PROGRAM, 2''ND STRING');
  writeln;
  writeln;

  SumClocks := EndClock - BeginClock;

  if SumClocks < TooSmallTime
    then
    begin
      writeln ('Measured time too small to obtain meaningful results');
      writeln ('Please increase number of runs');
      writeln;
    end
    else
    begin
      Microseconds := SumClocks * (MicrosecondsPerClock / NumberOfRuns);
                                (* Brackets to prevent integer overflow *)
      DhrystonesPerSecond := NumberOfRuns * (ClocksPerSecond / SumClocks);
      write ('Microseconds for one run through Dhrystone: ');
      writeln (Microseconds : 8 : 1);
      write ('Dhrystones per Second:                      ');
      writeln (DhrystonesPerSecond : 8 : 1);
      writeln;
    end;
  
end.