Skip to content

Commit

Permalink
feat(autotuner): add --sanitize argument (to invoke ThreadSanitizer)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasrothenberger committed Oct 28, 2024
1 parent 1f212cb commit dea4bd3
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 13 deletions.
1 change: 1 addition & 0 deletions discopop_library/EmpiricalAutotuning/ArgumentClasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class AutotunerArguments(GeneralArguments):
project_path: str
dot_dp_path: str
skip_cleanup: bool
sanitize: bool

def __post_init__(self) -> None:
self.__validate()
Expand Down
16 changes: 10 additions & 6 deletions discopop_library/EmpiricalAutotuning/Autotuner.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ def get_unique_configuration_id() -> int:

def run(arguments: AutotunerArguments) -> None:
logger.info("Starting discopop autotuner.")
debug_stats: List[Tuple[List[SUGGESTION_ID], float, int, bool, str]] = []
debug_stats: List[Tuple[List[SUGGESTION_ID], float, int, bool, bool, str]] = []
statistics_graph = StatisticsGraph()
statistics_step_num = 0

# get untuned reference result
reference_configuration = CodeConfiguration(arguments.project_path, arguments.dot_dp_path)
reference_configuration.execute(timeout=None, is_initial=True)
reference_configuration.execute(arguments, timeout=None, is_initial=True)
statistics_graph.set_root(
reference_configuration.get_statistics_graph_label(),
color=reference_configuration.get_statistics_graph_color(),
Expand All @@ -58,6 +58,7 @@ def run(arguments: AutotunerArguments) -> None:
cast(ExecutionResult, reference_configuration.execution_result).runtime,
cast(ExecutionResult, reference_configuration.execution_result).return_code,
cast(ExecutionResult, reference_configuration.execution_result).result_valid,
cast(ExecutionResult, reference_configuration.execution_result).thread_sanitizer,
reference_configuration.root_path,
)
)
Expand Down Expand Up @@ -141,7 +142,7 @@ def run(arguments: AutotunerArguments) -> None:
visited_configurations.append(current_config)
tmp_config = reference_configuration.create_copy(get_unique_configuration_id)
tmp_config.apply_suggestions(arguments, current_config)
tmp_config.execute(timeout=timeout_after)
tmp_config.execute(arguments, timeout=timeout_after)
statistics_graph.add_child(
"step "
+ str(statistics_step_num)
Expand All @@ -159,6 +160,7 @@ def run(arguments: AutotunerArguments) -> None:
cast(ExecutionResult, tmp_config.execution_result).runtime,
cast(ExecutionResult, tmp_config.execution_result).return_code,
cast(ExecutionResult, tmp_config.execution_result).result_valid,
cast(ExecutionResult, tmp_config.execution_result).thread_sanitizer,
tmp_config.root_path,
)
)
Expand Down Expand Up @@ -241,7 +243,7 @@ def run(arguments: AutotunerArguments) -> None:

# show debug stats
stats_str = "Configuration measurements:\n"
stats_str += "[time]\t[applied suggestions]\t[return code]\t[result valid]\t[path]\n"
stats_str += "[time]\t[applied suggestions]\t[return code]\t[result valid]\t[thread sanitizer]\t[path]\n"
for stats in sorted(debug_stats, key=lambda x: (x[1]), reverse=True):
stats_str += (
str(round(stats[1], 3))
Expand All @@ -254,19 +256,21 @@ def run(arguments: AutotunerArguments) -> None:
+ str(stats[3])
+ "\t"
+ str(stats[4])
+ "\t"
+ str(stats[5])
+ "\n"
)
logger.info(stats_str)

# export measurements for pdf creation
if False: # export all measurements
with open("measurements.csv", "w+") as f:
f.write("ID; time; return_code;\n")
f.write("ID; time; return_code; thread_sanitizer\n")
for stats in sorted(debug_stats, key=lambda x: x[1], reverse=True):
f.write(str(stats[0]) + "; " + str(round(stats[1], 3)) + "; " + str(stats[2]) + ";" + "\n")
else: # export only sequential and best measurement
with open("measurements.csv", "w+") as f:
f.write("ID; time; return_code;\n")
f.write("ID; time; return_code; thread_sanitizer\n")
# write sequential measurement
for stats in sorted(debug_stats, key=lambda x: x[1], reverse=True):
if str(stats[0]) == "[]":
Expand Down
21 changes: 19 additions & 2 deletions discopop_library/EmpiricalAutotuning/Classes/CodeConfiguration.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(self, root_path: str, config_dot_dp_path: str):
def __str__(self) -> str:
return self.root_path

def execute(self, timeout: Optional[float], is_initial: bool = False) -> None:
def execute(self, arguments: AutotunerArguments, timeout: Optional[float], is_initial: bool = False) -> None:
# create timeout string
timeout_string = "" if timeout is None else "timeout " + str(timeout) + " "
if is_initial:
Expand Down Expand Up @@ -77,12 +77,29 @@ def execute(self, timeout: Optional[float], is_initial: bool = False) -> None:
if validity_check_result.returncode != 0:
result_valid = False

# check for result validity using thread sanitizer
thread_sanitizer_valid = True
if os.path.exists(os.path.join(self.root_path, "DP_SANITIZE.sh")) and arguments.sanitize:
logger.info("Checking thread sanity: " + str(self))
thread_sanitizer_result = subprocess.run(
"./DP_SANITIZE.sh && ./DP_EXECUTE.sh",
cwd=self.root_path,
executable="/bin/bash",
shell=True,
capture_output=True,
)
thread_sanitizer_output = str(thread_sanitizer_result.stdout.decode("utf-8"))
logger.getChild("ThreadSanitizerOutput").debug(thread_sanitizer_output)
if "WARNING: ThreadSanitizer: data race" in thread_sanitizer_output:
thread_sanitizer_valid = False

# reporting
logger.debug("Execution took " + str(round(required_time, 4)) + " s")
logger.debug("Execution return code: " + str(result.returncode))
logger.debug("Execution result valid: " + str(result_valid))
logger.debug("ThreadSanitizer valid: " + str(thread_sanitizer_valid))

self.execution_result = ExecutionResult(required_time, result.returncode, result_valid)
self.execution_result = ExecutionResult(required_time, result.returncode, result_valid, thread_sanitizer_valid)

def create_copy(self, get_new_configuration_id: Callable[[], int]) -> CodeConfiguration:
# create a copy of the project folder
Expand Down
14 changes: 12 additions & 2 deletions discopop_library/EmpiricalAutotuning/Classes/ExecutionResult.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,23 @@ class ExecutionResult(object):
runtime: float
return_code: int
result_valid: bool
thread_sanitizer: bool

def __init__(self, runtime: float, return_code: int, result_valid: bool):
def __init__(self, runtime: float, return_code: int, result_valid: bool, thread_sanitizer: bool):
self.runtime = runtime
self.return_code = return_code
self.result_valid = result_valid
self.thread_sanitizer = thread_sanitizer

def __str__(self) -> str:
return (
"" + "time: " + str(self.runtime) + " code: " + str(self.return_code) + " valid: " + str(self.result_valid)
""
+ "time: "
+ str(self.runtime)
+ " code: "
+ str(self.return_code)
+ " valid: "
+ str(self.result_valid)
+ " TSAN: "
+ str(self.thread_sanitizer)
)
8 changes: 5 additions & 3 deletions discopop_library/EmpiricalAutotuning/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def parse_args() -> AutotunerArguments:
parser = ArgumentParser(description="DiscoPoP Autotuner")

# fmt: off

parser.add_argument("--log", type=str, default="WARNING", help="Specify log level: DEBUG, INFO, WARNING, ERROR, CRITICAL")
parser.add_argument("--write-log", action="store_true", help="Create Logfile.")
parser.add_argument("--project-path", type=str, default=os.getcwd(), help="Root path of the project to be tuned. \
Expand All @@ -27,8 +27,9 @@ def parse_args() -> AutotunerArguments:
DP_EXECUTE.sh may return not 0, if either the execution or validation of the result failed. \
A third script DP_VALIDATE.sh might be added to add a validation step, where return code 0 is interpreted as a success, i.e. a valid result.")
parser.add_argument("--dot-dp-path", type=str, default=os.path.join(os.getcwd(), ".discopop"), help="Path to the .discopop folder.")
parser.add_argument("--skip-cleanup", action="store_true", help="disable the deletion of created code variants. May require a lot of disk space." )
# fmt: on
parser.add_argument("--skip-cleanup", action="store_true", help="Disable the deletion of created code variants. May require a lot of disk space." )
parser.add_argument("--sanitize", action="store_true", help="Enable the invocation of ThreadSanitizer if DP_SANITIZE.sh is provided." )
# fmt: is provided.

arguments = parser.parse_args()

Expand All @@ -38,6 +39,7 @@ def parse_args() -> AutotunerArguments:
project_path=arguments.project_path,
dot_dp_path=arguments.dot_dp_path,
skip_cleanup=arguments.skip_cleanup,
sanitize=arguments.sanitize,
)


Expand Down

0 comments on commit dea4bd3

Please sign in to comment.