예제 #1
0
def test_replicated_loop(parser, tmpdir):
    '''Check code generation with two loops that have the same
    structure.

    '''
    reader = FortranStringReader("subroutine replicate()\n"
                                 "   INTEGER :: dummy\n"
                                 "   REAL :: zwx(10,10)\n"
                                 "   zwx(:,:) = 0.e0\n"
                                 "   zwx(:,:) = 0.e0\n"
                                 "END subroutine replicate\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.get('replicate').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children[0:1])
    acc_trans.apply(schedule.children[1:2])
    gen_code = str(psy.gen)

    assert ("  !$ACC DATA COPYOUT(zwx)\n"
            "  zwx(:, :) = 0.E0\n"
            "  !$ACC END DATA\n"
            "  !$ACC DATA COPYOUT(zwx)\n"
            "  zwx(:, :) = 0.E0\n"
            "  !$ACC END DATA" in gen_code)
    assert Compile(tmpdir).string_compiles(gen_code)
예제 #2
0
def test_kernels_in_data_region(parser):
    ''' Check that directives end up in the correct locations when enclosing
    a kernels region inside a data region. '''
    reader = FortranStringReader("program one_loop\n"
                                 "integer :: ji, jpj\n"
                                 "real(kind=wp) :: sto_tmp(5)\n"
                                 "do ji = 1,jpj\n"
                                 "  sto_tmp(ji) = 0.0\n"
                                 "end do\n"
                                 "end program one_loop\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_dtrans = TransInfo().get_trans_name('ACCDataTrans')
    acc_ktrans = TransInfo().get_trans_name('ACCKernelsTrans')
    schedule, _ = acc_ktrans.apply(schedule.children[:],
                                   {"default_present": True})
    schedule, _ = acc_dtrans.apply(schedule.children[:])
    new_code = str(psy.gen)
    assert ("  !$ACC DATA COPYOUT(sto_tmp)\n"
            "  !$ACC KERNELS DEFAULT(PRESENT)\n"
            "  DO ji = 1, jpj\n" in new_code)
    assert ("  END DO\n"
            "  !$ACC END KERNELS\n"
            "  !$ACC END DATA\n"
            "END PROGRAM one_loop" in new_code)
예제 #3
0
def test_no_code_blocks(parser):
    ''' Check that we refuse to include CodeBlocks (i.e. code that we
    don't recognise) within a data region. '''
    reader = FortranStringReader("program write_out\n"
                                 " integer :: ji, jpj\n"
                                 "real(kind=wp) :: sto_tmp(5)\n"
                                 "do ji = 1,jpj\n"
                                 "read(*,*) sto_tmp(ji)\n"
                                 "end do\n"
                                 "do ji = 1,jpj\n"
                                 "write(*,*) sto_tmp(ji)\n"
                                 "end do\n"
                                 "end program write_out\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    with pytest.raises(TransformationError) as err:
        _, _ = acc_trans.apply(schedule.children[0:1])
    assert ("'CodeBlock' cannot be enclosed by a ACCDataTrans"
            in str(err.value))
    with pytest.raises(TransformationError) as err:
        _, _ = acc_trans.apply(schedule.children[1:2])
    assert ("'CodeBlock' cannot be enclosed by a ACCDataTrans"
            in str(err.value))
예제 #4
0
def test_parallel_if_block(parser):
    ''' Check that we can enclose an IF-block within a parallel region. '''
    reader = FortranStringReader("program do_loop\n"
                                 "integer :: ji\n"
                                 "integer, parameter :: jpi=64\n"
                                 "logical :: init\n"
                                 "real :: sto_tmp(jpi), sto_tmp2(jpi)\n"
                                 "if(init)then\n"
                                 "  do ji = 1,jpi\n"
                                 "    sto_tmp(ji) = 1.0d0\n"
                                 "  end do\n"
                                 "else\n"
                                 "  do ji = 1,jpi\n"
                                 "    sto_tmp2(ji) = 1.0d0\n"
                                 "  end do\n"
                                 "end if\n"
                                 "end program do_loop\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    data_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans = TransInfo().get_trans_name('ACCParallelTrans')
    acc_trans.apply(schedule[0:1])
    data_trans.apply(schedule[0])
    code = str(psy.gen)
    assert ("  !$ACC DATA COPYOUT(sto_tmp,sto_tmp2)\n"
            "  !$ACC PARALLEL DEFAULT(PRESENT)\n"
            "  IF (init) THEN\n"
            "    DO ji = 1, jpi\n" in code)
    assert ("    END DO\n"
            "  END IF\n"
            "  !$ACC END PARALLEL\n"
            "  !$ACC END DATA\n" in code)
예제 #5
0
def test_omp_private_declaration():
    ''' Check code generation and private/shared declaration when
    an assignment is parallelised. In this case the code is like:
    !$omp parallel default(shared), private()
    jpk = 100
    do k=1, jpk ...
    enddo
    !$omp end parallel
    do k=1, jpk ...

    In this case jpk should not be declared private, since then it
    is not defined in the next loop.'''

    psy, invoke_info = get_invoke("explicit_do_two_loops.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    omp_parallel = TransInfo().get_trans_name('OMPParallelTrans')

    # Apply "omp parallel" around one assignment to a scalar variable
    # and a loop using this variable as loop boundary. Parallelising an
    # assignment statement is not allowed by default, so we need to disable
    # the node type check in order to apply the omp parallel transform.
    omp_parallel.apply(schedule.children[0:2], {'node-type-check': False})
    expected = "!$omp parallel default(shared), private(ji,jj,jk)"

    gen_code = str(psy.gen).lower()
    assert expected in gen_code
예제 #6
0
def test_explicit_loop(parser):
    ''' Check that we can apply the transformation to an explicit loop. '''
    reader = FortranStringReader("program do_loop\n"
                                 "real :: sto_tmp(jpj), sto_tmp2(jpj)\n"
                                 "do ji = 1,jpj\n"
                                 "  sto_tmp(ji) = 1.0d0\n"
                                 "end do\n"
                                 "do ji = 1,jpj\n"
                                 "  sto_tmp2(ji) = 1.0d0\n"
                                 "end do\n"
                                 "end program do_loop\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCLoopTrans')
    schedule, _ = acc_trans.apply(schedule.children[0])
    schedule, _ = acc_trans.apply(schedule.children[1], independent=False)
    code = str(psy.gen)
    assert ("PROGRAM do_loop\n"
            "  REAL :: sto_tmp(jpj), sto_tmp2(jpj)\n"
            "  !$ACC LOOP INDEPENDENT\n"
            "  DO ji = 1, jpj\n"
            "    sto_tmp(ji) = 1.0D0\n"
            "  END DO\n"
            "  !$ACC LOOP\n"
            "  DO ji = 1, jpj\n"
            "    sto_tmp2(ji) = 1.0D0\n"
            "  END DO\n"
            "END PROGRAM do_loop" in code)
예제 #7
0
def test_kernels_within_if(parser):
    ''' Check that we can put a kernels region within an if block. '''
    reader = FortranStringReader("program if_then\n"
                                 "if(do_this)then\n"
                                 "  do ji=1,jpi\n"
                                 "    fld(ji) = 1.0\n"
                                 "  end do\n"
                                 "else\n"
                                 "  fld2d(:,:) = 0.0\n"
                                 "end if\n"
                                 "end program if_then\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCKernelsTrans')

    schedule, _ = acc_trans.apply(schedule.children[0].if_body,
                                  default_present=True)
    schedule, _ = acc_trans.apply(schedule.children[0].else_body,
                                  default_present=True)
    new_code = str(psy.gen)
    assert ("  IF (do_this) THEN\n"
            "    !$ACC KERNELS DEFAULT(PRESENT)\n"
            "    DO ji = 1, jpi\n" in new_code)
    assert ("    END DO\n"
            "    !$ACC END KERNELS\n"
            "  ELSE\n"
            "    !$ACC KERNELS DEFAULT(PRESENT)\n"
            "    fld2d(:, :) = 0.0\n"
            "    !$ACC END KERNELS\n"
            "  END IF\n" in new_code)
예제 #8
0
def trans(psy):
    ''' Transform a specific Schedule by making all loops
    over levels OpenMP parallel.

    :param psy: the object holding all information on the PSy layer \
                to be modified.
    :type psy: :py:class:`psyclone.psyGen.PSy`

    :returns: the transformed PSy object
    :rtype:  :py:class:`psyclone.psyGen.PSy`

    '''
    from psyclone.psyGen import TransInfo
    from psyclone.nemo import NemoKern
    # Get the transformation we will apply
    ompt = TransInfo().get_trans_name('OMPParallelLoopTrans')
    for invoke in psy.invokes.invoke_list:
        # Get the Schedule of the target routine
        sched = invoke.schedule
        # Apply the OMP transformation to each loop over levels containing
        # a kernel
        for loop in sched.loops():
            kernels = loop.walk(NemoKern)
            if kernels and loop.loop_type == "levels":
                ompt.apply(loop)

    # Return the modified psy object
    return psy
예제 #9
0
def test_missed_array_case(parser):
    ''' Check that we raise the expected InternalError if our internal
    sanity check spots that we've missed an array access.
    TODO #309 - remove this test. '''
    code = ("program do_bound\n"
            "  integer :: ice_mask(8,8)\n"
            "  real(kind=wp) :: trim_width(8), zdta(8,8)\n"
            "  integer :: ji, jj, dom\n"
            "  do jj = 1, trim_width(dom)\n"
            "    do ji = 1, 8\n"
            "      select case(ice_mask(ji,jj))\n"
            "      case(0)\n"
            "        zdta(ji,jj) = 1.0\n"
            "      case(1)\n"
            "        zdta(ji,jj) = 0.0\n"
            "      end select\n"
            "    end do\n"
            "  end do\n"
            "end program do_bound\n")
    reader = FortranStringReader(code)
    ptree = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(ptree)
    schedule = psy.invokes.get('do_bound').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    # Put the second loop nest inside a data region
    acc_trans.apply(schedule.children)
    with pytest.raises(InternalError) as err:
        _ = str(psy.gen)
    assert ("ArrayReference 'ice_mask' present in source code ("
            "'ice_mask(ji, jj)') but not identified" in str(err.value))
예제 #10
0
def trans(psy):
    ''' Transform a specific Schedule by making all loops
    over levels OpenMP parallel.

    :param psy: the object holding all information on the PSy layer \
                to be modified.
    :type psy: :py:class:`psyclone.psyGen.PSy`

    :returns: the transformed PSy object
    :rtype:  :py:class:`psyclone.psyGen.PSy`

    '''
    from psyclone.psyGen import TransInfo
    from psyclone.nemo import NemoKern
    # Get the Schedule of the target routine
    sched = psy.invokes.get('tra_ldf_iso').schedule
    # Get the transformation we will apply
    ompt = TransInfo().get_trans_name('OMPParallelLoopTrans')
    # Apply it to each loop over levels containing a kernel
    for loop in sched.loops():
        # TODO loop.kernel method needs extending to cope with
        # multiple kernels
        kernels = loop.walk(NemoKern)
        if kernels and loop.loop_type == "levels":
            ompt.apply(loop)
    psy.invokes.get('tra_ldf_iso').schedule = sched
    # Return the modified psy object
    return psy
예제 #11
0
def test_parallel_single_loop(parser):
    ''' Check that we can apply the transformation to a single, explicit
    loop. '''
    reader = FortranStringReader(SINGLE_LOOP)
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    data_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans = TransInfo().get_trans_name('ACCParallelTrans')
    acc_trans.apply(schedule[0:1])
    data_trans.apply(schedule[0])
    code = str(psy.gen)

    assert ("PROGRAM do_loop\n"
            "  INTEGER :: ji\n"
            "  INTEGER, PARAMETER :: jpj = 128\n"
            "  REAL(KIND = wp) :: sto_tmp(jpj)\n"
            "  !$ACC DATA COPYOUT(sto_tmp)\n"
            "  !$ACC PARALLEL DEFAULT(PRESENT)\n"
            "  DO ji = 1, jpj\n"
            "    sto_tmp(ji) = 1.0D0\n"
            "  END DO\n"
            "  !$ACC END PARALLEL\n"
            "  !$ACC END DATA\n"
            "END PROGRAM do_loop" in code)
예제 #12
0
def test_omp_explicit_gen():
    ''' Check code generation for a single explicit loop containing
    a kernel. '''
    psy, invoke_info = get_invoke("explicit_do.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    omp_trans = TransInfo().get_trans_name('OMPParallelLoopTrans')

    for loop in schedule.loops():
        kernel = loop.kernel
        if kernel and loop.loop_type == "levels":
            omp_trans.apply(loop)
    gen_code = str(psy.gen).lower()

    expected = ("program explicit_do\n"
                "  implicit none\n"
                "  integer :: ji, jj, jk\n"
                "  integer, parameter :: jpi = 2, jpj = 4, jpk = 6\n"
                "  real :: r\n"
                "  real, dimension(jpi, jpj, jpk) :: umask\n"
                "  !$omp parallel do default(shared), private(ji,jj,jk), "
                "schedule(static)\n"
                "  do jk = 1, jpk\n"
                "    do jj = 1, jpj\n"
                "      do ji = 1, jpi\n"
                "        umask(ji, jj, jk) = ji * jj * jk / r\n"
                "      end do\n"
                "    end do\n"
                "  end do\n"
                "  !$omp end parallel do\n"
                "end program explicit_do")
    assert expected in gen_code
    # Check that calling gen a second time gives the same code
    gen_code = str(psy.gen).lower()
    assert expected in gen_code
예제 #13
0
def test_implicit_loop_sched2():
    ''' Check that we get the correct schedule when we transform an implicit
    loop over the i-j slab within an explicit loop levels. '''
    _, invoke_info = parse(os.path.join(BASE_PATH,
                                        "explicit_over_implicit.f90"),
                           api=API,
                           line_length=False)
    psy = PSyFactory(API).create(invoke_info)
    exp_trans = TransInfo().get_trans_name('NemoExplicitLoopTrans')
    sched = psy.invokes.invoke_list[0].schedule
    loop_levels = sched.children[0]
    _, _ = exp_trans.apply(loop_levels.children[0])
    # We should have 3 loops (one from the explicit loop over levels and
    # the other two from the implicit loops over ji and jj).
    loops = sched.walk(nemo.NemoLoop)
    assert len(loops) == 3
    assert loop_levels.children[0].loop_type == "lat"
    kerns = sched.kern_calls()
    assert not kerns
    _, _ = exp_trans.apply(loop_levels.children[0].children[0])
    gen_code = str(psy.gen)
    assert ("  INTEGER :: jj\n"
            "  INTEGER :: ji\n"
            "  DO jk = 1, jpk\n"
            "    DO jj = 1, jpj, 1\n"
            "      DO ji = 1, jpi, 1\n"
            "        umask(ji, jj, jk) = vmask(ji, jj, jk) + 1.0\n"
            "      END DO\n"
            "    END DO\n"
            "  END DO\n"
            "END PROGRAM explicit_over_implicit" in gen_code)
    # Check that we haven't got duplicate declarations of the loop vars
    assert gen_code.count("INTEGER :: ji") == 1
예제 #14
0
def test_array_section():
    '''Check code generation with a arrays accessed via an array section.

    '''
    psy, invoke_info = get_invoke("array_section.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children)
    gen_code = str(psy.gen)
    assert "!$ACC DATA COPYIN(b,c) COPYOUT(a)" in gen_code
예제 #15
0
def test_data_single_node(parser):
    ''' Check that the ACCDataTrans works if passed a single node rather
    than a list. '''
    reader = FortranStringReader(EXPLICIT_DO)
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.get('explicit_do').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule[0])
    assert isinstance(schedule[0], ACCDataDirective)
예제 #16
0
def test_data_no_gen_code():
    ''' Check that the ACCDataDirective.gen_code() method raises the
    expected InternalError as it should not be called. '''
    _, invoke_info = get_invoke("explicit_do.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children[0:2])
    with pytest.raises(InternalError) as err:
        schedule.children[0].gen_code(schedule)
    assert ("ACCDataDirective.gen_code should not have "
            "been called" in str(err.value))
예제 #17
0
def test_add_region_invalid_data_move():
    ''' Check that _add_region() raises the expected error if an invalid
    value for data_movement is supplied. '''
    _, invoke_info = get_invoke("explicit_do.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children)
    datadir = schedule.children[0]
    with pytest.raises(InternalError) as err:
        datadir._add_region("DATA", "END DATA", data_movement="invalid")
    assert ("optional data_movement argument must be one of ['present', "
            "'analyse'] but got 'invalid'" in str(err.value))
예제 #18
0
def test_data_view(parser, capsys):
    ''' Check that the ACCDataDirective.view() method works as expected. '''
    reader = FortranStringReader(EXPLICIT_DO)
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.get('explicit_do').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children)
    schedule.view()
    output, _ = capsys.readouterr()
    assert "[ACC DATA]" in output
    assert schedule.children[0].dag_name == "ACC_data_1"
예제 #19
0
def test_implicit_range_err(parser):
    ''' Check that we raise the expected error if we encounter an implicit
    loop with an explicit range (since we don't yet support that). '''
    exp_trans = TransInfo().get_trans_name('NemoExplicitLoopTrans')
    # Array syntax with an explicit range
    reader = FortranStringReader("program atest\n"
                                 "umask(1:jpi, 1, :) = 0.0D0\n"
                                 "end program atest\n")
    prog = parser(reader)
    psy = PSyFactory(API).create(prog)
    sched = psy.invokes.invoke_list[0].schedule
    with pytest.raises(NotImplementedError) as err:
        exp_trans.apply(sched.children[0])
    assert ("Support for implicit loops with specified bounds is not yet "
            "implemented: 'umask(1 : jpi, 1, :) = 0.0D0'" in str(err))
예제 #20
0
def test_add_region(parser):
    ''' Check that add_region works as expected. '''
    from fparser.two import Fortran2003
    reader = FortranStringReader(EXPLICIT_DO)
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.get('explicit_do').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children)
    datadir = schedule.children[0]
    datadir._add_region("data", "end data")
    assert isinstance(datadir._ast, Fortran2003.Comment)
    assert str(datadir._ast).lower() == "!$acc data"
    assert isinstance(datadir._ast_end, Fortran2003.Comment)
    assert str(datadir._ast_end).lower() == "!$acc end data"
예제 #21
0
def test_multikern_if(parser):
    ''' Check that we can include an if-block containing multiple
    loops within a kernels region. '''
    reader = FortranStringReader("program implicit_loop\n"
                                 "real(kind=wp) :: sto_tmp(5)\n"
                                 "if(do_this)then\n"
                                 "do jk = 1, 3\n"
                                 "  sto_tmp(jk) = jk\n"
                                 "end do\n"
                                 "else\n"
                                 "do jk = 1, 5\n"
                                 "  sto_tmp(jk) = jk\n"
                                 "end do\n"
                                 "end if\n"
                                 "end program implicit_loop\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCKernelsTrans')
    schedule, _ = acc_trans.apply(schedule.children[0:1], default_present=True)
    gen_code = str(psy.gen).lower()
    assert ("!$acc kernels default(present)\n"
            "  if (do_this) then\n"
            "    do jk = 1, 3\n" in gen_code)
    assert ("    end do\n"
            "  end if\n"
            "  !$acc end kernels\n"
            "end program implicit_loop" in gen_code)
예제 #22
0
def test_omp_explicit_gen():
    ''' Check code generation for a single explicit loop containing
    a kernel. '''
    _, invoke_info = parse(os.path.join(BASE_PATH, "explicit_do.f90"),
                           api=API,
                           line_length=False)
    psy = PSyFactory(API, distributed_memory=False).create(invoke_info)
    schedule = psy.invokes.get('explicit_do').schedule
    omp_trans = TransInfo().get_trans_name('OMPParallelLoopTrans')

    for loop in schedule.loops():
        kernel = loop.kernel
        if kernel and loop.loop_type == "levels":
            schedule, _ = omp_trans.apply(loop)
    gen_code = str(psy.gen).lower()
    expected = ("program explicit_do\n"
                "  implicit none\n"
                "  integer :: ji, jj, jk\n"
                "  integer :: jpi, jpj, jpk\n"
                "  real, dimension(jpi, jpj, jpk) :: umask\n"
                "  !$omp parallel do default(shared), private(ji,jj,jk), "
                "schedule(static)\n"
                "  do jk = 1, jpk\n"
                "    do jj = 1, jpj\n"
                "      do ji = 1, jpi\n"
                "        umask(ji, jj, jk) = ji * jj * jk / r\n"
                "      end do\n"
                "    end do\n"
                "  end do\n"
                "  !$omp end parallel do\n"
                "end program explicit_do")
    assert expected in gen_code
    # Check that calling gen a second time gives the same code
    gen_code = str(psy.gen).lower()
    assert expected in gen_code
예제 #23
0
def test_exp_loop_unrecognised_implicit(parser):
    ''' Check that we raise the expected error if we encounter an
    unrecognised form of implicit loop. '''
    exp_trans = TransInfo().get_trans_name('NemoExplicitLoopTrans')
    # Array syntax used in an unsupported index location
    reader = FortranStringReader("program test_prog\n"
                                 "real, dimension(3,3,3,3) :: umask\n"
                                 "umask(:, :, :, :) = 0.0D0\n"
                                 "end program test_prog\n")
    prog = parser(reader)
    psy = PSyFactory(API).create(prog)
    sched = psy.invokes.invoke_list[0].schedule
    with pytest.raises(TransformationError) as err:
        exp_trans.apply(sched.children[0])
    assert ("Array section in unsupported dimension (4) for code "
            "'umask(:, :, :, :) = 0.0D0'" in str(err))
예제 #24
0
def test_parallel_two_loops(parser):
    ''' Check that we can enclose two loops within a parallel region. '''
    reader = FortranStringReader("program do_loop\n"
                                 "integer :: ji\n"
                                 "integer, parameter :: jpi=11\n"
                                 "real :: sto_tmp(jpi), sto_tmp2(jpi)\n"
                                 "do ji = 1,jpi\n"
                                 "  sto_tmp(ji) = 1.0d0\n"
                                 "end do\n"
                                 "do ji = 1,jpi\n"
                                 "  sto_tmp2(ji) = 1.0d0\n"
                                 "end do\n"
                                 "end program do_loop\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCParallelTrans')
    schedule, _ = acc_trans.apply(schedule[0:2])
    code = str(psy.gen)
    assert ("PROGRAM do_loop\n"
            "  INTEGER :: ji\n"
            "  INTEGER, PARAMETER :: jpi = 11\n"
            "  REAL :: sto_tmp(jpi), sto_tmp2(jpi)\n"
            "  !$ACC PARALLEL\n"
            "  DO ji = 1, jpi\n"
            "    sto_tmp(ji) = 1.0D0\n"
            "  END DO\n"
            "  DO ji = 1, jpi\n"
            "    sto_tmp2(ji) = 1.0D0\n"
            "  END DO\n"
            "  !$ACC END PARALLEL\n"
            "END PROGRAM do_loop" in code)
예제 #25
0
def test_seq_loop(parser):
    ''' Check that we can apply the transformation with the 'sequential'
    clause. '''
    reader = FortranStringReader(SINGLE_LOOP)
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCLoopTrans')
    # An ACC Loop must be within a KERNELS or PARALLEL region
    kernels_trans = TransInfo().get_trans_name('ACCKernelsTrans')
    kernels_trans.apply(schedule.children)
    loops = schedule[0].walk(Loop)
    _ = acc_trans.apply(loops[0], {"sequential": True})
    code = str(psy.gen).lower()
    assert ("  real(kind = wp) :: sto_tmp(jpj)\n"
            "  !$acc kernels\n"
            "  !$acc loop seq\n"
            "  do ji = 1, jpj\n" in code)
예제 #26
0
def test_add_region_comment_err(parser):
    ''' Check that _add_region rejects begin and end strings that contain
    comments that are not directives. '''
    reader = FortranStringReader(EXPLICIT_DO)
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.get('explicit_do').schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children)
    datadir = schedule.children[0]
    with pytest.raises(InternalError) as err:
        datadir._add_region("!data", "!end data")
    assert ("start_text must be a plain label without directive or comment "
            "characters but got: '!data'" in str(err.value))
    with pytest.raises(InternalError) as err:
        datadir._add_region("data", "!end data")
    assert ("end_text must be a plain label without directive or comment "
            "characters but got: '!end data'" in str(err.value))
예제 #27
0
def test_kind_parameter(parser):
    ''' Check that we don't attempt to put kind parameters into the list
    of variables to copyin/out. '''
    reader = FortranStringReader("program kind_param\n"
                                 "integer :: ji, jpj\n"
                                 "real(kind=wp) :: sto_tmp(5)\n"
                                 "do ji = 1,jpj\n"
                                 "sto_tmp(ji) = 0._wp\n"
                                 "end do\n"
                                 "end program kind_param\n")
    code = parser(reader)
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    acc_trans.apply(schedule.children[0:1])
    gen_code = str(psy.gen)

    assert "copyin(wp)" not in gen_code.lower()
예제 #28
0
def test_kernels_dag_name(parser):
    ''' Check that we get the correct name for a DAG node for an OpenACC
    kernels directive. '''
    code = parser(FortranStringReader(EXPLICIT_LOOP))
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCKernelsTrans')
    schedule, _ = acc_trans.apply(schedule.children[0:2], default_present=True)
    assert schedule.children[0].dag_name == "ACC_kernels_1"
예제 #29
0
def test_data_ref():
    '''Check code generation with an array accessed via a derived type.

    '''
    psy, invoke_info = get_invoke("data_ref.f90", api=API, idx=0)
    schedule = invoke_info.schedule
    acc_trans = TransInfo().get_trans_name('ACCDataTrans')
    schedule, _ = acc_trans.apply(schedule.children)
    gen_code = str(psy.gen)
    assert "!$ACC DATA COPYIN(a) COPYOUT(prof,prof%npind)" in gen_code
예제 #30
0
def test_kernels_view(parser, capsys):
    ''' Test the ACCKernelsDirective.view() method. '''
    code = parser(FortranStringReader(EXPLICIT_LOOP))
    psy = PSyFactory(API, distributed_memory=False).create(code)
    schedule = psy.invokes.invoke_list[0].schedule
    acc_trans = TransInfo().get_trans_name('ACCKernelsTrans')
    schedule, _ = acc_trans.apply(schedule.children[0:2], default_present=True)
    schedule.view()
    output, _ = capsys.readouterr()
    assert "[ACC Kernels]" in output