def test_new_kern_no_clobber(tmpdir, monkeypatch): ''' Check that we create a new kernel with a new name when kernel-naming is set to 'multiple' and we would otherwise get a name clash. ''' # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", "") monkeypatch.setattr(config, "_kernel_naming", "multiple") # Change to temp dir (so kernel written there) old_cwd = tmpdir.chdir() psy, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) kern = kernels[0] old_mod_name = kern.module_name[:] # Create a file with the same name as we would otherwise generate with open(os.path.join(str(tmpdir), old_mod_name+"_0_mod.f90"), "w") as ffile: ffile.write("some code") rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) _ = str(psy.gen).lower() filename = os.path.join(str(tmpdir), old_mod_name+"_1_mod.f90") assert os.path.isfile(filename) old_cwd.chdir()
def test_new_kern_single_error(tmpdir, monkeypatch): ''' Check that we do not overwrite an existing, different kernel if there is a name clash and kernel-naming is 'single'. ''' # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", "") monkeypatch.setattr(config, "_kernel_naming", "single") # Change to temp dir (so kernel written there) old_cwd = tmpdir.chdir() _, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() kern = kernels[0] old_mod_name = kern.module_name[:] # Create a file with the same name as we would otherwise generate with open(os.path.join(str(tmpdir), old_mod_name+"_0_mod.f90"), "w") as ffile: ffile.write("some code") rtrans = ACCRoutineTrans() new_kern, _ = rtrans.apply(kern) # Generate the code - this should raise an error as we get a name # clash and the content of the existing file is not the same as that # which we would generate with pytest.raises(GenerationError) as err: new_kern.rename_and_write() assert ("transformed version of this Kernel 'testkern_0_mod.f90' already " "exists in the kernel-output directory ({0}) but is not the same " "as the current, transformed kernel and the kernel-renaming " "scheme is set to 'single'".format(str(tmpdir)) in str(err)) old_cwd.chdir()
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_1kern_trans(tmpdir, monkeypatch): ''' Check that we generate the correct code when an invoke contains the same kernel more than once but only one of them is transformed. ''' # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", "") # Change to temp dir (so kernel written there) old_cwd = tmpdir.chdir() psy, invoke = get_invoke("4_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() # We will transform the second kernel but not the first kern = kernels[1] rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) code = str(psy.gen).lower() tag = re.search('use testkern(.+?)_mod', code).group(1) # We should have a USE for the original kernel and a USE for the new one assert "use testkern{0}_mod, only: testkern{0}_code".format(tag) in code assert "use testkern, only: testkern_code" in code # Similarly, we should have calls to both the original and new kernels assert "call testkern_code(" in code assert "call testkern{0}_code(".format(tag) in code first = code.find("call testkern_code(") second = code.find("call testkern{0}_code(".format(tag)) assert first < second assert Dynamo0p3Build(tmpdir).code_compiles(psy) old_cwd.chdir()
def test_new_same_kern_single(tmpdir, monkeypatch): ''' Check that we do not overwrite an existing, identical kernel if there is a name clash and kernel-naming is 'single'. ''' # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", "") monkeypatch.setattr(config, "_kernel_naming", "single") rtrans = ACCRoutineTrans() # Change to temp dir (so kernel written there) old_cwd = tmpdir.chdir() _, invoke = get_invoke("4_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule # Apply the same transformation to both kernels. This should produce # two, identical transformed kernels. new_kernels = [] for kern in sched.coded_kernels(): new_kern, _ = rtrans.apply(kern) new_kernels.append(new_kern) # Generate the code - we should end up with just one transformed kernel new_kernels[0].rename_and_write() new_kernels[1].rename_and_write() assert new_kernels[1]._name == "testkern_0_code" assert new_kernels[1].module_name == "testkern_0_mod" out_files = os.listdir(str(tmpdir)) assert out_files == [new_kernels[1].module_name+".f90"] old_cwd.chdir()
def test_2kern_trans(tmpdir, monkeypatch): ''' Check that we generate correct code when we transform two kernels within a single invoke. ''' # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", "") # Change to temp dir (so kernel written there) old_cwd = tmpdir.chdir() psy, invoke = get_invoke("4.5.2_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) assert len(kernels) == 5 rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kernels[1]) _, _ = rtrans.apply(kernels[2]) # Generate the code (this triggers the generation of new kernels) code = str(psy.gen).lower() # Find the tags added to the kernel/module names for match in re.finditer('use testkern_any_space_2(.+?)_mod', code): tag = match.group(1) assert ("use testkern_any_space_2{0}_mod, only: " "testkern_any_space_2{0}_code".format(tag) in code) assert "call testkern_any_space_2{0}_code(".format(tag) in code assert os.path.isfile( os.path.join(str(tmpdir), "testkern_any_space_2{0}_mod.f90".format(tag))) assert "use testkern_any_space_2_mod, only" not in code assert "call testkern_any_space_2_code(" not in code assert Dynamo0p3Build(tmpdir).code_compiles(psy) old_cwd.chdir()
def test_no_inline_before_trans(monkeypatch, tmpdir): ''' Check that we reject attempts to transform kernels that have been marked for module in-lining. Issue #229. ''' # Even though this code will raise an exception at the end, it will # still create an (empty) file 'testkern_any_space_2_0_mod.f90'. # So change to tmpdir to avoid this. old_pwd = tmpdir.chdir() from psyclone.transformations import KernelModuleInlineTrans psy, invoke = get_invoke("4.5.2_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) assert len(kernels) == 5 inline_trans = KernelModuleInlineTrans() rtrans = ACCRoutineTrans() _, _ = inline_trans.apply(kernels[1]) with pytest.raises(TransformationError) as err: _, _ = rtrans.apply(kernels[1]) assert "because it will be module-inlined" in str(err) # Monkeypatch the validate() routine so we can check that we catch # the error at code-generation time monkeypatch.setattr(rtrans, "validate", lambda kern: None) _, _ = rtrans.apply(kernels[1]) with pytest.raises(NotImplementedError) as err: _ = str(psy.gen).lower() assert "Cannot module-inline a transformed kernel " in str(err) old_pwd.chdir()
def test_accroutine_err(monkeypatch): ''' Check that we raise the expected error if we can't find the source of the kernel subroutine. ''' import fparser _, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() kern = kernels[0] assert isinstance(kern, Kern) # Edit the fparser1 AST of the kernel so that it does not have a # subroutine of the correct name ast = kern._module_code mod = ast.content[0] # Find the subroutine statement for child in mod.content: if isinstance(child, fparser.one.block_statements.Subroutine): sub = child # Find the end subroutine statement for child in sub.content: if isinstance(child, fparser.one.block_statements.EndSubroutine): end = child monkeypatch.setattr(sub, "name", "some_other_name") monkeypatch.setattr(end, "name", "some_other_name") rtrans = ACCRoutineTrans() with pytest.raises(TransformationError) as err: _ = rtrans.apply(kern) assert ("Failed to find subroutine source for kernel testkern_code" in str(err))
def test_1kern_trans(kernel_outputdir): ''' Check that we generate the correct code when an invoke contains the same kernel more than once but only one of them is transformed. ''' psy, invoke = get_invoke("4_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() # We will transform the second kernel but not the first kern = kernels[1] rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) code = str(psy.gen).lower() tag = re.search('use testkern(.+?)_mod', code).group(1) # We should have a USE for the original kernel and a USE for the new one assert "use testkern{0}_mod, only: testkern{0}_code".format(tag) in code assert "use testkern_mod, only: testkern_code" in code # Similarly, we should have calls to both the original and new kernels assert "call testkern_code(" in code assert "call testkern{0}_code(".format(tag) in code first = code.find("call testkern_code(") second = code.find("call testkern{0}_code(".format(tag)) assert first < second assert LFRicBuild(kernel_outputdir).code_compiles(psy)
def test_accroutine(): ''' Test that we can transform a kernel by adding a "!$acc routine" directive to it. ''' from psyclone.gocean1p0 import GOKern from fparser.two import Fortran2003 _, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0) sched = invoke.schedule kern = sched.children[0].loop_body[0].loop_body[0] assert isinstance(kern, GOKern) rtrans = ACCRoutineTrans() assert rtrans.name == "ACCRoutineTrans" new_kern, _ = rtrans.apply(kern) # The transformation should have populated the fparser2 AST of # the kernel... assert new_kern._fp2_ast assert isinstance(new_kern._fp2_ast, Fortran2003.Program) # Check AST contains directive comments = walk_ast(new_kern._fp2_ast.content, [Fortran2003.Comment]) assert len(comments) == 1 assert str(comments[0]) == "!$acc routine" # Check that directive is in correct place (end of declarations) gen = str(new_kern._fp2_ast) assert ("REAL(KIND = go_wp), DIMENSION(:, :), INTENT(IN) :: sshn, sshn_u, " "sshn_v, hu, hv, un, vn\n" " !$acc routine\n" " ssha (ji, jj) = 0.0_go_wp\n" in gen)
def test_accroutine_empty_kernel(): ''' Check that the directive goes at the end of the declarations, even when the rest of the kernel is empty. ''' _, invoke = get_invoke("1_single_invoke.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.coded_kernels() rtrans = ACCRoutineTrans() new_kern, _ = rtrans.apply(kernels[0]) # Check that directive is in correct place (end of declarations) gen = str(new_kern._fp2_ast).lower() assert "!$acc routine\n end subroutine testkern_code" in gen
def test_builtin_no_trans(): ''' Check that we reject attempts to transform built-in kernels. ''' from psyclone.dynamo0p3_builtins import DynBuiltIn _, invoke = get_invoke("15.1.1_X_plus_Y_builtin.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(DynBuiltIn) rtrans = ACCRoutineTrans() with pytest.raises(TransformationError) as err: _ = rtrans.apply(kernels[0]) assert ("ACCRoutineTrans to a built-in kernel is not yet supported and " "kernel 'x_plus_y' is of type " in str(err))
def test_accroutine_module_use(): ''' Check that ACCRoutineTrans rejects a kernel if it contains a module use statement. ''' _, invoke = get_invoke("single_invoke_kern_with_use.f90", api="gocean1.0", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) rtrans = ACCRoutineTrans() with pytest.raises(TransformationError) as err: _ = rtrans.apply(kernels[0]) assert "'global' scope: ['rdt']. PSyclone cannot currently" in str(err)
def test_accroutine_module_use(): ''' Check that ACCRoutineTrans rejects a kernel if it contains a module use statement. ''' _, invoke = get_invoke("single_invoke_kern_with_use.f90", api="gocean1.0", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) rtrans = ACCRoutineTrans() with pytest.raises(TransformationError) as err: _ = rtrans.apply(kernels[0]) assert ("global scope: ['rdt']. If these symbols represent data then they" " must first" in str(err.value))
def test_new_kernel_dir(kernel_outputdir): ''' Check that we write out the transformed kernel to a specified directory. ''' psy, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0) sched = invoke.schedule kern = sched.coded_kernels()[0] rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) _ = str(psy.gen) file_list = os.listdir(str(kernel_outputdir)) assert len(file_list) == 1 assert file_list[0] == 'continuity_0_mod.f90'
def test_new_kernel_file(tmpdir, monkeypatch): ''' Check that we write out the transformed kernel to the CWD. ''' from fparser.two import Fortran2003, parser from fparser.common.readfortran import FortranFileReader # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", "") monkeypatch.setattr(config, "_kernel_naming", "multiple") # Change to temp dir (so kernel written there) old_cwd = tmpdir.chdir() psy, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0) sched = invoke.schedule kern = sched.children[0].loop_body[0].loop_body[0] rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) code = str(psy.gen).lower() # Work out the value of the tag used to re-name the kernel tag = re.search('use continuity(.+?)_mod', code).group(1) assert ("use continuity{0}_mod, only: continuity{0}_code".format(tag) in code) assert "call continuity{0}_code(".format(tag) in code # The kernel and module name should have gained the tag just identified # and be written to the CWD filename = os.path.join(str(tmpdir), "continuity{0}_mod.f90".format(tag)) assert os.path.isfile(filename) # Parse the new kernel file f2003_parser = parser.ParserFactory().create() reader = FortranFileReader(filename) prog = f2003_parser(reader) # Check that the module has the right name modules = walk_ast(prog.content, [Fortran2003.Module_Stmt]) assert str(modules[0].items[1]) == "continuity{0}_mod".format(tag) # Check that the subroutine has the right name subs = walk_ast(prog.content, [Fortran2003.Subroutine_Stmt]) found = False for sub in subs: if str(sub.items[1]) == "continuity{0}_code".format(tag): found = True break assert found # Check that the kernel type has been re-named dtypes = walk_ast(prog.content, [Fortran2003.Derived_Type_Def]) names = walk_ast(dtypes[0].content, [Fortran2003.Type_Name]) assert str(names[0]) == "continuity{0}_type".format(tag) from gocean1p0_build import GOcean1p0Build # If compilation fails this will raise an exception GOcean1p0Build(tmpdir).compile_file(filename) old_cwd.chdir()
def test_accroutine_rejects_transformed_kernel(): ''' Check that the ACCRoutineTrans rejects an already-transformed kernel (because it still works with the fparser2 parse tree and not the PSyIR - Issue #490). ''' rtrans = ACCRoutineTrans() _, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0) sched = invoke.schedule kern = sched.coded_kernels()[0] # Pretend that this kernel has previously been transformed kern.modified = True with pytest.raises(TransformationError) as err: rtrans.apply(kern) assert ("Cannot transform kernel 'continuity_code' because it has " "previously been transformed" in str(err.value))
def test_new_kernel_dir(tmpdir, monkeypatch): ''' Check that we write out the transformed kernel to a specified directory. ''' # Set the output directory in the configuration object config = Config.get() monkeypatch.setattr(config, "_kernel_output_dir", str(tmpdir)) psy, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0) sched = invoke.schedule kern = sched.children[0].loop_body[0].loop_body[0] rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) _ = str(psy.gen) file_list = os.listdir(str(tmpdir)) assert len(file_list) == 1 assert file_list[0] == 'continuity_0_mod.f90'
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): ''' 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
def test_new_kernel_file(kernel_outputdir, monkeypatch, fortran_reader): ''' Check that we write out the transformed kernel to the CWD. ''' # Ensure kernel-output directory is uninitialised config = Config.get() monkeypatch.setattr(config, "_kernel_naming", "multiple") psy, invoke = get_invoke("nemolite2d_alg_mod.f90", api="gocean1.0", idx=0) sched = invoke.schedule kern = sched.coded_kernels()[0] rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kern) # Generate the code (this triggers the generation of a new kernel) code = str(psy.gen).lower() # Work out the value of the tag used to re-name the kernel tag = re.search('use continuity(.+?)_mod', code).group(1) assert ("use continuity{0}_mod, only: continuity{0}_code".format(tag) in code) assert "call continuity{0}_code(".format(tag) in code # The kernel and module name should have gained the tag just identified # and be written to the CWD filename = os.path.join(str(kernel_outputdir), "continuity{0}_mod.f90".format(tag)) assert os.path.isfile(filename) # Parse the new kernel file psyir = fortran_reader.psyir_from_file(filename) # Check that the module has the right name assert isinstance(psyir, FileContainer) module = psyir.children[0] assert module.name == "continuity{0}_mod".format(tag) # Check that the subroutine has the right name found = False for sub in psyir.walk(Routine): if sub.name == "continuity{0}_code".format(tag): found = True break assert found from psyclone.tests.gocean1p0_build import GOcean1p0Build # If compilation fails this will raise an exception GOcean1p0Build(kernel_outputdir).compile_file(filename)
def test_no_inline_after_trans(monkeypatch): ''' Check that we reject attempts to inline a previously transformed kernel. Issue #229. ''' from psyclone.transformations import KernelModuleInlineTrans _, invoke = get_invoke("4.5.2_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(Kern) assert len(kernels) == 5 # Transform the kernel first inline_trans = KernelModuleInlineTrans() rtrans = ACCRoutineTrans() _, _ = rtrans.apply(kernels[1]) # Then attempt to inline it with pytest.raises(TransformationError) as err: _, _ = inline_trans.apply(kernels[1]) assert "because it has previously been transformed" in str(err) # Monkeypatch the validate() routine so we can check that we catch # the error at the psyGen level too. monkeypatch.setattr(inline_trans, "validate", lambda node, inline: None) with pytest.raises(NotImplementedError) as err: _, _ = inline_trans.apply(kernels[1]) assert "Cannot module-inline a transformed kernel " in str(err)
def test_no_inline_before_trans(monkeypatch): ''' Check that we reject attempts to transform kernels that have been marked for module in-lining. Issue #229. ''' from psyclone.transformations import KernelModuleInlineTrans psy, invoke = get_invoke("4.5.2_multikernel_invokes.f90", api="dynamo0.3", idx=0) sched = invoke.schedule kernels = sched.walk(sched.children, Kern) assert len(kernels) == 5 inline_trans = KernelModuleInlineTrans() rtrans = ACCRoutineTrans() _, _ = inline_trans.apply(kernels[1]) with pytest.raises(TransformationError) as err: _, _ = rtrans.apply(kernels[1]) assert "because it will be module-inlined" in str(err) # Monkeypatch the validate() routine so we can check that we catch # the error at code-generation time monkeypatch.setattr(rtrans, "validate", lambda kern: None) _, _ = rtrans.apply(kernels[1]) with pytest.raises(NotImplementedError) as err: _ = str(psy.gen).lower() assert "Cannot module-inline a transformed kernel " in str(err)