mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
Adding example source to support MCJIT/Kaleidoscope blog posts.
llvm-svn: 186854
This commit is contained in:
parent
1e13d52088
commit
208108a8e0
12
examples/Kaleidoscope/MCJIT/README.txt
Normal file
12
examples/Kaleidoscope/MCJIT/README.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
// Kaleidoscope with MCJIT
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
The files in this directory are meant to accompany a series of blog posts
|
||||||
|
that describe the process of porting the Kaleidoscope tutorial to use the MCJIT
|
||||||
|
execution engine instead of the older JIT engine.
|
||||||
|
|
||||||
|
When the blog posts are ready this file will be updated with links to the posts.
|
||||||
|
|
||||||
|
These directories contain Makefiles that allow the code to be built in a
|
||||||
|
standalone manner, independent of the larger LLVM build infrastructure.
|
11
examples/Kaleidoscope/MCJIT/cached/Makefile
Normal file
11
examples/Kaleidoscope/MCJIT/cached/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
all: toy-mcjit toy-jit toy-ir-gen
|
||||||
|
|
||||||
|
toy-mcjit : toy.cpp
|
||||||
|
clang++ toy.cpp -g -O3 -rdynamic -fno-rtti `llvm-config --cppflags --ldflags --libs core mcjit native irreader` -o toy-mcjit
|
||||||
|
|
||||||
|
toy-jit : toy-jit.cpp
|
||||||
|
clang++ toy-jit.cpp -g -O3 -rdynamic -fno-rtti `llvm-config --cppflags --ldflags --libs core jit native irreader` -o toy-jit
|
||||||
|
|
||||||
|
# This is a special build for the purpose of converting Kaleidoscope input to an IR file
|
||||||
|
toy-ir-gen : toy-jit.cpp
|
||||||
|
clang++ toy-jit.cpp -g -O3 -rdynamic -fno-rtti -DDUMP_FINAL_MODULE `llvm-config --cppflags --ldflags --libs core jit native irreader` -o toy-ir-gen
|
28
examples/Kaleidoscope/MCJIT/cached/README.txt
Normal file
28
examples/Kaleidoscope/MCJIT/cached/README.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
// Kaleidoscope with MCJIT
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
The files in this directory are meant to accompany the first in a series of
|
||||||
|
three blog posts that describe the process of porting the Kaleidoscope tutorial
|
||||||
|
to use the MCJIT execution engine instead of the older JIT engine.
|
||||||
|
|
||||||
|
When the blog post is ready this file will be updated with a link to the post.
|
||||||
|
|
||||||
|
The source code in this directory demonstrates the third version of the
|
||||||
|
program, now modified to accept an input IR file on the command line and,
|
||||||
|
optionally, to use a basic caching mechanism to store generated object images.
|
||||||
|
|
||||||
|
The toy-jit.cpp file contains a version of the original JIT-based source code
|
||||||
|
that has been modified to support the input IR file command line option.
|
||||||
|
|
||||||
|
This directory contain a Makefile that allow the code to be built in a
|
||||||
|
standalone manner, independent of the larger LLVM build infrastructure. To build
|
||||||
|
the program you will need to have 'clang++' and 'llvm-config' in your path. If
|
||||||
|
you attempt to build using the LLVM 3.3 release, some minor modifications will
|
||||||
|
be required.
|
||||||
|
|
||||||
|
This directory also contains a Python script that may be used to generate random
|
||||||
|
input for the program and test scripts to capture data for rough performance
|
||||||
|
comparisons. Another Python script will split generated input files into
|
||||||
|
definitions and function calls for the purpose of testing the IR input and
|
||||||
|
caching facilities.
|
219
examples/Kaleidoscope/MCJIT/cached/genk-timing.py
Normal file
219
examples/Kaleidoscope/MCJIT/cached/genk-timing.py
Normal file
@ -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!"
|
70
examples/Kaleidoscope/MCJIT/cached/split-lib.py
Normal file
70
examples/Kaleidoscope/MCJIT/cached/split-lib.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
class TimingScriptGenerator:
|
||||||
|
"""Used to generate a bash script which will invoke the toy and time it"""
|
||||||
|
def __init__(self, scriptname, outputname):
|
||||||
|
self.shfile = open(scriptname, 'w')
|
||||||
|
self.timeFile = outputname
|
||||||
|
self.shfile.write("echo \"\" > %s\n" % self.timeFile)
|
||||||
|
|
||||||
|
def writeTimingCall(self, irname, callname):
|
||||||
|
"""Echo some comments and invoke both versions of toy"""
|
||||||
|
rootname = irname
|
||||||
|
if '.' in irname:
|
||||||
|
rootname = irname[:irname.rfind('.')]
|
||||||
|
self.shfile.write("echo \"%s: Calls %s\" >> %s\n" % (callname, irname, 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 -use-object-cache -input-IR=%s < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (irname, callname, rootname, rootname))
|
||||||
|
self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
|
||||||
|
self.shfile.write("echo \"With MCJIT again\" >> %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 -use-object-cache -input-IR=%s < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (irname, callname, 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 -input-IR=%s < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (irname, callname, rootname, rootname))
|
||||||
|
self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
|
||||||
|
self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
|
||||||
|
|
||||||
|
class LibScriptGenerator:
|
||||||
|
"""Used to generate a bash script which will convert Kaleidoscope files to IR"""
|
||||||
|
def __init__(self, filename):
|
||||||
|
self.shfile = open(filename, 'w')
|
||||||
|
|
||||||
|
def writeLibGenCall(self, libname, irname):
|
||||||
|
self.shfile.write("./toy-ir-gen < %s 2> %s\n" % (libname, irname))
|
||||||
|
|
||||||
|
def splitScript(inputname, libGenScript, timingScript):
|
||||||
|
rootname = inputname[:-2]
|
||||||
|
libname = rootname + "-lib.k"
|
||||||
|
irname = rootname + "-lib.ir"
|
||||||
|
callname = rootname + "-call.k"
|
||||||
|
infile = open(inputname, "r")
|
||||||
|
libfile = open(libname, "w")
|
||||||
|
callfile = open(callname, "w")
|
||||||
|
print "Splitting %s into %s and %s" % (inputname, callname, libname)
|
||||||
|
for line in infile:
|
||||||
|
if not line.startswith("#"):
|
||||||
|
if line.startswith("print"):
|
||||||
|
callfile.write(line)
|
||||||
|
else:
|
||||||
|
libfile.write(line)
|
||||||
|
libGenScript.writeLibGenCall(libname, irname)
|
||||||
|
timingScript.writeTimingCall(irname, callname)
|
||||||
|
|
||||||
|
# Execution begins here
|
||||||
|
libGenScript = LibScriptGenerator("make-libs.sh")
|
||||||
|
timingScript = TimingScriptGenerator("time-lib.sh", "lib-timing.txt")
|
||||||
|
|
||||||
|
script_list = ["test-5000-3-50-50.k", "test-5000-10-100-10.k", "test-5000-10-5-10.k", "test-5000-10-1-0.k",
|
||||||
|
"test-1000-3-10-50.k", "test-1000-10-100-10.k", "test-1000-10-5-10.k", "test-1000-10-1-0.k",
|
||||||
|
"test-200-3-2-50.k", "test-200-10-40-10.k", "test-200-10-2-10.k", "test-200-10-1-0.k"]
|
||||||
|
|
||||||
|
for script in script_list:
|
||||||
|
splitScript(script, libGenScript, timingScript)
|
||||||
|
print "All done!"
|
1207
examples/Kaleidoscope/MCJIT/cached/toy-jit.cpp
Normal file
1207
examples/Kaleidoscope/MCJIT/cached/toy-jit.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1551
examples/Kaleidoscope/MCJIT/cached/toy.cpp
Normal file
1551
examples/Kaleidoscope/MCJIT/cached/toy.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4
examples/Kaleidoscope/MCJIT/complete/Makefile
Normal file
4
examples/Kaleidoscope/MCJIT/complete/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
all: toy
|
||||||
|
|
||||||
|
toy : toy.cpp
|
||||||
|
clang++ toy.cpp -g -O3 -rdynamic -fno-rtti `llvm-config --cppflags --ldflags --libs core jit mcjit native irreader` -o toy
|
25
examples/Kaleidoscope/MCJIT/complete/README.txt
Normal file
25
examples/Kaleidoscope/MCJIT/complete/README.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
// Kaleidoscope with MCJIT
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
The files in this directory are meant to accompany the first in a series of
|
||||||
|
three blog posts that describe the process of porting the Kaleidoscope tutorial
|
||||||
|
to use the MCJIT execution engine instead of the older JIT engine.
|
||||||
|
|
||||||
|
When the blog post is ready this file will be updated with a link to the post.
|
||||||
|
|
||||||
|
The source code in this directory combines all previous versions, including the
|
||||||
|
old JIT-based implementation, into a single file for easy comparison with
|
||||||
|
command line options to select between the various possibilities.
|
||||||
|
|
||||||
|
This directory contain a Makefile that allow the code to be built in a
|
||||||
|
standalone manner, independent of the larger LLVM build infrastructure. To build
|
||||||
|
the program you will need to have 'clang++' and 'llvm-config' in your path. If
|
||||||
|
you attempt to build using the LLVM 3.3 release, some minor modifications will
|
||||||
|
be required.
|
||||||
|
|
||||||
|
This directory also contains a Python script that may be used to generate random
|
||||||
|
input for the program and test scripts to capture data for rough performance
|
||||||
|
comparisons. Another Python script will split generated input files into
|
||||||
|
definitions and function calls for the purpose of testing the IR input and
|
||||||
|
caching facilities.
|
224
examples/Kaleidoscope/MCJIT/complete/genk-timing.py
Normal file
224
examples/Kaleidoscope/MCJIT/complete/genk-timing.py
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#!/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 (original)\" >> %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 -suppress-prompts -use-mcjit=true -enable-lazy-compilation=false < %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 MCJIT (lazy)\" >> %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 -suppress-prompts -use-mcjit=true -enable-lazy-compilation=true < %s > %s-mcjit-lazy.out 2> %s-mcjit-lazy.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 -suppress-prompts -use-mcjit=false < %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!"
|
70
examples/Kaleidoscope/MCJIT/complete/split-lib.py
Normal file
70
examples/Kaleidoscope/MCJIT/complete/split-lib.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
class TimingScriptGenerator:
|
||||||
|
"""Used to generate a bash script which will invoke the toy and time it"""
|
||||||
|
def __init__(self, scriptname, outputname):
|
||||||
|
self.shfile = open(scriptname, 'w')
|
||||||
|
self.timeFile = outputname
|
||||||
|
self.shfile.write("echo \"\" > %s\n" % self.timeFile)
|
||||||
|
|
||||||
|
def writeTimingCall(self, irname, callname):
|
||||||
|
"""Echo some comments and invoke both versions of toy"""
|
||||||
|
rootname = irname
|
||||||
|
if '.' in irname:
|
||||||
|
rootname = irname[:irname.rfind('.')]
|
||||||
|
self.shfile.write("echo \"%s: Calls %s\" >> %s\n" % (callname, irname, 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 -suppress-prompts -use-mcjit=true -enable-lazy-compilation=true -use-object-cache -input-IR=%s < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (irname, callname, rootname, rootname))
|
||||||
|
self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
|
||||||
|
self.shfile.write("echo \"With MCJIT again\" >> %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 -suppress-prompts -use-mcjit=true -enable-lazy-compilation=true -use-object-cache -input-IR=%s < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (irname, callname, 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 -suppress-prompts -use-mcjit=false -input-IR=%s < %s > %s-mcjit.out 2> %s-mcjit.err\n" % (irname, callname, rootname, rootname))
|
||||||
|
self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
|
||||||
|
self.shfile.write("echo \"\" >> %s\n" % self.timeFile)
|
||||||
|
|
||||||
|
class LibScriptGenerator:
|
||||||
|
"""Used to generate a bash script which will invoke the toy and time it"""
|
||||||
|
def __init__(self, filename):
|
||||||
|
self.shfile = open(filename, 'w')
|
||||||
|
|
||||||
|
def writeLibGenCall(self, libname, irname):
|
||||||
|
self.shfile.write("./toy -suppress-prompts -use-mcjit=false -dump-modules < %s 2> %s\n" % (libname, irname))
|
||||||
|
|
||||||
|
def splitScript(inputname, libGenScript, timingScript):
|
||||||
|
rootname = inputname[:-2]
|
||||||
|
libname = rootname + "-lib.k"
|
||||||
|
irname = rootname + "-lib.ir"
|
||||||
|
callname = rootname + "-call.k"
|
||||||
|
infile = open(inputname, "r")
|
||||||
|
libfile = open(libname, "w")
|
||||||
|
callfile = open(callname, "w")
|
||||||
|
print "Splitting %s into %s and %s" % (inputname, callname, libname)
|
||||||
|
for line in infile:
|
||||||
|
if not line.startswith("#"):
|
||||||
|
if line.startswith("print"):
|
||||||
|
callfile.write(line)
|
||||||
|
else:
|
||||||
|
libfile.write(line)
|
||||||
|
libGenScript.writeLibGenCall(libname, irname)
|
||||||
|
timingScript.writeTimingCall(irname, callname)
|
||||||
|
|
||||||
|
# Execution begins here
|
||||||
|
libGenScript = LibScriptGenerator("make-libs.sh")
|
||||||
|
timingScript = TimingScriptGenerator("time-lib.sh", "lib-timing.txt")
|
||||||
|
|
||||||
|
script_list = ["test-5000-3-50-50.k", "test-5000-10-100-10.k", "test-5000-10-5-10.k", "test-5000-10-1-0.k",
|
||||||
|
"test-1000-3-10-50.k", "test-1000-10-100-10.k", "test-1000-10-5-10.k", "test-1000-10-1-0.k",
|
||||||
|
"test-200-3-2-50.k", "test-200-10-40-10.k", "test-200-10-2-10.k", "test-200-10-1-0.k"]
|
||||||
|
|
||||||
|
for script in script_list:
|
||||||
|
splitScript(script, libGenScript, timingScript)
|
||||||
|
print "All done!"
|
1710
examples/Kaleidoscope/MCJIT/complete/toy.cpp
Normal file
1710
examples/Kaleidoscope/MCJIT/complete/toy.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4
examples/Kaleidoscope/MCJIT/initial/Makefile
Normal file
4
examples/Kaleidoscope/MCJIT/initial/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
all: toy-mcjit
|
||||||
|
|
||||||
|
toy-mcjit : toy.cpp
|
||||||
|
clang++ toy.cpp -g -O3 -rdynamic -fno-rtti `llvm-config --cppflags --ldflags --libs core mcjit native` -o toy-mcjit
|
18
examples/Kaleidoscope/MCJIT/initial/README.txt
Normal file
18
examples/Kaleidoscope/MCJIT/initial/README.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
// Kaleidoscope with MCJIT
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
The files in this directory are meant to accompany the first in a series of
|
||||||
|
three blog posts that describe the process of porting the Kaleidoscope tutorial
|
||||||
|
to use the MCJIT execution engine instead of the older JIT engine.
|
||||||
|
|
||||||
|
When the blog post is ready this file will be updated with a link to the post.
|
||||||
|
|
||||||
|
The source code in this directory demonstrates the initial working version of
|
||||||
|
the program before subsequent performance improvements are applied.
|
||||||
|
|
||||||
|
This directory contain a Makefile that allow the code to be built in a
|
||||||
|
standalone manner, independent of the larger LLVM build infrastructure. To build
|
||||||
|
the program you will need to have 'clang++' and 'llvm-config' in your path. If
|
||||||
|
you attempt to build using the LLVM 3.3 release, some minor modifications will
|
||||||
|
be required, as mentioned in the blog posts.
|
1381
examples/Kaleidoscope/MCJIT/initial/toy.cpp
Normal file
1381
examples/Kaleidoscope/MCJIT/initial/toy.cpp
Normal file
File diff suppressed because it is too large
Load Diff
7
examples/Kaleidoscope/MCJIT/lazy/Makefile
Normal file
7
examples/Kaleidoscope/MCJIT/lazy/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
all: toy-mcjit toy-jit
|
||||||
|
|
||||||
|
toy-mcjit : toy.cpp
|
||||||
|
clang++ toy.cpp -g -O3 -rdynamic -fno-rtti `llvm-config --cppflags --ldflags --libs core mcjit native` -o toy-mcjit
|
||||||
|
|
||||||
|
toy-jit : toy-jit.cpp
|
||||||
|
clang++ toy-jit.cpp -g -O3 -rdynamic `llvm-config --cppflags --ldflags --libs core jit native` -o toy-jit
|
25
examples/Kaleidoscope/MCJIT/lazy/README.txt
Normal file
25
examples/Kaleidoscope/MCJIT/lazy/README.txt
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
//===----------------------------------------------------------------------===/
|
||||||
|
// Kaleidoscope with MCJIT
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
The files in this directory are meant to accompany the first in a series of
|
||||||
|
three blog posts that describe the process of porting the Kaleidoscope tutorial
|
||||||
|
to use the MCJIT execution engine instead of the older JIT engine.
|
||||||
|
|
||||||
|
When the blog post is ready this file will be updated with a link to the post.
|
||||||
|
|
||||||
|
The source code in this directory demonstrates the second version of the
|
||||||
|
program, now modified to implement a sort of 'lazy' compilation.
|
||||||
|
|
||||||
|
The toy-jit.cpp file contains a version of the original JIT-based source code
|
||||||
|
that has been modified to disable most stderr output for timing purposes.
|
||||||
|
|
||||||
|
This directory contain a Makefile that allow the code to be built in a
|
||||||
|
standalone manner, independent of the larger LLVM build infrastructure. To build
|
||||||
|
the program you will need to have 'clang++' and 'llvm-config' in your path. If
|
||||||
|
you attempt to build using the LLVM 3.3 release, some minor modifications will
|
||||||
|
be required.
|
||||||
|
|
||||||
|
This directory also contains a Python script that may be used to generate random
|
||||||
|
input for the program and test scripts to capture data for rough performance
|
||||||
|
comparisons.
|
219
examples/Kaleidoscope/MCJIT/lazy/genk-timing.py
Normal file
219
examples/Kaleidoscope/MCJIT/lazy/genk-timing.py
Normal file
@ -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!"
|
1167
examples/Kaleidoscope/MCJIT/lazy/toy-jit.cpp
Normal file
1167
examples/Kaleidoscope/MCJIT/lazy/toy-jit.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1422
examples/Kaleidoscope/MCJIT/lazy/toy.cpp
Normal file
1422
examples/Kaleidoscope/MCJIT/lazy/toy.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user