diff --git a/discopop_library/discopop_optimizer/DataTransfers/DataTransfers.py b/discopop_library/discopop_optimizer/DataTransfers/DataTransfers.py index 4d13d9177..7c749f020 100644 --- a/discopop_library/discopop_optimizer/DataTransfers/DataTransfers.py +++ b/discopop_library/discopop_optimizer/DataTransfers/DataTransfers.py @@ -55,6 +55,12 @@ def get_path_context_iterative( # calculate context modifications for the current node context = __check_current_node(node_id, graph, model, context, experiment) + # set last_visited_device id + if node_data.device_id is not None: + context.last_visited_device_id = node_data.device_id + else: + context.last_visited_device_id = context.last_seen_device_ids[-1] + # calculate context modifications for the children of the current node context = __check_children(node_id, graph, model, context, experiment) @@ -219,9 +225,22 @@ def __check_current_node( ) return updated_context - context = context.calculate_and_perform_necessary_updates( - node_data.read_memory_regions, cast(int, context.last_seen_device_ids[-1]), node_data.node_id, graph, experiment - ) + # only allow updates on device switches + device_switch = False + if data_at(graph, node_id).device_id is None: + if context.last_seen_device_ids[-1] != context.last_visited_device_id: + device_switch = True + elif context.last_visited_device_id != data_at(graph, node_id).device_id: + device_switch = True + + if device_switch: + context = context.calculate_and_perform_necessary_updates( + node_data.read_memory_regions, + cast(int, context.last_seen_device_ids[-1]), + node_data.node_id, + graph, + experiment, + ) # add the writes performed by the given node to the context context = context.add_writes(node_data.written_memory_regions, cast(int, context.last_seen_device_ids[-1])) diff --git a/discopop_library/discopop_optimizer/PETParser/PETParser.py b/discopop_library/discopop_optimizer/PETParser/PETParser.py index e943ca94b..ab200ebdc 100644 --- a/discopop_library/discopop_optimizer/PETParser/PETParser.py +++ b/discopop_library/discopop_optimizer/PETParser/PETParser.py @@ -101,6 +101,10 @@ def parse(self) -> Tuple[nx.DiGraph, int]: if self.experiment.arguments.verbose: print("calculated data flow") + self.__propagate_reads_and_writes() + if self.experiment.arguments.verbose: + print("Propagated read/write information") + return self.graph, self.next_free_node_id def get_new_node_id(self) -> int: @@ -733,3 +737,16 @@ def inlined_data_flow_calculation(current_node, current_last_writes): for entry in self.out_data_flow[key]: if not self.graph.has_edge(key, entry): add_dataflow_edge(self.graph, key, entry) + + def __propagate_reads_and_writes(self): + # initialize queue + queue = [n for n in self.graph.nodes] + + while queue: + current = queue.pop() + current_data = data_at(self.graph, current) + parents = get_all_parents(self.graph, current) + queue += [p for p in parents if p not in queue] + for p in parents: + data_at(self.graph, p).written_memory_regions.update(current_data.written_memory_regions) + data_at(self.graph, p).read_memory_regions.update(current_data.read_memory_regions) diff --git a/discopop_library/discopop_optimizer/classes/context/ContextObject.py b/discopop_library/discopop_optimizer/classes/context/ContextObject.py index 31b602b53..d548f240c 100644 --- a/discopop_library/discopop_optimizer/classes/context/ContextObject.py +++ b/discopop_library/discopop_optimizer/classes/context/ContextObject.py @@ -23,6 +23,7 @@ class ContextObject(object): last_visited_node_id: int + last_visited_device_id: DeviceID last_seen_device_ids: List[DeviceID] seen_writes_by_device: Dict[DeviceID, Dict[MemoryRegion, Set[WriteDataAccess]]] necessary_updates: Set[Update] @@ -31,6 +32,7 @@ def __init__(self, initializing_node_id: int, last_seen_device_ids: Optional[Lis self.seen_writes_by_device = dict() self.necessary_updates = set() self.last_visited_node_id = initializing_node_id + self.last_visited_device_id = None self.last_seen_device_ids = last_seen_device_ids if last_seen_device_ids is not None else [] self.snapshot_stack = [] # type: ignore self.save_stack = [] # type: ignore # list of lists of ContextObjects, one list per branching depth @@ -59,6 +61,7 @@ def calculate_and_perform_necessary_updates( if device_id == reading_device_id: continue + if read.memory_region not in self.get_seen_writes_by_device(device_id): # read memory region is currently "unknown" to the device, thus is can be skipped continue @@ -88,7 +91,10 @@ def calculate_and_perform_necessary_updates( for data_write in unknown_writes: # if device <-> device update is required, split it into two distinct updates - if device_id != 0 and reading_device_id != 0: + if ( + device_id != experiment.get_system().get_host_device_id() + and reading_device_id != experiment.get_system().get_host_device_id() + ): # print("Device <-> Device update required!") # check if data is known to the host diff --git a/discopop_library/discopop_optimizer/classes/nodes/Loop.py b/discopop_library/discopop_optimizer/classes/nodes/Loop.py index ec079f19e..b3f3cf9a3 100644 --- a/discopop_library/discopop_optimizer/classes/nodes/Loop.py +++ b/discopop_library/discopop_optimizer/classes/nodes/Loop.py @@ -85,7 +85,8 @@ def get_hover_text(self) -> str: "Read: " + str([str(e) for e in self.read_memory_regions]) + "\n" "Write: " + str([str(e) for e in self.written_memory_regions]) + "\n" "Suggestion: " + str(self.suggestion) + "\n" - "Collapse: " + str(self.collapse_level) + "Collapse: " + str(self.collapse_level) + "\n" + "Device ID: " + str(self.device_id) ) def get_cost_model(self, experiment, all_function_nodes, current_device) -> CostModel: diff --git a/discopop_library/discopop_optimizer/classes/nodes/Workload.py b/discopop_library/discopop_optimizer/classes/nodes/Workload.py index 8d1fe4a0c..9e24c093b 100644 --- a/discopop_library/discopop_optimizer/classes/nodes/Workload.py +++ b/discopop_library/discopop_optimizer/classes/nodes/Workload.py @@ -63,7 +63,8 @@ def get_hover_text(self) -> str: "WL: " + str(self.sequential_workload) + "\n" "Read: " + str([str(e) for e in self.read_memory_regions]) + "\n" "Write: " + str([str(e) for e in self.written_memory_regions]) + "\n" - "Branch: " + str(self.branch_affiliation) + "Branch: " + str(self.branch_affiliation) + "\n" + "Device ID: " + str(self.device_id) ) def get_cost_model(self, experiment, all_function_nodes, current_device) -> CostModel: