Skip to content
Snippets Groups Projects
Commit a9c43262 authored by Hashim Sharif's avatar Hashim Sharif
Browse files

Merging

parents ba04e570 f6ce775c
No related branches found
No related tags found
No related merge requests found
# 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])
# 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()
# 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])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment