brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.8 KiB · 2e39f10 Raw
291 lines · python
1#!/usr/bin/env python2 3from __future__ import print_function4 5import sys6import random7 8 9class TimingScriptGenerator:10    """Used to generate a bash script which will invoke the toy and time it"""11 12    def __init__(self, scriptname, outputname):13        self.timeFile = outputname14        self.shfile = open(scriptname, "w")15        self.shfile.write('echo "" > %s\n' % self.timeFile)16 17    def writeTimingCall(self, filename, numFuncs, funcsCalled, totalCalls):18        """Echo some comments and invoke both versions of toy"""19        rootname = filename20        if "." in filename:21            rootname = filename[: filename.rfind(".")]22        self.shfile.write(23            'echo "%s: Calls %d of %d functions, %d total" >> %s\n'24            % (filename, funcsCalled, numFuncs, totalCalls, self.timeFile)25        )26        self.shfile.write('echo "" >> %s\n' % self.timeFile)27        self.shfile.write('echo "With MCJIT" >> %s\n' % self.timeFile)28        self.shfile.write(29            '/usr/bin/time -f "Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb"'30        )31        self.shfile.write(" -o %s -a " % self.timeFile)32        self.shfile.write(33            "./toy-mcjit < %s > %s-mcjit.out 2> %s-mcjit.err\n"34            % (filename, rootname, rootname)35        )36        self.shfile.write('echo "" >> %s\n' % self.timeFile)37        self.shfile.write('echo "With JIT" >> %s\n' % self.timeFile)38        self.shfile.write(39            '/usr/bin/time -f "Command %C\\n\\tuser time: %U s\\n\\tsytem time: %S s\\n\\tmax set: %M kb"'40        )41        self.shfile.write(" -o %s -a " % self.timeFile)42        self.shfile.write(43            "./toy-jit < %s > %s-jit.out 2> %s-jit.err\n"44            % (filename, rootname, rootname)45        )46        self.shfile.write('echo "" >> %s\n' % self.timeFile)47        self.shfile.write('echo "" >> %s\n' % self.timeFile)48 49 50class KScriptGenerator:51    """Used to generate random Kaleidoscope code"""52 53    def __init__(self, filename):54        self.kfile = open(filename, "w")55        self.nextFuncNum = 156        self.lastFuncNum = None57        self.callWeighting = 0.158        # A mapping of calls within functions with no duplicates59        self.calledFunctionTable = {}60        # A list of function calls which will actually be executed61        self.calledFunctions = []62        # A comprehensive mapping of calls within functions63        # used for computing the total number of calls64        self.comprehensiveCalledFunctionTable = {}65        self.totalCallsExecuted = 066 67    def updateTotalCallCount(self, callee):68        # Count this call69        self.totalCallsExecuted += 170        # Then count all the functions it calls71        if callee in self.comprehensiveCalledFunctionTable:72            for child in self.comprehensiveCalledFunctionTable[callee]:73                self.updateTotalCallCount(child)74 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)84 85    def updateCalledFunctionList(self, callee):86        """Maintains a list of functions that will actually be called"""87        # Update the total call count88        self.updateTotalCallCount(callee)89        # If this function is already in the list, don't do anything else90        if callee in self.calledFunctions:91            return92        # 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 too95        if callee in self.calledFunctionTable:96            for subCallee in self.calledFunctionTable[callee]:97                self.updateCalledFunctionList(subCallee)98 99    def setCallWeighting(self, weight):100        """Sets the probably of generating a function call"""101        self.callWeighting = weight102 103    def writeln(self, line):104        self.kfile.write(line + "\n")105 106    def writeComment(self, comment):107        self.writeln("# " + comment)108 109    def writeEmptyLine(self):110        self.writeln("")111 112    def writePredefinedFunctions(self):113        self.writeComment(114            "Define ':' for sequencing: as a low-precedence operator that ignores operands"115        )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('")127        self.writeln(128            "  putchard(114) : putchard(101) : putchard(115) : putchard(117) : putchard(108) : putchard(116) : putchard(40) :"129        )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()136 137    def writeRandomOperation(self, LValue, LHS, RHS):138        shouldCallFunc = self.lastFuncNum > 2 and random.random() < self.callWeighting139        if shouldCallFunc: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))143        else:144            possibleOperations = ["+", "-", "*", "/"]145            operation = random.choice(possibleOperations)146            if operation == "-":147                # Don't let our intermediate value become zero148                # This is complicated by the fact that '<' is our only comparison operator149                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")154                self.writeln(155                    "    %s = %s %s %f :"156                    % (LValue, LHS, operation, random.uniform(1, 100))157                )158            else:159                self.writeln("  %s = %s %s %s :" % (LValue, LHS, operation, RHS))160 161    def getNextFuncNum(self):162        result = self.nextFuncNum163        self.nextFuncNum += 1164        self.lastFuncNum = result165        return result166 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 rotated175        first = "temp3"176        second = "temp1"177        third = "temp2"178        # Write some random operations179        for i in range(elements):180            self.writeRandomOperation(first, second, third)181            # Rotate the variables182            temp = first183            first = second184            second = third185            third = temp186        self.writeln("  " + third + ";")187        self.writeEmptyLine()188 189    def writeFunctionCall(self):190        self.writeComment("Call the last function")191        arg1 = random.uniform(1, 100)192        arg2 = random.uniform(1, 100)193        self.writeln(194            "printresult(%d, func%d(%f, %f) )"195            % (self.lastFuncNum, self.lastFuncNum, arg1, arg2)196        )197        self.writeEmptyLine()198        self.updateCalledFunctionList(self.lastFuncNum)199 200    def writeFinalFunctionCounts(self):201        self.writeComment(202            "Called %d of %d functions" % (len(self.calledFunctions), self.lastFuncNum)203        )204 205 206def generateKScript(207    filename, numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting, timingScript208):209    """Generate a random Kaleidoscope script based on the given parameters"""210    print("Generating " + filename)211    print(212        "  %d functions, %d elements per function, %d functions between execution"213        % (numFuncs, elementsPerFunc, funcsBetweenExec)214    )215    print("  Call weighting = %f" % callWeighting)216    script = KScriptGenerator(filename)217    script.setCallWeighting(callWeighting)218    script.writeComment(219        "==========================================================================="220    )221    script.writeComment("Auto-generated script")222    script.writeComment(223        "  %d functions, %d elements per function, %d functions between execution"224        % (numFuncs, elementsPerFunc, funcsBetweenExec)225    )226    script.writeComment("  call weighting = %f" % callWeighting)227    script.writeComment(228        "==========================================================================="229    )230    script.writeEmptyLine()231    script.writePredefinedFunctions()232    funcsSinceLastExec = 0233    for i in range(numFuncs):234        script.writeFunction(elementsPerFunc)235        funcsSinceLastExec += 1236        if funcsSinceLastExec == funcsBetweenExec:237            script.writeFunctionCall()238            funcsSinceLastExec = 0239    # Always end with a function call240    if funcsSinceLastExec > 0:241        script.writeFunctionCall()242    script.writeEmptyLine()243    script.writeFinalFunctionCounts()244    funcsCalled = len(script.calledFunctions)245    print(246        "  Called %d of %d functions, %d total"247        % (funcsCalled, numFuncs, script.totalCallsExecuted)248    )249    timingScript.writeTimingCall(250        filename, numFuncs, funcsCalled, script.totalCallsExecuted251    )252 253 254# Execution begins here255random.seed()256 257timingScript = TimingScriptGenerator("time-toy.sh", "timing-data.txt")258 259dataSets = [260    (5000, 3, 50, 0.50),261    (5000, 10, 100, 0.10),262    (5000, 10, 5, 0.10),263    (5000, 10, 1, 0.0),264    (1000, 3, 10, 0.50),265    (1000, 10, 100, 0.10),266    (1000, 10, 5, 0.10),267    (1000, 10, 1, 0.0),268    (200, 3, 2, 0.50),269    (200, 10, 40, 0.10),270    (200, 10, 2, 0.10),271    (200, 10, 1, 0.0),272]273 274# Generate the code275for (numFuncs, elementsPerFunc, funcsBetweenExec, callWeighting) in dataSets:276    filename = "test-%d-%d-%d-%d.k" % (277        numFuncs,278        elementsPerFunc,279        funcsBetweenExec,280        int(callWeighting * 100),281    )282    generateKScript(283        filename,284        numFuncs,285        elementsPerFunc,286        funcsBetweenExec,287        callWeighting,288        timingScript,289    )290print("All done!")291