def test_access_info(): '''Test the AccessInfo class. ''' location = 12 access_info = AccessInfo(AccessType.READ, location, Node()) assert access_info.access_type == AccessType.READ assert access_info.location == location assert access_info.indices is None access_info.change_read_to_write() assert access_info.access_type == AccessType.WRITE with pytest.raises(InternalError) as err: access_info.change_read_to_write() assert "Trying to change variable to 'WRITE' which does not have "\ "'READ' access." in str(err) access_info.indices = ["i"] assert access_info.indices == ["i"] access_info = AccessInfo(AccessType.UNKNOWN, location, Node()) assert access_info.access_type == AccessType.UNKNOWN assert access_info.location == location assert access_info.indices is None access_info = AccessInfo(AccessType.UNKNOWN, location, Node(), ["i", "j"]) assert access_info.access_type == AccessType.UNKNOWN assert access_info.location == location assert access_info.indices == ["i", "j"]
def test_variable_access_info(): '''Test the VariableAccesInfo class, i.e. the class that manages a list of VariableInfo instances for one variable ''' vai = VariableAccessInfo("var_name") assert vai.var_name == "var_name" assert vai.is_written() is False assert vai.is_read() is False assert vai.all_accesses == [] vai.add_access(AccessType.READ, Node(), 2) assert vai.is_read() vai.change_read_to_write() assert not vai.is_read() assert vai.is_written() # Now we have one write access, which we should not be able to # change to write again: with pytest.raises(InternalError) as err: vai.change_read_to_write() assert "Trying to change variable 'var_name' to 'WRITE' which "\ "does not have 'READ' access." in str(err) assert vai.all_accesses[0] == vai[0] with pytest.raises(IndexError) as err: _ = vai[1] # Add a READ access - now we should not be able to # change read to write anymore: vai.add_access(AccessType.READ, Node(), 1) with pytest.raises(InternalError) as err: vai.change_read_to_write() assert "Variable 'var_name' had 2 accesses listed, "\ "not one in change_read_to_write." in str(err)
def test_variable_access_info_read_write(): # pylint: disable=invalid-name '''Test the handling of READWRITE accesses. A READWRITE indicates both a read and a write access, but if a variable as a READ and a WRITE access, this is not one READWRITE access. A READWRITE access is only used in subroutine calls (depending on kernel metadata) ''' vai = VariableAccessInfo("var_name") assert vai.has_read_write() is False # Add a READ and WRITE access at the same location, and make sure it # is not reported as READWRITE access vai.add_access(AccessType.READ, Node(), 2) vai.add_access(AccessType.WRITE, Node(), 2) assert vai.has_read_write() is False vai.add_access(AccessType.READWRITE, Node(), 2) assert vai.has_read_write() # Create a new instance, and add only one READWRITE access: vai = VariableAccessInfo("var_name") vai.add_access(AccessType.READWRITE, Node(), 2) assert vai.has_read_write() assert vai.is_read() assert vai.is_written()
def __init__(self, invoke, ast): Node.__init__(self) NemoFparser2ASTProcessor.__init__(self) self._invoke = invoke self._ast = ast self.process_nodes(self, ast.content, ast)
def __init__(self, invoke, ast): # pylint: disable=super-init-not-called, non-parent-init-called Node.__init__(self) NemoFparser2ASTProcessor.__init__(self) self._invoke = invoke self._ast = ast self.process_nodes(self, ast.content, ast)
def test_basegen_add_invalid_posn(): '''Check that attempting to call add on BaseGen with an invalid position argument raises an error''' from psyclone.psyGen import Node from psyclone.f2pygen import BaseGen parent = Node() bgen = BaseGen(parent, parent) obj = Node() with pytest.raises(Exception) as err: bgen.add(obj, position=['wrong']) assert "supported positions are ['append', 'first'" in str(err)
def test_basegen_add_auto(): ''' Check that attempting to call add on BaseGen raises an error if position is "auto"''' from psyclone.psyGen import Node from psyclone.f2pygen import BaseGen parent = Node() bgen = BaseGen(parent, parent) obj = Node() with pytest.raises(Exception) as err: bgen.add(obj, position=['auto']) assert "auto option must be implemented by the sub" in str(err)
def test_omploop_no_collapse(): ''' Check that the OMPLoopTrans.directive() method rejects the collapse argument ''' from psyclone.psyGen import Node from psyclone.transformations import OMPLoopTrans trans = OMPLoopTrans() pnode = Node() cnode = Node() with pytest.raises(NotImplementedError) as err: _ = trans._directive(pnode, cnode, collapse=2) assert ("The COLLAPSE clause is not yet supported for '!$omp do' " "directives" in str(err))
def test_accloop(): ''' Generic tests for the ACCLoopTrans transformation class ''' from psyclone.transformations import ACCLoopTrans from psyclone.psyGen import Node, ACCLoopDirective trans = ACCLoopTrans() assert trans.name == "ACCLoopTrans" assert str(trans) == "Adds an 'OpenACC loop' directive to a loop" pnode = Node() cnode = Node() tdir = trans._directive(pnode, [cnode]) assert isinstance(tdir, ACCLoopDirective)
def __init__(self, invoke, ast): # pylint: disable=super-init-not-called, non-parent-init-called Node.__init__(self) NemoFparser2Reader.__init__(self) self._invoke = invoke self._ast = ast # Whether or not we've already checked the associated Fortran for # potential name-clashes when inserting profiling code. # TODO this can be removed once #435 is done and we're no longer # manipulating the fparser2 parse tree. self._name_clashes_checked = False self.process_nodes(self, ast.content, ast)
def test_variables_access_info(): '''Test the implementation of VariablesAccessInfo, a class that manages a list of variables, each with a list of accesses. ''' var_accesses = VariablesAccessInfo() node1 = Node() var_accesses.add_access("read", AccessType.READ, node1) node2 = Node() var_accesses.add_access("written", AccessType.WRITE, node2) assert str(var_accesses) == "read: READ, written: WRITE" var_accesses.next_location() node = Node() var_accesses.add_access("written", AccessType.WRITE, node) var_accesses.next_location() var_accesses.add_access("read_written", AccessType.WRITE, node) var_accesses.add_access("read_written", AccessType.READ, node) assert str(var_accesses) == "read: READ, read_written: READ+WRITE, "\ "written: WRITE" assert set(var_accesses.all_vars) == set( ["read", "written", "read_written"]) all_accesses = var_accesses["read"].all_accesses assert all_accesses[0].node == node1 written_accesses = var_accesses["written"].all_accesses assert written_accesses[0].location == 0 assert written_accesses[1].location == 1 # Check that the location pointer is pointing to the next statement: assert var_accesses.location == 2 # Create a new instance var_accesses2 = VariablesAccessInfo() var_accesses2.add_access("new_var", AccessType.READ, node) var_accesses2.add_access("written", AccessType.READ, node) # Now merge the new instance with the previous instance: var_accesses.merge(var_accesses2) assert str(var_accesses) == "new_var: READ, read: READ, " \ "read_written: READ+WRITE, written: READ+WRITE" with pytest.raises(KeyError): _ = var_accesses["does_not_exist"] with pytest.raises(KeyError): var_accesses.is_read("does_not_exist") with pytest.raises(KeyError): var_accesses.is_written("does_not_exist") assert "READWRITE" not in str(var_accesses) var_accesses.add_access("readwrite", AccessType.READWRITE, node) assert "READWRITE" in str(var_accesses)
def __init__(self, children=None, parent=None): Node.__init__(self, children=children, parent=parent) # Store the name of the profile variable that is used for this # profile name. This allows to show the variable name in __str__ # (and also if we would call create_name in gen(), the name would # change every time gen() is called). self._var_name = NameSpaceFactory().create().create_name("profile") # Name of the region. In general at constructor time we might not # have a parent subroutine or a child for the kernel, so we leave # the name empty for now. The region and module names are set the # first time gen() is called (and then remain unchanged). self._region_name = None self._module_name = None
def test_check_intergrid(): ''' Test that the check_intergrid utility does not raise an error if the supplied node has no children. ''' from psyclone.psyGen import Node from psyclone.transformations import check_intergrid tnode = Node() check_intergrid(tnode)
def test_ompdirective_type(): ''' Check that we can query the type of an OMP Directive ''' from psyclone.psyGen import Node parent = Node() dirgen = DirectiveGen(parent, "omp", "begin", "do", "schedule(static)") ompdir = dirgen.root assert ompdir.type == "do"
def test_psyirvisitor_visit_no_method2(): '''Check that an exception is not raised if the method for the Node class does not exist and skip_nodes is set to True. ''' visitor = PSyIRVisitor(skip_nodes=True) result = visitor(Node()) assert result is None
def test_ompdirective_wrong_posn(): ''' Check that we raise an error if we request an OMP Directive with an invalid position ''' from psyclone.psyGen import Node parent = Node() with pytest.raises(RuntimeError) as err: _ = DirectiveGen(parent, "omp", "start", "do", "schedule(static)") assert "unrecognised position 'start'" in str(err)
def test_ompdirective_wrong(): ''' Check that we raise an error if we request an OMP Directive of unrecognised type ''' from psyclone.psyGen import Node parent = Node() with pytest.raises(RuntimeError) as err: _ = DirectiveGen(parent, "omp", "begin", "dosomething", "schedule(static)") assert "unrecognised directive type" in str(err)
def test_directive_wrong_type(): ''' Check that we raise an error if we request a Directive of unrecognised type ''' from psyclone.psyGen import Node parent = Node() with pytest.raises(RuntimeError) as err: _ = DirectiveGen(parent, "some_dir_type", "begin", "do", "schedule(static)") assert "unsupported directive language" in str(err)
def test_psyirvisitor_visit_no_method1(): '''Check that an exception is raised if the method for the Node class does not exist. ''' visitor = PSyIRVisitor() with pytest.raises(VisitorError) as excinfo: visitor(Node()) assert ("Visitor Error: Unsupported node 'Node' found: method names " "attempted were ['node_node']." in str(excinfo.value))
def test_variables_access_info_merge(): # pylint: disable=invalid-name '''Tests the merge operation of VariablesAccessInfo. ''' # First create one instance representing for example: # a=b; c=d var_accesses1 = VariablesAccessInfo() node = Node() var_accesses1.add_access("b", AccessType.READ, node) var_accesses1.add_access("a", AccessType.WRITE, node) var_accesses1.next_location() var_accesses1.add_access("d", AccessType.READ, node) var_accesses1.add_access("c", AccessType.WRITE, node) c_accesses = var_accesses1["c"] assert len(c_accesses.all_accesses) == 1 assert c_accesses[0].access_type == AccessType.WRITE # First create one instance representing for example: # e=f; g=h var_accesses2 = VariablesAccessInfo() var_accesses2.add_access("f", AccessType.READ, node) var_accesses2.add_access("e", AccessType.WRITE, node) var_accesses2.next_location() var_accesses2.add_access("h", AccessType.READ, node) var_accesses2.add_access("g", AccessType.WRITE, node) # Now merge the second instance into the first one var_accesses1.merge(var_accesses2) # The e=f access pattern should have the same location # as the c=d (since there is no next_location after # adding the b=a access): c_accesses = var_accesses1["c"] e_accesses = var_accesses1["e"] assert c_accesses[0].access_type == AccessType.WRITE assert e_accesses[0].access_type == AccessType.WRITE assert c_accesses[0].location == e_accesses[0].location # Test that the g=h part has a higher location than the # c=d data. This makes sure that merge() increases the # location number of accesses when merging. c_accesses = var_accesses1["c"] g_accesses = var_accesses1["g"] h_accesses = var_accesses1["h"] assert c_accesses[0].location < g_accesses[0].location assert g_accesses[0].location == h_accesses[0].location # Also make sure that the access location was properly increased # Originally we had locations 0,1. Then we merged accesses with # location 0,1 in - the one at 0 is merged with the current 1, # and the new location 1 increases the current location from # 1 to 2: # pylint: disable=protected-access assert var_accesses1._location == 2
def __init__(self, children=None, parent=None): '''Constructor for a ProfileNode that is inserted in a schedule. Parameters: :param children: A list of children nodes for this node. :type children: A list of :py::class::`psyclone.psyGen.Node` \ or derived classes. :param parent: The parent of this node. :type parent: A :py::class::`psyclone.psyGen.Node`. ''' Node.__init__(self, children=children, parent=parent) # Store the name of the profile variable that is used for this # profile name. This allows to show the variable name in __str__ # (and also if we would call create_name in gen(), the name would # change every time gen() is called). self._var_name = NameSpaceFactory().create().create_name("profile") # Name of the region. In general at constructor time we might not # have a parent subroutine or a child for the kernel, so we leave # the name empty for now. The region and module names are set the # first time gen() is called (and then remain unchanged). self._region_name = None self._module_name = None
def test_psyirvisitor_visit_attribute_error(): '''Check that an Attribute Error is raised if the method for the Node class does exist and the method itself raises an Attribute Error. This is checked because AttributeError is used to catch a method not existing. Therefore an AttributeError raised by a method that does exist could be mistaken as meaning that the method does not exist. ''' class MyPSyIRVisitor(PSyIRVisitor): '''Subclass PSyIRVisitor to make the node method exist but it itself raises an attribute error.''' def node_node(self, _): ''' Raise an AttributeError for testing purposes ''' raise AttributeError("Error") visitor = MyPSyIRVisitor() with pytest.raises(AttributeError) as excinfo: _ = visitor(Node()) assert str(excinfo.value) == "Error"
def test_variable_access_info_read_write(): '''Test the handling of READWRITE accesses. A READWRITE indicates both a read and a write access, but if a variable as a READ and a WRITE access, this is not one READWRITE access. A READWRITE access is only used in subroutine calls (depending on kernel metadata) ''' vai = VariableAccessInfo("var_name") assert vai.has_read_write() is False # Add a READ and WRITE access at the same location, and make sure it # is not reported as READWRITE access node = Node() vai.add_access(AccessType.READ, 2, node) assert vai[0].node == node assert vai[0].location == 2 vai.add_access(AccessType.WRITE, 2, Node()) assert vai.has_read_write() is False vai.add_access(AccessType.READWRITE, 2, Node()) assert vai.has_read_write() # Create a new instance, and add only one READWRITE access: vai = VariableAccessInfo("var_name") vai.add_access(AccessType.READWRITE, 2, Node()) assert vai.has_read_write() assert vai.is_read() assert vai.is_written() vai_array = VariableAccessInfo("array") vai_array.add_access(AccessType.READ, 2, Node(), [1]) vai_array.add_access(AccessType.WRITE, 3, Node(), ["i"]) assert vai_array.is_array() # Adding a non-array access marks this as not array: # TODO #500: once we have a symboltable, this test # needs to be adjusted. vai_array.add_access(AccessType.WRITE, 3, Node()) assert not vai_array.is_array()
def test_cw_assignment_and_reference(): '''Check the CWriter class assignment and reference methods generate the appropriate output. Also check that a reference visit raises an exception if it has children as this is not expected. ''' assignment = Assignment() assignment.addchild(Reference('a', parent=assignment)) assignment.addchild(Reference('b', parent=assignment)) # Generate C from the PSyIR schedule cwriter = CWriter() result = cwriter(assignment) assert result == "a = b;\n" # Now add a child to the reference node assignment.lhs.addchild(Node(parent=assignment)) # Generate C from the PSyIR schedule with pytest.raises(VisitorError) as excinfo: result = cwriter(assignment) assert "Expecting a Reference with no children but found: " \ in str(excinfo)