Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into 2617_generic_functi…
Browse files Browse the repository at this point in the history
…on_on_master
  • Loading branch information
hiker committed Jul 11, 2024
2 parents 9b6b693 + 81babb1 commit 2a1f3eb
Show file tree
Hide file tree
Showing 59 changed files with 1,183 additions and 539 deletions.
10 changes: 10 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,16 @@
55) PR #2445 for #2444. Changes the kernel-extraction tooling so
that filenames are construction using dashes instead of colons.

56) PR #2646 for #2641. Fixes incorrect module names within the
PSyData API (e.g. when profiling).

57) PR #2647 for #1992. Adds MPI support to PSyKE. Each rank will write
its own output file(s). The generated driver has been extended so that
the name of the file to use can be specified on the command line.

58) PR #2637 for #2138. Add Fortran frontend support to parser array
declarations with expressions in their shape dimensions.

release 2.5.0 14th of February 2024

1) PR #2199 for #2189. Fix bugs with missing maps in enter data
Expand Down
183 changes: 86 additions & 97 deletions doc/user_guide/profiling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -462,14 +462,30 @@ The automatic name generation depends on whether you are using a
PSyKAl DSL or only the transformation capabilities of PSyclone. If
you are transforming existing code:

* the ``module_name`` string is set to the name of the parent
function/subroutine/program. This name is unique as Fortran requires
* the ``module_name`` string is set to the module which contains the
current code. If there is no module (e.g. a stand-alone subroutine),
the subroutine name is used instead. This name is unique as Fortran requires
these names to be unique within a program.

* the ``region_name`` is set to an ``r`` (standing for region) followed by
an integer which uniquely identifies the profile within the parent
function/subroutine/program (based on the profile node's position in
the PSyIR representation relative to any other profile nodes).
* the ``region_name`` is set to the name of the subroutine, followed by
an ``r`` (standing for region) followed by an integer which uniquely identifies
the profile within the parent function/subroutine/program (based on the
profile node's position in the PSyIR representation relative to any other
profile nodes). If there is no module name (which means the ``module_name``
is already set to the subroutine name), only the ``r`` followed by an
integer number is specified.

Example:
.. code-block::
:caption: Profiling names used when transforming existing code.
:emphasize-lines: 2,4
! If the subroutine tra_adv is contained in module tra_adv_mod:
CALL profile_psy_data % PreStart("tra_adv_mod", "tra_adv-r0", 0, 0)
! If the subroutinetra_adv is not contained in a module:
CALL profile_psy_data % PreStart("tra_adv", "r0", 0, 0)
For the :ref:`LFRic <lfric-api>` and
:ref:`GOcean <gocean-api>` APIs:
Expand All @@ -486,96 +502,69 @@ For the :ref:`LFRic <lfric-api>` and
node's position in the PSyIR representation relative to any other
profile nodes). For example:

.. code-block::
:caption: PSyIR with profiling nodes.
:emphasize-lines: 2
InvokeSchedule[invoke='invoke_0', dm=True]
0: Profile[]
Schedule[]
0: Profile[]
Schedule[]
0: HaloExchange[field='f2', type='region', depth=1,
check_dirty=True]
1: HaloExchange[field='m1', type='region', depth=1,
check_dirty=True]
2: HaloExchange[field='m2', type='region', depth=1,
check_dirty=True]
1: Profile[]
Schedule[]
0: Loop[type='', field_space='w1', it_space='cells',
upper_bound='cell_halo(1)']
Literal[value:'1', DataType.INTEGER]
Literal[value:'mesh%get_last_halo_cell(1)',
DataType.INTEGER]
Literal[value:'1', DataType.INTEGER]
Schedule[]
0: CodedKern testkern_code(a,f1,f2,m1,m2)
[module_inline=False]
1: Profile[]
Schedule[]
0: Loop[type='', field_space='w1',
it_space='cells',
upper_bound='cell_halo(1)']
Literal[value:'1', DataType.INTEGER]
Literal[value:'mesh%get_last_halo_cell(1)',
DataType.INTEGER]
Literal[value:'1', DataType.INTEGER]
Schedule[]
0: CodedKern testkern_code(a,f1,f2,m1,m2)
[module_inline=False]
2: Loop[type='', field_space='w1', it_space='cells',
upper_bound='cell_halo(1)']
Literal[value:'1', DataType.INTEGER]
Literal[value:'mesh%get_last_halo_cell(1)', DataType.INTEGER]
Literal[value:'1', DataType.INTEGER]
Schedule[]
0: CodedKern testkern_qr_code(f1,f2,m1,a,m2,istp)
[module_inline=False]
This is the code created for this example:

.. code-block::
:caption: Created Fortran source code with profiling regions.
:emphasize-lines: 5,6,7,18,19,24,25
MODULE container
CONTAINS
SUBROUTINE invoke_0(a, f1, f2, m1, m2, istp, qr)
...
CALL psy_data_3%PreStart("multi_functions_multi_invokes_psy", "invoke_0-r0", &
.. code-block::
:caption: PSyIR with profiling nodes.
:emphasize-lines: 2,4,12
InvokeSchedule[invoke='invoke_0', dm=True]
0: Profile[]
Schedule[]
0: Profile[]
Schedule[]
0: HaloExchange[field='f2', type='region', depth=1,
check_dirty=True]
1: HaloExchange[field='m1', type='region', depth=1,
check_dirty=True]
2: HaloExchange[field='m2', type='region', depth=1,
check_dirty=True]
1: Profile[]
Schedule[]
0: Loop[type='', field_space='w1', it_space='cells',
upper_bound='cell_halo(1)']
Literal[value:'1', DataType.INTEGER]
Literal[value:'mesh%get_last_halo_cell(1)',
DataType.INTEGER]
Literal[value:'1', DataType.INTEGER]
Schedule[]
0: CodedKern testkern_code(a,f1,f2,m1,m2)
[module_inline=False]
This is the code created for this example:

.. code-block::
:caption: Created Fortran source code with profiling regions.
:emphasize-lines: 5,6,7,17,18,19,24,30
MODULE container
CONTAINS
SUBROUTINE invoke_0(a, f1, f2, m1, m2, istp, qr)
...
CALL psy_data_2%PreStart("multi_functions_multi_invokes_psy", "invoke_0-r0", &
0, 0)
CALL psy_data%PreStart("multi_functions_multi_invokes_psy", "invoke_0-r1", 0, 0)
IF (f2_proxy%is_dirty(depth=1)) THEN
CALL f2_proxy%halo_exchange(depth=1)
END IF
IF (m1_proxy%is_dirty(depth=1)) THEN
CALL m1_proxy%halo_exchange(depth=1)
END IF
IF (m2_proxy%is_dirty(depth=1)) THEN
CALL m2_proxy%halo_exchange(depth=1)
END IF
CALL psy_data%PreEnd()
CALL psy_data_1%PreStart("multi_functions_multi_invokes_psy", "invoke_0-r2", &
CALL psy_data%PreStart("multi_functions_multi_invokes_psy", "invoke_0-r1", 0, 0)
IF (f2_proxy%is_dirty(depth=1)) THEN
CALL f2_proxy%halo_exchange(depth=1)
END IF
IF (m1_proxy%is_dirty(depth=1)) THEN
CALL m1_proxy%halo_exchange(depth=1)
END IF
IF (m2_proxy%is_dirty(depth=1)) THEN
CALL m2_proxy%halo_exchange(depth=1)
END IF
CALL psy_data%PreEnd()
CALL psy_data_1%PreStart("multi_functions_multi_invokes_psy", "invoke_0-r2", &
0, 0)
DO cell=1,mesh%get_last_halo_cell(1)
CALL testkern_code(...)
END DO
...
CALL psy_data_2%PreStart("multi_functions_multi_invokes_psy", &
"invoke_0-testkern_code-r3", 0, 0)
DO cell=1,mesh%get_last_halo_cell(1)
CALL testkern_code(...)
END DO
...
CALL psy_data_2%PostEnd()
CALL psy_data_1%PostEnd()
...
DO cell=1,mesh%get_last_halo_cell(1)
CALL testkern_qr_code(...)
END DO
...
CALL psy_data_3%PostEnd()
...
END SUBROUTINE invoke_0
END MODULE container
DO cell=1,mesh%get_last_halo_cell(1)
CALL testkern_code(...)
END DO
CALL psy_data_1%PostEnd()
...
DO cell=1,mesh%get_last_halo_cell(1)
CALL testkern_qr_code(...)
END DO
...
CALL psy_data_2%PostEnd()
...
END SUBROUTINE invoke_0
END MODULE container
30 changes: 25 additions & 5 deletions doc/user_guide/psyke.rst
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,16 @@ are used or not.
Distributed memory
##################

As noted in the :ref:`PSyKAl Introduction <introduction_to_psykal>` section,
PSyKAl can support distributed memory. However, since the generated PSy-layer
code with DM enabled contains infrastructure calls (e.g. checks for runtime
status of field halos, halo exchanges etc.), code extraction is not allowed
when distributed memory is enabled.
Kernel extraction for distributed memory is supported in as much as each
process will write its own output file by adding its rank to the output
file name. So each kernel and each rank will produce one file. It is possible
to extract several consecutive kernels, but there must be no halo exchange
calls between the kernels. The extraction transformation will test for this
and raise an exception if this should happen.
The compiled driver program accepts the name of the extracted kernel file as
a command line parameter. If this is not specified, it will use the default
name (``module-region`` without a rank).


.. _psyke-intro-restrictions-shared:

Expand All @@ -176,6 +181,8 @@ The ``ExtractTrans`` transformation cannot be applied to:

* An inner Loop without its parent outer Loop in the GOcean API.

* Kernels that have a halo exchange call between them.

.. _psyke-use:

Use
Expand Down Expand Up @@ -381,6 +388,19 @@ and in
`lib/extract/netcdf
<https://github.com/stfc/PSyclone/tree/master/lib/extract/netcdf>`_.

All versions of the extraction libraries can be compiled with MPI
support by setting the variable ``MPI=yes``:

.. code-block:: shell
make MPI=yes ...
The only difference is that the output files will now have the process
rank in the name. The compiled driver program accepts the name of the
extracted kernel file as a command line parameter. If this is not specified,
it will use the default name (``module-region`` without a rank).


.. _extraction_for_gocean:

Extraction for GOcean
Expand Down
1 change: 1 addition & 0 deletions examples/gocean/eg5/extract/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
alg.f90
psy.f90
test.x90
extract_test.standalone
extract_test.netcdf
*.nc
Expand Down
17 changes: 16 additions & 1 deletion examples/gocean/eg5/extract/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@
# The dl_esm_inf extract wrapper library:
# export EXTRACT_DIR = ../../../../lib/extract/netcdf/dl_esm_inf

MPI?=no

ifeq ($(MPI), yes)
# -P suppresses linemarkers
FPP?=cpp -P -D_MPI
# We need to compile with mpif90 if MPI is enabled
F90?=mpif90
else
FPP?=cpp -P
endif

PSYROOT=../../../..
include $(PSYROOT)/examples/common.mk

Expand All @@ -51,7 +62,8 @@ TYPE?=standalone

GENERATED_FILES += *.o *.mod $(NAME) alg.f90 psy.f90 \
$(DRIVER_INIT).$(TYPE) $(DRIVER_INIT).f90 \
$(DRIVER_UPDATE).$(TYPE) $(DRIVER_UPDATE).f90
$(DRIVER_UPDATE).$(TYPE) $(DRIVER_UPDATE).f90 \
main.x90

# Location of the infrastucture code (which is a submodule of the
# PSyclone git repo).
Expand Down Expand Up @@ -142,6 +154,9 @@ $(KERNELS): $(INF_LIB)
%.o: %.f90
$(F90) $(F90FLAGS) -c $<

%.x90: %.X90
$(FPP) $< >$@

# This target requires that the netcdf (Fortran) development package be
# installed
$(EXTRACT_DIR)/lib_kernel_data_netcdf.a:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
Program test
!> This program is a simple gocean program that contains two invokes,
!> the first to initialise a few fields, the second to update a field.
!> It can be used with kernel extraction for both invokes. After
!> instrumenting the code using PSyclone with the extract_transform.py
!> script, it can be compiled, and when executed will create two kernel data
!> files. The instrumentation will also create two stand-alone driver
!> programs, which can be compiled. They will each read the corresponding
!> kernel data file, execute the kernel, and compare the results.

#ifdef _MPI
use mpi
#endif
USE field_mod
USE grid_mod
use decomposition_mod, only : decomposition_type
Expand All @@ -17,6 +29,11 @@ Program test
! interface does not provide a method for single precision).
real(kind=kind(1.0d0)) :: z
TYPE(grid_type), target :: grid
#ifdef _MPI
integer :: ierr

call MPI_Init(ierr)
#endif

call parallel_init()
call extract_PSyDataInit()
Expand All @@ -42,4 +59,9 @@ Program test

print *,a_fld%data(1:5, 1:5)
call extract_PSyDataShutdown()

#ifdef _MPI
call MPI_Finalize(ierr)
#endif

end program test
8 changes: 4 additions & 4 deletions examples/gocean/eg5/profile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ library, you should see:
...
profile_PSyDataInit called
...
PreStart called for module 'invoke_0' region 'r0'
PostEnd called for module 'invoke_0' region 'r0'
PreStart called for module 'invoke_1_update_field' region 'r0'
PostEnd called for module 'invoke_1_update_field' region 'r0'
PreStart called for module 'psy_test' region 'invoke_0-r0'
PostEnd called for module 'psy_test' region 'invoke_0-r0'
PreStart called for module 'psy_test' region 'invoke_1_update_field-r0'
PostEnd called for module 'psy_test' region 'invoke_1_update_field-r0'
...
profile_PSyDataShutdown called
```
Expand Down
8 changes: 4 additions & 4 deletions examples/gocean/eg5/profile/test.x90
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
!> stdout. Expected output:
!>
!> profile_PSyDataInit called
!> PreStart called for module 'psy_test' region 'invoke_0:r0'
!> PostEnd called for module 'psy_test' region 'invoke_0:r0'
!> PreStart called for module 'psy_test' region 'invoke_1_update_field:update_field_code:r0'
!> PostEnd called for module 'psy_test' region 'invoke_1_update_field:update_field_code:r0'
!> PreStart called for module 'psy_test' region 'invoke_0-r0'
!> PostEnd called for module 'psy_test' region 'invoke_0-r0'
!> PreStart called for module 'psy_test' region 'invoke_1_update_field-r0'
!> PostEnd called for module 'psy_test' region 'invoke_1_update_field-r0'

Program test
USE field_mod
Expand Down
1 change: 1 addition & 0 deletions examples/lfric/eg17/full_example_extract/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
extract.standalone
extract.netcdf
main.x90
main_alg.f90
main_psy.f90
main-*.nc
Expand Down
Loading

0 comments on commit 2a1f3eb

Please sign in to comment.