xref: /openbsd-src/gnu/llvm/llvm/examples/Kaleidoscope/MCJIT/complete/genk-timing.py (revision 09467b48e8bc8b4905716062da846024139afbf2)
1*09467b48Spatrick#!/usr/bin/env python
2*09467b48Spatrick
3*09467b48Spatrickfrom __future__ import print_function
4*09467b48Spatrick
5*09467b48Spatrickimport sys
6*09467b48Spatrickimport random
7*09467b48Spatrick
8*09467b48Spatrickclass TimingScriptGenerator:
9*09467b48Spatrick    """Used to generate a bash script which will invoke the toy and time it"""
10*09467b48Spatrick    def __init__(self, scriptname, outputname):
11*09467b48Spatrick        self.timeFile = outputname
12*09467b48Spatrick        self.shfile = open(scriptname, 'w')
13*09467b48Spatrick        self.shfile.write("echo \"\" > %s\n" % self.timeFile)
14*09467b48Spatrick
15*09467b48Spatrick    def writeTimingCall(self, filename, numFuncs, funcsCalled, totalCalls):
16*09467b48Spatrick        """Echo some comments and invoke both versions of toy"""
17*09467b48Spatrick        rootname = filename
18*09467b48Spatrick        if '.' in filename:
19*09467b48Spatrick            rootname = filename[:filename.rfind('.')]
20*09467b48Spatrick        self.shfile.write("echo \"%s: Calls %d of %d functions, %d total\" >> %s\n" % (filename, funcsCalled, numFuncs, totalCalls, self.timeFile))
21*09467b48Spatrick        self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
22*09467b48Spatrick        self.shfile.write("echo \"With MCJIT (original)\" >> %s\n" % self.timeFile)
23*09467b48Spatrick        self.shfile.write("/usr/bin/time -f \"Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb\"")
24*09467b48Spatrick        self.shfile.write(" -o %s -a " % self.timeFile)
25*09467b48Spatrick        self.shfile.write("./toy -suppress-prompts -use-mcjit=true -enable-lazy-compilation=false < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (filename, rootname, rootname))
26*09467b48Spatrick        self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
27*09467b48Spatrick        self.shfile.write("echo \"With MCJIT (lazy)\" >> %s\n" % self.timeFile)
28*09467b48Spatrick        self.shfile.write("/usr/bin/time -f \"Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb\"")
29*09467b48Spatrick        self.shfile.write(" -o %s -a " % self.timeFile)
30*09467b48Spatrick        self.shfile.write("./toy -suppress-prompts -use-mcjit=true -enable-lazy-compilation=true < %s > %s-mcjit-lazy.out 2> %s-mcjit-lazy.err\n" % (filename, rootname, rootname))
31*09467b48Spatrick        self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
32*09467b48Spatrick        self.shfile.write("echo \"With JIT\" >> %s\n" % self.timeFile)
33*09467b48Spatrick        self.shfile.write("/usr/bin/time -f \"Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb\"")
34*09467b48Spatrick        self.shfile.write(" -o %s -a " % self.timeFile)
35*09467b48Spatrick        self.shfile.write("./toy -suppress-prompts -use-mcjit=false < %s > %s-jit.out 2> %s-jit.err\n" % (filename, rootname, rootname))
36*09467b48Spatrick        self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
37*09467b48Spatrick        self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
38*09467b48Spatrick
39*09467b48Spatrickclass KScriptGenerator:
40*09467b48Spatrick    """Used to generate random Kaleidoscope code"""
41*09467b48Spatrick    def __init__(self, filename):
42*09467b48Spatrick        self.kfile = open(filename, 'w')
43*09467b48Spatrick        self.nextFuncNum = 1
44*09467b48Spatrick        self.lastFuncNum = None
45*09467b48Spatrick        self.callWeighting = 0.1
46*09467b48Spatrick        # A mapping of calls within functions with no duplicates
47*09467b48Spatrick        self.calledFunctionTable = {}
48*09467b48Spatrick        # A list of function calls which will actually be executed
49*09467b48Spatrick        self.calledFunctions = []
50*09467b48Spatrick        # A comprehensive mapping of calls within functions
51*09467b48Spatrick        # used for computing the total number of calls
52*09467b48Spatrick        self.comprehensiveCalledFunctionTable = {}
53*09467b48Spatrick        self.totalCallsExecuted = 0
54*09467b48Spatrick
55*09467b48Spatrick    def updateTotalCallCount(self, callee):
56*09467b48Spatrick        # Count this call
57*09467b48Spatrick        self.totalCallsExecuted += 1
58*09467b48Spatrick        # Then count all the functions it calls
59*09467b48Spatrick        if callee in self.comprehensiveCalledFunctionTable:
60*09467b48Spatrick            for child in self.comprehensiveCalledFunctionTable[callee]:
61*09467b48Spatrick                self.updateTotalCallCount(child)
62*09467b48Spatrick
63*09467b48Spatrick    def updateFunctionCallMap(self, caller, callee):
64*09467b48Spatrick        """Maintains a map of functions that are called from other functions"""
65*09467b48Spatrick        if not caller in self.calledFunctionTable:
66*09467b48Spatrick            self.calledFunctionTable[caller] = []
67*09467b48Spatrick        if not callee in self.calledFunctionTable[caller]:
68*09467b48Spatrick            self.calledFunctionTable[caller].append(callee)
69*09467b48Spatrick        if not caller in self.comprehensiveCalledFunctionTable:
70*09467b48Spatrick            self.comprehensiveCalledFunctionTable[caller] = []
71*09467b48Spatrick        self.comprehensiveCalledFunctionTable[caller].append(callee)
72*09467b48Spatrick
73*09467b48Spatrick    def updateCalledFunctionList(self, callee):
74*09467b48Spatrick        """Maintains a list of functions that will actually be called"""
75*09467b48Spatrick        # Update the total call count
76*09467b48Spatrick        self.updateTotalCallCount(callee)
77*09467b48Spatrick        # If this function is already in the list, don't do anything else
78*09467b48Spatrick        if callee in self.calledFunctions:
79*09467b48Spatrick            return
80*09467b48Spatrick        # Add this function to the list of those that will be called.
81*09467b48Spatrick        self.calledFunctions.append(callee)
82*09467b48Spatrick        # If this function calls other functions, add them too
83*09467b48Spatrick        if callee in self.calledFunctionTable:
84*09467b48Spatrick            for subCallee in self.calledFunctionTable[callee]:
85*09467b48Spatrick                self.updateCalledFunctionList(subCallee)
86*09467b48Spatrick
87*09467b48Spatrick    def setCallWeighting(self, weight):
88*09467b48Spatrick        """ Sets the probably of generating a function call"""
89*09467b48Spatrick        self.callWeighting = weight
90*09467b48Spatrick
91*09467b48Spatrick    def writeln(self, line):
92*09467b48Spatrick        self.kfile.write(line + '\n')
93*09467b48Spatrick
94*09467b48Spatrick    def writeComment(self, comment):
95*09467b48Spatrick        self.writeln('# ' + comment)
96*09467b48Spatrick
97*09467b48Spatrick    def writeEmptyLine(self):
98*09467b48Spatrick        self.writeln("")
99*09467b48Spatrick
100*09467b48Spatrick    def writePredefinedFunctions(self):
101*09467b48Spatrick        self.writeComment("Define ':' for sequencing: as a low-precedence operator that ignores operands")
102*09467b48Spatrick        self.writeComment("and just returns the RHS.")
103*09467b48Spatrick        self.writeln("def binary : 1 (x y) y;")
104*09467b48Spatrick        self.writeEmptyLine()
105*09467b48Spatrick        self.writeComment("Helper functions defined within toy")
106*09467b48Spatrick        self.writeln("extern putchard(x);")
107*09467b48Spatrick        self.writeln("extern printd(d);")
108*09467b48Spatrick        self.writeln("extern printlf();")
109*09467b48Spatrick        self.writeEmptyLine()
110*09467b48Spatrick        self.writeComment("Print the result of a function call")
111*09467b48Spatrick        self.writeln("def printresult(N Result)")
112*09467b48Spatrick        self.writeln("  # 'result('")
113*09467b48Spatrick        self.writeln("  putchard(114) : putchard(101) : putchard(115) : putchard(117) : putchard(108) : putchard(116) : putchard(40) :")
114*09467b48Spatrick        self.writeln("  printd(N) :");
115*09467b48Spatrick        self.writeln("  # ') = '")
116*09467b48Spatrick        self.writeln("  putchard(41) : putchard(32) : putchard(61) : putchard(32) :")
117*09467b48Spatrick        self.writeln("  printd(Result) :");
118*09467b48Spatrick        self.writeln("  printlf();")
119*09467b48Spatrick        self.writeEmptyLine()
120*09467b48Spatrick
121*09467b48Spatrick    def writeRandomOperation(self, LValue, LHS, RHS):
122*09467b48Spatrick        shouldCallFunc = (self.lastFuncNum > 2 and random.random() < self.callWeighting)
123*09467b48Spatrick        if shouldCallFunc:
124*09467b48Spatrick            funcToCall = random.randrange(1, self.lastFuncNum - 1)
125*09467b48Spatrick            self.updateFunctionCallMap(self.lastFuncNum, funcToCall)
126*09467b48Spatrick            self.writeln("  %s = func%d(%s, %s) :" % (LValue, funcToCall, LHS, RHS))
127*09467b48Spatrick        else:
128*09467b48Spatrick            possibleOperations = ["+", "-", "*", "/"]
129*09467b48Spatrick            operation = random.choice(possibleOperations)
130*09467b48Spatrick            if operation == "-":
131*09467b48Spatrick                # Don't let our intermediate value become zero
132*09467b48Spatrick                # This is complicated by the fact that '<' is our only comparison operator
133*09467b48Spatrick                self.writeln("  if %s < %s then" % (LHS, RHS))
134*09467b48Spatrick                self.writeln("    %s = %s %s %s" % (LValue, LHS, operation, RHS))
135*09467b48Spatrick                self.writeln("  else if %s < %s then" % (RHS, LHS))
136*09467b48Spatrick                self.writeln("    %s = %s %s %s" % (LValue, LHS, operation, RHS))
137*09467b48Spatrick                self.writeln("  else")
138*09467b48Spatrick                self.writeln("    %s = %s %s %f :" % (LValue, LHS, operation, random.uniform(1, 100)))
139*09467b48Spatrick            else:
140*09467b48Spatrick                self.writeln("  %s = %s %s %s :" % (LValue, LHS, operation, RHS))
141*09467b48Spatrick
142*09467b48Spatrick    def getNextFuncNum(self):
143*09467b48Spatrick        result = self.nextFuncNum
144*09467b48Spatrick        self.nextFuncNum += 1
145*09467b48Spatrick        self.lastFuncNum = result
146*09467b48Spatrick        return result
147*09467b48Spatrick
148*09467b48Spatrick    def writeFunction(self, elements):
149*09467b48Spatrick        funcNum = self.getNextFuncNum()
150*09467b48Spatrick        self.writeComment("Auto-generated function number %d" % funcNum)
151*09467b48Spatrick        self.writeln("def func%d(X Y)" % funcNum)
152*09467b48Spatrick        self.writeln("  var temp1 = X,")
153*09467b48Spatrick        self.writeln("      temp2 = Y,")
154*09467b48Spatrick        self.writeln("      temp3 in")
155*09467b48Spatrick        # Initialize the variable names to be rotated
156*09467b48Spatrick        first = "temp3"
157*09467b48Spatrick        second = "temp1"
158*09467b48Spatrick        third = "temp2"
159*09467b48Spatrick        # Write some random operations
160*09467b48Spatrick        for i in range(elements):
161*09467b48Spatrick            self.writeRandomOperation(first, second, third)
162*09467b48Spatrick            # Rotate the variables
163*09467b48Spatrick            temp = first
164*09467b48Spatrick            first = second
165*09467b48Spatrick            second = third
166*09467b48Spatrick            third = temp
167*09467b48Spatrick        self.writeln("  " + third + ";")
168*09467b48Spatrick        self.writeEmptyLine()
169*09467b48Spatrick
170*09467b48Spatrick    def writeFunctionCall(self):
171*09467b48Spatrick        self.writeComment("Call the last function")
172*09467b48Spatrick        arg1 = random.uniform(1, 100)
173*09467b48Spatrick        arg2 = random.uniform(1, 100)
174*09467b48Spatrick        self.writeln("printresult(%d, func%d(%f, %f) )" % (self.lastFuncNum, self.lastFuncNum, arg1, arg2))
175*09467b48Spatrick        self.writeEmptyLine()
176*09467b48Spatrick        self.updateCalledFunctionList(self.lastFuncNum)
177*09467b48Spatrick
178*09467b48Spatrick    def writeFinalFunctionCounts(self):
179*09467b48Spatrick        self.writeComment("Called %d of %d functions" % (len(self.calledFunctions), self.lastFuncNum))
180*09467b48Spatrick
181*09467b48Spatrickdef generateKScript(filename, numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting, timingScript):
182*09467b48Spatrick    """ Generate a random Kaleidoscope script based on the given parameters """
183*09467b48Spatrick    print("Generating " + filename)
184*09467b48Spatrick    print("  %d functions, %d elements per function, %d functions between execution" %
185*09467b48Spatrick          (numFuncs, elementsPerFunc, funcsBetweenExec))
186*09467b48Spatrick    print("  Call weighting = %f" % callWeighting)
187*09467b48Spatrick    script = KScriptGenerator(filename)
188*09467b48Spatrick    script.setCallWeighting(callWeighting)
189*09467b48Spatrick    script.writeComment("===========================================================================")
190*09467b48Spatrick    script.writeComment("Auto-generated script")
191*09467b48Spatrick    script.writeComment("  %d functions, %d elements per function, %d functions between execution"
192*09467b48Spatrick                         % (numFuncs, elementsPerFunc, funcsBetweenExec))
193*09467b48Spatrick    script.writeComment("  call weighting = %f" % callWeighting)
194*09467b48Spatrick    script.writeComment("===========================================================================")
195*09467b48Spatrick    script.writeEmptyLine()
196*09467b48Spatrick    script.writePredefinedFunctions()
197*09467b48Spatrick    funcsSinceLastExec = 0
198*09467b48Spatrick    for i in range(numFuncs):
199*09467b48Spatrick        script.writeFunction(elementsPerFunc)
200*09467b48Spatrick        funcsSinceLastExec += 1
201*09467b48Spatrick        if funcsSinceLastExec == funcsBetweenExec:
202*09467b48Spatrick            script.writeFunctionCall()
203*09467b48Spatrick            funcsSinceLastExec = 0
204*09467b48Spatrick    # Always end with a function call
205*09467b48Spatrick    if funcsSinceLastExec > 0:
206*09467b48Spatrick        script.writeFunctionCall()
207*09467b48Spatrick    script.writeEmptyLine()
208*09467b48Spatrick    script.writeFinalFunctionCounts()
209*09467b48Spatrick    funcsCalled = len(script.calledFunctions)
210*09467b48Spatrick    print("  Called %d of %d functions, %d total" % (funcsCalled, numFuncs, script.totalCallsExecuted))
211*09467b48Spatrick    timingScript.writeTimingCall(filename, numFuncs, funcsCalled, script.totalCallsExecuted)
212*09467b48Spatrick
213*09467b48Spatrick# Execution begins here
214*09467b48Spatrickrandom.seed()
215*09467b48Spatrick
216*09467b48SpatricktimingScript = TimingScriptGenerator("time-toy.sh", "timing-data.txt")
217*09467b48Spatrick
218*09467b48SpatrickdataSets = [(5000, 3,  50, 0.50), (5000, 10, 100, 0.10), (5000, 10, 5, 0.10), (5000, 10, 1, 0.0),
219*09467b48Spatrick            (1000, 3,  10, 0.50), (1000, 10, 100, 0.10), (1000, 10, 5, 0.10), (1000, 10, 1, 0.0),
220*09467b48Spatrick            ( 200, 3,   2, 0.50), ( 200, 10,  40, 0.10), ( 200, 10, 2, 0.10), ( 200, 10, 1, 0.0)]
221*09467b48Spatrick
222*09467b48Spatrick# Generate the code
223*09467b48Spatrickfor (numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting) in dataSets:
224*09467b48Spatrick    filename = "test-%d-%d-%d-%d.k" % (numFuncs, elementsPerFunc, funcsBetweenExec, int(callWeighting * 100))
225*09467b48Spatrick    generateKScript(filename, numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting, timingScript)
226*09467b48Spatrickprint("All done!")
227