示例#1
0
def test_omp_do_within_if():
    ''' Check that we can insert an OpenMP parallel do within an if block. '''
    from psyclone.transformations import OMPParallelLoopTrans
    otrans = OMPParallelLoopTrans()
    _, invoke_info = parse(os.path.join(BASE_PATH, "imperfect_nest.f90"),
                           api=API,
                           line_length=False)
    psy = PSyFactory(API, distributed_memory=False).create(invoke_info)
    schedule = psy.invokes.get('imperfect_nest').schedule
    loop = schedule[0].loop_body[1].else_body[0].else_body[0]
    assert isinstance(loop, nemo.NemoLoop)
    # Apply the transformation to a loop within an else clause
    schedule, _ = otrans.apply(loop)
    gen = str(psy.gen)
    expected = ("    ELSE\n"
                "      !$omp parallel do default(shared), private(ji,jj), "
                "schedule(static)\n"
                "      DO jj = 1, jpj, 1\n"
                "        DO ji = 1, jpi, 1\n"
                "          zdkt(ji, jj) = (ptb(ji, jj, jk - 1, jn) - "
                "ptb(ji, jj, jk, jn)) * wmask(ji, jj, jk)\n"
                "        END DO\n"
                "      END DO\n"
                "      !$omp end parallel do\n"
                "    END IF\n")
    assert expected in gen
示例#2
0
def test_omp_do_children_err():
    ''' Tests that we raise the expected error when an OpenMP parallel do
    directive has more than one child. '''
    from psyclone.transformations import OMPParallelLoopTrans
    from psyclone.psyGen import OMPParallelDoDirective
    otrans = OMPParallelLoopTrans()
    psy, invoke_info = get_invoke("imperfect_nest.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    otrans.apply(schedule[0].loop_body[2])
    directive = schedule[0].loop_body[2]
    assert isinstance(directive, OMPParallelDoDirective)
    # Make the schedule invalid by adding a second child to the
    # OMPParallelDoDirective
    directive.dir_body.children.append(Statement())
    with pytest.raises(GenerationError) as err:
        _ = psy.gen
    assert ("An OpenMP PARALLEL DO can only be applied to a single loop but "
            "this Node has 2 children:" in str(err.value))
示例#3
0
def test_omp_do_within_if():
    ''' Check that we can insert an OpenMP parallel do within an if block. '''
    from psyclone.transformations import OMPParallelLoopTrans
    otrans = OMPParallelLoopTrans()
    psy, invoke_info = get_invoke("imperfect_nest.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    loop = schedule[0].loop_body[1].else_body[0].else_body[0]
    assert isinstance(loop, nemo.NemoLoop)
    # Apply the transformation to a loop within an else clause
    otrans.apply(loop)
    gen = str(psy.gen).lower()
    expected = ("    else\n"
                "      !$omp parallel do default(shared), private(ji,jj), "
                "schedule(static)\n"
                "      do jj = 1, jpj, 1\n"
                "        do ji = 1, jpi, 1\n"
                "          zdkt(ji, jj) = (ptb(ji, jj, jk - 1, jn) - "
                "ptb(ji, jj, jk, jn)) * wmask(ji, jj, jk)\n"
                "        end do\n"
                "      end do\n"
                "      !$omp end parallel do\n"
                "    end if\n")
    assert expected in gen
示例#4
0
def test_profile_nemo_openmp(parser):
    ''' Check that the automatic kernel-level profiling handles a
    tightly-nested loop that has been parallelised using OpenMP. '''
    omptrans = OMPParallelLoopTrans()
    Profiler.set_options([Profiler.KERNELS])
    psy, schedule = get_nemo_schedule(
        parser, "program do_loop\n"
        "integer, parameter :: jpi=5, jpj=5\n"
        "integer :: ji, jj\n"
        "real :: sto_tmp(jpi,jpj)\n"
        "do jj = 1, jpj\n"
        "  do ji = 1,jpi\n"
        "    sto_tmp(ji,jj) = 1.0d0\n"
        "  end do\n"
        "end do\n"
        "end program do_loop\n")
    omptrans.apply(schedule[0])
    Profiler.add_profile_nodes(schedule, Loop)
    code = str(psy.gen).lower()
    assert ("  type(profile_psydatatype), target, save :: profile_psy_data0\n"
            "  call profile_psy_data0 % prestart('do_loop', 'r0', 0, 0)\n"
            "  !$omp parallel do default(shared), private(ji,jj), "
            "schedule(static)\n"
            "  do jj = 1, jpj" in code)
示例#5
0
def test_omp_do_missing_parent(monkeypatch):
    ''' Check that we raise the expected error when we cannot find the
    parent node in the fparser2 AST. '''
    from psyclone.transformations import OMPParallelLoopTrans
    otrans = OMPParallelLoopTrans()
    _, invoke_info = parse(os.path.join(BASE_PATH, "imperfect_nest.f90"),
                           api=API, line_length=False)
    psy = PSyFactory(API, distributed_memory=False).create(invoke_info)
    schedule = psy.invokes.get('imperfect_nest').schedule
    schedule, _ = otrans.apply(schedule.children[0])
    # Remove the reference to the fparser2 AST from the Schedule node
    monkeypatch.setattr(schedule, "_ast", None)
    with pytest.raises(InternalError) as err:
        _ = psy.gen
    assert ("Failed to find parent node in which to insert OpenMP parallel "
            "do directive" in str(err))
示例#6
0
def test_omp_do_children_err():
    ''' Tests that we raise the expected error when an OpenMP parallel do
    directive has more than one child. '''
    from psyclone.transformations import OMPParallelLoopTrans
    from psyclone.psyGen import OMPParallelDoDirective
    otrans = OMPParallelLoopTrans()
    _, invoke_info = parse(os.path.join(BASE_PATH, "imperfect_nest.f90"),
                           api=API, line_length=False)
    psy = PSyFactory(API, distributed_memory=False).create(invoke_info)
    schedule = psy.invokes.get('imperfect_nest').schedule
    new_sched, _ = otrans.apply(schedule.children[0].children[2])
    directive = new_sched.children[0].children[2]
    assert isinstance(directive, OMPParallelDoDirective)
    # Make the schedule invalid by adding a second child to the
    # OMPParallelDoDirective
    directive.children.append(new_sched.children[0].children[3])
    with pytest.raises(GenerationError) as err:
        _ = psy.gen
    assert ("An OpenMP PARALLEL DO can only be applied to a single loop but "
            "this Node has 2 children:" in str(err))
示例#7
0
def test_invalid_apply():
    '''Test the exceptions that should be raised by ReadOnlyVerifyTrans.

    '''
    _, invoke = get_invoke("test11_different_iterates_over_one_invoke.f90",
                           "gocean1.0",
                           idx=0)
    read_only = ReadOnlyVerifyTrans()
    omp = OMPParallelLoopTrans()
    _, _ = omp.apply(invoke.schedule[0])
    with pytest.raises(TransformationError) as err:
        _, _ = read_only.apply(invoke.schedule[0].dir_body[0],
                               options={"region_name": ("a", "b")})
    assert "Error in ReadOnlyVerifyTrans: Application to a Loop without its "\
           "parent Directive is not allowed." in str(err.value)

    with pytest.raises(TransformationError) as err:
        _, _ = read_only.apply(invoke.schedule[0].dir_body[0].loop_body[0],
                               options={"region_name": ("a", "b")})
    assert "Error in ReadOnlyVerifyTrans: Application to Nodes enclosed " \
           "within a thread-parallel region is not allowed." in str(err.value)