From de1964a6547a859ddb0845fe61153298bffc37b1 Mon Sep 17 00:00:00 2001 From: JanLJL Date: Fri, 30 Aug 2019 10:11:51 +0200 Subject: [PATCH] added tests for loop-carried deps and changed data structure of them to dict --- osaca/frontend.py | 12 +++++----- osaca/semantics/kernel_dg.py | 46 ++++++++++++++++++++---------------- tests/test_semantics.py | 20 ++++++++++++++++ 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/osaca/frontend.py b/osaca/frontend.py index 4ca3166..f20efd3 100755 --- a/osaca/frontend.py +++ b/osaca/frontend.py @@ -149,26 +149,26 @@ class Frontend(object): ) ) - def print_loopcarried_dependencies(self, dep_tuplelist, separator='|'): + def print_loopcarried_dependencies(self, dep_dict, separator='|'): print( '\n\nLoop-Carried Dependencies Analysis Report\n' + '-----------------------------------------' ) - for tup in dep_tuplelist: + for dep in dep_dict: print( '{:4d} {} {:4.1f} {} {:36}{} {}'.format( - tup[0]['line_number'], + dep, separator, sum( [ instr_form['latency'] if instr_form['latency'] is not None else 0 - for instr_form in tup[1] + for instr_form in dep_dict[dep]['dependencies'] ] ), separator, - tup[0]['line'], + dep_dict[dep]['root']['line'], separator, - [node['line_number'] for node in tup[1]], + [node['line_number'] for node in dep_dict[dep]['dependencies']], ) ) diff --git a/osaca/semantics/kernel_dg.py b/osaca/semantics/kernel_dg.py index c4ab26d..99d597a 100755 --- a/osaca/semantics/kernel_dg.py +++ b/osaca/semantics/kernel_dg.py @@ -17,6 +17,24 @@ class KernelDG(nx.DiGraph): self.dg = self.create_DG(self.kernel) self.loopcarried_deps = self.check_for_loopcarried_dep(self.kernel) + def create_DG(self, kernel): + # 1. go through kernel instruction forms (as vertices) + # 2. find edges (to dependend further instruction) + # 3. get LT value and set as edge weight + # 4. add instr forms as node attribute + dg = nx.DiGraph() + for i, instruction_form in enumerate(kernel): + dg.add_node(instruction_form['line_number']) + dg.nodes[instruction_form['line_number']]['instruction_form'] = instruction_form + for dep in self.find_depending(instruction_form, kernel[i + 1:]): + dg.add_edge( + instruction_form['line_number'], + dep['line_number'], + latency=instruction_form['latency'], + ) + dg.nodes[dep['line_number']]['instruction_form'] = dep + return dg + def check_for_loopcarried_dep(self, kernel): multiplier = len(kernel) + 1 # increase line number for second kernel loop @@ -43,34 +61,20 @@ class KernelDG(nx.DiGraph): ) # adjust line numbers # and add reference to kernel again - for i, dep in enumerate(loopcarried_deps): + loopcarried_deps_dict = {} + for dep in loopcarried_deps: nodes = [int(n / multiplier) for n in dep[1] if n >= first_line_no * multiplier] nodes = [self._get_node_by_lineno(x) for x in nodes] - loopcarried_deps[i] = (self._get_node_by_lineno(dep[0]), nodes) + loopcarried_deps_dict[dep[0]] = { + 'root': self._get_node_by_lineno(dep[0]), + 'dependencies': nodes, + } - return loopcarried_deps + return loopcarried_deps_dict def _get_node_by_lineno(self, lineno): return [instr for instr in self.kernel if instr.line_number == lineno][0] - def create_DG(self, kernel): - # 1. go through kernel instruction forms (as vertices) - # 2. find edges (to dependend further instruction) - # 3. get LT value and set as edge weight - # 4. add instr forms as node attribute - dg = nx.DiGraph() - for i, instruction_form in enumerate(kernel): - dg.add_node(instruction_form['line_number']) - for dep in self.find_depending(instruction_form, kernel[i + 1:]): - dg.add_edge( - instruction_form['line_number'], - dep['line_number'], - latency=instruction_form['latency'], - ) - dg.nodes[instruction_form['line_number']]['instruction_form'] = instruction_form - dg.nodes[dep['line_number']]['instruction_form'] = dep - return dg - def get_critical_path(self): if nx.algorithms.dag.is_directed_acyclic_graph(self.dg): longest_path = nx.algorithms.dag.dag_longest_path(self.dg, weight='latency') diff --git a/tests/test_semantics.py b/tests/test_semantics.py index bf8cf73..b687ff1 100755 --- a/tests/test_semantics.py +++ b/tests/test_semantics.py @@ -150,6 +150,26 @@ class TestSemanticTools(unittest.TestCase): self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=20))), 0) self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=21))), 0) + def test_cyclic_dag(self): + dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx) + dg.dg.add_edge(100, 101, latency=1.0) + dg.dg.add_edge(101, 102, latency=2.0) + dg.dg.add_edge(102, 100, latency=3.0) + with self.assertRaises(NotImplementedError): + dg.get_critical_path() + with self.assertRaises(NotImplementedError): + dg.get_loopcarried_dependencies() + + def test_loop_carried_dependency_x86(self): + dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx) + lc_deps = dg.get_loopcarried_dependencies() + self.assertEqual(len(lc_deps), 1) + self.assertEqual(lc_deps[7]['root'], dg.dg.nodes(data=True)[7]['instruction_form']) + self.assertEqual(len(lc_deps[7]['dependencies']), 1) + self.assertEqual( + lc_deps[7]['dependencies'][0], dg.dg.nodes(data=True)[7]['instruction_form'] + ) + def test_is_read_is_written_x86(self): # independent form HW model dag = KernelDG(self.kernel_x86, self.parser_x86, None)