diff options
Diffstat (limited to 'examples/Kaleidoscope/MCJIT/lazy/genk-timing.py')
-rw-r--r-- | examples/Kaleidoscope/MCJIT/lazy/genk-timing.py | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/examples/Kaleidoscope/MCJIT/lazy/genk-timing.py b/examples/Kaleidoscope/MCJIT/lazy/genk-timing.py new file mode 100644 index 0000000000..96dd6db5da --- /dev/null +++ b/examples/Kaleidoscope/MCJIT/lazy/genk-timing.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python + +import sys +import random + +class TimingScriptGenerator: + """Used to generate a bash script which will invoke the toy and time it""" + def __init__(self, scriptname, outputname): + self.timeFile = outputname + self.shfile = open(scriptname, 'w') + self.shfile.write("echo \"\" > %s\n" % self.timeFile) + + def writeTimingCall(self, filename, numFuncs, funcsCalled, totalCalls): + """Echo some comments and invoke both versions of toy""" + rootname = filename + if '.' in filename: + rootname = filename[:filename.rfind('.')] + self.shfile.write("echo \"%s: Calls %d of %d functions, %d total\" >> %s\n" % (filename, funcsCalled, numFuncs, totalCalls, self.timeFile)) + self.shfile.write("echo \"\" >> %s\n" % self.timeFile) + self.shfile.write("echo \"With MCJIT\" >> %s\n" % self.timeFile) + self.shfile.write("/usr/bin/time -f \"Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb\"") + self.shfile.write(" -o %s -a " % self.timeFile) + self.shfile.write("./toy-mcjit < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (filename, rootname, rootname)) + self.shfile.write("echo \"\" >> %s\n" % self.timeFile) + self.shfile.write("echo \"With JIT\" >> %s\n" % self.timeFile) + self.shfile.write("/usr/bin/time -f \"Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb\"") + self.shfile.write(" -o %s -a " % self.timeFile) + self.shfile.write("./toy-jit < %s > %s-jit.out 2> %s-jit.err\n" % (filename, rootname, rootname)) + self.shfile.write("echo \"\" >> %s\n" % self.timeFile) + self.shfile.write("echo \"\" >> %s\n" % self.timeFile) + +class KScriptGenerator: + """Used to generate random Kaleidoscope code""" + def __init__(self, filename): + self.kfile = open(filename, 'w') + self.nextFuncNum = 1 + self.lastFuncNum = None + self.callWeighting = 0.1 + # A mapping of calls within functions with no duplicates + self.calledFunctionTable = {} + # A list of function calls which will actually be executed + self.calledFunctions = [] + # A comprehensive mapping of calls within functions + # used for computing the total number of calls + self.comprehensiveCalledFunctionTable = {} + self.totalCallsExecuted = 0 + + def updateTotalCallCount(self, callee): + # Count this call + self.totalCallsExecuted += 1 + # Then count all the functions it calls + if callee in self.comprehensiveCalledFunctionTable: + for child in self.comprehensiveCalledFunctionTable[callee]: + self.updateTotalCallCount(child) + + def updateFunctionCallMap(self, caller, callee): + """Maintains a map of functions that are called from other functions""" + if not caller in self.calledFunctionTable: + self.calledFunctionTable[caller] = [] + if not callee in self.calledFunctionTable[caller]: + self.calledFunctionTable[caller].append(callee) + if not caller in self.comprehensiveCalledFunctionTable: + self.comprehensiveCalledFunctionTable[caller] = [] + self.comprehensiveCalledFunctionTable[caller].append(callee) + + def updateCalledFunctionList(self, callee): + """Maintains a list of functions that will actually be called""" + # Update the total call count + self.updateTotalCallCount(callee) + # If this function is already in the list, don't do anything else + if callee in self.calledFunctions: + return + # Add this function to the list of those that will be called. + self.calledFunctions.append(callee) + # If this function calls other functions, add them too + if callee in self.calledFunctionTable: + for subCallee in self.calledFunctionTable[callee]: + self.updateCalledFunctionList(subCallee) + + def setCallWeighting(self, weight): + """ Sets the probably of generating a function call""" + self.callWeighting = weight + + def writeln(self, line): + self.kfile.write(line + '\n') + + def writeComment(self, comment): + self.writeln('# ' + comment) + + def writeEmptyLine(self): + self.writeln("") + + def writePredefinedFunctions(self): + self.writeComment("Define ':' for sequencing: as a low-precedence operator that ignores operands") + self.writeComment("and just returns the RHS.") + self.writeln("def binary : 1 (x y) y;") + self.writeEmptyLine() + self.writeComment("Helper functions defined within toy") + self.writeln("extern putchard(x);") + self.writeln("extern printd(d);") + self.writeln("extern printlf();") + self.writeEmptyLine() + self.writeComment("Print the result of a function call") + self.writeln("def printresult(N Result)") + self.writeln(" # 'result('") + self.writeln(" putchard(114) : putchard(101) : putchard(115) : putchard(117) : putchard(108) : putchard(116) : putchard(40) :") + self.writeln(" printd(N) :"); + self.writeln(" # ') = '") + self.writeln(" putchard(41) : putchard(32) : putchard(61) : putchard(32) :") + self.writeln(" printd(Result) :"); + self.writeln(" printlf();") + self.writeEmptyLine() + + def writeRandomOperation(self, LValue, LHS, RHS): + shouldCallFunc = (self.lastFuncNum > 2 and random.random() < self.callWeighting) + if shouldCallFunc: + funcToCall = random.randrange(1, self.lastFuncNum - 1) + self.updateFunctionCallMap(self.lastFuncNum, funcToCall) + self.writeln(" %s = func%d(%s, %s) :" % (LValue, funcToCall, LHS, RHS)) + else: + possibleOperations = ["+", "-", "*", "/"] + operation = random.choice(possibleOperations) + if operation == "-": + # Don't let our intermediate value become zero + # This is complicated by the fact that '<' is our only comparison operator + self.writeln(" if %s < %s then" % (LHS, RHS)) + self.writeln(" %s = %s %s %s" % (LValue, LHS, operation, RHS)) + self.writeln(" else if %s < %s then" % (RHS, LHS)) + self.writeln(" %s = %s %s %s" % (LValue, LHS, operation, RHS)) + self.writeln(" else") + self.writeln(" %s = %s %s %f :" % (LValue, LHS, operation, random.uniform(1, 100))) + else: + self.writeln(" %s = %s %s %s :" % (LValue, LHS, operation, RHS)) + + def getNextFuncNum(self): + result = self.nextFuncNum + self.nextFuncNum += 1 + self.lastFuncNum = result + return result + + def writeFunction(self, elements): + funcNum = self.getNextFuncNum() + self.writeComment("Auto-generated function number %d" % funcNum) + self.writeln("def func%d(X Y)" % funcNum) + self.writeln(" var temp1 = X,") + self.writeln(" temp2 = Y,") + self.writeln(" temp3 in") + # Initialize the variable names to be rotated + first = "temp3" + second = "temp1" + third = "temp2" + # Write some random operations + for i in range(elements): + self.writeRandomOperation(first, second, third) + # Rotate the variables + temp = first + first = second + second = third + third = temp + self.writeln(" " + third + ";") + self.writeEmptyLine() + + def writeFunctionCall(self): + self.writeComment("Call the last function") + arg1 = random.uniform(1, 100) + arg2 = random.uniform(1, 100) + self.writeln("printresult(%d, func%d(%f, %f) )" % (self.lastFuncNum, self.lastFuncNum, arg1, arg2)) + self.writeEmptyLine() + self.updateCalledFunctionList(self.lastFuncNum) + + def writeFinalFunctionCounts(self): + self.writeComment("Called %d of %d functions" % (len(self.calledFunctions), self.lastFuncNum)) + +def generateKScript(filename, numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting, timingScript): + """ Generate a random Kaleidoscope script based on the given parameters """ + print "Generating " + filename + print(" %d functions, %d elements per function, %d functions between execution" % + (numFuncs, elementsPerFunc, funcsBetweenExec)) + print(" Call weighting = %f" % callWeighting) + script = KScriptGenerator(filename) + script.setCallWeighting(callWeighting) + script.writeComment("===========================================================================") + script.writeComment("Auto-generated script") + script.writeComment(" %d functions, %d elements per function, %d functions between execution" + % (numFuncs, elementsPerFunc, funcsBetweenExec)) + script.writeComment(" call weighting = %f" % callWeighting) + script.writeComment("===========================================================================") + script.writeEmptyLine() + script.writePredefinedFunctions() + funcsSinceLastExec = 0 + for i in range(numFuncs): + script.writeFunction(elementsPerFunc) + funcsSinceLastExec += 1 + if funcsSinceLastExec == funcsBetweenExec: + script.writeFunctionCall() + funcsSinceLastExec = 0 + # Always end with a function call + if funcsSinceLastExec > 0: + script.writeFunctionCall() + script.writeEmptyLine() + script.writeFinalFunctionCounts() + funcsCalled = len(script.calledFunctions) + print " Called %d of %d functions, %d total" % (funcsCalled, numFuncs, script.totalCallsExecuted) + timingScript.writeTimingCall(filename, numFuncs, funcsCalled, script.totalCallsExecuted) + +# Execution begins here +random.seed() + +timingScript = TimingScriptGenerator("time-toy.sh", "timing-data.txt") + +dataSets = [(5000, 3, 50, 0.50), (5000, 10, 100, 0.10), (5000, 10, 5, 0.10), (5000, 10, 1, 0.0), + (1000, 3, 10, 0.50), (1000, 10, 100, 0.10), (1000, 10, 5, 0.10), (1000, 10, 1, 0.0), + ( 200, 3, 2, 0.50), ( 200, 10, 40, 0.10), ( 200, 10, 2, 0.10), ( 200, 10, 1, 0.0)] + +# Generate the code +for (numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting) in dataSets: + filename = "test-%d-%d-%d-%d.k" % (numFuncs, elementsPerFunc, funcsBetweenExec, int(callWeighting * 100)) + generateKScript(filename, numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting, timingScript) +print "All done!" |