diff --git a/llvm/projects/hpvm-tensor-rt/code_autogenerators/benchmark_testing_automator.py b/llvm/projects/hpvm-tensor-rt/code_autogenerators/benchmark_testing_automator.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f5c28032d721dcf1e77ab52407a165c0251deb2
--- /dev/null
+++ b/llvm/projects/hpvm-tensor-rt/code_autogenerators/benchmark_testing_automator.py
@@ -0,0 +1,51 @@
+# Automates online benchmark testing with different clock speeds
+# Input: set of benchmark names to test
+# Set of benchmarks format: (full_bin_name, half_bin_name)
+import os
+import sys
+
+from collections import defaultdict
+from subprocess import Popen, PIPE
+
+def run_benchmark(bin_name, should_print_bin_output):
+    print("RUNNING %s" % bin_name)
+    proc = Popen("./%s" % bin_name, stdout = PIPE, universal_newlines = True)
+    proc_output = proc.communicate()[0]
+    assert proc.returncode == 0
+    
+    if should_print_bin_output:
+		print(proc_output)
+    print("FINISHED RUNNING %s" % bin_name)
+    return proc_output    
+
+
+def parse_binary_output(proc_output):
+    avg_time_key_ind = proc_output.find("Average time:")
+    assert avg_time_key_ind >= 0
+    avg_time = proc_output[avg_time_key_ind : proc_output.find("\n", avg_time_key_ind)]
+    print(avg_time)
+    return avg_time
+
+
+# Input: a list of tuples of benchmark names
+# Can change to input a file containing benchmarks to run 
+def run_benchmarks(builds_dir, output_filename, should_print_bin_output = True):
+    output_file = open(output_filename, "w")
+    for bin_name in os.listdir(builds_dir):
+        if bin_name.find("profiling") == -1:
+            continue
+        output_file.write("%s: %s\n" % (bin_name, \
+                parse_binary_output(run_benchmark(os.path.join(builds_dir, bin_name), \
+                should_print_bin_output))))
+        print(bin_name)
+    output_file.close()
+
+
+if __name__ == "__main__":
+    num_args = len(sys.argv)
+
+    if num_args != 3:
+        print("Usage: python online_benchmark_testing_automator.py <builds dir> <outputs_file_name>")
+        exit(1)
+    print("Output file name: %s" % sys.argv[2])
+    run_benchmarks(sys.argv[1], sys.argv[2])
diff --git a/llvm/projects/hpvm-tensor-rt/code_autogenerators/cmakelists_generator.py b/llvm/projects/hpvm-tensor-rt/code_autogenerators/cmakelists_generator.py
new file mode 100644
index 0000000000000000000000000000000000000000..04f6c5eec378276cd0c89fcc7013cb6996a90f2f
--- /dev/null
+++ b/llvm/projects/hpvm-tensor-rt/code_autogenerators/cmakelists_generator.py
@@ -0,0 +1,109 @@
+# Generates a CMakeLists.txt file for all generated files in a specific directory
+# Input: Arbitrarily long list containing names of all generated files directories
+# Ex: alexnet_cifar10_autogenerated_knobs mobilenet_cifar10_autogenerated_knobs
+# If inputted 0 parameters: Generates CMakeLists.txt file for all generated files in CURRENT dir
+
+import sys
+import os
+
+def get_all_generated_directory_names(): 
+    '''
+    Returns a list of all generated source code directories (<>_autogenerated_knobs)
+    in the current directory. Called when program is run with 0 args
+    '''
+    generated_dir_names = []
+    for dir_name in os.listdir("."):
+        print(dir_name)
+        if dir_name.endswith("autogenerated_knobs"):
+            generated_dir_names.append(dir_name)
+    return generated_dir_names
+
+
+def generate_cmakelists_setup(cmakelists_file):
+    '''
+    Copies over all the setup instructions (ex: finding libraries) from a "base" CMakeLists.txt
+    file. Ends copyng when we find the first instance of add_executable
+
+    Args:
+        cmakelists_file: File object to write cmake instructions to 
+
+    Assumption: All setup instructions are being any add_executable instructions
+    '''
+    BASE_CMAKELISTS_PATH = "/home/nvidia/Gitlab/hpvm/llvm/projects/hpvm-tensor-rt"
+    base_cmakelists_file = open(os.path.join(BASE_CMAKELISTS_PATH, "CMakeLists.txt"), "r")
+
+    find_lib_line = ""
+
+    for line in base_cmakelists_file:
+        if line.find("add_executable") != -1:
+            break
+
+        elif line.startswith("#"):
+            continue
+
+        # Special case: ignore / if -I flag exists
+        elif line.find("/") != -1 and line.find("-I") == -1: 
+            dot_dot_slash_ind = line.find("../")
+            dot_slash_ind = line.find("./")
+            if dot_dot_slash_ind != -1:
+                start_ind = dot_dot_slash_ind
+            elif dot_slash_ind != -1:
+                start_ind = dot_slash_ind
+            else:
+                slash_ind = line.find("/")
+                prev_space_ind = line[:slash_ind].rfind(" ")
+                start_ind = prev_space_ind + 1
+
+            old_rel_path = []
+            while start_ind < len(line):
+                if line[start_ind] == ")" or line[start_ind].isspace():
+                    break
+                old_rel_path.append(line[start_ind])
+                start_ind += 1
+            old_rel_path = ''.join(old_rel_path)
+            if os.path.isabs(old_rel_path):
+                cmakelists_file.write(line)
+            else:
+                new_path = os.path.join(BASE_CMAKELISTS_PATH, old_rel_path)
+                cmakelists_file.write(line.replace(old_rel_path, new_path))
+            continue
+        cmakelists_file.write(line)
+    base_cmakelists_file.close()
+
+
+def generate_cmakelists_file(cmakelists_file, source_file_dirs):
+    generate_cmakelists_setup(cmakelists_file)
+    LIBRARIES = "tensor_runtime ${GPU_PROFILER_LIB} ${SOC_SIMULATOR_LIB}"
+    cmake_instrs = []
+
+    for source_file_dir in source_file_dirs:
+        cmake_instrs.append("# %s" % source_file_dir)
+        for source_file in os.listdir(source_file_dir):
+            # Executable name = name of source code file without file extension
+            file_ext_ind = source_file.find(".cc")
+            if file_ext_ind == -1:
+                print("WARNING: Found file with wrong extension. Skipping. %s" % source_file)
+                continue
+            exec_name = source_file[ : file_ext_ind]
+            
+            source_file_path = os.path.join(source_file_dir, source_file)
+            cmake_instrs.append("add_executable(%s %s)" % (exec_name, source_file_path))
+            cmake_instrs.append("target_link_libraries(%s %s)\n" % (exec_name, LIBRARIES))
+        cmake_instrs.append("\n")
+    cmakelists_file.write('\n'.join(cmake_instrs))
+
+
+if __name__ == "__main__":
+    num_args = len(sys.argv)
+
+    if num_args >= 2 and sys.argv[1] == "--usage":
+        print("python cmakelists_generator.py <names of all generated files directories>")
+        print("If given no parameters: Generates CMakeLists.txt file for all generated files in CURRENT directory")
+        exit(1)
+
+    cmakelists_file = open("CMakeLists.txt", "w")
+    if num_args == 1:
+        generate_cmakelists_file(cmakelists_file, get_all_generated_directory_names())
+    else:
+        generate_cmakelists_file(cmakelists_file, sys.argv[1:])
+    cmakelists_file.close()
diff --git a/llvm/projects/hpvm-tensor-rt/online_benchmark_testing_automator.py b/llvm/projects/hpvm-tensor-rt/code_autogenerators/online_benchmark_testing_automator.py
similarity index 100%
rename from llvm/projects/hpvm-tensor-rt/online_benchmark_testing_automator.py
rename to llvm/projects/hpvm-tensor-rt/code_autogenerators/online_benchmark_testing_automator.py
diff --git a/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py b/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ee30bf36d170f403a645914486e500ff3bda546
--- /dev/null
+++ b/llvm/projects/hpvm-tensor-rt/code_autogenerators/source_code_autogenerator.py
@@ -0,0 +1,200 @@
+# Input: file of the following table format
+#   id    knob configurations (arbitrary # of columns)   orig_func_name     new_func_name 
+# Input: file containing list of filenames to generate modified sources for 
+# Generates:
+#   a new directory called <original_source_nane>_different_knobs
+#   files named <original_source_name>_<id>.txt within their respective directories
+
+import glob
+import sys
+import os
+import re
+
+class KnobConfiguration:
+    '''
+    Stores the configurations as well as other useful information for each knob configuration
+    Stores: id (may factor out if ids are guaranteed to start at 0/1 and be consecutive)
+            original function name
+            modified function name
+            new function parameters (knobs)
+            new function call (modified function name(knobs)) 
+    '''
+    def __init__(self, raw_config):
+        '''
+        Args: raw_config = line of configuration file to parse
+        '''
+        line_as_lst = raw_config.strip().split()
+
+        self.id = int(line_as_lst[0])
+        self.orig_func_name = line_as_lst[-2]
+        self.modified_func_name = line_as_lst[-1]
+        self.params = line_as_lst[1:-2]
+   
+
+def get_new_path(old_path, orig_source_code_dir):
+    '''
+    Returns a path that's compatible with the location of the generated source code
+
+    Args:
+        old_path: Original path of file that's being included
+        orig_source_code_dir: Path to original source code dir wrt the current dir
+    '''
+    if os.path.isabs(old_path): # Old path works
+        return old_path 
+    # Adding an extra .. because the path should be wrt the generated directory
+    return os.path.join("..", orig_source_code_dir, old_path)
+
+
+# "complete_line" = a valid line of code  
+def get_new_function_calls(complete_line, knob_config):
+    '''
+    Returns a copy of an inputted line of code such that all instances of old 
+    function calls are replaced with newFunctionCall(old params, knobs)
+
+    Note: The old calls aren't completely overriden, as we still need the old parameters but
+    insert new parameters as well
+
+    Args:
+        complete_line: A complete line of code to process
+        knob_config: KnobConfiguration object representing current configuration 
+    '''
+    orig_func_ind = complete_line.find(knob_config.orig_func_name)
+    new_line = []
+    line_start_ind = 0
+    last_ind = 0
+
+    while orig_func_ind != -1:
+        new_line.append(complete_line[line_start_ind : orig_func_ind])
+        line_start_ind = complete_line.find(")", orig_func_ind) + 1 
+        
+        old_func_call = complete_line[complete_line.find("(", orig_func_ind): line_start_ind]
+        new_line.append("%s%s, %s)" % (knob_config.modified_func_name, old_func_call[:-1], ', '.join(knob_config.params)))
+        orig_func_ind = complete_line.find(knob_config.orig_func_name, line_start_ind)
+	new_line.append(complete_line[line_start_ind : ])
+    #print(new_line)
+    return ''.join(new_line)
+
+
+def generate_source_code(table, dir_name, filename, source_name):
+    '''
+    Generates source code for all configurations in the table for one original source 
+    Args
+        table: List of KnobConfigurations
+        dir_name: Directory new sources should be placed in
+        filename: Filename of original source
+        source_name: Filename without the file extension (ex: foo/blah.cc --> blah)
+    '''
+    file_comment = "// AUTO-GENERATED SOURCE CODE. REPLACED ALL INSTANCES OF %s WITH %s\n"
+
+    source_file = open(filename, "r") 
+    filename_dir = os.path.dirname(filename)
+
+    for knob_config in table:
+        source_file.seek(0, 0)
+       
+        new_file_contents = [file_comment % (knob_config.orig_func_name, knob_config.modified_func_name)]
+
+        # Store complete line to handle cases where one line of code is split into two lines
+        complete_line = ""
+        for line in source_file:
+            # Replace the current path of the local include with a path that's compatible 
+            # with the location of the generated source code 
+            if line.startswith("#"):
+                include_file = line.split()[1]
+                if include_file.startswith("\""):
+                    new_include_path = get_new_path(include_file.replace("\"", ""), filename_dir.replace("\"", ""))
+                    new_file_contents.append("#include \"%s\"\n" % new_include_path)
+                else:
+                    new_file_contents.append(line)
+                continue
+            # Handles case where 1 actual line of code is split into 2 lines 
+            elif line.find("}") != -1 or line.find("{") != -1:
+                complete_line += line
+                new_file_contents.append(complete_line)
+                complete_line = ""
+                continue
+            elif line.find(";") == -1: # Last char is always \n
+                complete_line += line
+                continue
+
+            complete_line += line
+            orig_func_ind = complete_line.find(knob_config.orig_func_name)
+            if orig_func_ind != -1:
+				new_file_contents.append(get_new_function_calls(complete_line, knob_config))
+            else:
+                new_file_contents.append(complete_line)
+            complete_line = ""
+
+        new_filename = os.path.join(dir_name, "%s_%s.cc" % (source_name, knob_config.id))
+        new_file = open(new_filename, "w")
+        new_file.write(''.join(new_file_contents))
+        new_file.close()
+        print("Generated source code as %s" % new_filename)
+    source_file.close()
+
+
+def generate_all_sources(table, orig_files_filename):
+    '''
+    Generates directories and source code for all original sources for all knob configurations
+    Args:
+        table: List of KnobConfiguration objects
+        orig_files_filename: Filename of file containing all original source names to generate new
+               sources for 
+    '''
+    orig_files = open(orig_files_filename, "r")
+    for orig_filename in orig_files:
+        orig_filename = orig_filename.strip()
+
+        # Source name = original filename without the .cc 
+        last_slash_ind = orig_filename.rfind("/")
+        file_ext_ind = orig_filename.find(".cc")
+        if last_slash_ind == -1:
+            source_name = orig_filename[ : file_ext_ind]
+        else:
+            source_name = orig_filename[last_slash_ind + 1 : file_ext_ind]
+        print("Source name: %s" % source_name)
+       
+        # Start with a clean directory
+        dir_name = "%s_autogenerated_knobs" % source_name
+        print("Setting up directory: %s" % dir_name)
+        if os.path.isdir(dir_name):
+            print("Directory exists: clearing everything")
+            for old_file in glob.glob(os.path.join(dir_name, "*")):
+                os.remove(old_file)
+
+        else:
+            print("Generating directory: %s" % dir_name)
+            os.makedirs(dir_name)
+            
+        generate_source_code(table, dir_name, orig_filename, source_name)
+        print("\n")
+    orig_files.close()
+
+
+def parse_table(table_filename):
+    '''
+    Given the filename of a table, parses the table into a list of KnobConfigurations 
+    '''
+    # Can we assume that the ids always start at 1 --> if so, can index by knobs 
+    # else: need to use a dict
+    table = []
+    table_file = open(table_filename, "r")
+    for raw_config in table_file:
+        table.append(KnobConfiguration(raw_config))
+    table_file.close()  
+    return table
+    
+
+if __name__ == "__main__":
+    num_args = len(sys.argv)
+    if num_args != 3:
+        print("Usage: python source_code_autogenerator.py <table file> <original filenames file>")
+        if num_args >= 2 and sys.argv[1] == "--usage":
+            print("Table file format: <id> <knob configurations separated by spaces> <orig func name> <new func name>")
+            print("Original filenames file: <original_filename><newline> etc")
+        else:
+            print("Run with --usage flag for more detailed information")
+        exit(1)
+
+    table = parse_table(sys.argv[1])
+    generate_all_sources(table, sys.argv[2])