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)
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
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
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
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
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)
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))
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)
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
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
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
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
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"
def test_accenterdata(): ''' Generic tests for the ACCEnterDataTrans class ''' acct = ACCEnterDataTrans() assert acct.name == "ACCEnterDataTrans" assert str(acct) == "Adds an OpenACC 'enter data' directive"