Esempio n. 1
0
def test_class_definitions():
    '''Tests if the class-prefix can be set and behaves as expected.
    '''

    psy, invoke = get_invoke("test11_different_iterates_over_one_invoke.f90",
                             "gocean1.0",
                             idx=0)
    schedule = invoke.schedule

    data_trans = PSyDataTrans()
    data_trans.apply(schedule)
    code = str(psy.gen)

    # By default, no prefix should be used:
    assert "USE psy_data_mod, ONLY: PSyDataType" in code
    assert "TYPE(PSyDataType), target, save :: psy_data" in code
    assert "CALL psy_data" in code

    # This puts the new PSyDataNode with prefix "extract" around the
    # previous PSyDataNode, but the prefix was not used previously.
    data_trans.apply(schedule, {"prefix": "extract"})
    code = str(psy.gen)
    assert "USE extract_psy_data_mod, ONLY: extract_PSyDataType" in code
    assert "TYPE(extract_PSyDataType), target, save :: extract_psy_data" \
        in code
    assert "CALL extract_psy_data" in code
    # The old call must still be there (e.g. not somehow be changed
    # by setting the prefix)
    assert "USE psy_data_mod, ONLY: PSyDataType" in code
    assert "TYPE(PSyDataType), target, save :: psy_data" in code
    assert "CALL psy_data" in code

    # Now add a third class: "profile", and make sure all previous
    # and new declarations and calls are there:
    data_trans.apply(schedule, {"prefix": "profile"})
    code = str(psy.gen)
    assert "USE psy_data_mod, ONLY: PSyDataType" in code
    assert "USE extract_psy_data_mod, ONLY: extract_PSyDataType" in code
    assert "USE profile_psy_data_mod, ONLY: profile_PSyDataType" in code

    assert "TYPE(PSyDataType), target, save :: psy_data" in code
    assert "TYPE(extract_PSyDataType), target, save :: extract_psy_data" \
        in code
    assert "TYPE(profile_PSyDataType), target, save :: profile_psy_data" \
        in code

    assert "CALL psy_data" in code
    assert "CALL extract_psy_data" in code
    assert "CALL profile_psy_data" in code

    with pytest.raises(TransformationError) as err:
        data_trans.apply(schedule, {"prefix": "invalid-prefix"})
    assert "Error in 'prefix' parameter: found 'invalid-prefix', expected " \
        "one of " in str(err.value)
    assert "as defined in /" in str(err.value)
Esempio n. 2
0
def test_psy_data_node_incorrect_container():
    ''' Check that the PSyDataNode constructor raises the expected error if
    the symbol table already contains an entry for the PSyDataType that is
    not associated with the PSyData container. '''
    _, invoke = get_invoke("test11_different_iterates_over_one_invoke.f90",
                           "gocean1.0",
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule
    csym = schedule.symbol_table.new_symbol("some_mod",
                                            symbol_type=ContainerSymbol)
    schedule.symbol_table.new_symbol("PSyDataType",
                                     interface=GlobalInterface(csym))
    data_trans = PSyDataTrans()
    with pytest.raises(TransformationError) as err:
        data_trans.apply(schedule[0].loop_body)
    assert ("already a symbol named 'PSyDataType' which clashes with one of "
            "those used by the PSyclone PSyData API" in str(err.value))
Esempio n. 3
0
def test_psy_data_node_invokes_gocean1p0():
    '''Check that an invoke is instrumented correctly
    '''
    _, invoke = get_invoke("test11_different_iterates_over_one_invoke.f90",
                           "gocean1.0",
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule
    data_trans = PSyDataTrans()

    data_trans.apply(schedule[0])

    # Convert the invoke to code, and remove all new lines, to make
    # regex matching easier
    code = str(invoke.gen()).replace("\n", "")
    # First a simple test that the nesting is correct - the
    # PSyData regions include both loops. Note that indeed
    # the function 'compute_cv_code' is in the module file
    # kernel_ne_offset_mod.
    # Since this is only PSyData, which by default does not supply
    # variable information, the parameters to PreStart are both 0.
    correct_re = ("subroutine invoke.*"
                  "use psy_data_mod, only: PSyDataType.*"
                  r"TYPE\(PSyDataType\), target, save :: psy_data.*"
                  r"call psy_data%PreStart\(\"psy_single_invoke_different"
                  r"_iterates_over\", \"invoke_0:compute_cv_code:r0\","
                  r" 0, 0\).*"
                  "do j.*"
                  "do i.*"
                  "call.*"
                  "end.*"
                  "end.*"
                  r"call psy_data%PostEnd")

    assert re.search(correct_re, code, re.I) is not None

    # Check that if gen() is called more than once the same PSyDataNode
    # variables and region names are created:
    code_again = str(invoke.gen()).replace("\n", "")
    assert code == code_again
Esempio n. 4
0
def test_psy_data_trans_basic(capsys):
    '''Check basic functionality: node names, schedule view.
    '''
    _, invoke = get_invoke("test11_different_iterates_over_one_invoke.f90",
                           "gocean1.0",
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule
    # This test expects constant loop bounds
    schedule._const_loop_bounds = True

    data_trans = PSyDataTrans()
    assert "Create a sub-tree of the PSyIR that has a node of type " \
           "PSyDataNode at its root" in str(data_trans)

    assert data_trans.name == "PSyDataTrans"
    data_trans.apply(schedule)

    assert isinstance(invoke.schedule[0], PSyDataNode)

    schedule.view()
    out, _ = capsys.readouterr()

    gsched = colored("GOInvokeSchedule", GOInvokeSchedule._colour)
    sched = colored("Schedule", Schedule._colour)
    loop = Loop().coloured_name(True)
    data = invoke.schedule[0].coloured_name(True)

    # Do one test based on schedule view, to make sure colouring
    # and indentation is correct
    expected = (gsched + "[invoke='invoke_0', Constant loop bounds=True]\n"
                "    0: " + data + "[]\n"
                "        " + sched + "[]\n"
                "            0: " + loop +
                "[type='outer', field_space='go_cv', "
                "it_space='go_internal_pts']\n")
    assert expected in out

    # Insert a DataTrans call between outer and inner loop.
    # This tests that we find the subroutine node even
    # if it is not the immediate parent.
    data_trans.apply(invoke.schedule[0].psy_data_body[0].loop_body[0])

    new_sched_str = str(invoke.schedule)
    correct = ("""GOInvokeSchedule[invoke='invoke_0', \
Constant loop bounds=True]:
PSyDataStart[var=psy_data]
GOLoop[id:'', variable:'j', loop_type:'outer']
Literal[value:'2', Scalar<INTEGER, UNDEFINED>]
Literal[value:'jstop-1', Scalar<INTEGER, UNDEFINED>]
Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
Schedule:
PSyDataStart[var=psy_data_1]
GOLoop[id:'', variable:'i', loop_type:'inner']
Literal[value:'2', Scalar<INTEGER, UNDEFINED>]
Literal[value:'istop', Scalar<INTEGER, UNDEFINED>]
Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
Schedule:
kern call: compute_cv_code
End Schedule
End GOLoop
PSyDataEnd[var=psy_data_1]
End Schedule
End GOLoop
GOLoop[id:'', variable:'j', loop_type:'outer']
Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
Literal[value:'jstop+1', Scalar<INTEGER, UNDEFINED>]
Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
Schedule:
GOLoop[id:'', variable:'i', loop_type:'inner']
Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
Literal[value:'istop+1', Scalar<INTEGER, UNDEFINED>]
Literal[value:'1', Scalar<INTEGER, UNDEFINED>]
Schedule:
kern call: bc_ssh_code
End Schedule
End GOLoop
End Schedule
End GOLoop
PSyDataEnd[var=psy_data]
End Schedule""")

    assert correct in new_sched_str
Esempio n. 5
0
def test_psy_data_trans_empty_list():
    ''' Check that the transformation rejects an empty list of nodes. '''
    data_trans = PSyDataTrans()
    with pytest.raises(TransformationError) as err:
        data_trans.apply([])
    assert "Cannot apply transformation to an empty list" in str(err.value)
Esempio n. 6
0
def test_psy_data_node_options():
    '''Check that the options for PSyData work as expected.
    '''
    _, invoke = get_invoke("test11_different_iterates_over_one_invoke.f90",
                           "gocean1.0",
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule
    data_trans = PSyDataTrans()

    data_trans.apply(schedule[0].loop_body)
    data_node = schedule[0].loop_body[0]
    assert isinstance(data_node, PSyDataNode)

    from psyclone.f2pygen import ModuleGen
    # 1) Test that the listed variables will appear in the list
    # ---------------------------------------------------------
    mod = ModuleGen(None, "test")
    data_node.gen_code(mod,
                       options={
                           "pre_var_list": ["a"],
                           "post_var_list": ["b"]
                       })

    out = "\n".join([str(i.root) for i in mod.children])
    expected = [
        'CALL psy_data%PreDeclareVariable("a", a)',
        'CALL psy_data%PreDeclareVariable("b", b)',
        'CALL psy_data%ProvideVariable("a", a)', 'CALL psy_data%PostStart',
        'CALL psy_data%ProvideVariable("b", b)'
    ]
    for line in expected:
        assert line in out

    # 2) Test that variables suffixes are added as expected
    # -----------------------------------------------------
    mod = ModuleGen(None, "test")
    data_node.gen_code(mod,
                       options={
                           "pre_var_list": ["a"],
                           "post_var_list": ["b"],
                           "pre_var_postfix": "_pre",
                           "post_var_postfix": "_post"
                       })

    out = "\n".join([str(i.root) for i in mod.children])
    expected = [
        'CALL psy_data%PreDeclareVariable("a_pre", a)',
        'CALL psy_data%PreDeclareVariable("b_post", b)',
        'CALL psy_data%ProvideVariable("a_pre", a)', 'CALL psy_data%PostStart',
        'CALL psy_data%ProvideVariable("b_post", b)'
    ]
    for line in expected:
        assert line in out

    # 3) Check that we don't get any declaration if there are no variables:
    # ---------------------------------------------------------------------
    mod = ModuleGen(None, "test")
    data_node.gen_code(mod, options={})

    out = "\n".join([str(i.root) for i in mod.children])
    # Only PreStart and PostEnd should appear
    assert "PreStart" in out
    assert "PreDeclareVariable" not in out
    assert "ProvideVariable" not in out
    assert "PreEnd" not in out
    assert "PostStart" not in out
    assert "PostEnd" in out