Skip to content

Commit 1fc199e

Browse files
committed
Merge remote-tracking branch 'origin/master' into single_nemo_script
2 parents f0f5413 + 97dd02d commit 1fc199e

13 files changed

Lines changed: 121 additions & 67 deletions

changelog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
14) PR #3254 for #3253. Fix openmp parallel lowering with kernels and
2+
improve dependency messages
3+
14
13) PR #3239 for #3199. Add OMPCritical Directive and Transformation.
25

36
12) PR #3226 for #514. Refactor LFRic reductions to use OMPReductionClause.

src/psyclone/core/access_sequence.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,8 @@
4545

4646
from psyclone.core.access_type import AccessType
4747
from psyclone.core.signature import Signature
48-
49-
5048
from psyclone.errors import InternalError
49+
5150
if TYPE_CHECKING: # pragma: no cover
5251
from psyclone.psyir.nodes import Node
5352
from psyclone.psyir.symbols import Symbol
@@ -157,14 +156,19 @@ def description(self) -> str:
157156
messages.
158157
'''
159158
# pylint: disable=import-outside-toplevel
160-
from psyclone.psyir.nodes import Statement
159+
from psyclone.psyir.nodes import Assignment
161160
from psyclone.psyir.symbols import Symbol
162161
if isinstance(self.node, Symbol):
163162
text = f"the definition of Symbol '{self.node}'"
164163
else:
165-
stmt = self.node.ancestor(Statement, include_self=True)
166-
if stmt:
167-
text = f"'{stmt.debug_string()}'"
164+
from psyclone.psyGen import CodedKern
165+
kernel = self.node.ancestor(CodedKern, include_self=True)
166+
stmt = self.node.ancestor(Assignment, include_self=True)
167+
if kernel:
168+
text = f"'{self.node.debug_string()}' (inside '{kernel.name})'"
169+
elif stmt:
170+
text = (f"'{self.node.debug_string()}' "
171+
f"in '{stmt.debug_string().strip()}'")
168172
else:
169173
text = f"'{self.node.debug_string()}'"
170174
return text

src/psyclone/psyir/nodes/omp_directives.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,19 +1353,18 @@ def lower_to_language_level(self) -> Node:
13531353
)
13541354
self.dir_body.addchild(assignment, 0)
13551355

1356-
# Lower the first two children
1357-
for child in self.children[:2]:
1358-
child.lower_to_language_level()
1359-
1360-
# Create data sharing clauses (order alphabetically to make generation
1361-
# reproducible)
1356+
# Create data sharing clauses (before lowering, so the CodedKern
1357+
# semantics are taken into account)
13621358
private, fprivate, need_sync = self.infer_sharing_attributes()
1359+
1360+
# Order the clause variables alphabetically (to facilitate comparisons)
13631361
if reprod_red_call_list:
13641362
private.add(thread_idx)
13651363
private_clause = OMPPrivateClause.create(
13661364
sorted(private, key=lambda x: x.name))
13671365
fprivate_clause = OMPFirstprivateClause.create(
13681366
sorted(fprivate, key=lambda x: x.name))
1367+
13691368
# Check all of the need_sync nodes are synchronized in children.
13701369
# unless it has reduction_kernels which are handled separately
13711370
sync_clauses = self.walk(OMPDependClause)
@@ -1390,10 +1389,14 @@ def lower_to_language_level(self) -> Node:
13901389
self.children[2].replace_with(private_clause)
13911390
self.children[3].replace_with(fprivate_clause)
13921391

1392+
# Continue lowering children (but not the clauses we just added)
1393+
for child in self.children[:2]:
1394+
child.lower_to_language_level()
1395+
1396+
# Now finish the LFRic reductions (which need lowering first)
13931397
if reduction_kernels and not reprod_red_call_list:
1394-
self._add_reduction_clauses(need_sync=need_sync)
1398+
self._add_reduction_clauses()
13951399

1396-
# Now finish the reproducible reductions
13971400
for call in reversed(reprod_red_call_list):
13981401
call.reduction_sum_loop(self.parent, self.position,
13991402
self.scope.symbol_table)

src/psyclone/psyir/tools/dependency_tools.py

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def __init__(self, message, code, var_names=None, var_infos=None):
109109
# ------------------------------------------------------------------------
110110
def __str__(self):
111111
if len(self._var_names) == 0:
112-
return self._message
112+
return str(self._message)
113113
if len(self._var_names) == 1:
114114
return f"{self._message} Variable: '{self._var_names[0].strip()}'."
115115
return f"{self._message} Variables: {self._var_names}."
@@ -227,8 +227,9 @@ def _add_message(self, message, code, var_names=None, var_infos=None):
227227
"The var_infos argument to _add_message must "
228228
"be a list of Signature/AccessSequence pairs")
229229

230-
self._messages.append(Message(f"{message_type}: {message}", code,
231-
var_names, var_infos))
230+
self._messages.append(Message(
231+
LazyString(lambda: f"{message_type}: {message}"),
232+
code, var_names, var_infos))
232233

233234
# -------------------------------------------------------------------------
234235
def get_all_messages(self):
@@ -738,37 +739,35 @@ def _array_access_parallelisable(self, loop_variables, var_info):
738739
if not self._is_loop_carried_dependency(loop_variables,
739740
write_access,
740741
other_access):
742+
# We can capture the loop variable 'write_access' and
743+
# 'other_access' in the lambdas because we immidiately
744+
# return after creating the lambdas, not allowing the
745+
# variables to be redefined anymore.
746+
# pylint: disable=cell-var-from-loop
747+
741748
# There is a dependency. Try to give precise error
742749
# messages:
743750
if write_access is other_access:
744751
# The write access has a dependency on itself, e.g.
745752
# a(3) = ... or a((i-2)**2) = ...
746753
# Both would result in a write-write conflict
747-
node = write_access.node
748-
self._add_message(
749-
f"The write access to '{var_info.var_name}' in "
750-
f"'{node.debug_string()}' causes "
751-
f"a write-write race condition.",
754+
self._add_message(LazyString(
755+
lambda:
756+
(f"The write access to "
757+
f"{write_access.description} "
758+
f"causes a write-write race condition.")),
752759
DTCode.ERROR_WRITE_WRITE_RACE,
753760
[var_info.var_name])
754761
else:
755762
# Get 'read' or 'write' etc
756763
access_type = str(other_access.access_type).lower()
757764

758-
# We need to use default parameters for wnode and
759-
# onode, since otherwise the value of a variable might
760-
# be different when the message is actually evaluated.
761-
# Some pylint version complain here (because of the
762-
# above). The code is correct, so disable this
763-
# message:
764-
# pylint: disable=cell-var-from-loop
765765
self._add_message(LazyString(
766-
lambda wnode=write_access.node,
767-
onode=other_access.node:
766+
lambda:
768767
(f"The write access to "
769-
f"'{wnode.debug_string().strip()}' and the "
768+
f"{write_access.description} and the "
770769
f"{access_type} access to "
771-
f"'{onode.debug_string().strip()}' "
770+
f"{other_access.description} "
772771
f"are dependent and cannot be "
773772
f"parallelised.")),
774773
DTCode.ERROR_DEPENDENCY,

src/psyclone/tests/core/access_sequence_test.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from psyclone.psyir.nodes import (
4848
Assignment, Node, Reference, Return, ArrayReference)
4949
from psyclone.psyir.symbols import DataSymbol, INTEGER_TYPE, Symbol
50+
from psyclone.psyGen import CodedKern
5051

5152

5253
def test_access_info() -> None:
@@ -141,6 +142,26 @@ def test_access_info_description() -> None:
141142
assert ("definition of symbol 'test: datasymbol<scalar" in
142143
ainfo.description.lower())
143144

145+
# Assignment has a special description to provide more context
146+
ref1 = Reference(osym)
147+
ref2 = Reference(asym)
148+
assign = Assignment.create(ref1, ref2)
149+
ainfo = AccessInfo(AccessType.READ, ref2)
150+
assert "'test' in 'something = test'" in ainfo.description
151+
152+
# CodedKernel has a special description to provide more context
153+
class MockKern(CodedKern):
154+
''' Create a API agnostic subclass of CodedKern '''
155+
name = "kernel_name"
156+
157+
def __init__(self):
158+
Node.__init__(self)
159+
160+
mk = MockKern()
161+
mk._children = [assign]
162+
assign._parent = mk
163+
assert "'test' (inside 'kernel_name)'" in ainfo.description
164+
144165

145166
# -----------------------------------------------------------------------------
146167
def test_variable_access_sequence() -> None:

src/psyclone/tests/domain/gocean/transformations/gocean1p0_transformations_test.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import pytest
4444
from psyclone.configuration import Config
4545
from psyclone.domain.gocean.transformations import GOceanLoopFuseTrans
46+
from psyclone.domain.common.transformations import KernelModuleInlineTrans
4647
from psyclone.errors import GenerationError
4748
from psyclone.gocean1p0 import GOKern
4849
from psyclone.parse import ModuleManager
@@ -103,7 +104,7 @@ def test_loop_fuse_error():
103104
assert "Both nodes must be of the same GOLoop class." in str(err.value)
104105

105106

106-
def test_omp_parallel_loop(tmpdir, fortran_writer):
107+
def test_omp_paralleldo_loop(tmpdir, fortran_writer):
107108
'''Test that we can generate an OMP PARALLEL DO correctly,
108109
independent of whether or not we are generating constant loop bounds '''
109110
psy, invoke = get_invoke("single_invoke_three_kernels.f90", API, idx=0,
@@ -176,7 +177,7 @@ def test_omp_region_with_single_loop(tmpdir):
176177
within_omp_region = False
177178
call_count = 0
178179
for line in gen.split('\n'):
179-
if '!$omp parallel' in line:
180+
if '!$omp parallel default(shared) private(i,j)' in line:
180181
within_omp_region = True
181182
if '!$omp end parallel' in line:
182183
within_omp_region = False
@@ -192,7 +193,7 @@ def test_omp_region_with_single_loop(tmpdir):
192193
within_omp_region = False
193194
call_count = 0
194195
for line in gen.split('\n'):
195-
if '!$omp parallel' in line:
196+
if '!$omp parallel default(shared) private(i,j)' in line:
196197
within_omp_region = True
197198
if '!$omp end parallel' in line:
198199
within_omp_region = False
@@ -222,7 +223,7 @@ def test_omp_region_with_slice(tmpdir):
222223
within_omp_region = False
223224
call_count = 0
224225
for line in gen.split('\n'):
225-
if '!$omp parallel' in line:
226+
if '!$omp parallel default(shared) private(i,j)' in line:
226227
within_omp_region = True
227228
if '!$omp end parallel' in line:
228229
within_omp_region = False
@@ -288,7 +289,7 @@ def test_omp_region_no_slice(tmpdir):
288289
within_omp_region = False
289290
call_count = 0
290291
for line in gen.split('\n'):
291-
if '!$omp parallel' in line:
292+
if '!$omp parallel default(shared) private(i,j)' in line:
292293
within_omp_region = True
293294
if '!$omp end parallel' in line:
294295
within_omp_region = False
@@ -319,7 +320,7 @@ def test_omp_region_no_slice_const_bounds(tmpdir):
319320
within_omp_region = False
320321
call_count = 0
321322
for line in gen.split('\n'):
322-
if '!$omp parallel' in line:
323+
if '!$omp parallel default(shared) private(i,j)' in line:
323324
within_omp_region = True
324325
if '!$omp end parallel' in line:
325326
within_omp_region = False
@@ -452,6 +453,14 @@ def test_omp_region_retains_kernel_order3(tmpdir):
452453

453454
# Kernels should be in order {compute_cu, compute_cv, time_smooth}
454455
assert cu_idx < cv_idx < ts_idx
456+
457+
# Check that the two directive are different statements in above the
458+
# second loop (iterates over cv_fld internal) and that the private
459+
# clause (now on the parallel directive) only has i and j.
460+
assert ("!$omp parallel default(shared) private(i,j)\n"
461+
" !$omp do schedule(static)\n"
462+
" do j = cv_fld%internal%ystart" in gen)
463+
455464
assert GOceanBuild(tmpdir).code_compiles(psy)
456465

457466

@@ -482,7 +491,7 @@ def test_omp_region_before_loops_trans(tmpdir):
482491
omp_region_idx = -1
483492
omp_do_idx = -1
484493
for idx, line in enumerate(gen.split('\n')):
485-
if '!$omp parallel' in line:
494+
if '!$omp parallel default(shared) private(i,j)' in line:
486495
omp_region_idx = idx
487496
if '!$omp do' in line:
488497
omp_do_idx = idx
@@ -502,6 +511,11 @@ def test_omp_region_after_loops_trans(tmpdir):
502511
dist_mem=False)
503512
schedule = invoke.schedule
504513

514+
# We test with inlining because in the past we had an error when
515+
# producing the clauses if the calls were inlined.
516+
for kern in schedule.kernels():
517+
KernelModuleInlineTrans().apply(kern)
518+
505519
# Put an OpenMP do directive around each loop contained
506520
# in the schedule
507521
ompl = GOceanOMPLoopTrans()
@@ -519,7 +533,7 @@ def test_omp_region_after_loops_trans(tmpdir):
519533
omp_region_idx = -1
520534
omp_do_idx = -1
521535
for idx, line in enumerate(gen.split('\n')):
522-
if '!$omp parallel' in line:
536+
if '!$omp parallel default(shared) private(i,j)' in line:
523537
omp_region_idx = idx
524538
if '!$omp do' in line:
525539
omp_do_idx = idx

src/psyclone/tests/domain/gocean/transformations/gocean_move_iteration_boundaries_inside_kernel_trans_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ def test_go_move_iteration_boundaries_inside_kernel_two_kernels_apply_twice(
207207
ystop_1 = SIZE(uold_fld%data, dim=2)
208208
do j = 1, SIZE(uold_fld%data, dim=2), 1
209209
do i = 1, SIZE(uold_fld%data, dim=1), 1
210-
call time_smooth_code(i, j, u_fld%data, unew_fld%data, uold_fld%data, \
210+
call time_smooth_code(i, j, cu_fld%data, unew_fld%data, uold_fld%data, \
211211
xstart_1, xstop_1, ystart_1, ystop_1)
212212
enddo
213213
enddo

src/psyclone/tests/domain/gocean/transformations/gocean_opencl_trans_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ def test_set_kern_args(kernel_outputdir):
10471047

10481048
# There is also only one version of the set_args for the second kernel
10491049
assert generated_code.count("subroutine time_smooth_code_set_args("
1050-
"kernel_obj, u_fld, unew_fld, uold_fld, "
1050+
"kernel_obj, cu_fld, unew_fld, uold_fld, "
10511051
"xstart_1, xstop_1, ystart_1, ystop_1)") == 1
10521052
assert GOceanOpenCLBuild(kernel_outputdir).code_compiles(psy)
10531053

src/psyclone/tests/gocean1p0_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def test_two_kernels(tmpdir, dist_mem):
155155
second_kernel = (
156156
" do j = 1, SIZE(uold_fld%data, dim=2), 1\n"
157157
" do i = 1, SIZE(uold_fld%data, dim=1), 1\n"
158-
" call time_smooth_code(i, j, u_fld%data, unew_fld%data, "
158+
" call time_smooth_code(i, j, cu_fld%data, unew_fld%data, "
159159
"uold_fld%data)\n"
160160
" enddo\n"
161161
" enddo\n\n"

0 commit comments

Comments
 (0)