3 from __future__
import print_function
9 class TimingScriptGenerator
:
10 """Used to generate a bash script which will invoke the toy and time it"""
12 def __init__(self
, scriptname
, outputname
):
13 self
.timeFile
= outputname
14 self
.shfile
= open(scriptname
, "w")
15 self
.shfile
.write('echo "" > %s\n' % self
.timeFile
)
17 def writeTimingCall(self
, filename
, numFuncs
, funcsCalled
, totalCalls
):
18 """Echo some comments and invoke both versions of toy"""
21 rootname
= filename
[: filename
.rfind(".")]
23 'echo "%s: Calls %d of %d functions, %d total" >> %s\n'
24 % (filename
, funcsCalled
, numFuncs
, totalCalls
, self
.timeFile
)
26 self
.shfile
.write('echo "" >> %s\n' % self
.timeFile
)
27 self
.shfile
.write('echo "With MCJIT" >> %s\n' % self
.timeFile
)
29 '/usr/bin/time -f "Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb"'
31 self
.shfile
.write(" -o %s -a " % self
.timeFile
)
33 "./toy-mcjit < %s > %s-mcjit.out 2> %s-mcjit.err\n"
34 % (filename
, rootname
, rootname
)
36 self
.shfile
.write('echo "" >> %s\n' % self
.timeFile
)
37 self
.shfile
.write('echo "With JIT" >> %s\n' % self
.timeFile
)
39 '/usr/bin/time -f "Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb"'
41 self
.shfile
.write(" -o %s -a " % self
.timeFile
)
43 "./toy-jit < %s > %s-jit.out 2> %s-jit.err\n"
44 % (filename
, rootname
, rootname
)
46 self
.shfile
.write('echo "" >> %s\n' % self
.timeFile
)
47 self
.shfile
.write('echo "" >> %s\n' % self
.timeFile
)
50 class KScriptGenerator
:
51 """Used to generate random Kaleidoscope code"""
53 def __init__(self
, filename
):
54 self
.kfile
= open(filename
, "w")
56 self
.lastFuncNum
= None
57 self
.callWeighting
= 0.1
58 # A mapping of calls within functions with no duplicates
59 self
.calledFunctionTable
= {}
60 # A list of function calls which will actually be executed
61 self
.calledFunctions
= []
62 # A comprehensive mapping of calls within functions
63 # used for computing the total number of calls
64 self
.comprehensiveCalledFunctionTable
= {}
65 self
.totalCallsExecuted
= 0
67 def updateTotalCallCount(self
, callee
):
69 self
.totalCallsExecuted
+= 1
70 # Then count all the functions it calls
71 if callee
in self
.comprehensiveCalledFunctionTable
:
72 for child
in self
.comprehensiveCalledFunctionTable
[callee
]:
73 self
.updateTotalCallCount(child
)
75 def updateFunctionCallMap(self
, caller
, callee
):
76 """Maintains a map of functions that are called from other functions"""
77 if not caller
in self
.calledFunctionTable
:
78 self
.calledFunctionTable
[caller
] = []
79 if not callee
in self
.calledFunctionTable
[caller
]:
80 self
.calledFunctionTable
[caller
].append(callee
)
81 if not caller
in self
.comprehensiveCalledFunctionTable
:
82 self
.comprehensiveCalledFunctionTable
[caller
] = []
83 self
.comprehensiveCalledFunctionTable
[caller
].append(callee
)
85 def updateCalledFunctionList(self
, callee
):
86 """Maintains a list of functions that will actually be called"""
87 # Update the total call count
88 self
.updateTotalCallCount(callee
)
89 # If this function is already in the list, don't do anything else
90 if callee
in self
.calledFunctions
:
92 # Add this function to the list of those that will be called.
93 self
.calledFunctions
.append(callee
)
94 # If this function calls other functions, add them too
95 if callee
in self
.calledFunctionTable
:
96 for subCallee
in self
.calledFunctionTable
[callee
]:
97 self
.updateCalledFunctionList(subCallee
)
99 def setCallWeighting(self
, weight
):
100 """Sets the probably of generating a function call"""
101 self
.callWeighting
= weight
103 def writeln(self
, line
):
104 self
.kfile
.write(line
+ "\n")
106 def writeComment(self
, comment
):
107 self
.writeln("# " + comment
)
109 def writeEmptyLine(self
):
112 def writePredefinedFunctions(self
):
114 "Define ':' for sequencing: as a low-precedence operator that ignores operands"
116 self
.writeComment("and just returns the RHS.")
117 self
.writeln("def binary : 1 (x y) y;")
118 self
.writeEmptyLine()
119 self
.writeComment("Helper functions defined within toy")
120 self
.writeln("extern putchard(x);")
121 self
.writeln("extern printd(d);")
122 self
.writeln("extern printlf();")
123 self
.writeEmptyLine()
124 self
.writeComment("Print the result of a function call")
125 self
.writeln("def printresult(N Result)")
126 self
.writeln(" # 'result('")
128 " putchard(114) : putchard(101) : putchard(115) : putchard(117) : putchard(108) : putchard(116) : putchard(40) :"
130 self
.writeln(" printd(N) :")
131 self
.writeln(" # ') = '")
132 self
.writeln(" putchard(41) : putchard(32) : putchard(61) : putchard(32) :")
133 self
.writeln(" printd(Result) :")
134 self
.writeln(" printlf();")
135 self
.writeEmptyLine()
137 def writeRandomOperation(self
, LValue
, LHS
, RHS
):
138 shouldCallFunc
= self
.lastFuncNum
> 2 and random
.random() < self
.callWeighting
140 funcToCall
= random
.randrange(1, self
.lastFuncNum
- 1)
141 self
.updateFunctionCallMap(self
.lastFuncNum
, funcToCall
)
142 self
.writeln(" %s = func%d(%s, %s) :" % (LValue
, funcToCall
, LHS
, RHS
))
144 possibleOperations
= ["+", "-", "*", "/"]
145 operation
= random
.choice(possibleOperations
)
147 # Don't let our intermediate value become zero
148 # This is complicated by the fact that '<' is our only comparison operator
149 self
.writeln(" if %s < %s then" % (LHS
, RHS
))
150 self
.writeln(" %s = %s %s %s" % (LValue
, LHS
, operation
, RHS
))
151 self
.writeln(" else if %s < %s then" % (RHS
, LHS
))
152 self
.writeln(" %s = %s %s %s" % (LValue
, LHS
, operation
, RHS
))
153 self
.writeln(" else")
156 % (LValue
, LHS
, operation
, random
.uniform(1, 100))
159 self
.writeln(" %s = %s %s %s :" % (LValue
, LHS
, operation
, RHS
))
161 def getNextFuncNum(self
):
162 result
= self
.nextFuncNum
163 self
.nextFuncNum
+= 1
164 self
.lastFuncNum
= result
167 def writeFunction(self
, elements
):
168 funcNum
= self
.getNextFuncNum()
169 self
.writeComment("Auto-generated function number %d" % funcNum
)
170 self
.writeln("def func%d(X Y)" % funcNum
)
171 self
.writeln(" var temp1 = X,")
172 self
.writeln(" temp2 = Y,")
173 self
.writeln(" temp3 in")
174 # Initialize the variable names to be rotated
178 # Write some random operations
179 for i
in range(elements
):
180 self
.writeRandomOperation(first
, second
, third
)
181 # Rotate the variables
186 self
.writeln(" " + third
+ ";")
187 self
.writeEmptyLine()
189 def writeFunctionCall(self
):
190 self
.writeComment("Call the last function")
191 arg1
= random
.uniform(1, 100)
192 arg2
= random
.uniform(1, 100)
194 "printresult(%d, func%d(%f, %f) )"
195 % (self
.lastFuncNum
, self
.lastFuncNum
, arg1
, arg2
)
197 self
.writeEmptyLine()
198 self
.updateCalledFunctionList(self
.lastFuncNum
)
200 def writeFinalFunctionCounts(self
):
202 "Called %d of %d functions" % (len(self
.calledFunctions
), self
.lastFuncNum
)
207 filename
, numFuncs
, elementsPerFunc
, funcsBetweenExec
, callWeighting
, timingScript
209 """Generate a random Kaleidoscope script based on the given parameters"""
210 print("Generating " + filename
)
212 " %d functions, %d elements per function, %d functions between execution"
213 % (numFuncs
, elementsPerFunc
, funcsBetweenExec
)
215 print(" Call weighting = %f" % callWeighting
)
216 script
= KScriptGenerator(filename
)
217 script
.setCallWeighting(callWeighting
)
219 "==========================================================================="
221 script
.writeComment("Auto-generated script")
223 " %d functions, %d elements per function, %d functions between execution"
224 % (numFuncs
, elementsPerFunc
, funcsBetweenExec
)
226 script
.writeComment(" call weighting = %f" % callWeighting
)
228 "==========================================================================="
230 script
.writeEmptyLine()
231 script
.writePredefinedFunctions()
232 funcsSinceLastExec
= 0
233 for i
in range(numFuncs
):
234 script
.writeFunction(elementsPerFunc
)
235 funcsSinceLastExec
+= 1
236 if funcsSinceLastExec
== funcsBetweenExec
:
237 script
.writeFunctionCall()
238 funcsSinceLastExec
= 0
239 # Always end with a function call
240 if funcsSinceLastExec
> 0:
241 script
.writeFunctionCall()
242 script
.writeEmptyLine()
243 script
.writeFinalFunctionCounts()
244 funcsCalled
= len(script
.calledFunctions
)
246 " Called %d of %d functions, %d total"
247 % (funcsCalled
, numFuncs
, script
.totalCallsExecuted
)
249 timingScript
.writeTimingCall(
250 filename
, numFuncs
, funcsCalled
, script
.totalCallsExecuted
254 # Execution begins here
257 timingScript
= TimingScriptGenerator("time-toy.sh", "timing-data.txt")
261 (5000, 10, 100, 0.10),
265 (1000, 10, 100, 0.10),
275 for (numFuncs
, elementsPerFunc
, funcsBetweenExec
, callWeighting
) in dataSets
:
276 filename
= "test-%d-%d-%d-%d.k" % (
280 int(callWeighting
* 100),