Skip to content

Commit

Permalink
feat(optimizer): improved configuration output
Browse files Browse the repository at this point in the history
  • Loading branch information
lukasrothenberger committed Dec 13, 2023
1 parent 251ad58 commit d040f04
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 10 deletions.
53 changes: 53 additions & 0 deletions discopop_library/ParallelConfiguration/ParallelConfiguration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# This file is part of the DiscoPoP software (http://www.discopop.tu-darmstadt.de)
#
# Copyright (c) 2020, Technische Universitaet Darmstadt, Germany
#
# This software may be modified and distributed under the terms of
# the 3-Clause BSD License. See the LICENSE file in the package base
# directory for details.

import json
from typing import List, Tuple, Any, Dict
import warnings

from discopop_library.discopop_optimizer.classes.context.Update import Update, construct_update_from_dict
from discopop_library.discopop_optimizer.classes.types.Aliases import DeviceID

SuggestionId = int


class ParallelConfiguration(object):
"""Object to store, save and reconstruct configurations and suggestions to be applied by the patch applicator."""

__applied_patterns: List[Dict[str, Any]]
__data_movement: List[Update]

def __init__(self):
self.__applied_patterns = []
self.__data_movement = []

def reconstruct_from_file(self, file_path: str):
with open(file_path, "r") as f:
loaded_data = json.load(f)
self.__applied_patterns = loaded_data["applied_patterns"]

for values in loaded_data["data_movement"]:
self.__data_movement.append(construct_update_from_dict(values))

def dump_to_file(self, file_path: str):
dumpable_dict = dict()
dumpable_dict["applied_patterns"] = self.__applied_patterns
dumpable_dict["data_movement"] = [update.toDict() for update in self.__data_movement]

with open(file_path, "w") as f:
json.dump(dumpable_dict, f)

test = ParallelConfiguration()
test.reconstruct_from_file(file_path)

def add_pattern(self, pattern_id: SuggestionId, target_device_id: DeviceID):
tmp_dict = {"pattern_id": pattern_id, "device_id": target_device_id}
self.__applied_patterns.append(tmp_dict)

def add_data_movement(self, update: Update):
self.__data_movement.append(update)
28 changes: 27 additions & 1 deletion discopop_library/discopop_optimizer/classes/context/Update.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
# This software may be modified and distributed under the terms of
# the 3-Clause BSD License. See the LICENSE file in the package base
# directory for details.
from typing import Any, Dict, Optional
from discopop_library.discopop_optimizer.classes.types.Aliases import DeviceID
from discopop_library.discopop_optimizer.classes.types.DataAccessType import WriteDataAccess
from discopop_library.discopop_optimizer.classes.types.DataAccessType import (
WriteDataAccess,
write_data_access_from_dict,
)


class Update(object):
Expand Down Expand Up @@ -52,3 +56,25 @@ def __str__(self):
+ str(self.write_data_access.var_name)
+ ")"
)

def toDict(self) -> Dict[str, Any]:
result_dict: Dict[str, Any] = {}
result_dict["source_node_id"] = self.source_node_id
result_dict["target_node_id"] = self.target_node_id
result_dict["source_device_id"] = self.source_device_id
result_dict["target_device_id"] = self.target_device_id
result_dict["is_first_data_occurrence"] = self.is_first_data_occurrence
result_dict["write_data_access"] = self.write_data_access.toDict()
return result_dict


def construct_update_from_dict(values: Dict[str, Any]) -> Update:
update = Update(
values["source_node_id"],
values["target_node_id"],
values["source_device_id"],
values["target_device_id"],
write_data_access_from_dict(values["write_data_access"]),
values["is_first_data_occurrence"],
)
return update
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# This software may be modified and distributed under the terms of
# the 3-Clause BSD License. See the LICENSE file in the package base
# directory for details.
from typing import Optional
from typing import Any, Dict, Optional

from discopop_explorer.PEGraphX import MemoryRegion

Expand Down Expand Up @@ -37,3 +37,14 @@ def __str__(self):

def __hash__(self):
return self.unique_id

def toDict(self):
result_dict = {}
result_dict["memory_region"] = self.memory_region
result_dict["unique_id"] = self.unique_id
result_dict["var_name"] = self.var_name
return result_dict


def write_data_access_from_dict(values: Dict[str, Any]) -> WriteDataAccess:
return WriteDataAccess(values["memory_region"], values["unique_id"], values["var_name"])
5 changes: 3 additions & 2 deletions discopop_library/discopop_optimizer/optimization/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def evaluate_configuration(
experiment: Experiment,
decisions: List[int],
arguments: OptimizerArguments,
) -> Tuple[Tuple[int, ...], Expr]:
) -> Tuple[Tuple[int, ...], Expr, ContextObject]:
"""Evaluate the configuration specified by the decisions for the current set of substitutions.
Returns the used decisions and the calculated costs as a tuple.
Note: To compare values across ranges of system specifications, use the ranges obtainable via System.get_symbol_values_and_distributions
Expand Down Expand Up @@ -79,6 +79,7 @@ def evaluate_configuration(
].parallelizable_costs

result_model = copy.deepcopy(selected_function_models[main_function][0])
result_context = copy.deepcopy(selected_function_models[main_function][1])

# perform iterative substitutions
modification_found = True
Expand Down Expand Up @@ -115,4 +116,4 @@ def evaluate_configuration(
result = sympy.re(result_model.parallelizable_costs + result_model.sequential_costs) + sympy.im(
result_model.parallelizable_costs + result_model.sequential_costs
)
return (tuple(decisions), result)
return (tuple(decisions), result, result_context)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from sympy import Expr
import tqdm # type: ignore
from discopop_library.ParallelConfiguration.ParallelConfiguration import ParallelConfiguration # type: ignore
from discopop_library.discopop_optimizer.CostModels.CostModel import CostModel
from discopop_library.discopop_optimizer.OptimizerArguments import OptimizerArguments
from discopop_library.discopop_optimizer.Variables.Experiment import Experiment
Expand Down Expand Up @@ -41,6 +42,7 @@ def evaluate_all_decision_combinations(
global_arguments = arguments

costs_dict: Dict[Tuple[int, ...], Expr] = dict()
contexts_dict: Dict[Tuple[int, ...], ContextObject] = dict()

packed_decisions: List[List[List[int]]] = []
for function in available_decisions:
Expand Down Expand Up @@ -75,6 +77,7 @@ def evaluate_all_decision_combinations(
if arguments.verbose:
print("# raw:", local_result[0], "=", str(local_result[1]))
costs_dict[local_result[0]] = local_result[1]
contexts_dict[local_result[0]] = local_result[2]
if arguments.verbose:
print()

Expand Down Expand Up @@ -114,7 +117,7 @@ def evaluate_all_decision_combinations(
print("# Sorted and simplified costs of all combinations using PARALLEL PATTERN IDS")
print()

__dump_result_to_file_using_pattern_ids(experiment, optimizer_dir, costs_dict, arguments)
__dump_result_to_file_using_pattern_ids(experiment, optimizer_dir, costs_dict, contexts_dict, arguments)

return costs_dict

Expand All @@ -137,7 +140,11 @@ def __evaluate_configuration(param_tuple):


def __dump_result_to_file_using_pattern_ids(
experiment: Experiment, optimizer_dir: str, costs_dict: Dict[Tuple[int, ...], Expr], arguments: OptimizerArguments
experiment: Experiment,
optimizer_dir: str,
costs_dict: Dict[Tuple[int, ...], Expr],
contexts_dict: Dict[Tuple[int, ...], ContextObject],
arguments: OptimizerArguments,
):
# replace keys to allow dumping
dumpable_dict = dict()
Expand All @@ -157,14 +164,26 @@ def __dump_result_to_file_using_pattern_ids(
# dump the best option
for combination_tuple in sorted(costs_dict.keys(), key=lambda x: costs_dict[x]):
new_key_2 = []
best_configuration = ParallelConfiguration()
# collect applied suggestions
for node_id in combination_tuple:
# find pattern id
for pattern_id in experiment.suggestion_to_node_ids_dict:
if node_id in experiment.suggestion_to_node_ids_dict[pattern_id]:
new_key_2.append(
str(pattern_id) + "@" + str(data_at(experiment.optimization_graph, node_id).device_id)
)
best_option_path: str = os.path.join(optimizer_dir, "exhaustive_optimum.txt")
with open(best_option_path, "w") as fp:
fp.write(" ".join(new_key_2))
best_configuration.add_pattern(
pattern_id, data_at(experiment.optimization_graph, node_id).device_id
)
# collect data movement information
print("# Required updates..")
for update in contexts_dict[combination_tuple].necessary_updates:
best_configuration.add_data_movement(update)
print(" #", update)
print()
# export results to file
best_option_path: str = os.path.join(optimizer_dir, "exhaustive_configuration.json")
best_configuration.dump_to_file(best_option_path)

break
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ def __dump_result(
new_key_2.append(
str(pattern_id) + "@" + str(data_at(experiment.optimization_graph, node_id).device_id)
)
best_option_path: str = os.path.join(optimizer_dir, "evolutionary_optimum.txt")
best_option_path: str = os.path.join(optimizer_dir, "evolutionary_configuration.json")
with open(best_option_path, "w") as fp:
fp.write(" ".join(new_key_2))
break
Expand Down

0 comments on commit d040f04

Please sign in to comment.