#! /usr/bin/env python

"""
"PYSTONE" Benchmark Program

Version:        Python/1.1 (corresponds to C/1.1 plus 2 Pystone fixes)

Author:         Reinhold P. Weicker,  CACM Vol 27, No 10, 10/84 pg. 1013.

                Translated from ADA to C by Rick Richardson.
                Every method to preserve ADA-likeness has been used,
                at the expense of C-ness.

                Translated from C to Python by Guido van Rossum.

Version History:

                Version 1.1 corrects two bugs in version 1.0:

                First, it leaked memory: in Proc1(), NextRecord ends
                up having a pointer to itself.  I have corrected this
                by zapping NextRecord.PtrComp at the end of Proc1().

                Second, Proc3() used the operator != to compare a
                record to None.  This is rather inefficient and not
                true to the intention of the original benchmark (where
                a pointer comparison to None is intended; the !=
                operator attempts to find a method __cmp__ to do value
                comparison of the record).  Version 1.1 runs 5-10
                percent faster than version 1.0, so benchmark figures
                of different versions can't be compared directly.

"""

LOOPS = 50000

# use a global instance instead of globals
class G(object):pass
g = G()

import sys

from time import clock

__version__ = "1.1"

[Ident1, Ident2, Ident3, Ident4, Ident5] = range(1, 6)

class Record(object):

    def __init__(self, PtrComp = None, Discr = 0, EnumComp = 0,
                       IntComp = 0, StringComp = ""):
        self.PtrComp = PtrComp
        self.Discr = Discr
        self.EnumComp = EnumComp
        self.IntComp = IntComp
        self.StringComp = StringComp

    def copy(self):
        return Record(self.PtrComp, self.Discr, self.EnumComp,
                      self.IntComp, self.StringComp)

TRUE = 1
FALSE = 0

def main(loops=LOOPS):
    benchtime, stones = pystones(abs(loops))
    if loops >= 0:
        print "Pystone(%s) time for %d passes = %g" % \
              (__version__, loops, benchtime)
        print "This machine benchmarks at %g pystones/second" % stones


def pystones(loops=LOOPS):
    return Proc0(loops)

g.IntGlob = 0
g.BoolGlob = FALSE
g.Char1Glob = '\0'
g.Char2Glob = '\0'
g.Array1Glob = [0]*51
g.Array2Glob = map(lambda x: x[:], [g.Array1Glob]*51)
g.PtrGlb = None
g.PtrGlbNext = None

def Proc0(loops=LOOPS):
    #global IntGlob
    #global BoolGlob
    #global Char1Glob
    #global Char2Glob
    #global Array1Glob
    #global Array2Glob
    #global PtrGlb
    #global PtrGlbNext

    starttime = clock()
    #for i in range(loops):
    # this is bad with very large values of loops
    # XXX xrange support?
    i = 0
    while i < loops:
        i += 1
    # the above is most likely to vanish in C :-(
    nulltime = clock() - starttime

    g.PtrGlbNext = Record()
    g.PtrGlb = Record()
    g.PtrGlb.PtrComp = g.PtrGlbNext
    g.PtrGlb.Discr = Ident1
    g.PtrGlb.EnumComp = Ident3
    g.PtrGlb.IntComp = 40
    g.PtrGlb.StringComp = "DHRYSTONE PROGRAM, SOME STRING"
    String1Loc = "DHRYSTONE PROGRAM, 1'ST STRING"
    g.Array2Glob[8][7] = 10

    EnumLoc = None # addition for flow space
    starttime = clock()

    #for i in range(loops):
    # this is bad with very large values of loops
    # XXX xrange support?
    i = 0
    while i < loops:
        Proc5()
        Proc4()
        IntLoc1 = 2
        IntLoc2 = 3
        String2Loc = "DHRYSTONE PROGRAM, 2'ND STRING"
        EnumLoc = Ident2
        g.BoolGlob = not Func2(String1Loc, String2Loc)
        while IntLoc1 < IntLoc2:
            IntLoc3 = 5 * IntLoc1 - IntLoc2
            IntLoc3 = Proc7(IntLoc1, IntLoc2)
            IntLoc1 = IntLoc1 + 1
        Proc8(g.Array1Glob, g.Array2Glob, IntLoc1, IntLoc3)
        g.PtrGlb = Proc1(g.PtrGlb)
        CharIndex = 'A'
        while CharIndex <= g.Char2Glob:
            if EnumLoc == Func1(CharIndex, 'C'):
                EnumLoc = Proc6(Ident1)
            CharIndex = chr(ord(CharIndex)+1)
        IntLoc3 = IntLoc2 * IntLoc1
        IntLoc2 = IntLoc3 / IntLoc1
        IntLoc2 = 7 * (IntLoc3 - IntLoc2) - IntLoc1
        IntLoc1 = Proc2(IntLoc1)
        i += 1

    benchtime = clock() - starttime - nulltime
    if benchtime < 1E-8:
        benchtime = 1E-8   # time too short, meaningless results anyway
    return benchtime, (loops / benchtime)

def Proc1(PtrParIn):
    PtrParIn.PtrComp = NextRecord = g.PtrGlb.copy()
    PtrParIn.IntComp = 5
    NextRecord.IntComp = PtrParIn.IntComp
    NextRecord.PtrComp = PtrParIn.PtrComp
    NextRecord.PtrComp = Proc3(NextRecord.PtrComp)
    if NextRecord.Discr == Ident1:
        NextRecord.IntComp = 6
        NextRecord.EnumComp = Proc6(PtrParIn.EnumComp)
        NextRecord.PtrComp = g.PtrGlb.PtrComp
        NextRecord.IntComp = Proc7(NextRecord.IntComp, 10)
    else:
        PtrParIn = NextRecord.copy()
    NextRecord.PtrComp = None
    return PtrParIn

def Proc2(IntParIO):
    IntLoc = IntParIO + 10
    EnumLoc = None # addition for flow space
    while 1:
        if g.Char1Glob == 'A':
            IntLoc = IntLoc - 1
            IntParIO = IntLoc - g.IntGlob
            EnumLoc = Ident1
        if EnumLoc == Ident1:
            break
    return IntParIO

def Proc3(PtrParOut):
    #global IntGlob

    if g.PtrGlb is not None:
        PtrParOut = g.PtrGlb.PtrComp
    else:
        g.IntGlob = 100
    g.PtrGlb.IntComp = Proc7(10, g.IntGlob)
    return PtrParOut

def Proc4():
    #global Char2Glob

    BoolLoc = g.Char1Glob == 'A'
    BoolLoc = BoolLoc or g.BoolGlob
    g.Char2Glob = 'B'

def Proc5():
    #global Char1Glob
    #global BoolGlob

    g.Char1Glob = 'A'
    g.BoolGlob = FALSE

def Proc6(EnumParIn):
    EnumParOut = EnumParIn
    if not Func3(EnumParIn):
        EnumParOut = Ident4
    if EnumParIn == Ident1:
        EnumParOut = Ident1
    elif EnumParIn == Ident2:
        if g.IntGlob > 100:
            EnumParOut = Ident1
        else:
            EnumParOut = Ident4
    elif EnumParIn == Ident3:
        EnumParOut = Ident2
    elif EnumParIn == Ident4:
        pass
    elif EnumParIn == Ident5:
        EnumParOut = Ident3
    return EnumParOut

def Proc7(IntParI1, IntParI2):
    IntLoc = IntParI1 + 2
    IntParOut = IntParI2 + IntLoc
    return IntParOut

def Proc8(Array1Par, Array2Par, IntParI1, IntParI2):
    #global IntGlob

    IntLoc = IntParI1 + 5
    Array1Par[IntLoc] = IntParI2
    Array1Par[IntLoc+1] = Array1Par[IntLoc]
    Array1Par[IntLoc+30] = IntLoc
    for IntIndex in range(IntLoc, IntLoc+2):
        Array2Par[IntLoc][IntIndex] = IntLoc
    Array2Par[IntLoc][IntLoc-1] = Array2Par[IntLoc][IntLoc-1] + 1
    Array2Par[IntLoc+20][IntLoc] = Array1Par[IntLoc]
    g.IntGlob = 5

def Func1(CharPar1, CharPar2):
    CharLoc1 = CharPar1
    CharLoc2 = CharLoc1
    if CharLoc2 != CharPar2:
        return Ident1
    else:
        return Ident2

def Func2(StrParI1, StrParI2):
    IntLoc = 1
    while IntLoc <= 1:
        if Func1(StrParI1[IntLoc], StrParI2[IntLoc+1]) == Ident1:
            CharLoc = 'A'
            IntLoc = IntLoc + 1
    if CharLoc >= 'W' and CharLoc <= 'Z':
        IntLoc = 7
    if CharLoc == 'X':
        return TRUE
    else:
        if StrParI1 > StrParI2:
            IntLoc = IntLoc + 7
            return TRUE
        else:
            return FALSE

def Func3(EnumParIn):
    EnumLoc = EnumParIn
    if EnumLoc == Ident3: return TRUE
    return FALSE

def error(msg):
    print >> sys.stderr, msg,
    print >> sys.stderr, "usage: %s [number_of_loops]" % sys.argv[0]
    sys.exit(100)

def entrypoint(loops=None):
    import string # just a little test
    print string.replace("import works", "s", "x")
    if loops is None:
        loops = LOOPS  # initialize early, for slow space
        nargs = len(sys.argv) - 1
        if nargs > 1:
            error("%d arguments are too many;" % nargs)
        elif nargs == 1:
            try: loops = int(sys.argv[1])
            except ValueError:
                error("Invalid argument %r;" % sys.argv[1])
        else:
            if hasattr(sys, 'pypy_objspaceclass'):
                loops = LOOPS / 2000 # XXX rough estimate, adjust
    main(loops)

if __name__ == '__main__':
    entrypoint()
