def test_ifblock_children_region():
    ''' Check that we reject attempts to transform the conditional part of
    an If statement or to include both the if- and else-clauses in a region
    (without their parent). '''
    from psyclone.psyGen import IfBlock, Reference, Schedule
    from psyclone.transformations import ACCParallelTrans, TransformationError
    acct = ACCParallelTrans()
    # Construct a valid IfBlock
    ifblock = IfBlock()
    # Condition
    ref1 = Reference('condition1', parent=ifblock)
    ifblock.addchild(ref1)
    # If-body
    sch = Schedule(parent=ifblock)
    ifblock.addchild(sch)
    # Else-body
    sch2 = Schedule(parent=ifblock)
    ifblock.addchild(sch2)
    # Attempt to put all of the children of the IfBlock into a region. This
    # is an error because the first child is the conditional part of the
    # IfBlock.
    with pytest.raises(TransformationError) as err:
        super(ACCParallelTrans, acct)._validate(ifblock.children)
    assert ("transformation to the conditional expression (first child"
            in str(err))
    with pytest.raises(TransformationError) as err:
        super(ACCParallelTrans, acct)._validate(ifblock.children[1:])
    assert ("Cannot enclose both the if- and else- clauses of an IfBlock by "
            in str(err))
예제 #2
0
def trans(psy):
    ''' Take the supplied psy object, apply OpenACC transformations
    to the schedule of the first invoke and return the new psy object '''
    from psyclone.transformations import ACCParallelTrans, \
        ACCEnterDataTrans, ACCLoopTrans, ACCRoutineTrans, \
        KernelGlobalsToArguments
    ptrans = ACCParallelTrans()
    ltrans = ACCLoopTrans()
    dtrans = ACCEnterDataTrans()
    ktrans = ACCRoutineTrans()
    g2localtrans = KernelGlobalsToArguments()

    invoke = psy.invokes.invoke_list[0]
    schedule = invoke.schedule
    schedule.view()

    # Apply the OpenACC Loop transformation to *every* loop
    # nest in the schedule
    from psyclone.psyir.nodes import Loop
    for child in schedule.children:
        if isinstance(child, Loop):
            newschedule, _ = ltrans.apply(child, {"collapse": 2})
            schedule = newschedule

    # Put all of the loops in a single parallel region
    newschedule, _ = ptrans.apply(schedule.children)

    # Add an enter-data directive
    newschedule, _ = dtrans.apply(schedule)

    # Convert any accesses to global data into kernel arguments and then
    # put an 'acc routine' directive inside each kernel
    for kern in schedule.coded_kernels():
        if kern.name == "kern_use_var_code":
            # TODO #490 and #663. This currently won't work because the
            # KernelGlobalsToArguments transformation works on the PSyIR but
            # the subsequent ACCRoutineTrans works on the fparser2 parse tree.
            g2localtrans.apply(kern)
        _, _ = ktrans.apply(kern)
        # Ideally we would module-inline the kernel here (to save having to
        # rely on the compiler to do it) but this does not currently work
        # for the fparser2 AST (issue #229).
        # _, _ = itrans.apply(kern)

    invoke.schedule = newschedule
    newschedule.view()
    return psy
예제 #3
0
def trans(psy):
    ''' Take the supplied psy object, apply OpenACC transformations
    to the schedule of the first invoke and return the new psy object '''
    from psyclone.transformations import ACCParallelTrans, \
        ACCEnterDataTrans, ACCLoopTrans, ACCRoutineTrans, \
        KernelGlobalsToArguments, KernelModuleInlineTrans
    ptrans = ACCParallelTrans()
    ltrans = ACCLoopTrans()
    dtrans = ACCEnterDataTrans()
    ktrans = ACCRoutineTrans()
    itrans = KernelModuleInlineTrans()
    g2localtrans = KernelGlobalsToArguments()

    invoke = psy.invokes.invoke_list[0]
    schedule = invoke.schedule
    schedule.view()

    # Apply the OpenACC Loop transformation to *every* loop
    # nest in the schedule
    from psyclone.psyir.nodes import Loop
    for child in schedule.children:
        if isinstance(child, Loop):
            newschedule, _ = ltrans.apply(child, {"collapse": 2})
            schedule = newschedule

    # Put all of the loops in a single parallel region
    newschedule, _ = ptrans.apply(schedule.children)

    # Add an enter-data directive
    newschedule, _ = dtrans.apply(schedule)

    # Convert any accesses to global data into kernel arguments, put an
    # 'acc routine' directive inside, and module-inline each kernel
    for kern in schedule.coded_kernels():
        if kern.name == "kern_use_var_code":
            g2localtrans.apply(kern)
        _, _ = ktrans.apply(kern)
        _, _ = itrans.apply(kern)

    invoke.schedule = newschedule
    newschedule.view()
    return psy
예제 #4
0
def trans(psy):
    '''PSyclone transformation script for the dynamo0p3 api to apply
    OpenACC loop, parallel and enter data directives generically.

    '''
    loop_trans = ACCLoopTrans()
    parallel_trans = ACCParallelTrans()
    enter_data_trans = ACCEnterDataTrans()

    # Loop over all of the Invokes in the PSy object
    for invoke in psy.invokes.invoke_list:

        print("Transforming invoke '" + invoke.name + "'...")
        schedule = invoke.schedule
        for loop in schedule.loops():
            _, _ = loop_trans.apply(loop)
            _, _ = parallel_trans.apply(loop.parent)
        _, _ = enter_data_trans.apply(schedule)

    return psy
예제 #5
0
def test_regiontrans_wrong_options():
    '''Check that the validate method raises the expected error if passed
        options that are not contained in a dictionary.

    '''
    # RegionTrans is abstract so use a concrete sub-class
    region_trans = ACCParallelTrans()
    with pytest.raises(TransformationError) as excinfo:
        RegionTrans.validate(region_trans, None, options="invalid")
    assert ("Transformation apply method options argument must be a "
            "dictionary but found 'str'." in str(excinfo.value))
예제 #6
0
def trans(psy):
    ''' Take the supplied psy object, apply OpenACC transformations
    to the schedule of invoke_0 and return the new psy object '''
    from psyclone.transformations import ACCParallelTrans, \
        ACCDataTrans, ACCLoopTrans, ACCRoutineTrans, KernelModuleInlineTrans
    ptrans = ACCParallelTrans()
    ltrans = ACCLoopTrans()
    dtrans = ACCDataTrans()
    ktrans = ACCRoutineTrans()
    itrans = KernelModuleInlineTrans()

    invoke = psy.invokes.get('invoke_0_inc_field')
    schedule = invoke.schedule
    # schedule.view()

    # Apply the OpenACC Loop transformation to *every* loop
    # nest in the schedule
    from psyclone.psyGen import Loop
    for child in schedule.children:
        if isinstance(child, Loop):
            newschedule, _ = ltrans.apply(child, collapse=2)
            schedule = newschedule

    # Put all of the loops in a single parallel region
    newschedule, _ = ptrans.apply(schedule.children)

    # Add an enter-data directive
    newschedule, _ = dtrans.apply(schedule)

    # Put an 'acc routine' directive inside each kernel
    for kern in schedule.kern_calls():
        _, _ = ktrans.apply(kern)
        # Ideally we would module-inline the kernel here (to save having to
        # rely on the compiler to do it) but this does not currently work
        # for the fparser2 AST (issue #229).
        # _, _ = itrans.apply(kern)

    invoke.schedule = newschedule
    newschedule.view()
    return psy
예제 #7
0
def test_lfric_stencil():
    '''Check variable usage detection when OpenACC is used with a
    kernel that uses a stencil.

    '''
    # Use the OpenACC transforms to create the required kernels
    acc_par_trans = ACCParallelTrans()
    acc_enter_trans = ACCEnterDataTrans()
    _, invoke = get_invoke("14.4_halo_vector.f90", "dynamo0.3",
                           idx=0, dist_mem=False)
    sched = invoke.schedule
    _ = acc_par_trans.apply(sched.children)
    _ = acc_enter_trans.apply(sched)

    # Find the first kernel:
    kern = invoke.schedule.walk(CodedKern)[0]
    create_acc_arg_list = KernCallAccArgList(kern)
    var_accesses = VariablesAccessInfo()
    create_acc_arg_list.generate(var_accesses=var_accesses)
    var_info = str(var_accesses)
    assert "f1: READ+WRITE" in var_info
    assert "f2: READ" in var_info
    assert "f2_stencil_dofmap: READ" in var_info
예제 #8
0
def test_lfric_acc_operator():
    '''Check variable usage detection when OpenACC is used with
    a kernel that uses an operator.

    '''
    # Use the OpenACC transforms to enclose the kernels
    # with OpenACC directives.
    acc_par_trans = ACCParallelTrans()
    acc_enter_trans = ACCEnterDataTrans()
    _, invoke = get_invoke("20.0_cma_assembly.f90", "dynamo0.3",
                           idx=0, dist_mem=False)
    sched = invoke.schedule
    _ = acc_par_trans.apply(sched.children)
    _ = acc_enter_trans.apply(sched)

    # Find the first kernel:
    kern = invoke.schedule.walk(CodedKern)[0]
    create_acc_arg_list = KernCallAccArgList(kern)
    var_accesses = VariablesAccessInfo()
    create_acc_arg_list.generate(var_accesses=var_accesses)
    var_info = str(var_accesses)
    assert "lma_op1_proxy%ncell_3d: READ" in var_info
    assert "lma_op1_proxy%local_stencil: WRITE" in var_info
예제 #9
0
def test_regiontrans_wrong_children():
    ''' Check that the validate method raises the expected error if
        passed the wrong children of a Node. (e.g. those representing the
        bounds of a Loop.) '''
    # RegionTrans is abstract so use a concrete sub-class
    rtrans = ACCParallelTrans()
    # Construct a valid Loop in the PSyIR
    parent = Loop(parent=None)
    parent.addchild(Literal("1", INTEGER_TYPE, parent))
    parent.addchild(Literal("10", INTEGER_TYPE, parent))
    parent.addchild(Literal("1", INTEGER_TYPE, parent))
    parent.addchild(Schedule(parent=parent))
    with pytest.raises(TransformationError) as err:
        RegionTrans.validate(rtrans, parent.children)
    assert ("Cannot apply a transformation to multiple nodes when one or more "
            "is a Schedule" in str(err.value))
예제 #10
0
def test_ifblock_children_region():
    ''' Check that we reject attempts to transform the conditional part of
    an If statement or to include both the if- and else-clauses in a region
    (without their parent). '''
    acct = ACCParallelTrans()
    # Construct a valid IfBlock
    condition = Reference(DataSymbol('condition', BOOLEAN_TYPE))
    ifblock = IfBlock.create(condition, [], [])

    # Attempt to put all of the children of the IfBlock into a region. This
    # is an error because the first child is the conditional part of the
    # IfBlock.
    with pytest.raises(TransformationError) as err:
        super(ACCParallelTrans, acct).validate([ifblock.children[0]])
    assert ("transformation to the immediate children of a Loop/IfBlock "
            "unless it is to a single Schedule" in str(err.value))
    with pytest.raises(TransformationError) as err:
        super(ACCParallelTrans, acct).validate(ifblock.children[1:])
    assert (" to multiple nodes when one or more is a Schedule. "
            "Either target a single Schedule or " in str(err.value))
예제 #11
0
def test_accparallel():
    ''' Generic tests for the ACCParallelTrans class '''
    acct = ACCParallelTrans()
    assert acct.name == "ACCParallelTrans"
예제 #12
0
def test_accparallel():
    ''' Generic tests for the ACCParallelTrans class '''
    from psyclone.transformations import ACCParallelTrans
    acct = ACCParallelTrans()
    assert acct.name == "ACCParallelTrans"