예제 #1
0
def test_no_parent_accdirective():
    ''' Test that applying Extract Transformation on an orphaned
    ACCLoopDirective without its ancestor ACCParallelDirective
    when optimisations are applied raises a TransformationError. '''

    etrans = GOceanExtractTrans()
    acclpt = ACCLoopTrans()
    accpara = ACCParallelTrans()
    accdata = ACCEnterDataTrans()

    _, invoke = get_invoke("single_invoke_three_kernels.f90",
                           GOCEAN_API,
                           idx=0,
                           dist_mem=False)
    schedule = invoke.schedule

    # Apply the OpenACC Loop transformation to every loop in the Schedule
    for child in schedule.children:
        if isinstance(child, Loop):
            acclpt.apply(child)
    # Enclose all of these loops within a single ACC Parallel region
    accpara.apply(schedule.children)
    # Add a mandatory ACC enter-data directive
    accdata.apply(schedule)

    orphaned_directive = schedule.children[1].children[0]
    with pytest.raises(TransformationError) as excinfo:
        _, _ = etrans.apply(orphaned_directive)
    assert "Error in GOceanExtractTrans: Application to Nodes enclosed " \
           "within a thread-parallel region is not allowed." \
           in str(excinfo.value)
예제 #2
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.
    from psyclone.transformations import ACCParallelTrans, ACCEnterDataTrans
    from psyclone.psyGen import CodedKern
    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
예제 #3
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
    from psyclone.transformations import ACCParallelTrans, ACCEnterDataTrans
    from psyclone.psyGen import CodedKern
    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
예제 #4
0
def trans(psy):
    ''' Take the supplied psy object, apply OpenACC transformations
    to the schedule of invoke_0 and return the new psy object '''
    ptrans = ACCParallelTrans()
    ltrans = ACCLoopTrans()
    dtrans = ACCEnterDataTrans()
    ktrans = ACCRoutineTrans()

    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
    for child in schedule.children:
        if isinstance(child, Loop):
            ltrans.apply(child, {"collapse": 2})

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

    # Add an enter-data directive
    dtrans.apply(schedule)

    # Put an 'acc routine' directive inside each kernel
    for kern in schedule.coded_kernels():
        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)

    schedule.view()
    return psy
예제 #5
0
def test_lfric_acc():
    '''Check variable usage detection when OpenACC is used.

    '''
    # Use the OpenACC transforms to enclose the kernels
    # with OpenACC directives.
    from psyclone.transformations import ACCParallelTrans, ACCEnterDataTrans
    from psyclone.psyGen import CodedKern
    acc_par_trans = ACCParallelTrans()
    acc_enter_trans = ACCEnterDataTrans()
    _, invoke = get_invoke("1_single_invoke.f90", "dynamo0.3",
                           name="invoke_0_testkern_type", 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 "m1: READ" in var_info
    assert "m2: READ" in var_info
    assert "undf_w1: READ" in var_info
    assert "map_w1: READ" in var_info
    assert "undf_w2: READ" in var_info
    assert "map_w2: READ" in var_info
    assert "undf_w3: READ" in var_info
    assert "map_w3: READ" in var_info
예제 #6
0
def test_no_parent_accdirective():
    ''' Test that applying Extract Transformation on an orphaned
    ACCLoopDirective without its ancestor ACCParallelDirective
    when optimisations are applied raises a TransformationError. '''
    from psyclone.transformations import ACCParallelTrans, ACCEnterDataTrans, \
        ACCLoopTrans

    etrans = GOceanExtractRegionTrans()
    acclpt = ACCLoopTrans()
    accpara = ACCParallelTrans()
    accdata = ACCEnterDataTrans()

    _, invoke_info = parse(os.path.join(GOCEAN_BASE_PATH,
                                        "single_invoke_three_kernels.f90"),
                           api=GOCEAN_API)
    psy = PSyFactory(GOCEAN_API, distributed_memory=False).create(invoke_info)
    invoke = psy.invokes.invoke_list[0]
    schedule = invoke.schedule

    # Apply the OpenACC Loop transformation to every loop in the Schedule
    for child in schedule.children:
        if isinstance(child, Loop):
            schedule, _ = acclpt.apply(child)
    # Enclose all of these loops within a single ACC Parallel region
    schedule, _ = accpara.apply(schedule.children)
    # Add a mandatory ACC enter-data directive
    schedule, _ = accdata.apply(schedule)

    orphaned_directive = schedule.children[1].children[0]
    with pytest.raises(TransformationError) as excinfo:
        _, _ = etrans.apply(orphaned_directive)
    assert ("Extraction of Nodes enclosed within a thread parallel "
            "region is not allowed.") in str(excinfo)
예제 #7
0
def test_accenterdata_internalerr(monkeypatch):
    ''' Check that the ACCEnterDataTrans.apply() method raises an internal
    error if the validate method fails to throw out an invalid type of
    Schedule. '''
    acct = ACCEnterDataTrans()
    monkeypatch.setattr(acct, "validate", lambda sched, options: None)
    with pytest.raises(InternalError) as err:
        _, _ = acct.apply("Not a schedule")
    assert ("validate() has not rejected an (unsupported) schedule"
            in str(err.value))
예제 #8
0
def test_accenterdata_internalerr(monkeypatch):
    ''' Check that the ACCEnterDataTrans.apply() method raises an internal
    error if the _validate method fails to throw out an invalid type of
    Schedule. '''
    from psyclone.transformations import ACCEnterDataTrans
    from psyclone.psyGen import InternalError
    acct = ACCEnterDataTrans()
    monkeypatch.setattr(acct, "_validate", lambda sched: None)
    with pytest.raises(InternalError) as err:
        _, _ = acct.apply("Not a schedule")
    assert "validate() has not rejected an (unsupported) schedule" in str(err)
예제 #9
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
예제 #10
0
def trans(psy):
    '''PSyclone transformation script for the dynamo0p3 api to apply
    OpenACC loop, parallel and enter data directives generically.

    :param psy: a PSyclone PSy object which captures the algorithm and \
        kernel information required by PSyclone.
    :type psy: subclass of :py:class:`psyclone.psyGen.PSy`

    '''
    kernels_trans = ACCKernelsTrans()
    routine_trans = ACCRoutineTrans()
    ctrans = Dynamo0p3ColourTrans()
    loop_trans = ACCLoopTrans()
    enter_trans = ACCEnterDataTrans()
    const = LFRicConstants()

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

        schedule = invoke.schedule

        # Colour loops as required
        for loop in schedule.loops():
            if loop.field_space.orig_name \
               not in const.VALID_DISCONTINUOUS_NAMES \
               and loop.iteration_space == "cell_column":
                ctrans.apply(loop)

        # Add Kernels and Loop directives
        for loop in schedule.loops():
            if loop.loop_type != "colours":
                kernels_trans.apply([loop])
                loop_trans.apply(loop)

        # Add Routine directive to kernels
        for kernel in schedule.coded_kernels():
            routine_trans.apply(kernel)

        # Add Enter Data directive covering all of the PSy layer.
        enter_trans.apply(schedule)

        schedule.view()

    return psy
예제 #11
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
예제 #12
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
예제 #13
0
def test_accenterdata():
    ''' Generic tests for the ACCEnterDataTrans class '''
    from psyclone.transformations import ACCEnterDataTrans
    acct = ACCEnterDataTrans()
    assert acct.name == "ACCEnterDataTrans"
    assert str(acct) == "Adds an OpenACC 'enter data' directive"
예제 #14
0
def test_accenterdata():
    ''' Generic tests for the ACCEnterDataTrans class '''
    acct = ACCEnterDataTrans()
    assert acct.name == "ACCEnterDataTrans"
    assert str(acct) == "Adds an OpenACC 'enter data' directive"