def test_fusetrans_error_not_same_parent():
    ''' Check that we reject attempts to fuse loops which don't share the
    same parent '''
    from psyclone.transformations import LoopFuseTrans

    sch1 = Schedule()
    sch2 = Schedule()
    loop1 = Loop(variable=DataSymbol("i", INTEGER_TYPE), parent=sch1)
    loop2 = Loop(variable=DataSymbol("j", INTEGER_TYPE), parent=sch2)
    sch1.addchild(loop1)
    sch2.addchild(loop2)

    loop1.addchild(Literal("1", INTEGER_TYPE, parent=loop1))  # start
    loop1.addchild(Literal("10", INTEGER_TYPE, parent=loop1))  # stop
    loop1.addchild(Literal("1", INTEGER_TYPE, parent=loop1))  # step
    loop1.addchild(Schedule(parent=loop1))  # loop body

    loop2.addchild(Literal("1", INTEGER_TYPE, parent=loop2))  # start
    loop2.addchild(Literal("10", INTEGER_TYPE, parent=loop2))  # stop
    loop2.addchild(Literal("1", INTEGER_TYPE, parent=loop2))  # step
    loop2.addchild(Schedule(parent=loop2))  # loop body

    fuse = LoopFuseTrans()

    # Try to fuse loops with different parents
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert ("Error in LoopFuseTrans transformation. Loops do not have the "
            "same parent" in str(err.value))
def test_loop_fuse_trans():
    ''' test of the loop-fuse transformation '''
    _, info = parse(os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 "test_files", "gunghoproto",
                                 "3_two_functions_shared_arguments.f90"),
                    api="gunghoproto")
    psy = PSyFactory("gunghoproto").create(info)
    invoke = psy.invokes.get("invoke_0")
    schedule = invoke.schedule
    loop1 = schedule.children[0]
    loop2 = schedule.children[1]
    trans = LoopFuseTrans()
    schedule, _ = trans.apply(loop1, loop2)
    gen = str(psy.gen)
    for idx, line in enumerate(gen.split('\n')):
        if line.find("DO column=1,topology") != -1:
            do_idx = idx
        if line.find("CALL testkern1_code(") != -1:
            call1_idx = idx
        if line.find("CALL testkern2_code(") != -1:
            call2_idx = idx
        if line.find("END DO") != -1:
            enddo_idx = idx
    # 4 lines should be in sequence as calls have been fused into one loop
    assert enddo_idx-call2_idx == 1 and\
        call2_idx-call1_idx == 1 and\
        call1_idx-do_idx == 1
Exemple #3
0
def test_script_trans():
    ''' checks that generator.py works correctly when a
        transformation is provided as a script, i.e. it applies the
        transformations correctly. We use loop fusion as an
        example.'''
    from psyclone.parse import parse
    from psyclone.psyGen import PSyFactory
    from psyclone.transformations import LoopFuseTrans
    root_path = os.path.dirname(os.path.abspath(__file__))
    base_path = os.path.join(root_path, "test_files", "dynamo0p3")
    # first loop fuse explicitly (without using generator.py)
    parse_file = os.path.join(base_path, "4_multikernel_invokes.f90")
    _, invoke_info = parse(parse_file, api="dynamo0.3")
    psy = PSyFactory("dynamo0.3").create(invoke_info)
    invoke = psy.invokes.get("invoke_0")
    schedule = invoke.schedule
    loop1 = schedule.children[3]
    loop2 = schedule.children[4]
    trans = LoopFuseTrans()
    schedule.view()
    schedule, _ = trans.apply(loop1, loop2)
    invoke.schedule = schedule
    generated_code_1 = psy.gen
    schedule.view()
    # second loop fuse using generator.py and a script
    _, generated_code_2 = generate(parse_file,
                                   api="dynamo0.3",
                                   script_name=os.path.join(
                                       base_path, "loop_fuse_trans.py"))
    # remove module so we do not affect any following tests
    delete_module("loop_fuse_trans")
    # third - check that the results are the same ...
    assert str(generated_code_1) == str(generated_code_2)
def trans(psy):
    ''' a test loop fusion transformation for use with the transformation
    unit tests '''
    from psyclone.transformations import LoopFuseTrans
    invoke = psy.invokes.get("invoke_0")
    schedule = invoke.schedule
    loop1 = schedule.children[3]
    loop2 = schedule.children[4]
    transform = LoopFuseTrans()
    schedule, _ = transform.apply(loop1, loop2)
    invoke.schedule = schedule
    return psy
def test_loop_fuse_non_adjacent_nodes():
    ''' Test that an appropriate error is raised when we attempt to
    fuse two loops that are not adjacent to one another in the
    schedule '''
    _, invoke = get_invoke("openmp_fuse_test.f90", API, name="invoke_0")
    schedule = invoke.schedule
    lftrans = LoopFuseTrans()

    # Attempt to fuse two loops that are not adjacent to one another
    # in the schedule
    with pytest.raises(TransformationError):
        _, _ = lftrans.apply(schedule.children[0],
                             schedule.children[2])
def test_loop_fuse_on_non_siblings():
    ''' Test that an appropriate error is raised when we attempt to
    fuse two loops that do not share the same parent node in
    the schedule '''
    _, invoke = get_invoke("openmp_fuse_test.f90", API, name="invoke_0")
    schedule = invoke.schedule
    lftrans = LoopFuseTrans()

    # Attempt to fuse an outer loop with an inner loop
    with pytest.raises(TransformationError):
        _, _ = lftrans.apply(schedule.children[0],
                             schedule.children[1].
                             children[0])
Exemple #7
0
def test_loop_trans_name():
    ''' Check that the name method works as expected. '''
    # We have to use sub-classes of LoopTrans as it itself is abstract.
    trans1 = OMPParallelLoopTrans()
    assert trans1.name == "OMPParallelLoopTrans"
    trans2 = LoopFuseTrans()
    assert trans2.name == "LoopFuseTrans"
Exemple #8
0
def test_loop_fuse_non_adjacent_nodes():
    ''' Test that an appropriate error is raised when we attempt to
    fuse two loops that are not adjacent to one another in the
    schedule '''
    _, info = parse(os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 "test_files", "gocean0p1",
                                 "openmp_fuse_test.f90"),
                    api=API)
    psy = PSyFactory(API).create(info)
    invoke = psy.invokes.get('invoke_0')
    schedule = invoke.schedule
    lftrans = LoopFuseTrans()

    # Attempt to fuse two loops that are not adjacent to one another
    # in the schedule
    with pytest.raises(TransformationError):
        _, _ = lftrans.apply(schedule.children[0], schedule.children[2])
def test_loop_fuse_different_iterates_over():
    ''' Test that an appropriate error is raised when we attempt to
    fuse two loops that have differing values of ITERATES_OVER '''
    _, invoke = get_invoke("test11_different_iterates_over_"
                           "one_invoke.f90", 0)
    schedule = invoke.schedule
    lftrans = LoopFuseTrans()
    cbtrans = GOConstLoopBoundsTrans()

    # Attempt to fuse two loops that are iterating over different
    # things
    with pytest.raises(TransformationError):
        _, _ = lftrans.apply(schedule.children[0], schedule.children[1])

    # Turn off constant loop bounds (which should have no effect)
    # and repeat
    newsched, _ = cbtrans.apply(schedule, const_bounds=False)
    with pytest.raises(TransformationError):
        _, _ = lftrans.apply(newsched.children[0], newsched.children[1])
def test_loop_fuse_with_not_a_loop():
    ''' Test that an appropriate error is raised by the LoopFuseTrans
    base class wen we attempt to fuse a loop with something that
    is not a loop '''
    _, invoke = get_invoke("openmp_fuse_test.f90", API, name="invoke_0")
    schedule = invoke.schedule
    # Use the bare LoopFuseTrans in order tests its error checking
    lftrans = LoopFuseTrans()
    ompf = GOceanOMPParallelLoopTrans()
    # Enclose the first loop within an OMP parallel do
    new_sched, _ = ompf.apply(schedule.children[0])
    # Attempt to (erroneously) fuse this OMP parallel do
    # with the next loop in the schedule
    with pytest.raises(TransformationError) as ex:
        schedule, _ = lftrans.apply(new_sched.children[0],
                                    new_sched.children[1])
    # Exercise the __str__ method of TransformationError
    assert ("Target of LoopFuseTrans transformation must be a sub-class of "
            "Loop but got 'OMPParallelDoDirective'" in str(ex.value))
Exemple #11
0
def test_loop_fuse_with_not_a_loop():
    ''' Test that an appropriate error is raised by the LoopFuseTrans
    base class wen we attempt to fuse a loop with something that
    is not a loop '''
    _, info = parse(os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 "test_files", "gocean0p1",
                                 "openmp_fuse_test.f90"),
                    api=API)
    psy = PSyFactory(API).create(info)
    invoke = psy.invokes.get('invoke_0')
    schedule = invoke.schedule
    # Use the bare LoopFuseTrans in order tests its error checking
    lftrans = LoopFuseTrans()
    ompf = GOceanOMPParallelLoopTrans()
    # Enclose the first loop within an OMP parallel do
    new_sched, _ = ompf.apply(schedule.children[0])
    # Attempt to (erroneously) fuse this OMP parallel do
    # with the next loop in the schedule
    with pytest.raises(TransformationError) as ex:
        schedule, _ = lftrans.apply(new_sched.children[0],
                                    new_sched.children[1])
    # Exercise the __str__ method of TransformationError
    assert "Transformation" in str(ex)
def test_fusetrans_error_incomplete():
    ''' Check that we reject attempts to fuse loops which are incomplete. '''
    from psyclone.psyir.nodes import Return
    from psyclone.transformations import LoopFuseTrans
    sch = Schedule()
    loop1 = Loop(variable=DataSymbol("i", INTEGER_TYPE), parent=sch)
    loop2 = Loop(variable=DataSymbol("j", INTEGER_TYPE), parent=sch)
    sch.addchild(loop1)
    sch.addchild(loop2)

    fuse = LoopFuseTrans()

    # Check first loop
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert ("Error in LoopFuseTrans transformation. The target loop must have "
            "four children but found: []" in str(err.value))

    loop1.addchild(Literal("start", INTEGER_TYPE, parent=loop1))
    loop1.addchild(Literal("stop", INTEGER_TYPE, parent=loop1))
    loop1.addchild(Literal("step", INTEGER_TYPE, parent=loop1))
    loop1.addchild(Schedule(parent=loop1))
    loop1.loop_body.addchild(Return(parent=loop1.loop_body))

    # Check second loop
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert ("Error in LoopFuseTrans transformation. The target loop must have "
            "four children but found: []" in str(err.value))

    loop2.addchild(Literal("start", INTEGER_TYPE, parent=loop2))
    loop2.addchild(Literal("stop", INTEGER_TYPE, parent=loop2))
    loop2.addchild(Literal("step", INTEGER_TYPE, parent=loop2))
    loop2.addchild(Schedule(parent=loop2))
    loop2.loop_body.addchild(Return(parent=loop2.loop_body))

    # Validation should now pass
    fuse.validate(loop1, loop2)
def test_fusetrans_error_incomplete():
    ''' Check that we reject attempts to fuse loops which are incomplete. '''
    from psyclone.psyGen import Loop, Schedule, Literal, Return
    from psyclone.transformations import LoopFuseTrans, TransformationError
    sch = Schedule()
    loop1 = Loop(variable_name="i", parent=sch)
    loop2 = Loop(variable_name="j", parent=sch)
    sch.addchild(loop1)
    sch.addchild(loop2)

    fuse = LoopFuseTrans()

    # Check first loop
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert "Error in LoopFuse transformation. The first loop does not have " \
        "4 children." in str(err.value)

    loop1.addchild(Literal("start", parent=loop1))
    loop1.addchild(Literal("stop", parent=loop1))
    loop1.addchild(Literal("step", parent=loop1))
    loop1.addchild(Schedule(parent=loop1))
    loop1.loop_body.addchild(Return(parent=loop1.loop_body))

    # Check second loop
    with pytest.raises(TransformationError) as err:
        fuse.validate(loop1, loop2)
    assert "Error in LoopFuse transformation. The second loop does not have " \
        "4 children." in str(err.value)

    loop2.addchild(Literal("start", parent=loop2))
    loop2.addchild(Literal("stop", parent=loop2))
    loop2.addchild(Literal("step", parent=loop2))
    loop2.addchild(Schedule(parent=loop2))
    loop2.loop_body.addchild(Return(parent=loop2.loop_body))

    # Validation should now pass
    fuse.validate(loop1, loop2)