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 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
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 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])
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_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))
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)