[net.sources] Dhrystone benchmark, part 3 of 4

bea@siemens.UUCP (11/15/84)

(******************************************************************************)
(*                                                                            *)
(*                   "DHRYSTONE" Benchmark Program                            *)
(*                   -----------------------------                            *)
(*                                                                            *)
(*  Version:   Pascal / 2 (Measurement Version, for Berkeley UNIX Pascal)     *)
(*                                                                            *)
(*  File:      dhry-mea.p                                                     *)
(*                                                                            *)
(*  Date:      Oct. 1984                                                      *)
(*                                                                            *)
(*  Author:    Reinhold P. Weicker                                            *)
(*                                                                            *)
(******************************************************************************)
(*                                                                            *)
(*  This version uses calls to the Pascal runtime library of the Berkeley     *)
(*  UNIX system (4.2 bsd) for time measurement. For measurements on other     *)
(*  systems, these calls need to be modified.                                 *)
(*                                                                            *)
(******************************************************************************)
(*                                                                            *)
(*  The following program contains statements of a high level programming     *)
(*  language (here: Pascal) in a distribution considered representative:      *)
(*                                                                            *)
(*    assignments                  58 %                                       *)
(*    control statements           27 %                                       *)
(*    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 (= percentage)                       *)
(*                                                                            *)
(*     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 ...        6  |  counted every time                   *)
(*     while ... do ...            4  |  the loop condition                   *)
(*     repeat ... until            1  |  is evaluated                         *)
(*     case ... end                1                                          *)
(*     with                        1                                          *)
(*                                --                                          *)
(*                                27       27                                 *)
(*                                                                            *)
(*     P (...)  procedure call    10                                          *)
(*     X := F (...)                                                           *)
(*             function  call      5                                          *)
(*                                --                                          *)
(*                                15       15                                 *)
(*                                        ---                                 *)
(*                                        100                                 *)
(*                                                                            *)
(*    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               131        53.9 %                                *)
(*     Character              47        19.3 %                                *)
(*     Enumeration            31        12.8 %                                *)
(*     Boolean                13         5.3 %                                *)
(*     Pointer                11         4.5 %                                *)
(*     String30                6         2.5 %                                *)
(*     Array                   2         0.8 %                                *)
(*     Record                  2         0.8 %                                *)
(*                           ---       -------                                *)
(*                           243        99.9 %                                *)
(*                                                                            *)
(*  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               81        33.3 %                          *)
(*     global variable              57        23.5 %                          *)
(*     parameter                    45        18.5 %                          *)
(*        value                        23         9.5 %                       *)
(*        reference                    22         9.1 %                       *)
(*     function result               5         2.1 %                          *)
(*     constant                     55        22.6 %                          *)
(*                                 ---       -------                          *)
(*                                 243       100.0 %                          *)
(*                                                                            *)
(*                                                                            *)
(*  The program does 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.                                                                     *)
(*                                                                            *)
(*  As far as the program structure is concerned, no attempt has been made    *)
(*  to construct a Pascal version with several modules (similar to the Ada    *)
(*  and C versions) since Standard Pascal does not have a separate            *)
(*  compilation model.                                                        *)
(*                                                                            *)
(******************************************************************************)

program Dhrystone;
(****************)

const (* for measurement *)

  NumberOfExecutions	= 10000;
  NumberOfMeasurements	= 10;
  LargeRealNumber	= 1000000.0;

  MicrosecondsPerClock	= 1000;
        (* In Berkeley UNIX Pascal, the function "clock"        *)
        (* returns milliseconds                                 *)

type

  (* Global type definitions *)

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

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

  String30 = packed array [1..30] 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:
            (EnumComp2:    Enumeration;
             StringComp2:  String30);
          Ident3, Ident4, Ident5:
            (CharComp1,
             CharComp2:    char);
      end; (* record *)

var

  (* for measurement only *)

  ExecutionIndex:    1..NumberOfExecutions;
  MeasurementIndex:  1..NumberOfMeasurements;
  BeginClock,
  EndClock:          integer;
  SumClocks,
  EmptyLoopClocks,
  TimePerExecution,  
  SumTime,
  MinTime:           real;

  (* end of variables for measurement *)

  PointerGlob,
  NextPointerGlob: RecordPointer;
  IntGlob:         integer;

  BoolGlob:        boolean;
  CharGlob1,
  CharGlob2:       char;
  ArrayGlob1:      Array1DimInteger;
  ArrayGlob2:      Array2DimInteger;

  IntGlob1,
  IntGlob2,
  IntGlob3:       OneToFifty;
  CharIndex:      char;
  EnumGlob:       Enumeration;
  StringGlob1,
  StringGlob2:    String30;


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 (    IntPar1Val,
                     IntPar2Val:    OneToFifty;
                 var IntParRef:     OneToFifty);        forward;

procedure Proc8 (var ArrayPar1Ref:  Array1DimInteger;
                 var ArrayPar2Ref:  Array2DimInteger;
                     IntPar1Val,
                     IntPar2Val:    integer);            forward;

function Func1  (    CharPar1Val,
                     CharPar2Val:   CapitalLetter): 
                                            Enumeration; forward;

function Func2  (var StringPar1Ref,
                     StringPar2Ref: 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 CharGlob1 = '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
  else (* not executed *)
    IntGlob := 100;
  Proc7 (10, IntGlob, PointerGlob^.IntComp);
end; (* Proc3 *)


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


procedure Proc5; (* without parameters *)
    (* executed once *)
begin
  CharGlob1 := '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; (* (    IntPar1Val,
                         IntPar2Val:    OneToFifty;
                     var IntParRef:     OneToFifty) *)
    (* executed three times                               *)
    (* first call:      IntPar1Val = 2, IntPar2Val = 3,   *)
    (*                  IntParRef becomes 7              *)
    (* second call:     IntPar1Val = 6, IntPar2Val = 10,  *)
    (*                  IntParRef becomes 18              *)
    (* third call:      IntPar1Val = 10, IntPar2Val = 5,  *)
    (*                  IntParRef becomes 17              *)
var
  IntLoc: OneToFifty;
begin
  IntLoc := IntPar1Val + 2;
  IntParRef := IntPar2Val + IntLoc;
end; (* Proc7 *)


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


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


function Func2; (* (var StringPar1Ref,
                        StringPar2Ref: String30): boolean *)
    (* executed once, returns false              *)
    (* StringPar1Ref = 'DHRYSTONE PROGRAM, 1''ST STRING' *)
    (* StringPar2Ref = 'DHRYSTONE PROGRAM, 2''ND STRING' *)
var
  IntLoc:  OneToThirty;
  CharLoc: CapitalLetter;
begin
  IntLoc := 2;
  while IntLoc <= 2 do (* loop body executed once *)
    if Func1 (StringPar1Ref[IntLoc],
              StringPar2Ref[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 = 'X'
  then (* not executed *)
    Func2 := true
  else (* executed *)
  begin
    if StringPar1Ref > StringPar2Ref
    then (* not executed *)
    begin
      IntLoc := IntLoc + 7;
      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;
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';

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

  writeln;
  writeln ('Dhrystone Benchmark (March 84), Version Pascal / 2');
  writeln ('Times are CPU user time per execution, in microseconds');
  writeln;

  SumTime := 0.0;
  MinTime := LargeRealNumber;

  for MeasurementIndex :=  1 to NumberOfMeasurements do
  begin

    BeginClock := clock;

    (***************)
    (* Start timer *)
    (***************)
  
    for ExecutionIndex := 1 to NumberOfExecutions do
    begin

      Proc5;
      Proc4;
        (* CharGlob1 = 'A', CharGlob2 = 'B', BoolGlob = false *)
      IntGlob1 := 2;
      IntGlob2 := 3;
      StringGlob2 := 'DHRYSTONE PROGRAM, 2''ND STRING';
      EnumGlob := Ident2;
      BoolGlob := Func2 (StringGlob1, StringGlob2);
        (* BoolGlob = false *)
      while IntGlob1 < IntGlob2 do  (* loop body executed once *)
      begin
        IntGlob3 := 5 * IntGlob1 - IntGlob2;
          (* IntGlob3 = 7 *)
        Proc7 (IntGlob1, IntGlob2, IntGlob3);
          (* IntGlob3 = 7 *)
        IntGlob1 := IntGlob1 + 1;
      end; (* while *)
        (* IntGlob1 = 3 *)
      Proc8 (ArrayGlob1, ArrayGlob2, IntGlob1, IntGlob3);
        (* IntGlob = 5 *)
      Proc1 (PointerGlob);
      for CharIndex := 'A' to CharGlob2 do   (* loop body executed twice *)
        if EnumGlob = Func1 (CharIndex, 'C')
        then (* not executed *)
          Proc6 (Ident1, EnumGlob);
      (* IntGlob1 = 3, IntGlob2 = 3, IntGlob3 = 7 *)
      IntGlob3 := IntGlob2 * IntGlob1;
      IntGlob2 := IntGlob3 div IntGlob1;
      IntGlob2 := 7 * (IntGlob3 - IntGlob2) - IntGlob1;
      Proc2 (IntGlob1);
 
    end; (* for ExecutionIndex *)

    EndClock := clock;

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

    SumClocks := (EndClock - BeginClock) * MicrosecondsPerClock;

    (* Measure and subtract time for NumberOfExecutions empty loops *)

    BeginClock := clock;
    for ExecutionIndex := 1 to NumberOfExecutions do
    begin
      (* empty *)
    end;
    EndClock := clock;
    EmptyLoopClocks := (EndClock - BeginClock) * MicrosecondsPerClock;

    SumClocks := SumClocks - EmptyLoopClocks;

    TimePerExecution := SumClocks / NumberOfExecutions;

    write ('Time for run ', MeasurementIndex : 2, ':');
    writeln (TimePerExecution : 8 : 1);

    SumTime := SumTime + TimePerExecution;
    if TimePerExecution < MinTime
    then MinTime := TimePerExecution;

  end; (* for MeasurementIndex *)

  writeln;
  write ('Average execution time: ');
  writeln (SumTime/NumberOfMeasurements : 8 : 1);
  writeln;
  write ('Minimum execution time: ');
  writeln (MinTime : 8 : 1);
  writeln;
end.