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

Merging

parents ee4e8774 49152f89
No related branches found
No related tags found
No related merge requests found
......@@ -10,6 +10,12 @@ import sys
import os
import re
class Approx:
FP32 = 0
FP16 = 1
PERF = 2
SAMP = 3
class KnobConfiguration:
'''
Stores the configurations as well as other useful information for each knob configuration
......@@ -24,12 +30,45 @@ class KnobConfiguration:
Args: raw_config = line of configuration file to parse
'''
line_as_lst = raw_config.strip().split()
# approx,<id> knob1,knob2,etc IGNORE old_fun_name new_fun_name
approx_id_lst = line_as_lst[0].split(',')
assert len(approx_id_lst) == 2
self.id = int(approx_id_lst[1])
if approx_id_lst[0] == "fp32":
self.approx = Approx.FP32
return # special case
elif approx_id_lst[0] == "fp16":
self.approx = Approx.FP16
return # special case
elif approx_id_lst[0] == "perf":
self.approx = Approx.PERF
elif approx_id_lst[0] == "samp":
self.approx = Approx.SAMP
self.orig_func_name = line_as_lst[-2] # Second to last element
self.modified_func_name = line_as_lst[-1] # Last element
self.params = line_as_lst[1].split(",") # First element = knob configuration
# DEBUG
def __repr__(self):
if self.approx == Approx.FP32:
return "FP32"
elif self.approx == Approx.FP16:
return "FP16"
approx_type = None
if self.approx == Approx.PERF:
approx_type = "PERF"
elif self.approx == Approx.SAMP:
approx_type = "SAMP"
return "Approx: %s, ID: %d, Orig func nane: %s, Modified func nane: %s, Params: %s" \
% (approx_type, self.id, self.orig_func_name, self.modified_func_name, \
', '.join(self.params))
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):
'''
......@@ -71,10 +110,96 @@ def get_new_function_calls(complete_line, knob_config):
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 convert_local_paths(file_contents, orig_source_dir):
'''
Converts all local paths wrt the original source file's directory to paths compatible
with the current source code directory
Args:
file_contents: String containing source code read from file
orig_source_dir: Path of original source code dir wrt the current directory
'''
last_include_ind = file_contents.rfind("#include")
last_include_newline_ind = file_contents.find("\n", last_include_ind)
include_lines = file_contents[ : last_include_newline_ind].split("\n")
new_file_contents = []
for line in include_lines:
if line.startswith("#"):
include_file = line.split()[1]
if include_file.startswith("\""):
new_include_path = get_new_path(include_file.replace("\"", ""), orig_source_dir.replace("\"", ""))
new_file_contents.append("#include \"%s\"\n" % new_include_path)
else:
new_file_contents.append(line)
new_file_contents.append(file_contents[last_include_newline_ind : ])
return '\n'.join(new_file_contents)
def generate_fp32_source(new_file, source_file, orig_source_dir):
# Copy the source code over
new_file_contents = convert_local_paths(source_file.read(), orig_source_dir)
new_file.write(new_file_contents)
def generate_fp16_source(knob_config, new_file, source_file, orig_source_dir):
file_contents = source_file.read()
new_file_contents = convert_local_paths(file_contents, orig_source_dir)
# Replace all tensorOperation calls with tensorHalfOperation calls
# Derived from ../bin/replace_half_calls.py
# NOTE: Not very portable but I don't see another way of ONLY replacing tensorOperation FUNCTION calls
new_file_contents = new_file_contents.replace("tensorConvolution", "tensorHalfConvolution")
new_file_contents = new_file_contents.replace("tensorAdd", "tensorHalfAdd")
new_file_contents = new_file_contents.replace("tensorRelu", "tensorHalfRelu")
new_file_contents = new_file_contents.replace("tensorRelu2", "tensorHalfRelu2")
new_file_contents = new_file_contents.replace("tensorTanh", "tensorHalfTanh")
new_file_contents = new_file_contents.replace("tensorPooling", "tensorHalfPooling")
new_file_contents = new_file_contents.replace("tensorGemmGPU", "tensorHalfGemmGPU")
new_file.write(new_file_contents)
def generate_approx_source(knob_config, new_file, source_file, orig_source_dir):
new_file_contents = []
# 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("\"", ""), orig_source_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_file.write(''.join(new_file_contents))
def generate_source_code(table, dir_name, filename, source_name):
'''
Generates source code for all configurations in the table for one original source
......@@ -84,50 +209,20 @@ def generate_source_code(table, dir_name, filename, source_name):
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)
orig_source_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))
if knob_config.approx == Approx.FP16:
generate_fp16_source(knob_config, new_file, source_file, orig_source_dir)
elif knob_config.approx == Approx.FP32:
generate_fp32_source(new_file, source_file, orig_source_dir)
else:
generate_approx_source(knob_config, new_file, source_file, orig_source_dir)
new_file.close()
print("Generated source code as %s" % new_filename)
source_file.close()
......
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